【请求代理】springboot单机服务基于过滤器Filter实现第三方服务器接口请求代理功能
springboot单机服务基于过滤器Filter实现第三方服务器接口请求代理功能
- 一、前言
- 二、解决思路
- 三、基于gateway实现
- 四、基于过滤器Filter实现
- 五、问题总结
**注:本文源码获取或者更多资料,关注公众号:技术闲人**
一、前言
在项目开发时会遇到web端/接口请求第三方服务接口的场景,对web请求来说最后请求的服务地址是一个,避免跨域问题,在微服务场景经常使用gateway
等网关服务实现,或者使用nginx代理
组件实现,但是不同三方服务有不同的鉴权要求,但是后端服务最好有相同的鉴权;
二、解决思路
在非微服务架构和三方不同鉴权接口的服务场景下,通过过滤器Filter
实现请求转发,并使用适配器设计模式,兼容不同的三方服务请求(鉴权),减少重复代码开发,也能监控所有的服务请求,并对所有请求做限流、统计等操作;
三、基于gateway实现
在没有spring-boot-starter-web
依赖的场景下可以使用gateway,Spring MVC
(基于Servlet的Web应用程序)和Spring Cloud Gateway
(基于反应式编程的API网关),但是这两个组件是不兼容的。Spring Cloud Gateway是专为反应式编程设计的,使用Spring WebFlux
作为底层框架,而Spring MVC则基于Servlet API。
gateway实现代码:
package com.sk.proxytest;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class ProxyTestApplication {public static void main(String[] args) {SpringApplication.run(ProxyTestApplication.class, args);}@Beanpublic RouteLocator myRoutes(RouteLocatorBuilder builder) {return builder.routes().route(p -> p.path("/test/**").uri("http://127.0.0.1:8089/api")).build();}}
四、基于过滤器Filter实现
本文主要使用过滤器Filter实现,既能控制代理请求,又能最少开发量;
GET请求结果
POST请求结果
实现源码:
ProxyFilter.java
package com.sk.proxytest.proxy;import com.sk.proxytest.proxy.bean.ProxyParam;
import com.sk.proxytest.proxy.bean.ProxyResult;
import com.sk.proxytest.proxy.strategy.ProxyHandleService;
import com.sk.proxytest.proxy.strategy.ProxyHandleStrategyFactory;
import com.sk.proxytest.proxy.strategy.ProxyStrategyContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;@Slf4j
@Configuration
@WebFilter(filterName = "ProxyFilter", urlPatterns = "/proxy/*")
public class ProxyFilter implements Filter {@Resourceprivate RestTemplate restTemplate;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;String proxyType = request.getHeader("proxy-type");ProxyStrategyContext proxyStrategyContext = new ProxyStrategyContext();ProxyHandleService proxyHandleService = ProxyHandleStrategyFactory.getProxyHandleStrategy(proxyType);proxyStrategyContext.setProxyHandleStrategy(proxyHandleService);ProxyResult proxyResult = proxyStrategyContext.handleProxy(new ProxyParam());boolean flag = true;if (null != proxyResult) {PrintWriter writer = null;try {String body = IOUtils.toString(request.getInputStream());HttpEntity<?> entity = new HttpEntity<>(body, proxyResult.getHeaders());String url = proxyResult.getProxyUrl() + getNewUrl(request);log.info("-----------new-url:{}", url);ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.resolve(request.getMethod()), entity, String.class);response.setStatus(responseEntity.getStatusCodeValue());writer = response.getWriter();writer.write(responseEntity.getBody());writer.flush();flag = false;} catch (Exception e) {log.error("------error:{}", e);} finally {if (writer != null) {writer.close();}}}if (flag) {chain.doFilter(request, response);}}@Overridepublic void destroy() {Filter.super.destroy();}//获取被代理的url和参数private String getNewUrl(HttpServletRequest request) {String proxyUrl = request.getRequestURI().replace("/proxy", "");Map<String, String[]> parameterMap = request.getParameterMap();int i = 0;for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {String key = entry.getKey();String value = entry.getValue()[0];if (i == 0) {proxyUrl = proxyUrl + "?" + key + "=" + value;} else {proxyUrl = proxyUrl + "&" + key + "=" + value;}}return proxyUrl;}
}
ProxyHandleService.java
package com.sk.proxytest.proxy.strategy;import com.sk.proxytest.proxy.bean.ProxyParam;
import com.sk.proxytest.proxy.bean.ProxyResult;public interface ProxyHandleService {ProxyResult proxyHandle(ProxyParam proxyParam);}
AlibabaProxyHandleStrategy.java
package com.sk.proxytest.proxy.strategy;import com.sk.proxytest.proxy.bean.ProxyParam;
import com.sk.proxytest.proxy.bean.ProxyResult;
import org.springframework.http.HttpHeaders;public class AlibabaProxyHandleStrategy implements ProxyHandleService {@Overridepublic ProxyResult proxyHandle(ProxyParam proxyParam) {HttpHeaders headers = new HttpHeaders();//TODO 根据三方服务登录接口获取鉴权信息String token = "token--------";headers.add("token", token);headers.add("Content-Type","application/json");//三方服务ip和portString ip = "127.0.0.1";String port = "8080";String proxyUrl = "http://" + ip + ":" + port;return new ProxyResult(headers, proxyUrl);}
}
ProxyHandleStrategyFactory.java
package com.sk.proxytest.proxy.strategy;import java.util.HashMap;
import java.util.Map;public class ProxyHandleStrategyFactory {private static Map<String, ProxyHandleService> proxyHandleServiceMap;static {proxyHandleServiceMap = new HashMap<>();proxyHandleServiceMap.put("alibaba", new AlibabaProxyHandleStrategy());}public static ProxyHandleService getProxyHandleStrategy(String proxyType){return proxyHandleServiceMap.get(proxyType);}}
ProxyStrategyContext.java
package com.sk.proxytest.proxy.strategy;import com.sk.proxytest.proxy.bean.ProxyParam;
import com.sk.proxytest.proxy.bean.ProxyResult;public class ProxyStrategyContext {private ProxyHandleService proxyHandleService;public void setProxyHandleStrategy(ProxyHandleService proxyHandleService){this.proxyHandleService = proxyHandleService;}public ProxyResult handleProxy(ProxyParam proxyParam){if(proxyHandleService != null){return proxyHandleService.proxyHandle(proxyParam);}return null;}}
五、问题总结
在单机服务中,gateway过于重,并且与springMVC有冲突,nginx代理服务不能同一鉴权,或者同一鉴权太过于麻烦,过滤器Filter+适配器模式正好满足我们业务场景需求;
功能实现的方式选择还是要考虑业务场景。
相关文章:

【请求代理】springboot单机服务基于过滤器Filter实现第三方服务器接口请求代理功能
springboot单机服务基于过滤器Filter实现第三方服务器接口请求代理功能 一、前言二、解决思路三、基于gateway实现四、基于过滤器Filter实现五、问题总结 **注:本文源码获取或者更多资料,关注公众号:技术闲人**一、前言 在项目开发时会遇到w…...

.NET Core异步编程与多线程解析:提升性能与响应能力的关键技术
在.NET Core中,异步编程和多线程是构建高性能应用程序的核心技能。理解这两个概念不仅可以提升应用程序的响应能力,还能优化资源使用。本文将深入剖析异步编程和多线程的关键知识点,提供代码示例,并附上步骤以帮助理解。 1. 异步…...

Photoshop(PS) 抠图简单教程
目录 快速选择 魔棒 钢笔 橡皮擦 蒙版 通道 小结 可以发现,ps逐渐成为必备基础的办公软件。本文让ps新手轻松学会抠图。 快速选择 在抠图之前,先了解下选区的概念。ps中大多数的抠图操作都是基于选区的,先选区再Ctrl J提取选区。而快…...

项目管理中的常用工件(二):可视化工件
项目管理中的常用工件(二):可视化工件 亲和图(affinity diagram)因果图(cause-and-effect diagram)直方图(histogram)流程图(flowchart)散点图&am…...

Git入门与实战:版本控制的艺术
🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主 📌 擅长领域:全栈工程师、爬虫、ACM算法 🔥 微信:zsqtcyw 联系我领取学习资料 …...

[Mysql-DML数据操作语句]
目录 数据增加:INSERT 全字段插入: 部分字段插入: 一次性添加多条: 数据修改:UPDATE 数据删除:DELECT delete truncate drop 区别 数据增加:INSERT 总体格式:insert into 表…...

Tableau入门|数据可视化与仪表盘搭建
原视频链接(up:戴戴戴师兄),文章为笔者的自学笔记,用于复习回顾,原视频下方有原up整理的笔记,更加直观便捷。因为视频中间涉及的细节较多,建议一边操作,一边学习。 整体介绍 可视化…...

API 技术开发分享:连接电商平台数据获取的桥梁
在当今数字化的时代,API(Application Programming Interface,应用程序编程接口)技术成为了实现不同系统之间通信和数据交换的关键。它就像是一座无形的桥梁,使得各种应用能够相互协作,共享资源,…...

区块链如何助力数字版权保护和内容创作者的权益?
区块链技术可以助力数字版权保护和内容创作者的权益,主要有以下几个方面: 去中心化的版权登记和溯源:区块链可作为一个可信的去中心化数据库,记录并验证数字内容的版权信息。内容创作者可以将自己的作品信息存储在区块链上&#x…...

记一次老旧项目的整体技术升级
最近给公司采购的老旧的 node8 vue2.6 webpack3 npm 项目做构建优化 背景:整个项目 build 一次 20 min ,本地冷启动和热更新也忒慢,依赖 npm i 一下也得装个 20 min 众所周知,Node 版本,依赖包管理工具 和 构建工…...

2024年最受欢迎的五大上网审计设备和软件
在2024年的市场上,上网行为审计设备和软件种类繁多,它们帮助企业监控和管理员工的网络活动,确保网络安全并提高工作效率。下面是一些受欢迎的上网行为审计设备和软件。 2024年最受欢迎的上网行为审计设备和软件如下 1.安企神软件:…...

sed利用脚本处理文件
一、sed是什么 sed 命令是利用脚本来处理文本文件。它可以依照脚本的指令来处理、编辑文本文件。主要用来自动编 辑一个或多个文件、简化对文件的反复操作、编写转换程序等。 二、sed的原理 读入新的一行内容到缓存空间; 从指定的操作指令中取出第一条指令&…...

泰山派RK3566开发板800x1280MIPI屏设备树补丁
泰山派RK3566开发板800x1280MIPI屏设备树补丁 泰山派下800 X 1280分辨率MIPI屏调试,设备树补丁如下: https://download.csdn.net/download/qq_45143522/89584066 用kernel.patch文件,在泰山派内核源码下打补丁即可完成更新,或者…...

informer中的indexer机制的实现分析与源码解读
1. 背景 client-go工具下的tools/cache.indexer为informer提供缓存与索引的能力。可以实现快速通过索引找到对应的对象(pod, deployment,secret,configmap等)。 indexer再informer机制中的使用图示: indexer包括2部分: 一部分是store用于实际数据的存储,…...

英特尔宣布针对对Llama 3.1进行优化 以提升所有产品的性能
日前Meta正式发布了Llama 3.1开源大模型,以其庞大的参数量和卓越性能,首次在多项基准测试中击败了GPT-4o等业界领先的闭源模型。允许开发者自由地进行微调、蒸馏,甚至在任何地方部署,这种开放性为AI技术的普及和创新提供了无限可能…...

Python3网络爬虫开发实战(1)爬虫基础
一、URL 基础 URL也就是网络资源地址,其满足如下格式规范 scheme://[username:password]hostname[:port][/path][;parameters][?query][#fragment] scheme:协议,常用的协议有 Http,https,ftp等等;usern…...

Redis的五种数据类型与命令
目录 引言 一 Redis的特性 二 Redis的安装 三 Redis的优点 四 Redis的五种数据类型与命令 五 Redis的配置文件 引言 Redis是什么? Remote Dictionary Service(远程字典服务器) Redis 是一个开源的(BSD许可)的,C语言编写的,高性能的数…...

RocketMQ的详细讲解(四种mq的对比(activeMq、rabbitmq、rocketmq、kafka))
20240729 RocketMQ1 mq的三大作用 异步、削峰限流、解耦合2. 四种mq的对比(activeMq、rabbitmq、rocketmq、kafka)3 rocketmq特点1. 平台无关2. 能提供什么样的功能 4 rocketMq4.1 broker中的标题,来约束读和写4.2 rocketmq的结构4.3 读和写的…...

除了GPT,还有哪些好用的AI工具?
最强AI视频生成:小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/ 多得很,这20个免费的国产AI工具,打工人必备,除了比chatGPT好用,甚至还可以用来变现…...

04 | 深入浅出索引(上)
此系列文章为极客时间课程《MySQL 实战 45 讲》的学习笔记! 索引的常见模型 可以提供查询效率的数据结构有很多,常见的有三种:哈希表、有序数组、搜索数。 哈希表是一种以 key-value 形式存储的数据结构。输入一个 key,通过固定…...

Linux的yum源安装MySQL5.7
linux的yum源安装MySQL5.7 一、MySQL 1、简介 MySQL 是一种流行的关系型数据库管理系统(RDBMS),由瑞典公司 MySQL AB 开发,后来被 Oracle Corporation 收购。它是一个开源软件,提供了高效、稳定和可靠的数据管理解决…...

基于深度学习的音频自监督学习
基于深度学习的音频自监督学习(Self-Supervised Learning, SSL)是一种利用未标注的音频数据,通过设计自监督任务进行特征学习的方法。这种方法在需要大量标注数据的音频处理任务(如语音识别、情感分析等)中,…...

用uniapp 及socket.io做一个简单聊天app1
####相关的表结构,用的是mysql 用户表(Users) 存储用户的基本信息。 CREATE TABLE Users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(100) NOT NULL,email VARCHAR(100) UNIQUE,created_a…...

在Postman中引用JS库
前言 在做接口测试时,出于安全因素,请求参数需要做加密或者加上签名才能正常请求,例如:根据填写的请求参数进行hash计算进行签名。postman作为主流的接口调试工具也是支持请求预处理的,即在请求前使用JavaScript脚本对…...

学习笔记-系统框图简化求传递函数公式例题
简化系统结构图求系统传递函数例题 基础知识回顾 第四讲 控制系统的方框图 (zhihu.com) 「自控原理」2.3 方框图的绘制及化简_方框图化简-CSDN博客 自动控制原理笔记-结构图及其等效变换_结构图等效变换-CSDN博客 例子一 「自控原理」2.3 方框图的绘制及化简_方框图化简-CS…...

postgrsql——事务概述
事务概述 事务的特性 原子性(Atomicity): 事务被视为一个整体,其中的操作要么全部执行成功,要么全部不执行,即不存在部分执行的情况。这确保了事务的完整性和一致性。一致性(Consistency&…...

1.Spring Boot 简介(Spring MVC+Mybatis-plus)
文章目录 一,Spring Boot 简介二,搭建springboot项目并整合mybatis-plus框架1.pom导依赖2.添加启动项3.配置文件.yml 三,springboot集成 Spring MVC1.springmvc定义2.应用注解 一,Spring Boot 简介 SpringBoot是Spring的子工程(或…...

《计算机网络》(学习笔记)
目录 一、计算机网络体系结构 1.1 计算机网络概述 1.1.1 计算机网络的概念 1.1.2 计算机网络的组成 1.1.3 计算机网络的功能 1.1.4 电流交换、报文交换和分组交换 1.1.5 计算机网络的分类 1.1.6 计算机网络的性能指标 1.2 计算机网络体系结构与参考模型 1.2.1 计算机…...

指针函数和函数指针
函数名在表达式中应该如何被解读?答:函数名可以在表达式中被解读成“指向该函数的指针”。 函数指针和指针函数有什么区别?答:函数指针是一个指向函数的指针;指针函数是一个返回指针变量的函数。 一个函数能否有时候…...

Elasticsearch跨集群搜索
Elasticsearch(简称ES)是一种基于Lucene的搜索引擎,以其高性能、可扩展性和实时搜索能力而广受欢迎。在大型分布式系统中,跨集群搜索成为了一个重要的需求,它允许用户从多个Elasticsearch集群中联合查询数据࿰…...