0


spring boot通用转发请求

背景:公司云环境外网访问不了sit环境,但是和外部公司对接的时候需要在sit环境联调,外网无法回调sit环境, 但是公司的生产环境可以请求sit环境

外网回调–》请求生产环境 —》 /test/** 路由转发到sit环境
TestProxyController.java

importlombok.extern.slf4j.Slf4j;importorg.apache.commons.io.FileUtils;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.core.io.FileSystemResource;importorg.springframework.http.HttpEntity;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpMethod;importorg.springframework.http.client.ClientHttpRequest;importorg.springframework.http.client.ClientHttpResponse;importorg.springframework.http.client.SimpleClientHttpRequestFactory;importorg.springframework.http.converter.StringHttpMessageConverter;importorg.springframework.util.LinkedMultiValueMap;importorg.springframework.util.MultiValueMap;importorg.springframework.util.StreamUtils;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.client.RestTemplate;importorg.springframework.web.multipart.MultipartFile;importorg.springframework.web.multipart.MultipartHttpServletRequest;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.ByteArrayInputStream;importjava.io.File;importjava.io.IOException;importjava.io.InputStream;importjava.net.URI;importjava.net.URISyntaxException;importjava.nio.charset.StandardCharsets;importjava.util.ArrayList;importjava.util.Enumeration;importjava.util.List;importjava.util.Map;/**
 * 参考:https://www.jianshu.com/p/450e12a148b1
 * @date 2023/3/15
 */@Slf4j@RestControllerpublicclassTestProxyController{// 内网域名@Value("${test.url:https://x.sit.xxx.com}")privateString targetAddr;privatestaticRestTemplate restTemplate =newRestTemplate();publicstaticRestTemplategetRestemplate(){
        restTemplate.getMessageConverters().set(1,newStringHttpMessageConverter(StandardCharsets.UTF_8));return restTemplate;}/**
     * 代理所有请求
     *
     * @param request
     * @param response
     * @throws Exception
     */@RequestMapping(value ="/test/**")publicvoidproxy(HttpServletRequest request,HttpServletResponse response)throwsIOException,URISyntaxException{// String url = URLDecoder.decode(request.getRequestURL().toString(), "UTF-8");URI uri =newURI(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 =newURI(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 =newArrayList<MultipartFile>(map.values());MultiValueMap<String,Object> params =newLinkedMultiValueMap();for(MultipartFile file : valueList){File newFile =File.createTempFile("temp", file.getOriginalFilename());FileUtils.copyInputStreamToFile(file.getInputStream(), newFile);FileSystemResource resource =newFileSystemResource(newFile);
                params.add(file.getName(), resource);}Enumeration<String> headerNames = request.getHeaderNames();// 设置请求头HttpHeaders headers =newHttpHeaders();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 =newHttpEntity<MultiValueMap<String,Object>>(params, headers);String res =getRestemplate().postForEntity(target, files,String.class).getBody();InputStream is =newByteArrayInputStream(res.getBytes("UTF-8"));
            stream = is;}else{// 其他请求例如get post put delete都可使用ClientHttpRequest delegate =newSimpleClientHttpRequestFactory().createRequest(newUri, httpMethod);Enumeration<String> headerNames = request.getHeaderNames();// 设置请求头while(headerNames.hasMoreElements()){String headerName = headerNames.nextElement();Enumeration<String> v = request.getHeaders(headerName);List<String> arr =newArrayList<>();while(v.hasMoreElements()){
                    arr.add(v.nextElement());}
                delegate.getHeaders().addAll(headerName, arr);}MyRequestWrapper wrapper =newMyRequestWrapper(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方式

importorg.apache.commons.io.IOUtils;importorg.apache.commons.lang3.StringUtils;importjavax.servlet.ReadListener;importjavax.servlet.ServletInputStream;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletRequestWrapper;importjava.io.BufferedReader;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.net.URLEncoder;importjava.nio.charset.Charset;importjava.util.Arrays;importjava.util.Map;publicclassMyRequestWrapperextendsHttpServletRequestWrapper{privatefinalString body;publicMyRequestWrapper(HttpServletRequest request)throwsIOException{super(request);this.body =getBodyString(request);}publicStringgetBody(){return body;}publicstaticStringgetBodyString(finalHttpServletRequest request)throwsIOException{String contentType = request.getContentType();String bodyString ="";StringBuilder sb =newStringBuilder();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{returnIOUtils.toString(request.getInputStream(),Charset.forName("UTF-8"));}}@OverridepublicServletInputStreamgetInputStream()throwsIOException{finalByteArrayInputStream bais =newByteArrayInputStream(body.getBytes());returnnewServletInputStream(){@OverridepublicbooleanisFinished(){returnfalse;}@OverridepublicbooleanisReady(){returnfalse;}@Overridepublicintread(){return bais.read();}@OverridepublicvoidsetReadListener(ReadListener readListener){}};}@OverridepublicBufferedReadergetReader()throwsIOException{returnnewBufferedReader(newInputStreamReader(this.getInputStream()));}}

本文转载自: https://blog.csdn.net/liufang1991/article/details/129559677
版权归原作者 项哥 所有, 如有侵权,请联系我们删除。

“spring boot通用转发请求”的评论:

还没有评论