国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringCloud Gateway獲取請(qǐng)求響應(yīng)body大小

這篇具有很好參考價(jià)值的文章主要介紹了SpringCloud Gateway獲取請(qǐng)求響應(yīng)body大小。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前提

本文獲取請(qǐng)求、響應(yīng)body大小方法的前提 : 網(wǎng)關(guān)只做轉(zhuǎn)發(fā)邏輯,不修改請(qǐng)求、相應(yīng)的body內(nèi)容。
SpringCloud Gateway內(nèi)部的機(jī)制類似下圖,HttpServer(也就是NettyServer)接收外部的請(qǐng)求,在Gateway內(nèi)部請(qǐng)求將會(huì)通過(guò)HttpClient(Netty實(shí)現(xiàn)的客戶端)發(fā)送給后端應(yīng)用。
本文的body獲取方式,基于HttpClient端實(shí)現(xiàn),通過(guò)獲取HttpClient發(fā)送、接收后端的請(qǐng)求、響應(yīng)body實(shí)現(xiàn)。如果SpringCloudGateway內(nèi)部邏輯修改了body,那么本文方式獲取的body大小將會(huì)存在歧義誤差。
如果想要在HttpServer層獲取到報(bào)文大小,可以嘗試自定義實(shí)現(xiàn)Netty的ChannelDuplexHandler,嘗試獲取到報(bào)文大小。
SpringCloud Gateway獲取請(qǐng)求響應(yīng)body大小,SpringCloudGateway,gateway,spring cloud,java

SpringCloud Gateway底層基于異步模型Netty實(shí)現(xiàn),調(diào)用時(shí)相關(guān)的body內(nèi)容不直接加載到內(nèi)存。如果使用簡(jiǎn)單的SpringCloud Gateway Filter讀取報(bào)文,讀取body大小,會(huì)大幅影響網(wǎng)關(guān)性能。因此需要考慮一種方法,在不影響網(wǎng)關(guān)性能的前提下,獲取請(qǐng)求、響應(yīng)body大小。

方式一、重寫(xiě)SpringCloudGateway Filter類

重寫(xiě) NettyRoutingFilter 獲取 Request Body

