利用SpringBoot中的RestTemplate实现反向代理

SpringBoot调用高德地图IP定位API (RestTemplate) 奇怪的目录增加了!前言正文了解API接口编写代码完成依赖注入获取用户IP向API接口发送请求后记 前言 各位读者好久不见,由于最近都在摸鱼 准备明年的春招以及去尝试一下校招,所以这一个多月都没在写博客。言归正传,最近手头一个项目有一个要求,要求记录访问者的ip信息和访问的页面等信息,所以我采用了高德地图的IP定位API。 高德地图IP定位API https://lbs.amap.com/api/webservice/guide/api/ipconfig/ 正文 在这里其实有如下两种选择: 工具类的方式 阅读详情

今天分享另一种利用RestTemplate客户端工具来实现简单而高效的反向代理功能,底层无论使用哪种web服务均可使用。

什么是反向代理

反向代理是指以代理服务器接收客户端请求,然后将请求转发给内部服务器,并将内部服务器的响应返回给客户端。

客户端只与反向代理服务器通信,不直接访问内部服务器。

为什么选择RestTemplate实现反向代理

集成便捷:RestTemplate是Spring框架的核心组件,在SpringBoot项目中使用非常方便 功能丰富:支持各种HTTP方法、请求头处理、响应类型转换等 可定制性强:可以通过配置ClientHttpRequestFactory来自定义连接池、超时等参数 便于扩展:可以结合拦截器实现更复杂的代理逻辑

实现步骤

1. 添加依赖

首先在pom.xml中添加必要的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.14</version>
</dependency>

2. 配置RestTemplate

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        
        return new RestTemplate(factory);
    }
}

3. 实现代理控制器

@RestController
@RequestMapping("/proxy")
public class ProxyController {

    @Autowired
    private RestTemplate restTemplate;
    
    // 目标服务器基础URL
    private static final String TARGET_SERVER = "http://target-service.com";
    
    @RequestMapping("/**")
    public ResponseEntity<String> proxyRequest(HttpServletRequest request,
                                              @RequestBody(required = false) String body) {
        try {
            // 构建目标URL
            String requestUri = request.getRequestURI();
            String proxyPath = requestUri.substring("/proxy".length());
            String queryString = request.getQueryString();
            
            StringBuilder targetUrl = new StringBuilder(TARGET_SERVER);
            targetUrl.append(proxyPath);
            if (queryString != null) {
                targetUrl.append("?").append(queryString);
            }
            
            // 复制请求头
            HttpHeaders headers = new HttpHeaders();
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                // 排除一些不需要转发的头部
                if (!headerName.equalsIgnoreCase("host")) {
                    headers.set(headerName, request.getHeader(headerName));
                }
            }
            
            // 创建请求实体
            HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
            
            // 确定HTTP方法
            HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod());
            
            // 发送请求并获取响应
            ResponseEntity<String> responseEntity = 
                restTemplate.exchange(targetUrl.toString(), httpMethod, httpEntity, String.class);
            
            return responseEntity;
            
        } catch (Exception e) {
            return ResponseEntity
                .status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("代理请求失败: " + e.getMessage());
        }
    }
}

4. 处理文件上传和下载

对于需要处理文件上传和下载的情况,可以这样实现:

