基于若依Gateway中Filter的读取参数、修改请求体

若依使用的GateWay引用的pom为

<!-- SpringCloud Gateway -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

其实就是cloud的一套如果在GateWay调用feign接口前面的文章已经提到过了,这里就解决如果拦截post请求下面的body信息并重新添加参数往后传。

如何使用feign接口icon-default.png?t=N7T8https://blog.csdn.net/tao724624173/article/details/138125217看过不少帖子有很多大佬有不不同的看法,比如若依自带就是AuthFilter中有重新修改headers的信息,既然head可以改,那body自然也可以改。

因为我使用的filter不是实现GlobalFilter的大家觉得写法可能有出入其实是一样的,下面废话不多说直接贴代码。

@Component
public class DemoFilter extends AbstractGatewayFilterFactory<Object> {

    private static final Logger log = LoggerFactory.getLogger(DemoFilter.class);

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            //校验请求方式
            if (request.getMethod() != HttpMethod.POST) {
                return chain.filter(exchange);
            }

            String path = request.getURI().getPath();

            try {
                String rspStr = resolveBodyFromRequest(request);
                if (rspStr == null || rspStr.trim().length() == 0) {
                    throw new ServiceException(ResultCode.PARAM_CANNOT_NULL);
                }

                //获取的body信息
                JSONObject obj = JSON.parseObject(rspStr);
                log.info("请求路径和参数:{},obj{}", path, JSON.toJSONString(obj));

                //添加body信息
                obj.put("name", "莫小邪");

                //重构body
                byte[] bytes = obj.toJSONString().getBytes(StandardCharsets.UTF_8);
                DataBuffer bodyDataBuffer = stringToDataBuffer(bytes);
                Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
                // 重构header
                ServerHttpRequest newRequest = request.mutate().build();
                HttpHeaders newHeaders = new HttpHeaders();
                newHeaders.putAll(exchange.getRequest().getHeaders());
                //新增heads
                newHeaders.put("AK", Arrays.asList("123456"));

                newRequest = new ServerHttpRequestDecorator(newRequest) {
                    @Override
                    public HttpHeaders getHeaders() {
                        return newHeaders;
                    }

                    @Override
                    public Flux<DataBuffer> getBody() {
                        return bodyFlux;
                    }
                };
                return chain.filter(exchange.mutate().request(newRequest).build());
            } catch (Exception e) {
                if (e.getCause() instanceof ServiceException) {
                    ServiceException se = (ServiceException) e.getCause();
                    return unauthorizedResponse(exchange, se.getMessage());
                }
                log.error("[鉴权异常处理]请求路径:{},msg:{}", exchange.getRequest().getPath(), e.getMessage());
                return unauthorizedResponse(exchange, ResultCode.AUTHENTICATION_REQUEST_FAILED.getMessage());
            }
        };
    }

    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());
        });
        return bodyRef.get();
    }

    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
    }

    private DataBuffer stringToDataBuffer(byte[] bytes) {
        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
        DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
        buffer.write(bytes);
        return buffer;
    }
}

其实这段中主要是这段重构body和head的其他都是一样的。

之前也参考了其他人的但是感觉代码量有点大,并不适合自己有兴趣的可以去看看。

Spring Cloud Gateway 读取、修改请求体(解决request body内容被截断)

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Cloud Gateway可以使用过滤器修改请求参数。可以通过实现GlobalFilter或者GatewayFilter接口filter方法来实现。 下面是一个实现修改请求参数的例子: ```java @Component public class ModifyRequestBodyFilter implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { HttpHeaders headers = exchange.getRequest().getHeaders(); String contentType = headers.getFirst(HttpHeaders.CONTENT_TYPE); if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType)) { // 获取请求参数 return DataBufferUtils.join(exchange.getRequest().getBody()) .flatMap(dataBuffer -> { byte[] bytes = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); String bodyStr = new String(bytes, StandardCharsets.UTF_8); // 修改请求参数 JSONObject jsonObject = JSON.parseObject(bodyStr); jsonObject.put("key", "value"); String newBodyStr = jsonObject.toJSONString(); byte[] newBytes = newBodyStr.getBytes(StandardCharsets.UTF_8); // 将修改后的请求设置回去 Flux<DataBuffer> flux = Flux.just(exchange.getResponse() .bufferFactory().wrap(newBytes)); HttpHeaders headers1 = new HttpHeaders(); headers1.putAll(headers); headers1.setContentLength(newBytes.length); headers1.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); ServerHttpRequest request = exchange.getRequest().mutate() .headers(h -> h.addAll(headers1)) .build(); ServerWebExchange newExchange = exchange.mutate().request(request).build(); return chain.filter(newExchange); }); } return chain.filter(exchange); } } ``` 在这个例子,我们实现了一个名为ModifyRequestBodyFilter的过滤器,它会在请求头的Content-Type为application/json时修改请求参数。具实现步骤如下: 1. 获取请求参数。 2. 将请求参数转换为JSON对象并修改。 3. 将修改后的请求设置回去。 4. 调用chain.filter方法继续处理请求
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值