【SpringCloudAlibaba專題】Springcloud gateway之獲取requestBody踩坑(G版本)

在這裏插入圖片描述


#前言
之前寫springcloud gateway收集日誌,由於之前沒有調研全面,導致了一個小坑,無法記錄post方法獲取requestBody

踩坑示範

ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(response) {
            @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);
                        String responseResult = new String(content, Charset.forName("UTF-8"));
                        normalMsg.append("status=").append(this.getStatusCode());
                        normalMsg.append(";header=").append(this.getHeaders());
                        normalMsg.append(";responseResult=").append(responseResult);
                        normalMsg.append(RESPONSE_TAIL);
                        log.info(normalMsg.toString());
                        return bufferFactory.wrap(content);
                    }));
                }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };
public class RecorderServerHttpRequestDecorator extends ServerHttpRequestDecorator {

    private final List<DataBuffer> dataBuffers = new ArrayList<>();

    public RecorderServerHttpRequestDecorator(ServerHttpRequest delegate) {
        super(delegate);
        super.getBody().map(dataBuffer -> {
            dataBuffers.add(dataBuffer);
            return dataBuffer;
        }).subscribe();
    }

    @Override
    public Flux<DataBuffer> getBody() {
        return copy();
    }

    private Flux<DataBuffer> copy() {
        return Flux.fromIterable(dataBuffers)
                .map(buf -> buf.factory().wrap(buf.asByteBuffer()));
    }


}
  1. 之前的思路是,直接Flux<DataBuffer> body = serverHttpRequest.getBody();,這種方式獲取。
  2. 獲取到body然後再將其包裝成新的request傳遞下去(因爲requestBody只能獲取一次,其他filte就會獲取不到)。

這裏面會產生兩個問題:

  1. 在封裝的時候這個subscribe是異步的,可以沒有把body的內容放進去,就直接放行了。
  2. 還有就是如果能放進去,最大也只能獲取了1024b

爬坑案例

我定義兩個filter,一個用做緩存,一個取出,什麼意思呢?

  1. 先讓請求走緩存filter,緩存放到exchange裏面,作爲它的一個變量。
  2. 從日誌的filter取出來這個變量。

CacheRequestBodyFilter

@Slf4j
@Component
public class CacheRequestBodyFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 將 request body 中的內容 copy 一份,記錄到 exchange 的一個自定義屬性中
        Object cachedRequestBodyObject = exchange.getAttributeOrDefault(FilterConstant.CACHED_REQUEST_BODY_OBJECT_KEY, null);
        // 如果已經緩存過,略過
        if (cachedRequestBodyObject != null) {
            return chain.filter(exchange);
        }
        // 如果沒有緩存過,獲取字節數組存入 exchange 的自定義屬性中
        return DataBufferUtils.join(exchange.getRequest().getBody())
                .map(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    DataBufferUtils.release(dataBuffer);
                    return bytes;
                }).defaultIfEmpty(new byte[0])
                .doOnNext(bytes -> exchange.getAttributes().put(FilterConstant.CACHED_REQUEST_BODY_OBJECT_KEY, bytes))
                .then(chain.filter(exchange));
    }

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

LoggerFilter

給出核心代碼,詳細見github:

Object cachedRequestBodyObject = exchange.getAttributes().get(FilterConstant.CACHED_REQUEST_BODY_OBJECT_KEY);
        if (cachedRequestBodyObject != null) {
            byte[] body = (byte[]) cachedRequestBodyObject;
            String string = new String(body);
            log.info("request body:");
            log.info(string);
        }

可以給個post請求下網關,看是否能獲取到requestBoy,如果可以的話,請給代碼一個star,有什麼建議歡迎下方評論。

github地址:https://github.com/fafeidou/fast-cloud-nacos/blob/master/fast-cloud-nacos-examples/cloud-rpc-examples/api-gateway/

發佈了97 篇原創文章 · 獲贊 100 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章