成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

如何實(shí)現(xiàn)SpringCloudGateway請(qǐng)求響應(yīng)日志

這篇文章主要講解了“如何實(shí)現(xiàn)SpringCloud Gateway請(qǐng)求響應(yīng)日志”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何實(shí)現(xiàn)SpringCloud Gateway請(qǐng)求響應(yīng)日志”吧!

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)寧武免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000+企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

如何實(shí)現(xiàn)SpringCloud Gateway請(qǐng)求響應(yīng)日志

獲取輸入輸出參數(shù)

首先我們先定義一個(gè)日志體

@Data public class GatewayLog {     /**訪問(wèn)實(shí)例*/     private String targetServer;     /**請(qǐng)求路徑*/     private String requestPath;     /**請(qǐng)求方法*/     private String requestMethod;     /**協(xié)議 */     private String schema;     /**請(qǐng)求體*/     private String requestBody;     /**響應(yīng)體*/     private String responseData;     /**請(qǐng)求ip*/     private String ip;  /**請(qǐng)求時(shí)間*/     private Date requestTime;  /**響應(yīng)時(shí)間*/     private Date responseTime;     /**執(zhí)行時(shí)間*/     private long executeTime; }

【關(guān)鍵】在網(wǎng)關(guān)定義日志過(guò)濾器,獲取輸入輸出參數(shù)

