SpringCloudGateway过滤器获取request和response的body

该博客主要介绍了一个实现于Spring Cloud Gateway的全局过滤器,用于在POST请求中捕获并记录请求和响应体。过滤器通过订阅请求体,缓存数据,然后在响应时读取并处理数据,释放内存,并将响应体转换为大写。同时,它还展示了如何设置过滤器的执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("当前过滤器order:{}", getOrder());

        return HttpMethod.POST.equals(exchange.getRequest().getMethod()) ?
                DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
                    DataBufferUtils.retain(dataBuffer);
                    Flux<DataBuffer> cachedFlux = Flux.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
                    ServerHttpRequest decoratedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return cachedFlux;
                        }
                    };
                    String requestBody = resolveBodyFromRequest(decoratedRequest.getBody());
                    ServerHttpResponse originalResponse = exchange.getResponse();
                    DataBufferFactory bufferFactory = originalResponse.bufferFactory();
                    ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
                        @Override
                        public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                            if (body instanceof Flux) {
                                Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                                return super.writeWith(fluxBody.map(dataBuffer -> {
                                    // probably should reuse buffers
                                    byte[] content = new byte[dataBuffer.readableByteCount()];
                                    dataBuffer.read(content);
                                    //释放掉内存
                                    DataBufferUtils.release(dataBuffer);
                                    String responseBody = new String(content, Charset.forName("UTF-8"));
                                    log.info("requestBody:{}", requestBody);
                                    log.info("responseBody:{}", responseBody);
                                    byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();
                                    return bufferFactory.wrap(uppedContent);
                                }));
                            }
                            // if body is not a flux. never got there.
                            return super.writeWith(body);
                        }
                    };
                    return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build());
                }) : chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -10;
    }

    /**
     * spring cloud gateway 获取post请求的body体
     *
     * @param body
     * @return
     */
    private String resolveBodyFromRequest(Flux<DataBuffer> body) {
        AtomicReference<String> bodyRef = new AtomicReference<>();
        // 缓存读取的request body信息
        body.subscribe(dataBuffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(dataBuffer.asByteBuffer());
            DataBufferUtils.release(dataBuffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();

    }

}

仅限POST请求,且order<-1

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>
Spring Cloud Gateway 是一个基于 Spring Framework 的轻量级、高性能的 API 网关,它允许开发者路由、过滤、增强拦截网络流量,包括 HTTP 请求的 body 部分。 在 Spring Cloud Gateway 中,你可以通过 `WebFlux` 的响应拦截器机制来截获并处理请求的 body。具体步骤如下: 1. **创建拦截器**:首先,你需要自定义一个 `GlobalFilter` 或 `ExchangeFilterFunction` 类,这是 Gateway 提供的用于添加全局过滤功能的接口。 ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterFunction; import org.springframework.stereotype.Component; @Component public class BodyLoggingFilter implements GatewayFilterFunction { @Override public GatewayFilter apply(String id) { return new LoggingBodyGatewayFilter(id); } } ``` 这里 `LoggingBodyGatewayFilter` 是一个具体的拦截器实现,它会记录请求的 body 内容。 2. **配置启用**:在 Gateway 的配置类(如 `application.yml` 或 `application.properties`)中注册这个过滤器,并指定需要应用的路径前缀。 ```yaml spring: cloud: gateway: filters: - Predicates: path=/api/** filter-factory: com.example.BodyLoggingFilter ``` 这表示对所有路径以 `/api` 开头的请求都会应用你的拦截器。 3. **拦截逻辑**:在 `LoggingBodyGatewayFilter` 中,你可以获取到 `ServerWebExchange` 对象,从中读取请求体的内容,然后进行处理、日志记录等操作。 ```java @Component public class LoggingBodyGatewayFilter extends ServerWebExchangeConverter { private final String id; public LoggingBodyGatewayFilter(String id) { this.id = id; } @Override protected Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange).flatMap(response -> { // 这里可以访问 request body Object requestBody = exchange.getAttributes().get(BodyExtractor.REQUEST_BODY_ATTRIBUTE); log.info("Received request with ID {} and body: {}", id, requestBody); return response; }); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值