欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud?Gateway之請(qǐng)求應(yīng)答日志打印方式

 更新時(shí)間:2022年03月09日 16:06:12   作者:weixin_34082177  
這篇文章主要介紹了SpringCloud?Gateway之請(qǐng)求應(yīng)答日志打印方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Gateway請(qǐng)求應(yīng)答日志打印

請(qǐng)求應(yīng)答日志時(shí)在日常開發(fā)調(diào)試問題的重要手段之一,那么如何基于Spring Cloud Gateway做呢,請(qǐng)看我上代碼。

第一步

創(chuàng)建RecorderServerHttpRequestDecorator,緩存請(qǐng)求參數(shù),解決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()));
? ? }??
}

第二步

創(chuàng)建訪問日志全局過濾器,然后在此過濾器進(jìn)行日志構(gòu)造。

@Slf4j
public class AccessLogGlobalFilter implements GlobalFilter , Ordered {?
? ? private static final String REQUEST_PREFIX = "Request Info [ ";?
? ? private static final String REQUEST_TAIL = " ]";?
? ? private static final String RESPONSE_PREFIX = "Response Info [ ";?
? ? private static final String RESPONSE_TAIL = " ]";?
? ? private StringBuilder normalMsg = new StringBuilder();
?
? ? @Override
? ? public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
? ? ? ? ServerHttpRequest request = exchange.getRequest();
? ? ? ? RecorderServerHttpRequestDecorator requestDecorator = new RecorderServerHttpRequestDecorator(request);
? ? ? ? InetSocketAddress address = requestDecorator.getRemoteAddress();
? ? ? ? HttpMethod method = requestDecorator.getMethod();
? ? ? ? URI url = requestDecorator.getURI();
? ? ? ? HttpHeaders headers = requestDecorator.getHeaders();
? ? ? ? Flux<DataBuffer> body = requestDecorator.getBody();
? ? ? ? //讀取requestBody傳參
? ? ? ? AtomicReference<String> requestBody = new AtomicReference<>("");
? ? ? ? body.subscribe(buffer -> {
? ? ? ? ? ? CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
? ? ? ? ? ? requestBody.set(charBuffer.toString());
? ? ? ? });
? ? ? ? String requestParams = requestBody.get();
? ? ? ? normalMsg.append(REQUEST_PREFIX);
? ? ? ? normalMsg.append(";header=").append(headers);
? ? ? ? normalMsg.append(";params=").append(requestParams);
? ? ? ? normalMsg.append(";address=").append(address.getHostName() + address.getPort());
? ? ? ? normalMsg.append(";method=").append(method.name());
? ? ? ? normalMsg.append(";url=").append(url.getPath());
? ? ? ? normalMsg.append(REQUEST_TAIL);
?
? ? ? ? ServerHttpResponse response = exchange.getResponse();
?
? ? ? ? DataBufferFactory bufferFactory = response.bufferFactory();
? ? ? ? normalMsg.append(RESPONSE_PREFIX);
? ? ? ? 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);
? ? ? ? ? ? ? ? ? ? }));
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return super.writeWith(body); // if body is not a flux. never got there.
? ? ? ? ? ? }
? ? ? ? };
?
? ? ? ? return chain.filter(exchange.mutate().request(requestDecorator).response(decoratedResponse).build());
? ? }
?
? ? @Override
? ? public int getOrder() {
? ? ? ? return -2;
? ? }?
}

最后結(jié)果:

