RestTemplate转发请求,支持所有请求类型

最近项目中遇到网关跨区域转发请求问题,需要根据用户所在区域将请求转发到对应的区域网关,特将RestTemplate转发请求代码整理出来,供后续学习参考;

package com.dahua.retailcloud.gateway.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/**
 * 路由代理工具类
 *
 * 将请求重新包装发送
 *
 * 支持所有请求;
 *
 * 支持form-data,表单,文件上传
 *
 * @author pansh
 * @since 2021-12-16 16:37:54
 */
@Slf4j
@Component
public class RoutingDelegateUtil {

    @Resource
    @Qualifier(value = "remoteRestTemplate")
    private RestTemplate restTemplate;

    /**
     * 上传form表单,文件
     */
    private final static String CONTENT_TYPE_FORM = "multipart/form-data;";

    /**
     * 请求转发统一处理
     * @param request
     * @param routeUrl 路由地址,统一前缀
     * @return
     * @throws Exception
     */
    public ResponseEntity<String> redirect(HttpServletRequest request, String routeUrl) throws Exception {
        String contentType = request.getContentType();
        log.info("getContentType={}", contentType);
        // multipart/form-data处理
        if (StringUtils.isNotEmpty(contentType) && contentType.contains(CONTENT_TYPE_FORM)) {
            return redirectFile(request, routeUrl);
        } else {
            return redirect(request, routeUrl, "");
        }
    }

    /**
     * 上传form表单,文件
     *
     * 请求转发处理
     * @param request
     * @param routeUrl
     * @return
     * @throws IOException
     */
    public ResponseEntity<String> redirectFile(HttpServletRequest request, String routeUrl) throws IOException {
        // build up the redirect URL
        String redirectUrl = createRedictUrl(request, routeUrl, "");
        log.info("redirectFile redirectUrl={}", redirectUrl);
        String method = request.getMethod();
        //设置请求头
        MultiValueMap<String, String> headers = parseRequestHeader(request);

        // 组装form参数
        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
        StandardMultipartHttpServletRequest standardMultipartHttpServletRequest = (StandardMultipartHttpServletRequest)request;
        // 组装form参数-文件
        MultiValueMap<String, MultipartFile> multiValueMap = standardMultipartHttpServletRequest.getMultiFileMap();
        for (Map.Entry<String, List<MultipartFile>> entries : multiValueMap.entrySet()) {
            for (MultipartFile multipartFile : entries.getValue()) {
                String fileName = multipartFile.getOriginalFilename();
                log.info("redirectFile MultipartFile: fileName={}", fileName);
                File file = File.createTempFile("spw-", fileName);
                multipartFile.transferTo(file);
                FileSystemResource fileSystemResource = new FileSystemResource(file);
                form.add(entries.getKey(), fileSystemResource);
            }
        }
        // 组装form参数-一般属性
        Enumeration<String> enumeration = standardMultipartHttpServletRequest.getParameterNames();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            String value = standardMultipartHttpServletRequest.getParameter(name);
            log.info("redirectFile enumeration: name={}, value={}", name, value);
            form.add(name, value);
        }

        // 用HttpEntity封装整个请求报文
        HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<>(form, headers);

        return restTemplate.exchange(redirectUrl, HttpMethod.valueOf(method),formEntity,String.class);
    }

    /**
     * 非form-data请求转发处理
     * @param request
     * @param routeUrl
     * @param prefix
     * @return
     * @throws Exception
     */
    public ResponseEntity<String> redirect(HttpServletRequest request, String routeUrl, String prefix) throws Exception {
        // build up the redirect URL
        String redirectUrl = createRedictUrl(request,routeUrl, prefix);
        log.info("redirectUrl={}", redirectUrl);
        RequestEntity requestEntity = createRequestEntity(request, redirectUrl);
        return restTemplate.exchange(requestEntity, String.class);
    }

    /**
     * 构建重定向地址
     * @param request
     * @param routeUrl
     * @param prefix
     * @return
     */
    private String createRedictUrl(HttpServletRequest request, String routeUrl, String prefix) {
        String queryString = request.getQueryString();
        return routeUrl + request.getRequestURI().substring(1, request.getRequestURI().length()).replace(prefix, "") +
                (queryString != null ? "?" + queryString : "");
    }

    /**
     * 构建请求实体
     * @param request
     * @param url
     * @return
     * @throws URISyntaxException
     * @throws IOException
     */
    private RequestEntity createRequestEntity(HttpServletRequest request, String url) throws URISyntaxException, IOException {
        String method = request.getMethod();
        HttpMethod httpMethod = HttpMethod.resolve(method);
        MultiValueMap<String, String> headers = parseRequestHeader(request);
        byte[] body = parseRequestBody(request);
        return new RequestEntity<>(body, headers, httpMethod, new URI(url));
    }

    /**
     * 解析请求体
     * @param request
     * @return
     * @throws IOException
     */
    private byte[] parseRequestBody(HttpServletRequest request) throws IOException {
        InputStream inputStream = request.getInputStream();
        return StreamUtils.copyToByteArray(inputStream);
    }

    /**
     * 解析请求头
     * @param request
     * @return
     */
    private MultiValueMap<String, String> parseRequestHeader(HttpServletRequest request) {
        HttpHeaders headers = new HttpHeaders();
        List<String> headerNames = Collections.list(request.getHeaderNames());
        for (String headerName : headerNames) {
            List<String> headerValues = Collections.list(request.getHeaders(headerName));
            for (String headerValue : headerValues) {
                headers.add(headerName, headerValue);
            }
        }
        return headers;
    }
}

上一篇:Spring RestTemplate


下一篇:《微服务零基础入门教程》一步一步,带你走进微服务的世界