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<DataBuffer>中获取字符串的方法
     * @return 请求体
     */
    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        //获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();

        AtomicReference<String> 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<Void> 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<DataBuffer> cachedFlux = Flux
                                .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
                    });
        }
    }

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

}

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Gateway是一个基于Spring Cloud的微服务,它提供了一系列过滤器、路由和负载均衡等功能,可以用于构建分布式系统中的API。 要记录缓存请求body和form表单,可以通过自定义过滤器来实现。首先,需要创建一个实现了GatewayFilter和Ordered接口的自定义过滤器类。在这个过滤器中,可以获取请求body和form表单,并将其缓存起来。 下面是一个简单的实现示例: ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class RequestLoggingFilter implements GatewayFilter, Ordered { private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject"; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取请求body和form表单 String body = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY); String form = exchange.getRequest().getHeaders().getFirst("Content-Type"); // TODO: 在这里记录缓存body和form表单 return chain.filter(exchange); } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } } ``` 在这个过滤器中,我们通过`exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY)`方法获取到了请求body,并通过`exchange.getRequest().getHeaders().getFirst("Content-Type")`方法获取到了请求的form表单。 接下来,可以在`filter`方法中实现对缓存的记录逻辑,比如将body和form表单保存到数据库或日志中。 最后,将自定义的过滤器类添加到Spring Cloud Gateway的路由中,以便生效。 以上是一个简单的示例,实际情况可能会更复杂,需要根据具体的业务需求进行适当的调整和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值