重寫(xiě)Gateway自帶的org.springframework.cloud.gateway.filter.NettyRoutingFilter。
修改類的filter內(nèi)的代碼,在底層獲取請(qǐng)求body的大小,并在exchange保存。

Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
      .headers(headers -> {
         ...
      }).request(method).uri(url).send((req, nettyOutbound) -> {
         ...
         return nettyOutbound.send(request.getBody().map(body -> {
            // 修改此處代碼,獲取請(qǐng)求body的大小,并將獲取到的結(jié)果存入exchange內(nèi)。
            int size = body.readableByteCount();
            exchange.getAttributes().put("gw-request-body-size", size);
            return getByteBuf(body);
         }));
      }).responseConnection((res, connection) -> {
        ...

重寫(xiě) NettyWriteResponseFilter 獲取 Response Body

重寫(xiě)Gateway自帶的org.springframework.cloud.gateway.filter.NettyWriteResponseFilter
修改類filter內(nèi)的代碼,在底層獲取響應(yīng)body的大小,并在exchange保存。

return chain.filter(exchange)
      .doOnError(throwable -> cleanup(exchange))
      .then(Mono.defer(() -> {
        ...
         // TODO: needed?
         final Flux<DataBuffer> body = connection
               .inbound()
               .receive()
               .retain()
               .map(byteBuf -> {
                  // 獲取響應(yīng)報(bào)文的長(zhǎng)度,并將結(jié)果寫(xiě)入exchange內(nèi)。
                  int respSize = byteBuf.readableBytes();
                  exchange.getAttributes().put("gw-response-body-size", respSize);
                  return wrap(byteBuf, response);
               });
      ...

自定義Filter打印報(bào)文大小

通過(guò)上述的2個(gè)方法,request、response body的大小已經(jīng)寫(xiě)入exchange內(nèi),只需要實(shí)現(xiàn)一個(gè)自定義的Filter,就可以獲取到報(bào)文的大小。假設(shè)自定義的Filter命名為BodySizeFilter,它的Order需要在NettyWriteResponseFilter之前。
SpringCloud Gateway獲取請(qǐng)求響應(yīng)body大小,SpringCloudGateway,gateway,spring cloud,java

在filter方法內(nèi),從exchange獲取request、response body大小。

@Slf4j
@Component
public class BodySizeFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange)
                .then(Mono.defer(() -> {
                    Integer exchangeReq = exchange.getAttribute("gw-request-body-size");
                    Integer exchangeResp = exchange.getAttribute("gw-response-body-size");
                    log.info("req from exchange: {}", exchangeReq);
                    log.info("resp from exchange: {}", exchangeResp);
                    return Mono.empty();
                }));
    }
    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }
}

方式二、自定義Netty Handler

另一種方式是基于Netty的Hander,非重寫(xiě)SpringCloud Gateway類。本文構(gòu)建的SpringCloudGateway版本為2.2.9.RELEASE

實(shí)現(xiàn)自定義的Netty ChannelDuplexHandler

重寫(xiě)2個(gè)方法 write、channelRead。

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.UUID;

@Slf4j
public class HttpClientLoggingHandler extends ChannelDuplexHandler {
    private static final AttributeKey<Long> RESP_SIZE = AttributeKey.valueOf("resp-size");

    private static final AttributeKey<Long> REQ_SIZE = AttributeKey.valueOf("req-size");

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        if (msg instanceof ByteBuf) {
            final ByteBuf buf = (ByteBuf) msg;
            // 讀取報(bào)文大小,一筆請(qǐng)求可能存在多個(gè) msg,也就是一個(gè)請(qǐng)求報(bào)文,可能分多次經(jīng)過(guò)write方法。
            int length = buf.readableBytes();
            long size;
            // 將結(jié)果以attribute形式保存在channel內(nèi),一筆完整的調(diào)用對(duì)應(yīng)一個(gè)完整的context上下文。
            Attribute<Long> sizeAttr = ctx.channel().attr(REQ_SIZE);
            if (sizeAttr.get() == null) {
                size = 0L;
            } else {
                size = sizeAttr.get();
            }
            // 每次累加當(dāng)前請(qǐng)求的報(bào)文大小。
            size += length;
            ctx.channel().attr(REQ_SIZE).set(size);
        }
        super.write(ctx, msg, promise);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ByteBuf) {
            final ByteBuf buf = (ByteBuf) msg;
            // 獲取響應(yīng)body的大小,一筆響應(yīng)可能存在多個(gè) msg,也就是一個(gè)響應(yīng)報(bào)文,可能分多次經(jīng)過(guò)channelRead方法。
            int length = buf.readableBytes();
            long size;
            Attribute<Long> sizeAttr = ctx.channel().attr(RESP_SIZE);
            if (sizeAttr.get() == null) {
                size = 0L;
            } else {
                size = ctx.channel().attr(RESP_SIZE).get();
            }
            size += length;
            // 將結(jié)果以attribute形式保存在channel內(nèi),一筆完整的調(diào)用對(duì)應(yīng)一個(gè)完整的context上下文。
            ctx.channel().attr(RESP_SIZE).set(size);
        }
        super.channelRead(ctx, msg);
    }
}

將自定義Handler配置到網(wǎng)關(guān)內(nèi)。

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.config.HttpClientCustomizer;
import org.springframework.context.annotation.Configuration;
import reactor.netty.channel.BootstrapHandlers;
import reactor.netty.http.client.HttpClient;

@Slf4j
@Configuration
public class GwHttpClientCustomizer implements HttpClientCustomizer {
    @Override
    public HttpClient customize(HttpClient client) {
        // 本文基于2.2.9.RELEASE的SpringCloud Gateway實(shí)現(xiàn)。
        return client.tcpConfiguration(tcpClient ->
                tcpClient.bootstrap(b ->
                        BootstrapHandlers.updateConfiguration(b, "client-log", (connectionObserver, channel) -> {
                            channel.pipeline().addFirst("client-log", new HttpClientLoggingHandler());
                        })
                )
        );
    }
}

通過(guò)上述自定義的方法,一筆完整的調(diào)用中請(qǐng)求、響應(yīng)body的大小,已經(jīng)被計(jì)算保存在netty channel內(nèi),只需要自定義SpringCloud Gateway Filter獲取到結(jié)果。

import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.netty.Connection;

import java.util.function.Consumer;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CLIENT_RESPONSE_CONN_ATTR;

/**
 * @author luobo on 2023/08/01 3:51 PM
 */
@Slf4j
@Component
public class BodySizeFilter implements GlobalFilter, Ordered {

    private static final AttributeKey<Long> REQ_SIZE = AttributeKey.valueOf("req-size");

