精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SpringCloud 微服務中網關如何記錄請求響應日志?

網絡 網絡管理
getOrder()方法返回的值必須要<-1,否則標準的NettyWriteResponseFilter將在您的過濾器被調用的機會之前發送響應,即不會執行獲取后端響應參數的方法。

大家好,我是飄渺。

在基于SpringCloud開發的微服務中,我們一般會選擇在網關層記錄請求和響應日志,并將其收集到ELK中用作查詢和分析。

今天我們就來看看如何實現此功能。

日志實體類

首先我們在網關中定義一個日志實體,用于組裝日志對象;

@Data
public class AccessLog {

    /**用戶編號**/
    private Long userId;

    /**路由**/
    private String targetServer;

    /**協議**/
    private String schema;
    
    /**請求方法名**/
    private String requestMethod;
    
    /**訪問地址**/
    private String requestUrl;

    /**請求IP**/
    private String clientIp;

    /**查詢參數**/
    private MultiValueMap<String, String> queryParams;
    
    /**請求體**/
    private String requestBody;
    
    /**請求頭**/
    private MultiValueMap<String, String> requestHeaders;

     /**響應體**/
    private String responseBody;
    
    /**響應頭**/
    private MultiValueMap<String, String> responseHeaders;
    
     /**響應結果**/
    private HttpStatusCode httpStatusCode;
    
     /**開始請求時間**/
    private LocalDateTime startTime;
    
    /**結束請求時間**/
    private LocalDateTime endTime;
    
    /**執行時長,單位:毫秒**/
    private Integer duration;

}

網關日志過濾器

接下來我們在網關中定義一個Filter,用于收集日志信息。

@Component
public class AccessLogFilter implements GlobalFilter, Ordered {

    private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();

    /**
     * 打印日志
     * @param accessLog 網關日志
     */
    private void writeAccessLog(AccessLog accessLog) {
        log.info("----access---- : {}", JsonUtils.obj2StringPretty(accessLog));
    }

