最近项目中遇到网关跨区域转发请求问题,需要根据用户所在区域将请求转发到对应的区域网关,特将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;
}
}