SpringCloudGateway网关处拦截并修改请求

SpringCloudGateway网关处拦截并修改请求

img

需求背景

老系统没有引入Token的概念,之前的租户Id拼接在请求上,有的是以Get,Param传参形式;有的是以Post,Body传参的。需要在网关层拦截请求并进行请求修改后转发到对应服务。

举个例子:

Get请求:

/user/getInfo?userId=1 经过网关处理后变为 /user/getInfo?userId=1&&tenantId=2333

Post请求:

/user/getInfo Body携带参数为:

{userId: "1"
}

经过网关处理后变为

{userId: "1",tenantId: "2333"
}

解决办法

  1. 全局过滤器配置: 通过@Bean注解配置一个全局过滤器,用于在请求被转发到微服务前进行处理。
  2. 处理GET请求: 如果是GET请求,直接修改URL并返回,不对请求体进行修改。
  3. 处理非GET请求: 对非GET请求,使用装饰者模式创建ModifyRequestBodyServerHttpRequestDecorator对象,对请求体进行修改。
  4. 去掉Content-Length头: 在修改请求体的同时,通过mutate()方法去掉请求头中的Content-Length
  5. 修改请求体的装饰者类: 定义了一个内部类ModifyRequestBodyServerHttpRequestDecorator,继承自ServerHttpRequestDecorator,用于实现请求体的修改。

代码示例:

// 导入必要的类和包
package com.***.gateway.config;import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;import java.io.IOException;
import java.nio.charset.StandardCharsets;@Configuration
@Slf4j
public class GatewayConfig {// 配置全局过滤器@Beanpublic GlobalFilter customGlobalFilter() {return (exchange, chain) -> {// 获取原始请求对象ServerHttpRequest request = exchange.getRequest();// 构建URI组件构建器,用于修改请求URLUriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUri(request.getURI());// 初始化租户IDString tenantId = "";// 检查请求头中是否包含 "TenantId",如果有则获取其值if (request.getHeaders().containsKey("TenantId")) {tenantId = request.getHeaders().get("TenantId").get(0);uriBuilder.queryParam("tenantId", tenantId);}// 如果请求是GET请求,则直接返回if (request.getMethodValue().equals("GET")) {log.info("请求是Get请求,url is {}", uriBuilder.build().toUri());ServerHttpRequest modifiedRequest = request.mutate().uri(uriBuilder.build().toUri()).build();// 创建新的ServerWebExchange,该对象包含修改后的请求ServerWebExchange modifiedExchange = exchange.mutate().request(modifiedRequest).build();// 继续执行过滤器链return chain.filter(modifiedExchange);}// 使用装饰者模式修改请求体ServerHttpRequest modifiedRequest = new ModifyRequestBodyServerHttpRequestDecorator(request, tenantId, exchange.getResponse().bufferFactory());// 去掉Content-Length请求头modifiedRequest = modifiedRequest.mutate().header("Content-Length", (String) null).build();// 创建新的ServerWebExchange,该对象包含修改后的请求ServerWebExchange modifiedExchange = exchange.mutate().request(modifiedRequest).build();// 继续执行过滤器链return chain.filter(modifiedExchange);};}// 定义修改请求体的装饰者类private static class ModifyRequestBodyServerHttpRequestDecorator extends ServerHttpRequestDecorator {private final String tenantId;private final DataBufferFactory bufferFactory;private final ObjectMapper objectMapper = new ObjectMapper();// 构造方法,传入原始请求、tenantId和数据缓冲工厂ModifyRequestBodyServerHttpRequestDecorator(ServerHttpRequest delegate, String tenantId, DataBufferFactory bufferFactory) {super(delegate);this.tenantId = tenantId;this.bufferFactory = bufferFactory;}// 重写获取请求体的方法,对请求体进行修改@NotNull@Overridepublic Flux<DataBuffer> getBody() {return super.getBody().map(dataBuffer -> {// 读取原始请求体数据byte[] bytes = new byte[dataBuffer.readableByteCount()];dataBuffer.read(bytes);String body = new String(bytes, StandardCharsets.UTF_8);// 修改请求体内容String newBody = modifyJsonBody(body);// 创建新的 DataBufferbyte[] newData = newBody.getBytes(StandardCharsets.UTF_8);return bufferFactory.wrap(newData);});}// 对 JSON 请求体进行修改,添加 tenantId 字段private String modifyJsonBody(String originalBody) {try {JsonNode jsonNode = objectMapper.readTree(originalBody);((ObjectNode) jsonNode).put("tenantId", tenantId);return objectMapper.writeValueAsString(jsonNode);} catch (IOException e) {log.error("Error modifying JSON body", e);return originalBody;}}}
}

解决路径文章参考

http://t.csdnimg.cn/9kos5

http://t.csdnimg.cn/Aklwh

关于装饰者模式

装饰者模式是一种结构型设计模式,它允许你通过将对象放入包含行为的特殊封装类中来为原始对象添加新的行为。这种模式能够在不修改原始对象的情况下,动态地扩展其功能。在上段代码里,主要使用装饰者模式去修改Body 的传参。

