簡體   English   中英

如何使用 Spring 5 Webclient 打印原始 HTTP 請求和 HTTP 響應?

[英]How to print raw HTTP Request and HTTP Response with Spring 5 Webclient?

Spring MVC 允許記錄請求和響應主體,以便更輕松地調試和驗證消息內容。 這是我的項目出於審計目的所必需的,日志消息必須包含完整的請求和響應正文。

使用 Spring Web Reactive 和 Webclient,如何記錄沒有十六進制值的請求和響應正文?

所需的格式是 RAW HTTP 請求,例如。

PUT /api/v1/target/{id}

HTTP/1.1
Host: https://testsite.com:8080
Authorization: Bearer myToken
Content-Type: application/json

{
  "test": "test
}

目前,其他答案僅使用 Reactor Netty 調試日志或僅輸出請求的 HTTP 標頭提供粗略的 hex+msg 輸出。 前任。 當前實現:

         +-------------------------------------------------+
     |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d |HTTP/1.1 200 OK.|
|00000010| 0a 53 65 72 76 65 72 3a 20 6e 67 69 6e 78 2f 31 |.Server: nginx/1|
|00000020| 2e 31 36 2e 31 0d 0a 44 61 74 65 3a 20 4d 6f 6e |.16.1..Date: Mon|
|00000030| 2c 20 30 35 20 4f 63 74 20 32 30 32 30 20 31 33 |, 05 Oct 2020 13|
|00000040| 3a 35 39 3a 33 36 20 47 4d 54 0d 0a 43 6f 6e 74 |:59:36 GMT..Cont|
|00000050| 65 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 |ent-Type: applic|
|00000060| 61 74 69 6f 6e 2f 6a 73 6f 6e 3b 20 63 68 61 72 |ation/json; char|
|00000070| 73 65 74 3d 75 74 66 2d 38 0d 0a 43 6f 6e 74 65 |set=utf-8..Conte|
|00000080| 6e 74 2d 4c 65 6e 67 74 68 3a 20 31 30 37 38 0d |nt-Length: 1078.|
|00000090| 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 65 |.Connection: kee|
|000000a0| 70 2d 61 6c 69 76 65 0d 0a 58 2d 50 6f 77 65 72 |p-alive..----|
.....
.....

這更難閱讀,審計員也難以復制粘貼。

有沒有辦法改變這種格式? 如何簡單地打印請求正文。

我可以打破 Spring Webflux 中的非阻塞建議。 RestTemplate 被列為棄用目標,這意味着 Webclient 將用於阻止操作。 對於這個項目,審計比績效更重要。

在測試包含的評論中的所有選項后回答這里。

拉入相關的依賴項

# Gradle    
implementation group: 'org.eclipse.jetty', name: 'jetty-reactive-httpclient', version: '1.1.4'

# Maven
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-reactive-httpclient</artifactId>
    <version>1.1.4</version>
</dependency>

創建將在 webclient 流程中執行的方法。 在webclient的定義中使用:

// org.eclipse.jetty.client.api.Request
private Request enhance(Request inboundRequest) {
    StringBuilder log = new StringBuilder();
    // Request Logging
    inboundRequest.onRequestBegin(request ->
            log.append("Request: \n")
            .append("URI: ")
            .append(request.getURI())
            .append("\n")
            .append("Method: ")
            .append(request.getMethod()));
    inboundRequest.onRequestHeaders(request -> {
        log.append("\nHeaders:\n");
        for (HttpField header : request.getHeaders()) {
            log.append("\t\t" + header.getName() + " : " + header.getValue() + "\n");
        }
    });
    inboundRequest.onRequestContent((request, content) ->
            log.append("Body: \n\t")
            .append(content.toString()));
    log.append("\n");

    // Response Logging
    inboundRequest.onResponseBegin(response ->
            log.append("Response:\n")
            .append("Status: ")
            .append(response.getStatus())
            .append("\n"));
    inboundRequest.onResponseHeaders(response -> {
       log.append("Headers:\n");
       for (HttpField header : response.getHeaders()) {
           log.append("\t\t" + header.getName() + " : " + header.getValue() + "\n");
       }
    });
    inboundRequest.onResponseContent(((response, content) -> {
        var bufferAsString = StandardCharsets.UTF_8.decode(content).toString();
        log.append("Response Body:\n" + bufferAsString);
    }));

    // Add actual log invocation
    logger.info("HTTP ->\n");
    inboundRequest.onRequestSuccess(request -> logger.info(log.toString()));
    inboundRequest.onResponseSuccess(response -> logger.info(log.toString()));

    // Return original request
    return inboundRequest;
}

使用以下方法定義 webclient(這包括將 webclient 定義為要根據需要注入的 bean 的示例):

@Bean
public WebClient jettyHttpClient() {
    SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
    HttpClient httpClient = new HttpClient(sslContextFactory) {
        @Override
        public Request newRequest(URI uri) {
            Request request = super.newRequest(uri);
            return enhance(request);
        }
    };
    return WebClient.builder().clientConnector(new JettyClientHttpConnector(httpClient)).build();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM