gateway 网关拦截 POST 请求的参数

前言

公司的开发采用了 gateway 作为微服务的网关,笔者使用中发现,gateway 网关拦截 POST 请求的参数非常麻烦,百度了很多种方法,有的获取不到,有的被读取到了,但是在往下居然获取不到了,千辛万苦终于找到了比较好的方式,以下做个笔记

相关坑

  • 过滤器中的 Body 只能被读取一次,读取后之后在就读取不到了(坑爹)
  • 由于异步问题,直接获取参数内容可能会为空,并且不同的 SpringBoot 版本,有的能获取到,有的获取不到(坑爹的异步)
  • 由于异步问题,参数采用消费的模式,一但被读取使用后,后续就将无法再次读取到

最终处理方式

思路

  • 先读取参数,并全局保存到 ServerWebExchange 中
  • 读取完成后,重新构建请求,解决只能读取一次的问题
  • 在下级过滤器中通过 ServerWebExchange 对象获取

代码

读取参数的过滤器

  • 首先在一步回调中读取参数,防止获取不到
  • 保存到 exchange 中
  • 重新构造请求,防止参数失效
@Component
public class ReqPostBodyFilter implements Ordered, GlobalFilter {

    @Override
    public int getOrder() {
        return 1;
    }

    @SuppressWarnings("NullableProblems")
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest req = exchange.getRequest();
        ServerHttpResponse res = exchange.getResponse();
        String method = req.getMethodValue();
        MediaType ct = req.getHeaders().getContentType();
        if (HttpMethod.POST.matches(method) {
            return DataBufferUtils.join(req.getBody()).flatMap(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                String bodyStr = new String(bytes, StandardCharsets.UTF_8);
                exchange.getAttributes().put("POST_BODY", bodyStr);
                DataBufferUtils.release(dataBuffer);
                Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                    DataBuffer buffer = res.bufferFactory().wrap(bytes);
                    return Mono.just(buffer);
                });
                ServerHttpRequest mutateReq = new ServerHttpRequestDecorator(req) {
                    @Override
                    public Flux<DataBuffer> getBody() {
                        return cachedFlux;
                    }
                };
                return chain.filter(exchange.mutate().request(mutateReq).build());
            });
        }
        return chain.filter(exchange);
    }
    
}

使用参数的过滤器

  • 直接从全局获取
  • getOrder方法的返回值必须比 读取参数的过滤器返回的数值大,否则获取不到
@Component
public class UserFilter implements Ordered, GlobalFilter {
    
    @Autowired
    private RouterWhiteList routerWhiteList;

    @Override
    public int getOrder() {
        return 2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		String body = (String) exchange.getAttributes().get("POST_BODY");
        return chain.filter(exchange);
    }
    
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
网关拦截并添加参数可以使用Spring Cloud Gateway的GlobalFilter来实现。在GlobalFilter的实现中,可以通过ServerWebExchange对象获取到当前请求的信息,包括请求的URL、请求方法、请求体等。 例如,下面是一个示例代码,演示如何在请求中添加一个名为“myParam”的参数: ``` @Component public class MyGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); URI uri = request.getURI(); HttpHeaders headers = request.getHeaders(); HttpMethod httpMethod = request.getMethod(); String requestBody = ""; if (httpMethod == HttpMethod.POST || httpMethod == HttpMethod.PUT) { requestBody = exchange.getAttributeOrDefault(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR, ""); } // 添加参数 MultiValueMap<String, String> queryParams = request.getQueryParams(); queryParams.add("myParam", "myValue"); // 构造新的请求 ServerHttpRequest newRequest = request.mutate() .uri(uri) .headers(headers) .method(httpMethod, httpMethod == HttpMethod.POST || httpMethod == HttpMethod.PUT ? new CustomCachedBodyOutputMessage(exchange, requestBody) : new EmptyBodyOutputMessage()) .build(); // 转发请求 return chain.filter(exchange.mutate().request(newRequest).build()); } @Override public int getOrder() { return -1; } } ``` 在上面代码中,我们首先获取了请求的URL、请求方法、请求头以及请求体(如果是POST或PUT请求)。然后,在请求参数列表中添加了一个名为“myParam”的参数。最后,构造了一个新的请求,并将其转发给下一个过滤器或目标服务。 需要注意的是,如果请求方法是POST或PUT,我们需要通过CustomCachedBodyOutputMessage类来保存请求体,因为在GatewayFilter中获取请求体会导致请求体被读取两次,这可能会导致一些问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值