spring boot通用转发请求

这篇具有很好参考价值的文章主要介绍了spring boot通用转发请求。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot学习笔记(十三)获取HTTP请求参数

    SpringBoot获取参数代码 User类: (1)路径参数 使用@PathVariable获取 (2)URL参数 1、使用@RequestParam获取 2、使用request的getParameter方法获取 3、直接在controller里使用同名的方法参数获取 4、使用实体类的同名属性接收参数 (3)表单参数 获取方式Url参数一样获取。GET请求只能拿到

    2024年02月04日
    浏览(41)
  • Spring Boot进阶(75):从容应对HTTP请求——Spring Boot与OkHttp完美结合

            在现代的Web应用程序中,HTTP请求成为了构建客户端和服务器端之间通信的一个重要手段。Spring Boot是一个灵活的Web框架,它提供了与HTTP请求相关的许多特性和API。OkHttp是一个流行的HTTP客户端库,它提供了面向对象的API,以便开发人员轻松地在其应用中进行HTTP请求

    2024年02月06日
    浏览(33)
  • Spring Boot进阶(72):【教程】用Spring Boot和HttpClient实现高效的HTTP请求

      随着系统规模的不断扩大和复杂度的提升,异步通信这种模式越来越被广泛应用于各种分布式系统中。RocketMQ作为一个高性能、高可靠性、分布式消息队列,得到了众多企业的青睐。本文将介绍如何使用Spring Boot整合RocketMQ,实现异步通信。   那么,具体如何实现呢?这

    2024年02月09日
    浏览(36)
  • spring boot请求http接口的三种方式

    HttpURLConnection 是 Java 中的 HTTP 客户端实现,,适用于简单的请求需要。 HttpURLConnection主要工作内容:打开socket连接,封装http请求报文,解析请求报文。 OkHttp 是一个第三方的 HTTP 客户端库,它比 Java 标准的 HttpURLConnection 更高效、更实用。主要特点包括: 比 HttpURLConnection 快得多

    2024年02月14日
    浏览(51)
  • 【SpringBoot应用篇】Spring Boot 配置HTTP 响应内容压缩

    5、默认情况下,要执行压缩,响应的长度至少为 2048 字节,可以通过 server.compression.min-response-size 属性配置。 6、默认情况下,仅当响应的内容类型为以下内容之一时,才会对其进行压缩,可以通过 mime-types 属性配置:text/html,text/xml,text/plain,text/css,text/javascript,application/javasc

    2024年02月16日
    浏览(35)
  • SpringBoot项目报错:java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getHttpServletMapp

    技术版本: SpringBoot2.04 错误场景描述: 项目可以正常启动,但后台接口一被请求就报下面这个错误: 原因分析: 1、Tomcat版本问题。 2、jar包冲突,具体是servlet-api这个jar包。 解决方案: 1、SringBoot项目使用的是内置Tomcat,如果本地的pom文件中引入了servlet-api依赖,删掉这个

    2024年02月12日
    浏览(32)
  • Spring Boot各版本与Java版本的对应兼容关系,与构建工具(Maven、Gradle)版本的对应兼容关系,对servlet 容器的支持

    by:垃圾程序员 当前文章具有时效性,在当前springboot的版本下做的整合。之后大家视情况可以直接到Spring的官网查看 Spring | Home Level up your Java code and explore what Spring can do for you. https://spring.io/ 下面是Spring Boot各个版本的支持时间 下面是Spring Boot 推荐使用的各个版面,并标注出

    2024年02月10日
    浏览(34)
  • Caddy反向代理转发修改http请求路径

    Caddy是个非常不错的开源服务器产品,简单易用,自带ssl。只是没啥详细的中文文档,遇到问题只能看官方文档。 记录一下使用Caddy转发http请求的方法。 问题:将http://192.168.1.10:7077/product/*的请求转发到http://192.168.1.12:7078/*。这里其实是两个需求,一个是转发端口,还有个是去

    2024年02月12日
    浏览(36)
  • nginx 如何将 https 请求转发到 http

    网站之前是 https 的,通过 nginx 设置好了,现在不想用 https 了,但发散到外界的一些网址还是 https 的,此时只能通过 nginx 去转发 https 请求到 http 才能实现之前的链接能正常访问。 具体设置如下: https 的其它设置不需要动,只需要在 server 字段添加一条:

    2024年02月11日
    浏览(42)
  • 如何实现Http请求报头的自动转发之设计

    HeaderForwarder组件不仅能够从当前接收请求提取指定的HTTP报头,并自动将其添加到任何一个通过HttpClient发出的请求中,它同时也提供了一种基于Context/ContextScope的编程模式是我们可以很方便地将任何报头添加到指定范围内的所有由HttpClient发出的请求中。现在我们来简单聊聊该

    2024年02月09日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包