    private static final AttributeKey<Long> RESP_SIZE = AttributeKey.valueOf("resp-size");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange)
                .then(Mono.defer(() -> {
                    // SpringCloud Gateway內(nèi)將每個(gè)調(diào)用的Connection保存在exchange內(nèi)
                    // connection 可以獲取到 channel
                    Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);
                    Attribute<Long> respSize = connection.channel().attr(RESP_SIZE);
                    Attribute<Long> reqSize = connection.channel().attr(REQ_SIZE);
                    long resp;
                    if (respSize.get() == null) {
                        resp = 0L;
                    } else {
                        resp = respSize.get();
                    }
                    long req;
                    if (reqSize.get() == null) {
                        req = 0L;
                    } else {
                        req = reqSize.get();
                    }
                    log.info("------------------------> resp size: {}", resp);
                    log.info("------------------------> req size: {}", req);
                    // 每次調(diào)用結(jié)束需要清空保存的值(因?yàn)檫B接會(huì)復(fù)用)
                    respSize.set(null);
                    reqSize.set(null);
                    return Mono.empty();
                }));
    }

    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }
}

通過(guò)此方法獲取的body大小會(huì)比真實(shí)的body大 ,因?yàn)樗苏?qǐng)求和響應(yīng)頭的信息。


總結(jié)

本人更加推薦使用方式一。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-622653.html

