Spring Cloud Gateway 如何动态添加请求参数,java程序员面试书籍

简单来说,问题就是 Spring Cloud Gateway 如何动态添加请求参数。

Spring Cloud Gateway Add Request Parameter

  1. 查看官方文档,提供了下面的示例:

docs.spring.io/spring-clou…

image.png

但是是在配置文件写明的,看起来好像只能是固定值。

  1. 在github上看到也有人提了类似问题,

github.com/spring-clou…

image.png

但是实现的效果也跟配置文件差不多。

  1. 在stackoverflow上也查了类似回答:

stackoverflow.com/questions/6…

image.png

大概思路有了方向。

解决方案

====

在 Spring Cloud Gateway 源码上,发现了这两个类 AddRequestParameterGatewayFilterFactoryModifyRequestBodyGatewayFilterFactory

image.png

代码内容如下:

AddRequestParameterGatewayFilterFactory


//

// Source code recreated from a .class file by IntelliJ IDEA

// (powered by FernFlower decompiler)

//

package org.springframework.cloud.gateway.filter.factory;

import java.net.URI;

import org.springframework.cloud.gateway.filter.GatewayFilter;

import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory.NameValueConfig;

import org.springframework.http.server.reactive.ServerHttpRequest;

import org.springframework.util.StringUtils;

import org.springframework.web.util.UriComponentsBuilder;

public class AddRequestParameterGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

public AddRequestParameterGatewayFilterFactory() {

}

public GatewayFilter apply(NameValueConfig config) {

return (exchange, chain) -> {

URI uri = exchange.getRequest().getURI();

StringBuilder query = new StringBuilder();

String originalQuery = uri.getRawQuery();

if (StringUtils.hasText(originalQuery)) {

query.append(originalQuery);

if (originalQuery.charAt(originalQuery.length() - 1) != ‘&’) {

query.append(‘&’);

}

}

query.append(config.getName());

query.append(‘=’);

query.append(config.getValue());

try {

URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(query.toString()).build(true).toUri();

ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();

return chain.filter(exchange.mutate().request(request).build());

} catch (RuntimeException var8) {

throw new IllegalStateException(“Invalid URI query: “” + query.toString() + “””);

}

};

}

}

复制代码

ModifyRequestBodyGatewayFilterFactory


//

// Source code recreated from a .class file by IntelliJ IDEA

// (powered by FernFlower decompiler)

//

package org.springframework.cloud.gateway.filter.factory.rewrite;

import java.util.Map;

import org.springframework.cloud.gateway.filter.GatewayFilter;

import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;

import org.springframework.cloud.gateway.support.BodyInserterContext;

import org.springframework.cloud.gateway.support.CachedBodyOutputMessage;

import org.springframework.cloud.gateway.support.DefaultServerRequest;

import org.springframework.core.io.buffer.DataBuffer;

import org.springframework.http.HttpHeaders;

import org.springframework.http.codec.ServerCodecConfigurer;

import org.springframework.http.server.reactive.ServerHttpRequestDecorator;

import org.springframework.web.reactive.function.BodyInserter;

import org.springframework.web.reactive.function.BodyInserters;

import org.springframework.web.reactive.function.server.ServerRequest;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

public class ModifyRequestBodyGatewayFilterFactory extends AbstractGatewayFilterFactory<ModifyRequestBodyGatewayFilterFactory.Config> {

public ModifyRequestBodyGatewayFilterFactory() {

super(ModifyRequestBodyGatewayFilterFactory.Config.class);

}

/** @deprecated */

@Deprecated

public ModifyRequestBodyGatewayFilterFactory(ServerCodecConfigurer codecConfigurer) {

this();

}

public GatewayFilter apply(ModifyRequestBodyGatewayFilterFactory.Config config) {

return (exchange, chain) -> {

Class inClass = config.getInClass();

ServerRequest serverRequest = new DefaultServerRequest(exchange);

Mono<?> modifiedBody = serverRequest.bodyToMono(inClass).flatMap((o) -> {

return config.rewriteFunction.apply(exchange, o);

});

BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, config.getOutClass());

CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getRequest().getHeaders());

return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {

ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {

public HttpHeaders getHeaders() {

HttpHeaders httpHeaders = new HttpHeaders();

httpHeaders.putAll(super.getHeaders());

httpHeaders.set(“Transfer-Encoding”, “chunked”);

return httpHeaders;

}

public Flux getBody() {

return outputMessage.getBody();

}

};

return chain.filter(exchange.mutate().request(decorator).build());

}));

};

}