@PostMapping("/upload/**")
public ResponseEntity<byte[]> proxyUpload(HttpServletRequest request, 
                                        MultipartHttpServletRequest multipartRequest) {
    try {
        // 获取文件部分
        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
        multipartRequest.getFileMap().forEach((name, file) -> {
            try {
                ByteArrayResource resource = new ByteArrayResource(file.getBytes()) {
                    @Override
                    public String getFilename() {
                        return file.getOriginalFilename();
                    }
                };
                parts.add(name, resource);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
        
        // 获取其他表单参数
        multipartRequest.getParameterMap().forEach((name, values) -> {
            for (String value : values) {
                parts.add(name, value);
            }
        });
        
        // 构建URL
        String requestUri = request.getRequestURI();
        String proxyPath = requestUri.substring("/proxy/upload".length());
        String targetUrl = TARGET_SERVER + "/upload" + proxyPath;
        
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        
        // 发送请求
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(parts, headers);
        ResponseEntity<byte[]> response = restTemplate.exchange(
            targetUrl, HttpMethod.POST, requestEntity, byte[].class);
            
        return response;
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

5. 增强功能:实现请求拦截和转换

通过添加拦截器,我们可以在请求前后进行处理:

@Configuration
@Slf4j
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);

        RestTemplate restTemplate = new RestTemplate(factory);
        // 添加拦截器
        restTemplate.setInterceptors(
            Collections.singletonList((request, body, execution) -> {
                log.info("请求URL: {}", request.getURI());
                // 请求前处理
                HttpHeaders headers = request.getHeaders();
                headers.add("X-Forwarded-By", "Spring-Proxy");

                // 执行请求
                ClientHttpResponse response = execution.execute(request, body);

                // 响应后处理
                // 这里可以修改响应,例如添加头部、修改内容等

                return response;
            })
        );

        return restTemplate;
    }
}

6. 连接池配置

@Configuration
@Slf4j
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        /*HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);*/

        PoolingHttpClientConnectionManager connectionManager =
                new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(100);
        connectionManager.setDefaultMaxPerRoute(20);

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS))
                .setResponseTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS))
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

        HttpComponentsClientHttpRequestFactory factory =
                new HttpComponentsClientHttpRequestFactory(httpClient);

        RestTemplate restTemplate = new RestTemplate(factory);
        // 添加拦截器
        restTemplate.setInterceptors(
            Collections.singletonList((request, body, execution) -> {
                log.info("请求URL: {}", request.getURI());
                // 请求前处理
                HttpHeaders headers = request.getHeaders();
                headers.add("X-Forwarded-By", "Spring-Proxy");

                // 执行请求
                ClientHttpResponse response = execution.execute(request, body);

                // 响应后处理
                // 这里可以修改响应,例如添加头部、修改内容等

                return response;
            })
        );

        return restTemplate;
    }
}

安全考虑

请求验证:确保只转发合法请求 敏感信息过滤:过滤敏感头部或请求内容 限流措施:防止过多请求导致目标服务过载

// 示例:请求验证
private boolean validateRequest(HttpServletRequest request) {
    // 实现验证逻辑,例如检查认证信息、IP白名单等
    String authToken = request.getHeader("Authorization");
    return authToken != null && authService.isValidToken(authToken);
}

总结

通过SpringBoot和RestTemplate,我们可以快速实现一个功能完备的反向代理。

相比于专门的代理服务器如Nginx,这种方式更加灵活,可以与业务逻辑紧密结合,适合实现特定的代理需求。

但对于大规模的代理场景,还是推荐使用专门的代理软件。

RestTemplate工具类,支持http和https请求以及http携带body请求 一、添加依赖 支持http携带body请求,不需要可以不添加 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> 阅读详情

相关推荐

Springboot实现VNC的反向代理

背景 ​ 用户需要通过前端HTML页面的noVNC(noVNC是什么?)客户端连接底层VNC Server服务端,为了防止VNC Server的IP暴露,因此需要做一层代理。正常情况下使用Nginx、Apache等都可以搞定,但是由于项目架构的一些问题,暂时不能再加一台反向代理服务器,所以决定写一个单独的模块实现反向代理的功能。 ​ 在网上和Github上找了一下,使用了HTTP-Proxy-Servlet,引入该依赖搭建一个Spring Boot项目。 搭建 引入代理的依赖 ...

qq_46388795的博客 1256

如何在 Spring Boot 中使用反向代理

本文介绍了如何在 Spring Boot 应用中使用反向代理。通过使用反向代理,可以实现负载均衡和故障转移等功能,提高系统的稳定性和可靠性。在实际应用中,还需要根据实际情况进行更加复杂的反向代理配置,例如根据请求路径进行转发、设置请求头等。

it_xushixiong的博客 2945

route-forward springboot实现路由转发程序

想实现一个轻量级的接口反向代理和转发的一个接口服务,可以通过这个服务做一些需要认证才能访问的接口给到前端使用,这样就实现了一种认证可以调用多种第三方系统的服务。

小白的技术之路 1563

基于Spring Boot 实现简单的反向代理功能

通常情况下,我们会在application.yml去配置哪些path需要被转发到具体的服务上去,例如yml复制代码my:routes:txt复制代码uri: 最终请求的服务地址,如果是lb:// 开头的,说明需要进行负责均衡path: 用于匹配代理的路径,命中的会被进行代理转发。

m0_71777195的博客 5431

Spring boot2X负载均衡和反向代理实现过程解析

主要介绍了Spring boot2X负载均衡和反向代理实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

STM32H743IIT6上LVGL移植实战:从零到触摸屏驱动的完整配置流程