Request Info [ ;header={cache-control=[no-cache], Postman-Token=[790488a5-a284-4a0e-968f-1b588cb26688], Content-Type=[application/json], User-Agent=[PostmanRuntime/3.0.9], Accept=[*/*], Host=[localhost:8084], cookie=[JSESSIONID=E161AC22204E626FBE6E96EE7B62EE70], accept-encoding=[gzip, deflate], content-length=[13], Connection=[keep-alive]};params={"name":"ss"};address=0:0:0:0:0:0:0:159621;method=POST;url=/account/testBody ]Response Info [ ;status=200;header={Content-Type=[text/plain;charset=UTF-8], Content-Length=[41], Date=[Mon, 18 Mar 2019 08:21:57 GMT]};responseResult=account hellowordAccountEntity{name='ss'} ]

以上代碼即可完成請(qǐng)求應(yīng)答日志打印功能。

Gateway全局請(qǐng)求日志打印

實(shí)現(xiàn)GlobalFilter則所有該自定義Filter會(huì)對(duì)所有的路由生效。

把請(qǐng)求體的數(shù)據(jù)存入exchange

便于打印日志時(shí)獲取

package com.qykj.gateway.filter;
import com.qykj.gateway.ConstantFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.DataBufferUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
?* @calssName AppCacheRequestBodyFilter
?* @Description 將 request body 中的內(nèi)容 copy 一份,記錄到 exchange 的一個(gè)自定義屬性中
?* @Author jiangshaoneng
?* @DATE 2020/9/27 14:42
?*/
public class GlobalCacheRequestBodyFilter implements GlobalFilter, Ordered {
? ? private static final Logger logger = LoggerFactory.getLogger(GlobalCacheRequestBodyFilter.class);
? ? private int order;
? ? @Override
? ? public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
? ? ? ? //logger.info("GlobalCacheRequestBodyFilter ...");
? ? ? ? // 將 request body 中的內(nèi)容 copy 一份,記錄到 exchange 的一個(gè)自定義屬性中
? ? ? ? Object cachedRequestBodyObject = exchange.getAttributeOrDefault(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, null);
? ? ? ? // 如果已經(jīng)緩存過,略過
? ? ? ? if (cachedRequestBodyObject != null) {
? ? ? ? ? ? return chain.filter(exchange);
? ? ? ? }
? ? ? ? // 如果沒有緩存過,獲取字節(jié)數(shù)組存入 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(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, bytes))
? ? ? ? ? ? ? ? .then(chain.filter(exchange));
? ? }
? ? @Override
? ? public int getOrder() {
? ? ? ? return this.order;
? ? }
? ? public GlobalCacheRequestBodyFilter(int order){
? ? ? ? this.order = order;
? ? }
}

編寫全局日志攔截器代碼

/**
?* @calssName LogFilter
?* @Description 全局日志打印,請(qǐng)求日志以及返回日志,并在返回結(jié)果日志中添加請(qǐng)求時(shí)間
?* @Author jiangshaoneng
?* @DATE 2020/9/25 14:54
?*/
public class GlobalLogFilter implements GlobalFilter, Ordered {
? ? private static final Logger logger = LoggerFactory.getLogger(GlobalLogFilter.class);
? ? private int order;
? ? private static final String REQUEST_PREFIX = "\n--------------------------------- Request ?Info -----------------------------";
? ? private static final String REQUEST_TAIL ? = "\n-----------------------------------------------------------------------------";
? ? private static final String RESPONSE_PREFIX = "\n--------------------------------- Response Info -----------------------------";
? ? private static final String RESPONSE_TAIL ? = "\n-------------------------------------------------------------------------->>>";
? ? @Override
? ? public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
? ? ? ? long start = DateUtil.getCurrentTime();
? ? ? ? StringBuilder reqMsg = new StringBuilder();
? ? ? ? StringBuilder resMsg = new StringBuilder();
? ? ? ? // 獲取請(qǐng)求信息
? ? ? ? ServerHttpRequest request = exchange.getRequest();
? ? ? ? InetSocketAddress address = request.getRemoteAddress();
? ? ? ? String method = request.getMethodValue();
? ? ? ? URI uri = request.getURI();
? ? ? ? HttpHeaders headers = request.getHeaders();
? ? ? ? // 獲取請(qǐng)求body
? ? ? ? Object cachedRequestBodyObject = exchange.getAttributeOrDefault(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, null);
? ? ? ? byte[] body = (byte[]) cachedRequestBodyObject;
? ? ? ? String params = new String(body);
? ? ? ? // 獲取請(qǐng)求query
? ? ? ? Map queryMap = request.getQueryParams();
? ? ? ? String query = JSON.toJSONString(queryMap);
? ? ? ? // 拼接請(qǐng)求日志
? ? ? ? reqMsg.append(REQUEST_PREFIX);
? ? ? ? reqMsg.append("\n header=").append(headers);
? ? ? ? reqMsg.append("\n query=").append(query);
? ? ? ? reqMsg.append("\n params=").append(params);
? ? ? ? reqMsg.append("\n address=").append(address.getHostName()).append(address.getPort());
? ? ? ? reqMsg.append("\n method=").append(method);
? ? ? ? reqMsg.append("\n url=").append(uri.getPath());
? ? ? ? reqMsg.append(REQUEST_TAIL);
? ? ? ? logger.info(reqMsg.toString()); // 打印入?yún)⑷罩?
? ? ? ? ServerHttpResponse response = exchange.getResponse();
? ? ? ? DataBufferFactory bufferFactory = response.bufferFactory();
? ? ? ? resMsg.append(RESPONSE_PREFIX);
? ? ? ? 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 -> {
? ? ? ? ? ? ? ? ? ? ? ? byte[] content = new byte[dataBuffer.readableByteCount()];
? ? ? ? ? ? ? ? ? ? ? ? dataBuffer.read(content);
? ? ? ? ? ? ? ? ? ? ? ? String responseResult = new String(content, Charset.forName("UTF-8"));
? ? ? ? ? ? ? ? ? ? ? ? resMsg.append("\n status=").append(this.getStatusCode());
? ? ? ? ? ? ? ? ? ? ? ? resMsg.append("\n header=").append(this.getHeaders());
? ? ? ? ? ? ? ? ? ? ? ? resMsg.append("\n responseResult=").append(responseResult);
? ? ? ? ? ? ? ? ? ? ? ? resMsg.append(RESPONSE_TAIL);
? ? ? ? ? ? ? ? ? ? ? ? // 計(jì)算請(qǐng)求時(shí)間
? ? ? ? ? ? ? ? ? ? ? ? long end = DateUtil.getCurrentTime();
? ? ? ? ? ? ? ? ? ? ? ? long time = end - start;
? ? ? ? ? ? ? ? ? ? ? ? resMsg.append("耗時(shí)ms:").append(time);
? ? ? ? ? ? ? ? ? ? ? ? logger.info(resMsg.toString()); // 打印結(jié)果日志
? ? ? ? ? ? ? ? ? ? ? ? return bufferFactory.wrap(content);
? ? ? ? ? ? ? ? ? ? }));
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return super.writeWith(body);
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? return chain.filter(exchange.mutate().response(decoratedResponse).build());
? ? }
? ? @Override
? ? public int getOrder() {
? ? ? ? return this.order;
? ? }
? ? public GlobalLogFilter(int order){
? ? ? ? this.order = order;
? ? }
}