    /**
     * 順序必須是<-1,否則標準的NettyWriteResponseFilter將在您的過濾器得到一個被調用的機會之前發送響應
     * 也就是說如果不小于 -1 ,將不會執行獲取后端響應的邏輯
     * @return
     */
    @Override
    public int getOrder() {
        return -100;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 將 Request 中可以直接獲取到的參數,設置到網關日志
        ServerHttpRequest request = exchange.getRequest();

        AccessLog gatewayLog = new AccessLog();
        gatewayLog.setTargetServer(WebUtils.getGatewayRoute(exchange).getId());
        gatewayLog.setSchema(request.getURI().getScheme());
        gatewayLog.setRequestMethod(request.getMethod().name());
        gatewayLog.setRequestUrl(request.getURI().getRawPath());
        gatewayLog.setQueryParams(request.getQueryParams());
        gatewayLog.setRequestHeaders(request.getHeaders());
        gatewayLog.setStartTime(LocalDateTime.now());
        gatewayLog.setClientIp(WebUtils.getClientIP(exchange));

        // 繼續 filter 過濾
        MediaType mediaType = request.getHeaders().getContentType();
        if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType)
                || MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) { // 適合 JSON 和 Form 提交的請求
            return filterWithRequestBody(exchange, chain, gatewayLog);
        }
        return filterWithoutRequestBody(exchange, chain, gatewayLog);
    }


    /**
     * 沒有請求體的請求只需要記錄日志
     */
    private Mono<Void> filterWithoutRequestBody(ServerWebExchange exchange, GatewayFilterChain chain, AccessLog accessLog) {
        // 包裝 Response,用于記錄 Response Body
        ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, accessLog);

        return chain.filter(exchange.mutate().response(decoratedResponse).build())
                .then(Mono.fromRunnable(() -> writeAccessLog(accessLog)));
    }

    /**
     * 需要讀取請求體
     * 參考 {@link ModifyRequestBodyGatewayFilterFactory} 實現
     */
    private Mono<Void> filterWithRequestBody(ServerWebExchange exchange, GatewayFilterChain chain, AccessLog gatewayLog) {
        // 設置 Request Body 讀取時,設置到網關日志
        ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);

        Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
            gatewayLog.setRequestBody(body);
            return Mono.just(body);
        });

        // 通過 BodyInserter 插入 body(支持修改body), 避免 request body 只能獲取一次
        BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
        HttpHeaders headers = new HttpHeaders();
        headers.putAll(exchange.getRequest().getHeaders());
        // the new content type will be computed by bodyInserter
        // and then set in the request decorator
        headers.remove(HttpHeaders.CONTENT_LENGTH);

        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);

        // 通過 BodyInserter 將 Request Body 寫入到 CachedBodyOutputMessage 中
        return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
            // 重新封裝請求
            ServerHttpRequest decoratedRequest = requestDecorate(exchange, headers, outputMessage);
            // 記錄響應日志
            ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, gatewayLog);
            // 記錄普通的
            return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build())
                    .then(Mono.fromRunnable(() -> writeAccessLog(gatewayLog))); // 打印日志

        }));
    }

    /**
     * 記錄響應日志
     * 通過 DataBufferFactory 解決響應體分段傳輸問題。
     */
    private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange, AccessLog accessLog) {
        ServerHttpResponse response = exchange.getResponse();

        return new ServerHttpResponseDecorator(response) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    DataBufferFactory bufferFactory = response.bufferFactory();
                    // 計算執行時間
                    accessLog.setEndTime(LocalDateTime.now());
                    accessLog.setDuration((int) (LocalDateTimeUtil.between(accessLog.getStartTime(),
                            accessLog.getEndTime()).toMillis()));
                    accessLog.setResponseHeaders(response.getHeaders());
                    accessLog.setHttpStatusCode(response.getStatusCode());

                    // 獲取響應類型,如果是 json 就打印
                    String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);

                    if (StrUtil.isNotBlank(originalResponseContentType)
                            && originalResponseContentType.contains("application/json")) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);

                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                            // 設置 response body 到網關日志
                            byte[] content = readContent(dataBuffers);
                            String responseResult = new String(content, StandardCharsets.UTF_8);
                            accessLog.setResponseBody(responseResult);

                            // 響應
                            return bufferFactory.wrap(content);
                        }));
                    }
                }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };
    }


    /**
     * 請求裝飾器,支持重新計算 headers、body 緩存
     *
     * @param exchange 請求
     * @param headers 請求頭
     * @param outputMessage body 緩存
     * @return 請求裝飾器
     */
    private ServerHttpRequestDecorator requestDecorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) {
        return new ServerHttpRequestDecorator(exchange.getRequest()) {

            @Override
            public HttpHeaders getHeaders() {
                long contentLength = headers.getContentLength();
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                if (contentLength > 0) {
                    httpHeaders.setContentLength(contentLength);
                } else {
                    // TODO: this causes a 'HTTP/1.1 411 Length Required' // on
                    // httpbin.org
                    httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                }
                return httpHeaders;
            }

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

    /**
     * 從dataBuffers中讀取數據
     * @author jam
     * @date 2024/5/26 22:31
     */
    private byte[] readContent(List<? extends DataBuffer> dataBuffers) {
        // 合并多個流集合,解決返回體分段傳輸
        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
        DataBuffer join = dataBufferFactory.join(dataBuffers);
        byte[] content = new byte[join.readableByteCount()];
        join.read(content);
        // 釋放掉內存
        DataBufferUtils.release(join);
        return content;
    }

}

代碼較長建議直接拷貝到編輯器,只要注意下面一個關鍵點:

getOrder()方法返回的值必須要<-1,否則標準的NettyWriteResponseFilter將在您的過濾器被調用的機會之前發送響應,即不會執行獲取后端響應參數的方法。

通過上面的兩步我們已經可以獲取到請求的輸入輸出參數了,在 writeAccessLog()中將其打印到日志文件,方便通過ELK進行收集。

在實際項目中,網關日志量一般會非常大,不建議使用數據庫進行存儲。

實際效果

服務正常響應:

圖片

服務異常響應:

圖片圖片

責任編輯:武曉燕 來源: JAVA日知錄
相關推薦

2021-03-26 06:01:45

日志MongoDB存儲

2021-03-09 09:33:42

網關授權微服務

2021-08-11 05:00:48

Spring 日志手段

2021-08-13 07:52:35

微服務網關數據

2022-05-12 08:21:13

項目網關模塊

2021-05-14 09:15:32

SpringCloud微服務日志

2021-06-09 09:42:50

SpringCloud微服務灰度發布

2024-03-18 08:48:52

Spring多端認證微服務

2022-04-14 08:51:49

微服務Redisson分布式鎖

2025-06-17 07:37:53

2011-08-01 13:57:20

iPhone 網絡

2024-03-06 08:36:36

2022-09-01 08:17:15

Gateway微服務網關

2017-03-09 19:39:54

微服務架構重構

2023-06-09 14:46:36

2019-09-24 08:44:09

OpenrestyAPI網關

2022-05-16 08:22:11

網關過濾器路由

2021-01-25 15:00:44

微服務分布式日志

2024-08-05 10:03:53

2024-10-29 08:44:18

點贊
收藏

51CTO技術棧公眾號

久久96国产精品久久99软件| 欧美激情第一页xxx| 中文字幕第80页| 国产黄大片在线观看画质优化| 国产在线视频不卡二| 欧美激情欧美狂野欧美精品| 右手影院亚洲欧美| 日韩亚洲国产免费| 午夜成人免费电影| 在线观看福利一区| 凸凹人妻人人澡人人添| 美国av一区二区| 久久免费国产视频| 精品在线观看一区| 狼人精品一区二区三区在线 | 亚洲裸体xxxx| 中文字幕国产高清| 综合在线影院| 亚洲国产美国国产综合一区二区| 欧洲高清一区二区| 亚洲国产精彩视频| 免费观看30秒视频久久| 91国在线精品国内播放| 久久久久亚洲av片无码| 精品视频久久| 日韩电影第一页| 特种兵之深入敌后| 久久电影天堂| 91成人国产精品| 免费一级特黄特色毛片久久看| 天堂а√在线官网| 国产亲近乱来精品视频| 精品久久久久久中文字幕动漫| 国产又黄又大又粗的视频| 久久久久中文| 欧美中在线观看| 日韩精品视频免费播放| 欧美韩日一区| 一区二区三区国产在线观看| 黄色国产在线观看| 久久97精品| 精品欧美黑人一区二区三区| 黄色一级片免费播放| 成人在线免费av| 色爱区综合激月婷婷| 免费国产a级片| a级片在线免费| 亚洲一区在线观看免费| 六月婷婷激情网| 老司机午夜在线| 国产精品久久久久久久蜜臀| 亚洲成人自拍视频| 国产天堂在线| 欧美激情一二三区| 亚欧精品在线| 天堂中文а√在线| 亚洲人成伊人成综合网小说| 欧美性视频在线播放| 看女生喷水的网站在线观看| 亚洲视频中文字幕| 法国空姐在线观看免费| 亚洲卡一卡二| 亚洲va欧美va人人爽| 黄色一级视频在线播放| 色老头在线一区二区三区| 欧美日韩亚洲天堂| www.xxx亚洲| 国产在视频一区二区三区吞精| 欧美三日本三级三级在线播放| 免费涩涩18网站入口| 人人玩人人添人人澡欧美| 制服丝袜日韩国产| 成年人性生活视频| 欧美sss在线视频| 亚洲欧美日韩精品| 自拍偷拍你懂的| 亚洲成人av| 久久久欧美一区二区| 久久夜色精品国产噜噜亚洲av| 久久久人人人| 成人黄色免费片| 国产91绿帽单男绿奴| 91麻豆免费在线观看| 亚洲国产高清国产精品| 成人在线影视| 精品久久久久久电影| 成人性生生活性生交12| 91午夜精品| 国产香蕉精品视频一区二区三区| 熟女av一区二区| 激情成人综合| 国产精品日韩一区| 亚洲国产综合网| 国产日韩一级二级三级| 欧美日韩午夜爽爽| 亚洲性受xxx喷奶水| 欧美欧美午夜aⅴ在线观看| 国产成人精品一区二区三区在线观看| 日韩mv欧美mv国产网站| 日韩视频永久免费观看| 亚洲男人的天堂在线视频| 久久99国产乱子伦精品免费| 精品1区2区| 秋霞午夜在线观看| 欧美性色xo影院| 日韩欧美色视频| 波多野结衣在线播放一区| 久久久久国产视频| 亚洲无码精品在线播放| 91丨九色丨蝌蚪丨老版| 蜜臀av.com| yiren22亚洲综合| 亚洲第一在线视频| 乱h高h女3p含苞待放| 三级欧美在线一区| 国产精品一区二区三区不卡| 毛片网站在线免费观看| 在线观看中文字幕不卡| 久久一区二区电影| 欧美成人tv| 国产日韩av在线| 人成在线免费视频| 香蕉成人啪国产精品视频综合网 | 国产精品夜夜嗨| 日韩免费电影一区二区| aa国产成人| 欧美一级二级在线观看| 我要看一级黄色录像| 水野朝阳av一区二区三区| 精品国产一二| 8x8ⅹ拨牐拨牐拨牐在线观看| 制服丝袜激情欧洲亚洲| 多男操一女视频| 男女性色大片免费观看一区二区| 久久国产精品 国产精品| 欧美性猛片xxxxx免费中国| 这里只有精品视频在线观看| 亚洲综合第一区| 日韩和欧美的一区| 欧美日韩一区二区视频在线 | 黑人巨大精品欧美一区二区免费 | 久久久精品综合| 欧美激情 国产精品| 久久超级碰碰| 97人人做人人爱| 日韩在线视频观看免费| 亚洲成人午夜电影| 男女一区二区三区| 国产欧美日本| 女人一区二区三区| 日本久久免费| 在线丨暗呦小u女国产精品| 成人免费视频国产免费| 国产欧美日韩在线观看| 九色91popny| 久久一区91| 91精品综合久久久久久五月天| 毛片免费不卡| 精品日产卡一卡二卡麻豆| 国产午夜久久久| caoporn国产精品| 无码精品a∨在线观看中文| 蜜乳av综合| 国产精品久久一区| 久久久久久久久免费视频| 日韩一区二区免费在线观看| 精品午夜福利视频| 91香蕉视频黄| 亚洲最大成人在线观看| 99久久激情| 国产精品99久久久久久久| 久热在线观看视频| 一本色道久久88综合日韩精品| 伊人影院中文字幕| 一二三四社区欧美黄| 国产成人精品无码片区在线| 老司机久久99久久精品播放免费| 一区二区三区四区五区视频| 色悠久久久久综合先锋影音下载| 国内精品模特av私拍在线观看| 你懂的视频在线播放| 欧美精品色一区二区三区| 久久久久久久久久久久国产| 91丨九色丨尤物| 一级黄色片在线免费观看| 在线视频观看日韩| 亚洲成人第一| 精品国产导航| 国产欧美欧洲在线观看| 97超碰在线免费| 在线观看日韩专区| 男人天堂一区二区| 欧美一a一片一级一片| 九九视频免费看| 久久精品一区二区三区不卡| 国产在线视频三区| 久久综合九色| 99er在线视频| 91日韩在线| 久久久久久国产精品免费免费| 亚洲ww精品| 日产精品99久久久久久| 污污视频在线| 中文字幕亚洲字幕| 桃花色综合影院| 日韩欧美在线影院| 中文字幕精品无码亚| 亚洲成国产人片在线观看| 最新日韩免费视频| 91麻豆swag| 亚洲av午夜精品一区二区三区| 日韩经典一区二区| 久久久久久人妻一区二区三区| 久久美女视频| 清纯唯美一区二区三区| 成人18夜夜网深夜福利网| 国产一区视频在线播放| 欧美极品影院| 国产91ⅴ在线精品免费观看| 日本三级在线观看网站| 久久久国产视频| 国产福利片在线| 国产视频精品久久久| 免费激情视频网站| 日韩一区二区三区电影| 国产又粗又大又爽视频| 日韩欧美在线看| 日本最新中文字幕| 亚洲成人免费观看| 欧美日韩免费一区二区| 中文字幕综合网| 中文字幕求饶的少妇| 日本一区二区在线不卡| 欧美做受高潮6| 久久伊人蜜桃av一区二区| 国产精品无码在线| 99视频有精品| 日韩aaaaa| 99久久免费国产| 亚洲av无码一区二区三区网址 | 在线看福利影| 久久综合国产精品台湾中文娱乐网| av国产在线观看| 在线播放精品一区二区三区| 国产福利小视频在线观看| 一个人www欧美| 第一页在线观看| 自拍亚洲一区欧美另类| 日本在线观看视频| 精品国产一区久久久| 毛片在线播放a| 久久99热精品| 成人女同在线观看| 88xx成人精品| 日韩久久一区二区三区| 国产精品美女主播| 色综合久久久| 91久久爱成人| 懂色av一区二区| 蜜桃成人在线| 清纯唯美综合亚洲| 成年人三级视频| 伊人久久成人| 久久精品午夜福利| 免费观看一级特黄欧美大片| 中文字幕第一页在线视频| 国产a精品视频| 在线观看国产免费视频| 国产午夜三级一区二区三| 国产第一页精品| 一区二区三区欧美亚洲| 免费成人看片网址| 久久夜色精品国产噜噜亚洲av| 亚瑟在线精品视频| 日韩精品成人免费观看视频| 欧美日韩在线播放三区四区| 国产丝袜在线视频| 亚洲国产一区二区三区在线观看 | 日本精品国产| 国产一区二区三区四区五区加勒比 | 自拍视频在线播放| 欧美猛交ⅹxxx乱大交视频| 国产拍在线视频| 国产精品色婷婷视频| 91久久精品无嫩草影院| 欧美日韩在线观看一区| 91精品精品| 久久婷婷国产精品| 国内精品免费在线观看| 一区二区三区少妇| 综合网在线视频| 国产超碰人人爽人人做人人爱| 欧美日免费三级在线| 黄色小视频免费观看| 中文字幕精品—区二区| 三级资源在线| 国产精品嫩草视频| 超碰在线成人| 美国av在线播放| 鲁大师成人一区二区三区 | 日韩精品一区二区三区中文在线| 精品一区二区三区自拍图片区| 成人久久久久| 男女激情无遮挡| 国产一区在线视频| 亚洲精品国产一区黑色丝袜| 亚洲综合偷拍欧美一区色| 中文字幕男人天堂| 亚洲精品v天堂中文字幕| 精品国产丝袜高跟鞋| 国产99久久精品一区二区 夜夜躁日日躁| 国产精品一区二区三区av| 欧洲精品一区色| 亚洲精品孕妇| 成年人性生活视频| 中文字幕一区二区三区四区| 日韩在线视频不卡| 亚洲成人av片| av观看在线| 国产欧美日韩视频| 中文字幕av一区二区三区人| 欧美狂野激情性xxxx在线观| 久久精品国产999大香线蕉| 亚洲黄色在线网站| 性做久久久久久久免费看| 国产成人麻豆精品午夜在线 | 久久天天狠狠| 欧美日本一区二区高清播放视频| 粉色视频免费看| 亚洲国产精品国自产拍av| 视频一区二区三区四区五区| 精品精品国产高清a毛片牛牛 | 亚洲卡一卡二卡三| 久久影院资源网| 日韩成人一区| 亚洲国内在线| 日本vs亚洲vs韩国一区三区二区| 日本黄色片在线播放| 欧美日韩国产中字| 日本黄色大片视频| 久久久久久亚洲精品中文字幕| 日本久久伊人| av在线免费观看国产| 国产剧情一区二区三区| 在线看的片片片免费| 91精品黄色片免费大全| 理论片午午伦夜理片在线播放| 国产精品一二三视频| 成人直播大秀| 向日葵污视频在线观看| 国产精品色婷婷| 一级黄色片网站| 另类天堂视频在线观看| 久久爱www.| 高清无码一区二区在线观看吞精| 国产精品自拍av| 国产真人真事毛片| 亚洲精品福利在线观看| 欧美日韩精品免费观看视完整| 日韩不卡av| 老司机精品视频一区二区三区| 日韩在线一卡二卡| 日韩一区二区三区av| а√天堂中文在线资源8| 九九九九九九精品| 日韩vs国产vs欧美| www深夜成人a√在线| 欧美精品一区二区三区在线| 女厕盗摄一区二区三区| 日韩电影免费观看在| 狠狠色狠狠色合久久伊人| 精品视频久久久久| 亚洲欧洲日韩国产| 国产精品亚洲成在人线| 精品少妇人欧美激情在线观看| 91麻豆免费看片| 这里只有精品6| 欧美激情喷水视频| 精品少妇av| 免费黄色av网址| 91精品办公室少妇高潮对白| 麻豆传媒视频在线| 精品国产91亚洲一区二区三区www| 视频在线观看国产精品| 很污很黄的网站| 亚洲经典中文字幕| 欧美网站免费| 欧美成人三级在线视频| 欧美激情中文不卡| 欧美亚洲精品在线观看| 国产精品美女无圣光视频| 激情视频一区二区三区| 久久婷婷五月综合| 精品久久久久久久久久久院品网| 欧美色999| 性一交一乱一伧国产女士spa| 国产亚洲欧美在线| 欧美一级淫片免费视频魅影视频| 国产精品久久久久久久久久久久久| 欧美日本二区|