背景:公司云环境外网访问不了sit环境,但是和外部公司对接的时候需要在sit环境联调,外网无法回调sit环境, 但是公司的生产环境可以请求sit环境
外网回调–》请求生产环境 —》 /test/** 路由转发到sit环境
TestProxyController.java文章来源:https://www.toymoban.com/news/detail-566292.html
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
/**
* 参考:https://www.jianshu.com/p/450e12a148b1
* @date 2023/3/15
*/
@Slf4j
@RestController
public class TestProxyController {
// 内网域名
@Value("${test.url:https://x.sit.xxx.com}")
private String targetAddr;
private static RestTemplate restTemplate = new RestTemplate();
public static RestTemplate getRestemplate(){
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
return restTemplate;
}
/**
* 代理所有请求
*
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value = "/test/**")
public void proxy(HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException {
// String url = URLDecoder.decode(request.getRequestURL().toString(), "UTF-8");
URI uri = new URI(request.getRequestURI());
String path = uri.getPath();
String query = request.getQueryString();
String target = targetAddr + path.replace("/test", "");
if (query != null && !query.equals("") && !query.equals("null")) {
target = target + "?" + query;
}
log.info("testProxy target:{}", target);
URI newUri = new URI(target);
// 执行代理查询
String methodName = request.getMethod();
HttpMethod httpMethod = HttpMethod.resolve(methodName);
if (httpMethod == null) {
return;
}
InputStream stream = null;
String contentType = request.getContentType();
log.info("testProxy target:{}, contentType:{}", target, contentType);
// 兼容文件上传的请求
if (contentType != null && contentType.startsWith("multipart/form-data")) {
MultipartHttpServletRequest mulReq = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> map = mulReq.getFileMap();
List<MultipartFile> valueList = new ArrayList<MultipartFile>(map.values());
MultiValueMap<String, Object> params = new LinkedMultiValueMap();
for (MultipartFile file : valueList) {
File newFile = File.createTempFile("temp", file.getOriginalFilename());
FileUtils.copyInputStreamToFile(file.getInputStream(), newFile);
FileSystemResource resource = new FileSystemResource(newFile);
params.add(file.getName(), resource);
}
Enumeration<String> headerNames = request.getHeaderNames();
// 设置请求头
HttpHeaders headers = new HttpHeaders();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.set(headerName, request.getHeader(headerName));
}
// 手动设置请求头的token信息
headers.set("Authorization", request.getHeader("Authorization"));
// 用HttpEntity封装整个请求报文
HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<MultiValueMap<String, Object>>(params, headers);
String res = getRestemplate().postForEntity(target, files, String.class).getBody();
InputStream is = new ByteArrayInputStream(res.getBytes("UTF-8"));
stream = is;
} else {
// 其他请求例如get post put delete都可使用
ClientHttpRequest delegate = new SimpleClientHttpRequestFactory().createRequest(newUri, httpMethod);
Enumeration<String> headerNames = request.getHeaderNames();
// 设置请求头
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
Enumeration<String> v = request.getHeaders(headerName);
List<String> arr = new ArrayList<>();
while (v.hasMoreElements()) {
arr.add(v.nextElement());
}
delegate.getHeaders().addAll(headerName, arr);
}
MyRequestWrapper wrapper = new MyRequestWrapper(request);
StreamUtils.copy(wrapper.getInputStream(), delegate.getBody());
log.info("testProxy target:{}, proxyBody:{}", target, wrapper.getBody());
// 执行远程调用
ClientHttpResponse clientHttpResponse = delegate.execute();
response.setStatus(clientHttpResponse.getStatusCode().value());
// 设置响应头
clientHttpResponse.getHeaders().forEach((key, value) -> value.forEach(it -> {
// Spring boot框架会自己添加请求头,不过滤Transfer-Encoding和Content-Length可能会影响代理结果
if(!key.equalsIgnoreCase("Transfer-Encoding") && !key.equalsIgnoreCase("Content-Length")) {
response.setHeader(key, it);
}
}));
stream = clientHttpResponse.getBody();
}
// 将获取到的输入流再次输出到页面输出流中
StreamUtils.copy(stream, response.getOutputStream());
}
}
MyRequestWrapper.java,兼容x-www-form-urlencoded方式文章来源地址https://www.toymoban.com/news/detail-566292.html
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Map;
public class MyRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public MyRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.body = getBodyString(request);
}
public String getBody() {
return body;
}
public static String getBodyString(final HttpServletRequest request) throws IOException {
String contentType = request.getContentType();
String bodyString = "";
StringBuilder sb = new StringBuilder();
if (StringUtils.isNotBlank(contentType) && (contentType.contains("multipart/form-data") || contentType.contains("x-www-form-urlencoded"))) {
Map<String, String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> next : parameterMap.entrySet()) {
String[] values = next.getValue();
String value = null;
if (values != null) {
if (values.length == 1) {
value = values[0];
} else {
value = Arrays.toString(values);
}
}
sb.append(next.getKey()).append("=").append(URLEncoder.encode(value, "utf8")).append("&");
}
if (sb.length() > 0) {
bodyString = sb.toString().substring(0, sb.toString().length() - 1);
}
return bodyString;
} else {
return IOUtils.toString(request.getInputStream(), Charset.forName("UTF-8"));
}
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes());
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public int read() {
return bais.read();
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
到了这里,关于spring boot通用转发请求的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!