public static class Config {

private Class inClass;

private Class outClass;

private Map<String, Object> inHints;

private Map<String, Object> outHints;

private RewriteFunction rewriteFunction;

public Config() {

}

public Class getInClass() {

return this.inClass;

}

public ModifyRequestBodyGatewayFilterFactory.Config setInClass(Class inClass) {

this.inClass = inClass;

return this;

}

public Class getOutClass() {

return this.outClass;

}

public ModifyRequestBodyGatewayFilterFactory.Config setOutClass(Class outClass) {

this.outClass = outClass;

return this;

}

public Map<String, Object> getInHints() {

return this.inHints;

}

public ModifyRequestBodyGatewayFilterFactory.Config setInHints(Map<String, Object> inHints) {

this.inHints = inHints;

return this;

}

public Map<String, Object> getOutHints() {

return this.outHints;

}

public ModifyRequestBodyGatewayFilterFactory.Config setOutHints(Map<String, Object> outHints) {

this.outHints = outHints;

return this;

}

public RewriteFunction getRewriteFunction() {

return this.rewriteFunction;

}

public <T, R> ModifyRequestBodyGatewayFilterFactory.Config setRewriteFunction(Class inClass, Class outClass, RewriteFunction<T, R> rewriteFunction) {

this.setInClass(inClass);

this.setOutClass(outClass);

this.setRewriteFunction(rewriteFunction);

return this;

}

public ModifyRequestBodyGatewayFilterFactory.Config setRewriteFunction(RewriteFunction rewriteFunction) {

this.rewriteFunction = rewriteFunction;

return this;

}

}

}

复制代码

实际上,可以当作官方提供的参考示例。

照着类似内容,我们可以依样画葫芦,在自己的网关过滤器上实现添加参数的功能。

实现代码

====

鉴权过滤器主要处理流程


@Component

public class AuthFilter implements GlobalFilter, Ordered {

private static final Logger LOGGER = LoggerFactory.getLogger(AuthFilter.class);

private static AntPathMatcher antPathMatcher;

static {

antPathMatcher = new AntPathMatcher();

}

@Override

public int getOrder() {

return FilterOrderConstant.getOrder(this.getClass().getName());

}

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

ServerHttpRequest request = exchange.getRequest();

URI uri = request.getURI();

String url = uri.getPath();

String host = uri.getHost();

// 跳过不需要验证的路径

Stream skipAuthUrls = UrlConstant.skipAuthUrls.stream();

if(skipAuthUrls.anyMatch(path -> antPathMatcher.match(path, url))){

// 直接返回

ServerHttpRequest.Builder builder = request.mutate();

return chain.filter(exchange.mutate().request(builder.build()).build());

}

// 从请求头中取出token

String token = request.getHeaders().getFirst(“Authorization”);

// 取出token包含的身份信息

// 校验token逻辑不再阐述

BaseDTO baseDTO = getClaim(token);

if(null == baseDTO){

// 鉴权不通过,拿不到身份信息

return illegalResponse(exchange, “{“code”: “401”,“msg”: “unauthorized.”}”);

}

// 将现在的request,添加当前身份信息

ServerHttpRequest.Builder builder = request.mutate();

Stream addRequestParameterUrls = UrlConstant.addRequestParameterUrls.stream();

if (addRequestParameterUrls.anyMatch(path -> antPathMatcher.match(path, url))){

// 需要添加请求参数

if(request.getMethod() == HttpMethod.GET){

// get请求 处理参数

return addParameterForGetMethod(exchange, chain, uri, baseDTO, builder);

}

if(request.getMethod() == HttpMethod.POST){

// post请求 处理参数

MediaType contentType = request.getHeaders().getContentType();

if(MediaType.APPLICATION_JSON.equals(contentType)

|| MediaType.APPLICATION_JSON_UTF8.equals(contentType)){

// 请求内容为 application json

return addParameterForPostMethod(exchange, chain, baseDTO);

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

分享

1、算法大厂——字节跳动面试题

2、2000页互联网Java面试题大全

3、高阶必备,算法学习

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)**
[外链图片转存中…(img-S1Lyd4dO-1712183791402)]

分享

1、算法大厂——字节跳动面试题

[外链图片转存中…(img-w1p4nIoD-1712183791402)]

2、2000页互联网Java面试题大全

[外链图片转存中…(img-BqzFrJW9-1712183791403)]

3、高阶必备,算法学习

[外链图片转存中…(img-YorRHaol-1712183791403)]

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值