本文详细记录了在STM32H743IIT6高性能MCU上,从零开始移植LVGL图形库到7寸RGB触摸屏的完整实战流程。内容涵盖工程搭建、显示与触摸驱动配置、LVGL核心优化及常见问题排查,重点讲解了如何利用STM32H743的硬件特性(如DMA2D、LTDC)提升GUI性能,为嵌入式GUI开发提供了一份详实的配置指南。

spark7igniter的博客 549

springboot 直接转发调用_spring boot实现超轻量级网关的方法(反向代理、转发)

在我们的rest服务中,需要暴露一个中间件的接口给用户,但是需要经过rest服务的认证,这是典型的网关使用场景。可以引入网关组件来搞定,但是引入zuul等中间件会增加系统复杂性,这里实现一个超轻量级的网关,只实现请求转发,认证等由rest服务的spring security来搞定。如何进行请求转发呢? 熟悉网络请求的同学应该很清楚,请求无非就是请求方式、HTTP header,以及请求body,我...

weixin_39600400的博客 2169

手把手教你用示波器实测LVDS/CML信号:从波形解读到故障排查(附实测图)

本文详细介绍了如何使用示波器实测LVDS和CML信号,从波形解读到故障排查的全过程。涵盖差分探头选择、示波器配置、标准波形特征解读、眼图分析技巧以及高速信号捕获要点,帮助硬件工程师快速诊断和解决信号完整性问题。附实测图和案例,提升高速数字电路设计效率。

weixin_27215337的博客 200

SpringBoot实现轻量级接口反向代理、转发

想实现一个轻量级的接口反向代理和转发的一个接口服务,可以通过这个服务做一些需要认证才能访问的接口给到前端使用,这样就实现了一种认证可以调用多种第三方系统的服务。基本逻辑就是将请求的请求方式、请求头、请求体提取出来,将这些信息转发到另外一个接口

weixin_44953227的博客 2031

全同态加密:CKKS

不论是 LSB 编码的 BGV,还是 MSB 编码的 BFV,它们的同态运算都是对 $\mathbb Z_t$ 上明文的**精确计算**,因为**密文中的明文空间和噪声空间是分离的**。例如,在 BGV 中是 $te+m$,在 BFV 中是 $\delta m+e$。但是,这种精确计算是在同余意义下的,如果将明文视为实数,那么实际上同态运算时的噪声破坏了明文的 MSB $\lfloor m/t \rfloor$,仅保留了 LSB $[m]_t$,

weixin_44885334的博客 7546

Fluent 中多相流模型全面解析

3.颗粒或液滴在连续相中的运动:若关注颗粒或液滴在连续相中的运动轨迹、分布规律以及与连续相的相互作用,如喷雾干燥、气力输送等过程,Eulerian-Lagrangian 模型则是最佳选择。Eulerian-Eulerian 模型可以准确模拟气体在固体颗粒中的流动情况,包括颗粒的流化状态、气体与颗粒之间的传热传质过程,为气固流化床的优化设计和操作提供依据。通过该模型,可以了解混合器内不同位置的混合程度、颗粒的运动轨迹以及液固相间的相互作用,从而改进混合器的结构和操作条件,提高混合效率。

khhdp的博客 3086

正向代理与反向代理

正向代理是客户端的代理,服务器不知道真正的客户端是谁;反向代理是服务器的代理,客户端不知道真正的服务器是谁正向代理一般是客户端架设的;反向代理一般是服务器架设的正向代理主要是用来解决访问限制问题;反向代理则是提供负载均衡、安全防护等作用。二者都能提高访问速度。百度安全验证百度安全验证。

myli92的博客 1139

Java云上香云祭祀线上祭祀系统小程序源码

云上香云祭祀线上祭祀系统”,不仅是一种祭祀方式的创新,更是对传统文化的一次深情致敬。它让我们明白,无论时代如何变迁,对亲人的怀念与尊重永远不会改变。在这个特别的平台上,让我们共同守护那份跨越时空的爱与思念,让心灵得以安放,让生命之树常青。🌳。

2401_84413757的博客 803

springboot项目用RestTemplate调用第三方接口

1. 导入依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> 2. 创建配置类 import java.nio.charset.StandardCharsets; i

weixin_42656705的博客 460

Prokka实战:10分钟搞定细菌基因组注释(附详细参数解析)

本文深入解析Prokka细菌基因组注释工具的核心参数与实战策略。通过拆解其集成化工作流程,详细解读物种分类、功能注释、输出控制等关键参数,并提供快速初筛、高质量发表、质粒注释及批量处理四种典型场景的高效参数组合方案,帮助用户精准掌控注释过程,将原始序列转化为有价值的生物学见解。