在代碼中配置全局?jǐn)r截器

/**
?* @calssName GatewayConfig
?* @Description 網(wǎng)關(guān)配置
?* @Author jiangshaoneng
?* @DATE 2020/9/25 14:26
?*/
@Configuration
public class GatewayConfig {
? ? /**
? ? ?* 全局過濾器:請(qǐng)求日志打印
? ? ?*/
? ? @Bean
? ? public GlobalLogFilter globalLogFilter(){
? ? ? ? // 該值越小權(quán)重卻大,所以應(yīng)根據(jù)具體項(xiàng)目配置。需要盡早的獲取到參數(shù),一般會(huì)是一個(gè)比較小的值
? ? ? ? return new GlobalLogFilter(-20);?
? ? }
? ??
? ? // 其他的路由配置 ...?
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • JavaSE圖像驗(yàn)證碼簡單識(shí)別程序詳解

    JavaSE圖像驗(yàn)證碼簡單識(shí)別程序詳解

    這篇文章主要為大家詳細(xì)介紹了JavaSE圖像驗(yàn)證碼簡單識(shí)別程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • spring mvc路徑匹配原則詳解

    spring mvc路徑匹配原則詳解

    這篇文章主要介紹了spring mvc路徑匹配原則詳解,小編覺得還是挺不錯(cuò)的,這里分享給大家,需要的朋友可以參考下,下面就和小編一起來看看吧
    2018-02-02
  • SpringBoot實(shí)現(xiàn)異步事件驅(qū)動(dòng)的方法

    SpringBoot實(shí)現(xiàn)異步事件驅(qū)動(dòng)的方法

    本文主要介紹了SpringBoot實(shí)現(xiàn)異步事件驅(qū)動(dòng)的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • java實(shí)現(xiàn)帶有背景圖片的窗體

    java實(shí)現(xiàn)帶有背景圖片的窗體

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)帶有背景圖片的窗體,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • mybatis foreach遍歷LIST讀到數(shù)據(jù)為null的問題

    mybatis foreach遍歷LIST讀到數(shù)據(jù)為null的問題

    這篇文章主要介紹了mybatis foreach遍歷LIST讀到數(shù)據(jù)為null的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2022-02-02
  • java觀感示例分享

    java觀感示例分享

    這篇文章主要介紹了java觀感示例,該實(shí)例查詢并生成了系統(tǒng)中存在觀感對(duì)應(yīng)的按鈕并在用戶點(diǎn)擊相應(yīng)按鈕時(shí)將窗口的觀感切換到指定的觀感上
    2014-03-03
  • Java多線程之 FutureTask:帶有返回值的函數(shù)定義和調(diào)用方式

    Java多線程之 FutureTask:帶有返回值的函數(shù)定義和調(diào)用方式

    這篇文章主要介紹了Java多線程之 FutureTask:帶有返回值的函數(shù)定義和調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • MyBatis新增數(shù)據(jù)并返回主鍵值方式

    MyBatis新增數(shù)據(jù)并返回主鍵值方式

    這篇文章主要介紹了MyBatis新增數(shù)據(jù)并返回主鍵值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java?switch?case語句舉例詳解

    Java?switch?case語句舉例詳解

    這篇文章主要給大家介紹了關(guān)于Java?switch?case語句舉例詳解的相關(guān)資料,switch case語句是一種流程控制語句,用于根據(jù)不同的條件執(zhí)行不同的代碼塊,需要的朋友可以參考下
    2023-10-10
  • JDBC基礎(chǔ)教程

    JDBC基礎(chǔ)教程

    這篇文章主要介紹了JDBC基礎(chǔ)知識(shí)與操作技巧,講述原理與基本技巧的基礎(chǔ)上分析了安全問題與操作注意事項(xiàng),非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-12-12

最新評(píng)論