/**  * 日志過(guò)濾器,用于記錄日志  * @author jianzh6  * @date 2020/3/24 17:17  */ @Slf4j @Component public class AccessLogFilter implements GlobalFilter, Ordered {     @Autowired     private AccessLogService accessLogService;      private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();      @Override     public int getOrder() {         return -100;     }      @Override     @SuppressWarnings("unchecked")     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {          ServerHttpRequest request = exchange.getRequest();          // 請(qǐng)求路徑         String requestPath = request.getPath().pathWithinApplication().value();          Route route = getGatewayRoute(exchange);           String ipAddress = WebUtils.getServerHttpRequestIpAddress(request);          GatewayLog gatewayLog = new GatewayLog();         gatewayLog.setSchema(request.getURI().getScheme());         gatewayLog.setRequestMethod(request.getMethodValue());         gatewayLog.setRequestPath(requestPath);         gatewayLog.setTargetServer(route.getId());         gatewayLog.setRequestTime(new Date());         gatewayLog.setIp(ipAddress);          MediaType mediaType = request.getHeaders().getContentType();          if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType) || MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)){             return writeBodyLog(exchange, chain, gatewayLog);         }else{             return writeBasicLog(exchange, chain, gatewayLog);         }     }      private Mono<Void> writeBasicLog(ServerWebExchange exchange, GatewayFilterChain chain, GatewayLog accessLog) {         StringBuilder builder = new StringBuilder();         MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();         for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {             builder.append(entry.getKey()).append("=").append(StringUtils.join(entry.getValue(), ","));         }         accessLog.setRequestBody(builder.toString());          //獲取響應(yīng)體         ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, accessLog);          return chain.filter(exchange.mutate().response(decoratedResponse).build())                 .then(Mono.fromRunnable(() -> {                     // 打印日志                     writeAccessLog(accessLog);                 }));     }       /**      * 解決 request body 只能讀取一次問(wèn)題,      * 參考: org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory      * @param exchange      * @param chain      * @param gatewayLog      * @return      */     @SuppressWarnings("unchecked")     private Mono writeBodyLog(ServerWebExchange exchange, GatewayFilterChain chain, GatewayLog gatewayLog) {         ServerRequest serverRequest = ServerRequest.create(exchange,messageReaders);          Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)                 .flatMap(body ->{                     gatewayLog.setRequestBody(body);                     return Mono.just(body);                 });          // 通過(guò) BodyInserter 插入 body(支持修改body), 避免 request body 只能獲取一次         BodyInserter 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);          return bodyInserter.insert(outputMessage,new BodyInserterContext())                 .then(Mono.defer(() -> {                     // 重新封裝請(qǐng)求                     ServerHttpRequest decoratedRequest = requestDecorate(exchange, headers, outputMessage);                      // 記錄響應(yīng)日志                     ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange, gatewayLog);                      // 記錄普通的                     return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build())                             .then(Mono.fromRunnable(() -> {                                 // 打印日志                                 writeAccessLog(gatewayLog);                             }));                 }));     }      /**      * 打印日志      * @author javadaily      * @date 2021/3/24 14:53      * @param gatewayLog 網(wǎng)關(guān)日志      */     private void writeAccessLog(GatewayLog gatewayLog) {         log.info(gatewayLog.toString());       }        private Route getGatewayRoute(ServerWebExchange exchange) {         return exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);     }       /**      * 請(qǐng)求裝飾器,重新計(jì)算 headers      * @param exchange      * @param headers      * @param outputMessage      * @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();             }         };     }       /**      * 記錄響應(yīng)日志      * 通過(guò) DataBufferFactory 解決響應(yīng)體分段傳輸問(wèn)題。      */     private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange, GatewayLog gatewayLog) {         ServerHttpResponse response = exchange.getResponse();         DataBufferFactory bufferFactory = response.bufferFactory();          return new ServerHttpResponseDecorator(response) {             @Override             public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {                 if (body instanceof Flux) {                     Date responseTime = new Date();                     gatewayLog.setResponseTime(responseTime);                     // 計(jì)算執(zhí)行時(shí)間                     long executeTime = (responseTime.getTime() - gatewayLog.getRequestTime().getTime());                      gatewayLog.setExecuteTime(executeTime);                      // 獲取響應(yīng)類型,如果是 json 就打印                     String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);                       if (ObjectUtil.equal(this.getStatusCode(), HttpStatus.OK)                             && StringUtil.isNotBlank(originalResponseContentType)                             && originalResponseContentType.contains("application/json")) {                          Flux<? extends DataBuffer> fluxBody = Flux.from(body);                         return super.writeWith(fluxBody.buffer().map(dataBuffers -> {                              // 合并多個(gè)流集合,解決返回體分段傳輸                             DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();                             DataBuffer join = dataBufferFactory.join(dataBuffers);                             byte[] content = new byte[join.readableByteCount()];                             join.read(content);                              // 釋放掉內(nèi)存                             DataBufferUtils.release(join);                             String responseResult = new String(content, StandardCharsets.UTF_8);                                gatewayLog.setResponseData(responseResult);                              return bufferFactory.wrap(content);                         }));                     }                 }                 // if body is not a flux. never got there.                 return super.writeWith(body);             }         };     } }

代碼較長(zhǎng)建議直接拷貝到編輯器,只要注意下面一個(gè)關(guān)鍵點(diǎn):

getOrder()方法返回的值必須要<-1,「否則標(biāo)準(zhǔn)的NettyWriteResponseFilter將在您的過(guò)濾器被調(diào)用的機(jī)會(huì)之前發(fā)送響應(yīng),即不會(huì)執(zhí)行獲取后端響應(yīng)參數(shù)的方法」

通過(guò)上面的兩步我們已經(jīng)可以獲取到請(qǐng)求的輸入輸出參數(shù)了,在  writeAccessLog()中將其輸出到了日志文件,大家可以在Postman發(fā)送請(qǐng)求觀察日志。

存儲(chǔ)日志

如果需要將日志持久化方便后期檢索的話可以考慮將日志存儲(chǔ)在MongoDB中,實(shí)現(xiàn)過(guò)程很簡(jiǎn)單。(安裝MongoDB可以參考這篇文章:實(shí)戰(zhàn)|MongoDB的安裝配置)

  • 引入MongoDB

<dependency>     <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId> </dependency>

由于gateway是基于webflux,所以我們需要選擇reactive版本。

  • 在GatewayLog上添加對(duì)應(yīng)的注解

@Data @Document public class GatewayLog {     @Id     private String id;  ... }
  • 建立AccessLogRepository

@Repository public interface AccessLogRepository extends ReactiveMongoRepository<GatewayLog,String> {    }
  • 建立Service

public interface AccessLogService {      /**      * 保存AccessLog      * @param gatewayLog 請(qǐng)求響應(yīng)日志      * @return 響應(yīng)日志      */     Mono<GatewayLog> saveAccessLog(GatewayLog gatewayLog);  }
  • 建立實(shí)現(xiàn)類

@Service public class AccessLogServiceImpl implements AccessLogService {     @Autowired     private AccessLogRepository accessLogRepository;      @Override     public Mono<GatewayLog> saveAccessLog(GatewayLog gatewayLog) {         return accessLogRepository.insert(gatewayLog);     } }
  • 在Nacos配置中心添加MongoDB對(duì)應(yīng)配置

spring:   data:     mongodb:       host: xxx.xx.x.xx       port: 27017       database: accesslog       username: accesslog       password: xxxxxx

執(zhí)行請(qǐng)求,打開(kāi)MongoDB客戶端,查看日志結(jié)果

如何實(shí)現(xiàn)SpringCloud Gateway請(qǐng)求響應(yīng)日志

感謝各位的閱讀,以上就是“如何實(shí)現(xiàn)SpringCloud Gateway請(qǐng)求響應(yīng)日志”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何實(shí)現(xiàn)SpringCloud Gateway請(qǐng)求響應(yīng)日志這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

當(dāng)前標(biāo)題:如何實(shí)現(xiàn)SpringCloudGateway請(qǐng)求響應(yīng)日志
文章起源:http://jinyejixie.com/article16/ijcjgg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、關(guān)鍵詞優(yōu)化、建站公司、全網(wǎng)營(yíng)銷(xiāo)推廣、微信公眾號(hào)、服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司
金秀| 西乌| 海盐县| 龙门县| 宁阳县| 察哈| 兴化市| 普宁市| 贺兰县| 宁晋县| 五台县| 淮北市| 滨州市| 闽清县| 依兰县| 阿巴嘎旗| 南安市| 南安市| 宁晋县| 黔西县| 西峡县| 岢岚县| 泾阳县| 蕉岭县| 和平区| 卫辉市| 棋牌| 德昌县| 新竹县| 龙游县| 茶陵县| 新和县| 印江| 漠河县| 嘉兴市| 凤凰县| 丰都县| 潮州市| 安岳县| 淅川县| 上虞市|