主要角色:

  1. Component(组件): 定义一个抽象接口或抽象类,声明对象的一些基本操作。
  2. ConcreteComponent(具体组件): 实现了Component接口,是被装饰的具体对象,也是我们最终要添加新行为的对象。
  3. Decorator(装饰者抽象类): 继承了Component,并持有一个Component对象的引用,同时实现了Component定义的接口。它可以通过该引用调用Component的操作,同时可以添加、扩展或修改Component的行为。
  4. ConcreteDecorator(具体装饰者): 扩展Decorator,具体实现新行为的类。

装饰者模式的工作流程:

  1. 客户端通过Component接口与ConcreteComponent对象进行交互。
  2. ConcreteComponent对象处理客户端的请求。
  3. 客户端可以通过Decorator接口与ConcreteDecorator对象进行交互,Decorator持有ConcreteComponent的引用。
  4. ConcreteDecorator在调用ConcreteComponent的操作前后,可以添加、扩展或修改行为。

给普通咖啡加点糖和牛奶

代码示例:

public class DecoratorPatternExample {// Component(组件)interface Coffee {String getDescription();double cost();}// ConcreteComponent(具体组件)static class SimpleCoffee implements Coffee {@Overridepublic String getDescription() {return "Simple Coffee";}@Overridepublic double cost() {return 1.0;}}// Decorator(装饰者抽象类)abstract static class CoffeeDecorator implements Coffee {protected Coffee decoratedCoffee;public CoffeeDecorator(Coffee coffee) {this.decoratedCoffee = coffee;}@Overridepublic String getDescription() {return decoratedCoffee.getDescription();}@Overridepublic double cost() {return decoratedCoffee.cost();}}// ConcreteDecorator(具体装饰者)static class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return super.getDescription() + ", with Milk";}@Overridepublic double cost() {return super.cost() + 0.5;}}// ConcreteDecorator(具体装饰者)static class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return super.getDescription() + ", with Sugar";}@Overridepublic double cost() {return super.cost() + 0.2;}}public static void main(String[] args) {// 创建一个简单的咖啡Coffee simpleCoffee = new SimpleCoffee();System.out.println("Cost: " + simpleCoffee.cost() + ", Description: " + simpleCoffee.getDescription());// 使用装饰者模式添加牛奶和糖Coffee milkSugarCoffee = new MilkDecorator(new SugarDecorator(simpleCoffee));System.out.println("Cost: " + milkSugarCoffee.cost() + ", Description: " + milkSugarCoffee.getDescription());}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/237867.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工业自动化的通信核心—钡铼技术R10A工业级路由器介绍

随着工业自动化的快速发展&#xff0c;工业通信技术也日新月异。在这个信息时代&#xff0c;工业通信设备的稳定性、可靠性和高效性变得尤为重要。作为工业自动化的核心部件之一&#xff0c;钡铼技术R10A工业级路由器以其出色的性能和卓越的功能在行业内赢得了广泛的赞誉。本文…

docker学习(十二、Redis主从容错迁移)

文章目录 一、容错切换迁移挂一个master节点6381&#xff0c;查看集群信息主节点挂一个&#xff0c;对应从节点切换为主节点&#xff0c;数据获取测试恢复挂的主节点&#xff0c;主从关系变化 二、小思考 docker搭建Redis集群相关知识&#xff1a; docker学习&#xff08;九、分…

C# SQLite基础工具类

目录 1、安装System.Data.SQLite工具包 2、创建数据库 3、数据库的连接与断开 4、执行一条SQL语句 5、批量执行sql语句 6、返回首行首列值 7、执行sql语句返回datatable 1、安装System.Data.SQLite工具包 2、创建数据库 /// <summary> /// 数据库路径 …

FAQ:Operator Overloading篇

文章目录 1、What’s the deal with operator overloading? &#xff08;运算符重载是怎么回事?&#xff09;2、What are the benefits of operator overloading?&#xff08;运算符重载有什么好处&#xff1f;&#xff09;3、What are some examples of operator overloadi…

Github2023-12-22开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-22统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4TypeScript项目2非开发语言项目2C项目1C项目1HTML项目1Dart项目1 Tailwind CSS&#xff1a;快速U…

main函数获取传入的参数

文章目录 代码获取到参数转整型 代码 #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <stdint.h>static uint8_t optstr[] "?:i:o:v:h:"; static struct option long_options[] {{"input", required_…

c# opencv 提取图片文字,如读取身份证号

在C#中使用OpenCV读取身份证号码并不是一个直接的任务&#xff0c;因为OpenCV主要是一个用于图像处理和计算机视觉的库&#xff0c;它并不直接支持文本识别功能。然而&#xff0c;你可以结合其他OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xf…

spark-thrift-server 报错 Wrong FS

文章目录 [toc]具体报错实际原因查看 hive 元数据修改 spark-thrift-server 配置修改 hive 元数据 具体报错 spark-thrift-server 执行删表语句&#xff0c;出现如下报错 Error: org.apache.hive.service.cli.HiveSQLException: Error running query: org.apache.spark.sql.Ana…

kibana-7.15.2 一分钟下载、安装、部署 linux

文章目录 一、下载安装部署 1. 下载2. 解压3. 修改配置 二、kibana 启动 2.1. 创建kibana 用户2.2. 赋予权限2.3. 切换用户2.4. kibana启动2.5. 监控服务2.6. 监控服务2.7. kibana停止2.8. 效果图 三、kibana 启动2 3.1. 浏览器访问3.2. 效果图 一、下载安装部署 https:…

HTML美化网页

使用CSS3美化的原因 用css美化页面文本,使页面漂亮、美观、吸引用户 可以更好的突出页面的主题内容,使用户第一眼可以看到页面主要内容 具有良好的用户体验 <span>标签 作用 能让某几个文字或者某个词语凸显出来 有效的传递页面信息用css美化页面文本&#xff0c;使页面漂…

面试题:JVM 对锁都进行了哪些优化?

文章目录 锁优化自旋锁和自适应自旋锁消除锁粗化逃逸分析方法逃逸线程逃逸通过逃逸分析&#xff0c;编译器对代码的优化 锁优化 jvm 在加锁的过程中&#xff0c;会采用自旋、自适应、锁消除、锁粗化等优化手段来提升代码执行效率。 自旋锁和自适应自旋 现在大多的处理器都是…

易点易动设备管理系统:解决企业设备管理难题的利器

在现代企业中&#xff0c;设备管理是一个至关重要的环节。无论是制造业、物流业还是服务业&#xff0c;设备的高效管理对于企业的运营和竞争力都至关重要。然而&#xff0c;许多企业在设备管理方面面临着各种挑战。为了解决这些难题&#xff0c;易点易动设备管理系统应运而生。…

C语言数组与指针的关系,使用指针访问数组元素方法

数组与指针 如果您阅读过上一章节“C语言数组返回值”中的内容&#xff0c;那么您是否会产生一个疑问&#xff0c;C语言的函数要返回一个数组&#xff0c;为什么要将函数的返回值类型指定为指针的类型&#xff1f;换句话说&#xff0c;C语言中数组和指针到底是什么关系呢&…

[vue]Echart使用手册

[vue]Echart使用手册 使用环境Echart的使用Echart所有组件和图表类型Echart 使用方法 使用环境 之前是在JQuery阶段使用Echart&#xff0c;直接引入Echart的js文件即可&#xff0c;现在是在vue中使用,不仅仅时echarts包&#xff0c;还需要安装vue-echarts&#xff1a; "…

Pycharm解释器的配置: System Intgerpreter 、Pipenv Environment、Virtualenv Environment

文章目录 前提1. 环境准备2. 了解虚拟环境 一、进入Interpreter设置页二、添加Interpreter1. 方式一2. 方式二 三、 System Interpreter四、 Pipenv Environment前提条件&#xff1a;详细步骤1&#xff09; 选择pipenv2&#xff09; 设置Base Interpreter3&#xff09; 设置Pip…

程序员福利:好用的第三方api接口

空号检测&#xff1a;通过手机号码查询其在网活跃度&#xff0c;返回包括空号、停机等状态。手机在网状态&#xff1a;支持传入三大运营商的号码&#xff0c;查询手机号在网状态&#xff0c;返回在网等多种状态。反欺诈&#xff08;羊毛盾&#xff09;&#xff1a;反机器欺诈&a…

计算机网络个人小结

不同层的数据报的名称 应用层: data TCP层: segment IP 层: packet MAC层: frame MTU vs MSS: MTU&#xff1a;一个网络包的最大长度&#xff0c;以太网中一般为 1500 字节。 https://www.xiaolincoding.com/network/1_base/how_os_deal_network_package.html#linux-%E7%BD%91…

Centos9(Stream)配置Let‘s Encrypt (免费https证书)

1. 安装snap&#xff0c;用来安装certbot&#xff1a; sudo dnf install epel-release sudo dnf upgrade sudo yum install snapd sudo systemctl enable --now snapd.socket sudo ln -s /var/lib/snapd/snap /snap snap install core snap refresh core 2. 安装 certbot命令…

Ubuntu搭建Nodejs服务器

转自&#xff1a;https://www.8kiz.cn/archives/3228.html 在Ubuntu上搭建Node.js服务器&#xff0c;按照以下步骤进行&#xff1a; 打开终端。 使用包管理器安装Node.js。可以使用以下命令安装Node.js&#xff1a; sudo apt update sudo apt install nodejs安装Node.js后&a…

基于Java SSM框架实现人事员工考勤签到请假管理系统项目【项目源码+论文说明】

基于java的SSM框架实现人事员工考勤签到请假管理系统演示 摘要 在高速发展的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;人们对人事管理系统越来越重视&#xff0…