weixin_29271053的博客 442

PCL 基于强度的双边滤波【2026最新版】

基于强度信息的双边滤波代码实现、滤波前后点云未出现变化的原因以及获取带有强度pcd点云的方法。本文由优快云点云侠原创,博客长期更新,本文最近一次更新时间为:2026年5月24日。

点云侠的博客 29万+

Springboot 反向代理

Springboot 反向代理

wu_di 547

MounRiver Studio(MRS)使用技巧:添加头文件目录;增加代码分组

MounRiver Studio(MRS)使用技巧:添加头文件目录

cheng___yi的博客 1809

springboot使用Map接收请求参数 @RequestBody 使用RestTemplate发送http get和post源码 接口中转相当于反向代理

模拟一个请求 Spring @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。 ...

chenhao0568的专栏 1万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

SpringBoot解决跨域问题

一、同源策略 同源,就是咱们域名、端口号、ip、采用的协议都相同,那么我们就是同源的 反之就是不同源的!!! 出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。 所以,用最简单的话来说,就是前端可以发请求给服务器,服务器也可以进行响应,只是因为浏览器会对请求头进行判断,所以要么前端设置请求头,要么后端设置请求

qq_46028126的博客 652

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

SpringBoot+Vue高校行政事务管理系统开发实践

现代Web开发中,前后端分离架构已成为主流技术方案。SpringBoot作为Java生态的微服务框架,通过自动配置和starter依赖简化了后端开发;Vue.js则以其响应式特性和组合式API提升了前端开发效率。这种技术组合在企业级应用中展现出显著优势,特别是在需要快速迭代的教育信息化领域。以高校行政管理系统为例,通过整合MyBatis-Plus的数据访问能力和Element Plus的UI组件,可以高效实现会议管理、公文流转等核心功能。系统采用MySQL存储业务数据,利用Echarts进行数据可视化,最终

weixin_34262482的博客 334

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

整合SpringBoot与Vue对接Dify的实践指南

本文详细介绍了SpringBoot与Vue整合对接Dify AI平台的实践方案。首先说明环境准备要求,包括JDK8+、Node.js等基础工具安装。然后分步骤展示了:1)SpringBoot后端配置OkHttp客户端实现Dify API调用;2)Vue前端通过Axios封装接口请求;3)解决跨域问题的CORS配置方案;4)生产环境部署建议和安全注意事项。文中提供了完整的代码示例,涵盖从后端服务层到前端组件调用的全流程实现,为开发者快速集成Dify的AI能力提供了清晰的实践指南。

专注于技术研发行业技术主要有AI人工智能视觉识别、物联网技术、电商平台、app原生技术、微信小程序、鸿蒙语言开发、办公企业oa、ERP等,致力于做东半球最优秀的程序员 228

spring boot实现超轻量级网关(反向代理、转发)

在我们的rest服务中,需要暴露一个中间件的接口给用户,但是需要经过rest服务的认证,这是典型的网关使用场景。可以引入网关组件来搞定,但是引入zuul等中间件会增加系统复杂性,这里实现一个超轻量级的网关,只实现请求转发,认证等由rest服务的spring security来搞定。 如何进行请求转发呢? 熟悉网络请求的同学应该很清楚,请求无非就是请求方式、HTTP header,以及请求body,我们将这些信息取出来,透传给转发的url即可。 举例: /graphdb/**...

zzhongcy的专栏 2107

基于YOLO与SpringBoot的血液细胞智能检测系统开发

目标检测技术作为计算机视觉的核心任务之一,通过YOLO等算法实现物体的实时定位与分类。在医疗影像领域,结合深度学习的目标检测系统能显著提升细胞识别的准确率和效率。本文介绍的血液细胞智能检测系统,采用YOLOv8/v10/v11/v12多版本模型架构,配合SpringBoot+Vue的全栈技术方案,实现了98%以上的识别准确率和3秒/样本的检测速度。系统创新性地整合了DeepSeek大语言模型进行结果分析,并设计了模型热切换机制保障服务稳定性,为临床检验提供了高效的AI解决方案。该技术方案可广泛应用于病理诊断

weixin_34212762的博客 445
上一篇: Spring Boot 整合 MinIO 实现全场景文件管理:从基础操作到分片上传
下一篇: Spring Boot Filter、Interceptor、AOP 的使用场景与选型
程序员职业指南
博客等级 码龄4年 2136粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值