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

SpringCloud?Gateway之請求應答日志打印方式

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

Gateway請求應答日志打印

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

第一步

創(chuàng)建RecorderServerHttpRequestDecorator,緩存請求參數(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)建訪問日志全局過濾器,然后在此過濾器進行日志構造。

@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;
? ? }?
}

最后結果:

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'} ]

以上代碼即可完成請求應答日志打印功能。

Gateway全局請求日志打印

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

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

便于打印日志時獲取

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 中的內容 copy 一份,記錄到 exchange 的一個自定義屬性中
?* @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 中的內容 copy 一份,記錄到 exchange 的一個自定義屬性中
? ? ? ? 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 全局日志打印,請求日志以及返回日志,并在返回結果日志中添加請求時間
?* @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();
? ? ? ? // 獲取請求信息
? ? ? ? ServerHttpRequest request = exchange.getRequest();
? ? ? ? InetSocketAddress address = request.getRemoteAddress();
? ? ? ? String method = request.getMethodValue();
? ? ? ? URI uri = request.getURI();
? ? ? ? HttpHeaders headers = request.getHeaders();
? ? ? ? // 獲取請求body
? ? ? ? Object cachedRequestBodyObject = exchange.getAttributeOrDefault(ConstantFilter.CACHED_REQUEST_BODY_OBJECT_KEY, null);
? ? ? ? byte[] body = (byte[]) cachedRequestBodyObject;
? ? ? ? String params = new String(body);
? ? ? ? // 獲取請求query
? ? ? ? Map queryMap = request.getQueryParams();
? ? ? ? String query = JSON.toJSONString(queryMap);
? ? ? ? // 拼接請求日志
? ? ? ? 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);
? ? ? ? ? ? ? ? ? ? ? ? // 計算請求時間
? ? ? ? ? ? ? ? ? ? ? ? long end = DateUtil.getCurrentTime();
? ? ? ? ? ? ? ? ? ? ? ? long time = end - start;
? ? ? ? ? ? ? ? ? ? ? ? resMsg.append("耗時ms:").append(time);
? ? ? ? ? ? ? ? ? ? ? ? logger.info(resMsg.toString()); // 打印結果日志
? ? ? ? ? ? ? ? ? ? ? ? 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;
? ? }
}

在代碼中配置全局攔截器

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

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

相關文章

  • JavaSE圖像驗證碼簡單識別程序詳解

    JavaSE圖像驗證碼簡單識別程序詳解

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

    spring mvc路徑匹配原則詳解

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

    SpringBoot實現(xiàn)異步事件驅動的方法

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

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

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

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

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

    java觀感示例分享

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

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

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

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

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

    Java?switch?case語句舉例詳解

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

    JDBC基礎教程

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

最新評論