• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

gateway 网关拦截 POST 请求的参数

武飞扬头像
被遗忘的优雅
帮助1

前言

公司的开发采用了 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);
    }
    
}
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfjaiib
系列文章
更多 icon
同类精品
更多 icon
继续加载