gateway网关局部过滤器获取前端请求body为空

gateway网关获取请求body为空

最近在项目中,有一个业务需要就是对指定接口传的参数与redis缓存中的值做比较,我与网上大多数一样都是这样直接获取

@Component
public class testGatewayFilterFactory extends AbstractGatewayFilterFactory {

 @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            //从请求里获取请求体
            String requestBodyStr = resolveBodyFromRequest(request);
            try {
                //验证请求body中是否含有某个字段
                testDao.containsStr(requestBodyStr);
            } catch (Exception e) {
                //异常信息返回
                e.printStackTrace();
                ServerHttpResponse response = exchange.getResponse();
                JSONObject message = new JSONObject();
                message.put("STATUS", -1);
                message.put("DATA", e.getMessage());
                byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer = response.bufferFactory().wrap(bits);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //指定编码,否则在浏览器中会中文乱码
                response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            }
            // 修改路径
            String newPath ="/test" + request.getPath();
            ServerHttpRequest newRequest = request.mutate()
                    .path(newPath)
                    .build();
            exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
            //放行
            return chain.filter(exchange.mutate()
                    .request(newRequest).build());
        };
    }
   /**
     * 从Flux中获取字符串的方法
     * @return 请求体
     */
    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        //获取请求体
        Flux body = serverHttpRequest.getBody();

        AtomicReference bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        //获取request body
        return bodyRef.get();
    }
    }

但是获取的body一直是空的。网上说是要先通过全局过滤器先把body缓存起来,之后后面的过滤器中再使用exchange.getRequest().getBody()来获取body时,就能获取到了。但是我testGatewayFilterFactory这个过滤器设置的级别order是0,级别在我设置的过滤器中是最高的,指定方法第一个进的filter也是它,为什么还要缓存起来呢。后来在自己定义的一个全局过滤器打断点,发现请求方法进入了testGatewayFilterFactory局部过滤器之后没执行完,又到了全局过滤器,这时候我觉得应该是要将body缓存起来,试了一下还真的可以。只是现在还不知道具体的原因,希望有小伙伴能告诉我。不过获取body为空的问题是解决了。
主要就是在增加一个全局过滤器,把级别设置为最高,把body缓存好。上代码网上也有很多

@Component
public class testBodyGlobalFilter implements Ordered, GlobalFilter {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (exchange.getRequest().getHeaders().getContentType() == null) {
            return chain.filter(exchange);
        } else {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        DataBufferUtils.retain(dataBuffer);
                        Flux cachedFlux = Flux
                                .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
                    });
        }
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

}

Ordered.HIGHEST_PRECEDENCE就是最高级别的,所有请求第一个走的都是这个过滤器,加了这个过滤器后,testGatewayFilterFactory 这个局部过滤器就可以获取到body的数据了。

你可能感兴趣的:(gateway,微服务,java,网关,filter,gateway,过滤器)