到了這里,關(guān)于SpringCloud Gateway獲取請(qǐng)求響應(yīng)body大小的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Java】SpringCloud Gateway自定義過(guò)濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問(wèn)題

    【Java】SpringCloud Gateway自定義過(guò)濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問(wèn)題

    這個(gè)情況出現(xiàn)在,我需要進(jìn)行驗(yàn)證碼的校驗(yàn),因此用戶的請(qǐng)求首先需要被驗(yàn)證碼過(guò)濾器校驗(yàn),而驗(yàn)證碼過(guò)濾器不需要設(shè)定為全局過(guò)濾器,因此我就單純的把它設(shè)定為了一個(gè)局部過(guò)濾器,代碼如下 然后我進(jìn)行請(qǐng)求的時(shí)候,json參數(shù)如下 然后請(qǐng)求經(jīng)過(guò)解析后會(huì)發(fā)現(xiàn),字符串居然是

    2024年02月09日
    瀏覽(17)
  • SpringCloud GateWay通過(guò)過(guò)濾器GatewayFilter修改請(qǐng)求或響應(yīng)內(nèi)容

    Spring Cloud Gateway在有些場(chǎng)景中需要獲取request body內(nèi)容進(jìn)行參數(shù)校驗(yàn)或參數(shù)修改,我們通過(guò)在GatewayFilter中獲取請(qǐng)求內(nèi)容來(lái)獲取和修改請(qǐng)求體,下面我們就基于ServerWebExchange來(lái)實(shí)現(xiàn): ServerWebExchange命名為服務(wù)網(wǎng)絡(luò)交換器,存放著重要的請(qǐng)求-響應(yīng)屬性、請(qǐng)求實(shí)例和響應(yīng)實(shí)例等等,有

    2024年02月16日
    瀏覽(23)
  • SpringCloudGateway獲取body中的參數(shù),最優(yōu)雅的方式

    ? ? ? ? 項(xiàng)目需要在Gateway中獲取請(qǐng)求參數(shù),原生提供了request.getQueryParams()方法獲取請(qǐng)求參數(shù),但是只能獲得url上的param,對(duì)于form body中的參數(shù)獲取不到。找了很多方法,網(wǎng)上普遍都是通過(guò)自定義Filter緩存Body中的內(nèi)容,然后再獲取緩存的Body,此處的緩存實(shí)現(xiàn)方法各異,有些還

    2024年02月15日
    瀏覽(20)
  • springcloud的gateway之GlobalFilter獲取請(qǐng)求信息及requestBody

    《本文參考地址》 RequestGlobalFilter.java ResponseGlobalFilter.java RequestAndResponseGlobalFilter.java

    2024年02月16日
    瀏覽(21)
  • 記一次線上bug排查-----SpringCloud Gateway組件 請(qǐng)求頭accept-encoding導(dǎo)致響應(yīng)結(jié)果亂碼

    記一次線上bug排查-----SpringCloud Gateway組件 請(qǐng)求頭accept-encoding導(dǎo)致響應(yīng)結(jié)果亂碼

    ? ? ? ?基于公司的業(yè)務(wù)需求,在SpringCloud Gateway組件的基礎(chǔ)上,寫(xiě)了一個(gè)轉(zhuǎn)發(fā)服務(wù),測(cè)試開(kāi)發(fā)階段運(yùn)行正常,并實(shí)現(xiàn)初步使用。但三個(gè)月后,PostMan請(qǐng)求接口,返回異常,經(jīng)排查,從日志中獲取到轉(zhuǎn)發(fā)響應(yīng)的結(jié)果為亂碼: ? ? ?? 跟蹤日志: 轉(zhuǎn)發(fā)到目標(biāo)接口,響應(yīng)結(jié)果已亂碼

    2024年02月04日
    瀏覽(23)
  • SpringCloudGateway過(guò)濾器(全局認(rèn)證、IP攔截、請(qǐng)求參數(shù)過(guò)濾、響應(yīng)參數(shù)過(guò)濾)

    全局過(guò)濾器(認(rèn)證) IP網(wǎng)關(guān)過(guò)濾器 請(qǐng)求參數(shù)網(wǎng)關(guān)過(guò)濾器

    2024年02月14日
    瀏覽(53)
  • http請(qǐng)求和響應(yīng)格式說(shuō)明,http的get和post請(qǐng)求方式說(shuō)明,http的請(qǐng)求體body的幾種數(shù)據(jù)格式

    http請(qǐng)求和響應(yīng)格式說(shuō)明,http的get和post請(qǐng)求方式說(shuō)明,http的請(qǐng)求體body的幾種數(shù)據(jù)格式

    一個(gè)HTTP請(qǐng)求報(bào)文由 請(qǐng)求行(request line)、請(qǐng)求頭部(header)、空行和請(qǐng)求數(shù)據(jù) 4個(gè)部分組成, 請(qǐng)求報(bào)文的一般格式 1、第一行必須是一個(gè)請(qǐng)求行(request-line),用來(lái)說(shuō)明請(qǐng)求類型,要訪問(wèn)的資源以及所使用的HTTP版本 2、緊接著是一個(gè)請(qǐng)求頭(header),用來(lái)說(shuō)明服務(wù)器要使用的附加信息

    2024年02月02日
    瀏覽(30)
  • SpringCloud Gateway 3.x 響應(yīng)頭添加 Skywalking TraceId

    在微服務(wù)架構(gòu)中,一次請(qǐng)求可能會(huì)被多個(gè)服務(wù)處理,而每個(gè)服務(wù)又會(huì)產(chǎn)生相應(yīng)的日志,且每個(gè)服務(wù)也會(huì)有多個(gè)實(shí)例。在這種情況下,如果系統(tǒng)發(fā)生異常,沒(méi)有 Trace ID,那么在進(jìn)行日志分析和追蹤時(shí)就會(huì)非常困難,因?yàn)槲覀儫o(wú)法將所有相關(guān)的日志信息串聯(lián)起來(lái)。 如果將 Trace I

    2023年04月24日
    瀏覽(28)
  • springcloud gateway中打印請(qǐng)求參數(shù),請(qǐng)求路徑和返回?cái)?shù)據(jù)

    springcloud gateway中打印請(qǐng)求參數(shù),請(qǐng)求路徑和返回?cái)?shù)據(jù)

    在平時(shí)前后端聯(lián)調(diào)過(guò)程中,需要查詢?nèi)罩究吹角岸苏?qǐng)求的接口,上送的參數(shù),返回?cái)?shù)據(jù)這樣有利于我們定位問(wèn)題;話不多說(shuō)直接上代碼。 在gateway模塊中,新建一個(gè)filter的包,然后創(chuàng)建改類,即可在控制臺(tái)和日志文件里面打印出請(qǐng)求參數(shù),只寫(xiě)了常用的 post 和 get 請(qǐng)求的方式;

    2024年02月15日
    瀏覽(24)
  • Gateway全局異常處理及請(qǐng)求響應(yīng)監(jiān)控

    Gateway全局異常處理及請(qǐng)求響應(yīng)監(jiān)控

    我們?cè)谏弦黄恼禄趬簻y(cè)進(jìn)行Feign調(diào)優(yōu)完成的服務(wù)間調(diào)用的性能調(diào)優(yōu),此時(shí)我們也關(guān)注到一個(gè)問(wèn)題,如果我們統(tǒng)一從網(wǎng)關(guān)調(diào)用服務(wù),但是網(wǎng)關(guān)因?yàn)槟承┰驁?bào)錯(cuò)或者沒(méi)有找到服務(wù)怎么辦呢? 如下所示,筆者通過(guò)網(wǎng)關(guān)調(diào)用 account 服務(wù),但是 account 服務(wù)還沒(méi)起來(lái)。此時(shí)請(qǐng)求還沒(méi)

    2024年02月04日
    瀏覽(24)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包