249

私はしばらくの間SpringRestTemplateを使用していて、その要求と応答をデバッグしようとしているときに一貫して壁にぶつかりました。基本的に、「verbose」オプションをオンにしてcurlを使用したときに表示されるものと同じものを探しています。例えば ​​:

curl -v http://twitter.com/statuses/public_timeline.rss

送信されたデータと受信されたデータ(ヘッダー、Cookieなどを含む)の両方を表示します。

次のような関連する投稿を確認しました: Spring RestTemplateに応答を記録するにはどうすればよいですか? しかし、私はこの問題を解決することができませんでした。

これを行う1つの方法は、実際にRestTemplateソースコードを変更し、そこにいくつかの追加のロギングステートメントを追加することですが、このアプローチは本当に最後の手段であることがわかります。Spring Web Client/RestTemplateにすべてをもっとわかりやすい方法でログに記録するように指示する方法があるはずです。

私の目標は、次のようなコードでこれを実行できるようにすることです。

restTemplate.put("http://someurl", objectToPut, urlPathValues);

次に、ログファイルまたはコンソールで(curlで取得するのと同じタイプのデバッグ情報を)取得します。これは、Spring RestTemplateを使用していて、問題がある人にとっては非常に役立つと思います。curlを使用してRestTemplateの問題をデバッグしても、機能しない場合があります(場合によっては)。

4

28 に答える 28

226

ClientHttpRequestInterceptorリクエストとレスポンスをトレースするための完全な実装で例を完了するには、次のようにします。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

    final static Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        traceRequest(request, body);
        ClientHttpResponse response = execution.execute(request, body);
        traceResponse(response);
        return response;
    }

    private void traceRequest(HttpRequest request, byte[] body) throws IOException {
        log.info("===========================request begin================================================");
        log.debug("URI         : {}", request.getURI());
        log.debug("Method      : {}", request.getMethod());
        log.debug("Headers     : {}", request.getHeaders() );
        log.debug("Request body: {}", new String(body, "UTF-8"));
        log.info("==========================request end================================================");
    }

    private void traceResponse(ClientHttpResponse response) throws IOException {
        StringBuilder inputStringBuilder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));
        String line = bufferedReader.readLine();
        while (line != null) {
            inputStringBuilder.append(line);
            inputStringBuilder.append('\n');
            line = bufferedReader.readLine();
        }
        log.info("============================response begin==========================================");
        log.debug("Status code  : {}", response.getStatusCode());
        log.debug("Status text  : {}", response.getStatusText());
        log.debug("Headers      : {}", response.getHeaders());
        log.debug("Response body: {}", inputStringBuilder.toString());
        log.info("=======================response end=================================================");
    }

}

次に、aと:RestTemplateを使用してインスタンス化します。BufferingClientHttpRequestFactoryLoggingRequestInterceptor

RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new LoggingRequestInterceptor());
restTemplate.setInterceptors(interceptors);

インターセプターと最初の呼び出しコードの両方で応答本文を使用するため、BufferingClientHttpRequestFactoryが必要です。デフォルトの実装では、応答本文を1回だけ読み取ることができます。

于 2015-10-08T07:54:30.317 に答える
155

Spring Bootでは、プロパティ(または他の12ファクターメソッド)でこれを設定することにより、完全な要求/応答を取得できます。

logging.level.org.apache.http=DEBUG

この出力

-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connecting to localhost/127.0.0.1:41827
-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connection established 127.0.0.1:39546<->127.0.0.1:41827
-DEBUG o.a.http.impl.execchain.MainClientExec   : Executing request POST /v0/users HTTP/1.1
-DEBUG o.a.http.impl.execchain.MainClientExec   : Target auth state: UNCHALLENGED
-DEBUG o.a.http.impl.execchain.MainClientExec   : Proxy auth state: UNCHALLENGED
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> POST /v0/users HTTP/1.1
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Content-Type: application/json;charset=UTF-8
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Content-Length: 56
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Host: localhost:41827
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Connection: Keep-Alive
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Accept-Encoding: gzip,deflate
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "POST /v0/users HTTP/1.1[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Content-Type: application/json;charset=UTF-8[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Content-Length: 56[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Host: localhost:41827[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "{"id":null,"email":"xenoterracide@gmail.com","new":true}"

と応答

-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connecting to localhost/127.0.0.1:41827
-DEBUG .i.c.DefaultHttpClientConnectionOperator : Connection established 127.0.0.1:39546<->127.0.0.1:41827
-DEBUG o.a.http.impl.execchain.MainClientExec   : Executing request POST /v0/users HTTP/1.1
-DEBUG o.a.http.impl.execchain.MainClientExec   : Target auth state: UNCHALLENGED
-DEBUG o.a.http.impl.execchain.MainClientExec   : Proxy auth state: UNCHALLENGED
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> POST /v0/users HTTP/1.1
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Content-Type: application/json;charset=UTF-8
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Content-Length: 56
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Host: localhost:41827
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Connection: Keep-Alive
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)
-DEBUG org.apache.http.headers                  : http-outgoing-0 >> Accept-Encoding: gzip,deflate
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "POST /v0/users HTTP/1.1[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Content-Type: application/json;charset=UTF-8[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Content-Length: 56[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Host: localhost:41827[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_102)[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "[\r][\n]"
-DEBUG org.apache.http.wire                     : http-outgoing-0 >> "{"id":null,"email":"xenoterracide@gmail.com","new":true}"

またはlogging.level.org.apache.http.wire=DEBUG、関連情報がすべて含まれているようです。

于 2016-08-23T19:48:20.507 に答える
83

@hstoerrの答えをいくつかのコードで拡張します:


LoggingRequestInterceptorを作成して、リクエストの応答をログに記録します

public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

    private static final Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {

        ClientHttpResponse response = execution.execute(request, body);

        log(request,body,response);

        return response;
    }

    private void log(HttpRequest request, byte[] body, ClientHttpResponse response) throws IOException {
        //do logging
    }
}

RestTemplateを設定する

RestTemplate rt = new RestTemplate();

//set interceptors/requestFactory
ClientHttpRequestInterceptor ri = new LoggingRequestInterceptor();
List<ClientHttpRequestInterceptor> ris = new ArrayList<ClientHttpRequestInterceptor>();
ris.add(ri);
rt.setInterceptors(ris);
rt.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
于 2014-03-24T20:41:44.870 に答える
44

最善の策は、ファイルに追加logging.level.org.springframework.web.client.RestTemplate=DEBUGすることです。application.properties

設定などの他のソリューションは、Apachelog4j.logger.httpclient.wireを使用することを前提としているため、常に機能するとは限りません。これは常に正しいとは限りません。log4jHttpClient

ただし、この構文は最新バージョンのSpringBootでのみ機能することに注意してください。

于 2016-07-04T13:15:20.393 に答える
36

spring-rest-template-loggerRestTemplateを使用してHTTPトラフィックをログに記録できます。

Mavenプロジェクトに依存関係を追加します。

<dependency>
    <groupId>org.hobsoft.spring</groupId>
    <artifactId>spring-rest-template-logger</artifactId>
    <version>2.0.0</version>
</dependency>

RestTemplate次に、次のようにカスタマイズします。

RestTemplate restTemplate = new RestTemplateBuilder()
    .customizers(new LoggingCustomizer())
    .build()

次の場所でデバッグログが有効になっていることを確認しapplication.propertiesます。

logging.level.org.hobsoft.spring.resttemplatelogger.LoggingCustomizer = DEBUG

これで、すべてのRestTemplateHTTPトラフィックがorg.hobsoft.spring.resttemplatelogger.LoggingCustomizerデバッグレベルでログに記録されます。

免責事項:私はこのライブラリを作成しました。

于 2017-11-01T10:16:15.770 に答える
33

使用するxenoterracideによって与えられた解決策

logging.level.org.apache.http=DEBUG

良いですが、問題はデフォルトでApacheHttpComponentsが使用されないことです。

Apache HttpComponentsを使用するには、pom.xmlに追加します

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpasyncclient</artifactId>
</dependency>

で構成RestTemplateします:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsAsyncClientHttpRequestFactory());
于 2017-02-01T15:38:51.397 に答える
31

これらの答えのどれも実際に問題の100%を解決しません。mjj1409はそのほとんどを取得しますが、応答のログ記録の問題を回避するので便利です。これには少し手間がかかります。Paul Sabouは、現実的に見えるソリューションを提供していますが、実際に実装するのに十分な詳細を提供していません(そして、それは私にとってはまったく機能しませんでした)。Sofieneはログを取得しましたが、重大な問題がありました。入力ストリームがすでに消費されているため、応答が読み取れなくなりました。

BufferingClientHttpResponseWrapperを使用して応答オブジェクトをラップし、応答本文を複数回読み取ることができるようにすることをお勧めします。

public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

    @Override
    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
            final ClientHttpRequestExecution execution) throws IOException {
        ClientHttpResponse response = execution.execute(request, body);

        response = log(request, body, response);

        return response;
    }

    private ClientHttpResponse log(final HttpRequest request, final byte[] body, final ClientHttpResponse response) {
        final ClientHttpResponse responseCopy = new BufferingClientHttpResponseWrapper(response);
        logger.debug("Method: ", request.getMethod().toString());
        logger.debug("URI: ", , request.getURI().toString());
        logger.debug("Request Body: " + new String(body));
        logger.debug("Response body: " + IOUtils.toString(responseCopy.getBody()));
        return responseCopy;
    }

}

応答本文はメモリにロードされ、複数回読み取ることができるため、これはInputStreamを消費しません。クラスパスにBufferingClientHttpResponseWrapperがない場合は、次の簡単な実装を見つけることができます。

https://github.com/spring-projects/spring-android/blob/master/spring-android-rest-template/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java

RestTemplateを設定するには:

LoggingRequestInterceptor loggingInterceptor = new LoggingRequestInterceptor();
restTemplate.getInterceptors().add(loggingInterceptor);
于 2016-03-01T21:07:20.233 に答える
25

私はついにこれを正しい方法で行う方法を見つけました。ソリューションのほとんどは、 ログを取得できるようにSpringとSLF4Jを構成するにはどうすればよいですか?

実行する必要があることが2つあるようです。

  1. log4j.propertiesに次の行を追加します。log4j.logger.httpclient.wire=DEBUG
  2. Springがロギング設定を無視しないことを確認してください

2番目の問題は、主にslf4jが使用されている春の環境で発生します(私の場合のように)。そのため、slf4jを使用する場合は、次の2つのことが発生することを確認してください。

  1. クラスパスにcommons-loggingライブラリはありません:これは、pomに除外記述子を追加することで実行できます:

            <exclusions><exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    
  2. log4j.propertiesファイルは、Springが検索/表示できるクラスパスのどこかに保存されます。これに問題がある場合、最後の解決策は、log4j.propertiesファイルをデフォルトのパッケージに入れることです(良い習慣ではありませんが、期待どおりに機能することを確認するだけです)。

于 2011-11-01T08:41:48.483 に答える
25

RestTemplateのロギング

オプション1.デバッグログを開きます。

RestTemplateを構成する

  • デフォルトでは、RestTemplateは標準のJDK機能に依存してHTTP接続を確立します。ApacheHttpComponentsなどの別のHTTPライブラリを使用するように切り替えることができます

    @Bean public RestTemplate restTemplate(RestTemplateBuilder builder){RestTemplate restTemplate = builder.build(); restTemplateを返します。}

ロギングを構成する

  • application.yml

    ロギング:レベル:org.springframework.web.client.RestTemplate:DEBUG

オプション2.インターセプターの使用

ラッパーの応答

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;

public final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {

    private final ClientHttpResponse response;

    private byte[] body;


    BufferingClientHttpResponseWrapper(ClientHttpResponse response) {
        this.response = response;
    }

    public HttpStatus getStatusCode() throws IOException {
        return this.response.getStatusCode();
    }

    public int getRawStatusCode() throws IOException {
        return this.response.getRawStatusCode();
    }

    public String getStatusText() throws IOException {
        return this.response.getStatusText();
    }

    public HttpHeaders getHeaders() {
        return this.response.getHeaders();
    }

    public InputStream getBody() throws IOException {
        if (this.body == null) {
            this.body = StreamUtils.copyToByteArray(this.response.getBody());
        }
        return new ByteArrayInputStream(this.body);
    }

    public void close() {
        this.response.close();
    }
}

インターセプターを実装する

package com.example.logging;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

public class LoggingRestTemplate implements ClientHttpRequestInterceptor {

    private final static Logger LOGGER = LoggerFactory.getLogger(LoggingRestTemplate.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body,
            ClientHttpRequestExecution execution) throws IOException {
        traceRequest(request, body);
        ClientHttpResponse response = execution.execute(request, body);
        return traceResponse(response);
    }

    private void traceRequest(HttpRequest request, byte[] body) throws IOException {
        if (!LOGGER.isDebugEnabled()) {
            return;
        }
        LOGGER.debug(
                "==========================request begin==============================================");
        LOGGER.debug("URI                 : {}", request.getURI());
        LOGGER.debug("Method            : {}", request.getMethod());
        LOGGER.debug("Headers         : {}", request.getHeaders());
        LOGGER.debug("Request body: {}", new String(body, "UTF-8"));
        LOGGER.debug(
                "==========================request end================================================");
    }

    private ClientHttpResponse traceResponse(ClientHttpResponse response) throws IOException {
        if (!LOGGER.isDebugEnabled()) {
            return response;
        }
        final ClientHttpResponse responseWrapper = new BufferingClientHttpResponseWrapper(response);
        StringBuilder inputStringBuilder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(responseWrapper.getBody(), "UTF-8"));
        String line = bufferedReader.readLine();
        while (line != null) {
            inputStringBuilder.append(line);
            inputStringBuilder.append('\n');
            line = bufferedReader.readLine();
        }
        LOGGER.debug(
                "==========================response begin=============================================");
        LOGGER.debug("Status code    : {}", responseWrapper.getStatusCode());
        LOGGER.debug("Status text    : {}", responseWrapper.getStatusText());
        LOGGER.debug("Headers            : {}", responseWrapper.getHeaders());
        LOGGER.debug("Response body: {}", inputStringBuilder.toString());
        LOGGER.debug(
                "==========================response end===============================================");
        return responseWrapper;
    }

}

RestTemplateを構成する

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    RestTemplate restTemplate = builder.build();
    restTemplate.setInterceptors(Collections.singletonList(new LoggingRestTemplate()));
    return restTemplate;
}

ロギングを構成する

  • LoggingRestTemplateのパッケージを確認してください。例application.yml

    ロギング:レベル:com.example.logging:DEBUG

オプション3.httpcomponentを使用する

httpcomponentの依存関係をインポートする

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpasyncclient</artifactId>

RestTemplateを構成する

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    RestTemplate restTemplate = builder.build();
    restTemplate.setRequestFactory(new HttpComponentsAsyncClientHttpRequestFactory());
    return restTemplate;
}

ロギングを構成する

  • LoggingRestTemplateのパッケージを確認してください。例application.yml

    ロギング:レベル:org.apache.http:デバッグ

于 2017-11-24T06:34:11.980 に答える
20

----2019年7月----

(Spring Bootを使用)

Spring Bootは、ゼロ構成の魔法をすべて備えているため、RestTemplateを使用して単純なJSON応答本文を検査またはログに記録する簡単な方法を提供していないことに驚きました。私はここで提供されるさまざまな回答とコメントを調べ、現在のオプションを考えると、(まだ)機能し、合理的な解決策のように思える自分の蒸留バージョンを共有しています(私はGradle4.4でSpringBoot2.1.6を使用しています)。

1.httpプロキシとしてFiddlerを使用する

これは、独自のインターセプターを作成したり、基盤となるhttpクライアントをapacheに変更したりするという面倒な作業をすべて回避するため、実際には非常に洗練されたソリューションです(以下を参照)。

Fiddlerをインストールして実行します

その後

-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888VMオプションに追加

2.ApacheHttpClientを使用する

ApacheHttpClientをMavenまたはGradleの依存関係に追加します。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.9</version>
</dependency>

HttpComponentsClientHttpRequestFactoryRestTemplateのRequestFactoryとして使用します。これを行う最も簡単な方法は次のとおりです。

RestTemplate restTemplate = new RestTemplate();

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

ファイルでDEBUGを有効にしapplication.propertiesます(Spring Bootを使用している場合)

logging.level.org.apache.http=DEBUG

Spring Bootを使用している場合は、ロギングフレームワークが設定されていることを確認する必要があります。たとえば、を含むspring-boot-starter依存関係を使用しますspring-boot-starter-logging

3.インターセプターを使用する

他の回答やコメントの提案、反対提案、落とし穴を読んで、その道を進むかどうかを自分で決めましょう。

4.本文なしでURLと応答ステータスをログに記録します

これは本文のログ記録の規定された要件を満たしていませんが、REST呼び出しのログ記録を開始するための迅速で簡単な方法です。完全なURLと応答ステータスが表示されます。

次の行をファイルに追加するだけapplication.propertiesです(Spring Bootを使用していると仮定し、以下を含むSpring Bootスターター依存関係を使用していると仮定しますspring-boot-starter-logging

logging.level.org.springframework.web.client.RestTemplate = DEBUG

出力は次のようになります。

2019-07-29 11:53:50.265 DEBUG o.s.web.client.RestTemplate : HTTP GET http://www.myrestservice.com/Endpoint?myQueryParam=myValue
2019-07-29 11:53:50.276 DEBUG o.s.web.client.RestTemplate : Accept=[application/json]
2019-07-29 11:53:50.584 DEBUG o.s.web.client.RestTemplate : Response 200 OK
2019-07-29 11:53:50.585 DEBUG o.s.web.client.RestTemplate : Reading to [org.mynamespace.MyJsonModelClass]
于 2019-07-29T11:00:10.673 に答える
18

他の応答で述べたように、応答本体は、繰り返し読み取ることができるように特別な処理が必要です(デフォルトでは、その内容は最初の読み取りで消費されます)。

BufferingClientHttpRequestFactoryリクエストを設定するときにを使用する代わりに、インターセプター自体がレスポンスをラップし、コンテンツが保持され、繰り返し読み取ることができることを確認できます(ロガーとレスポンスのコンシューマーが):

私の迎撃機、

  • ラッパーを使用して応答本文をバッファリングします
  • よりコンパクトな方法でログに記録する
  • ステータスコード識別子もログに記録します(例:201作成済み)
  • 同時ログエントリを複数のスレッドから簡単に区別できるようにする要求シーケンス番号が含まれています

コード:

public class LoggingInterceptor implements ClientHttpRequestInterceptor {

    private final Logger log = LoggerFactory.getLogger(getClass());
    private AtomicInteger requestNumberSequence = new AtomicInteger(0);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        int requestNumber = requestNumberSequence.incrementAndGet();
        logRequest(requestNumber, request, body);
        ClientHttpResponse response = execution.execute(request, body);
        response = new BufferedClientHttpResponse(response);
        logResponse(requestNumber, response);
        return response;
    }

    private void logRequest(int requestNumber, HttpRequest request, byte[] body) {
        if (log.isDebugEnabled()) {
            String prefix = requestNumber + " > ";
            log.debug("{} Request: {} {}", prefix, request.getMethod(), request.getURI());
            log.debug("{} Headers: {}", prefix, request.getHeaders());
            if (body.length > 0) {
                log.debug("{} Body: \n{}", prefix, new String(body, StandardCharsets.UTF_8));
            }
        }
    }

    private void logResponse(int requestNumber, ClientHttpResponse response) throws IOException {
        if (log.isDebugEnabled()) {
            String prefix = requestNumber + " < ";
            log.debug("{} Response: {} {} {}", prefix, response.getStatusCode(), response.getStatusCode().name(), response.getStatusText());
            log.debug("{} Headers: {}", prefix, response.getHeaders());
            String body = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);
            if (body.length() > 0) {
                log.debug("{} Body: \n{}", prefix, body);
            }
        }
    }

    /**
     * Wrapper around ClientHttpResponse, buffers the body so it can be read repeatedly (for logging & consuming the result).
     */
    private static class BufferedClientHttpResponse implements ClientHttpResponse {

        private final ClientHttpResponse response;
        private byte[] body;

        public BufferedClientHttpResponse(ClientHttpResponse response) {
            this.response = response;
        }

        @Override
        public HttpStatus getStatusCode() throws IOException {
            return response.getStatusCode();
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return response.getRawStatusCode();
        }

        @Override
        public String getStatusText() throws IOException {
            return response.getStatusText();
        }

        @Override
        public void close() {
            response.close();
        }

        @Override
        public InputStream getBody() throws IOException {
            if (body == null) {
                body = StreamUtils.copyToByteArray(response.getBody());
            }
            return new ByteArrayInputStream(body);
        }

        @Override
        public HttpHeaders getHeaders() {
            return response.getHeaders();
        }
    }
}

構成:

 @Bean
    public RestTemplateBuilder restTemplateBuilder() {
        return new RestTemplateBuilder()
                .additionalInterceptors(Collections.singletonList(new LoggingInterceptor()));
    }

ログ出力の例:

2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 >  Request: POST http://localhost:53969/payment/v4/private/payment-lists/10022/templates
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 >  Headers: {Accept=[application/json, application/json], Content-Type=[application/json;charset=UTF-8], Content-Length=[986]}
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 >  Body: 
{"idKey":null, ...}
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 <  Response: 200 OK 
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 <  Headers: {Content-Type=[application/json;charset=UTF-8], Transfer-Encoding=[chunked], Date=[Mon, 08 Oct 2018 08:58:53 GMT]}
2018-10-08 10:58:53 [main] DEBUG x.y.z.LoggingInterceptor - 2 <  Body: 
{ "idKey" : "10022", ...  }
于 2018-10-08T09:01:11.900 に答える
12

他の回答で説明されているHttpClientロギングに加えて、要求と応答の本文を読み取ってログに記録するClientHttpRequestInterceptorを導入することもできます。他のものもHttpClientを使用している場合、またはカスタムログ形式が必要な場合は、これを実行することをお勧めします。注意:応答を2回読み取ることができるように、RestTemplateにBufferingClientHttpRequestFactoryを指定する必要があります。

于 2014-02-25T14:42:05.397 に答える
10

application.properties

logging.level.org.springframework.web.client=DEBUG

application.yml

logging:
  level:  
    root: WARN
    org.springframework.web.client: DEBUG
于 2019-01-10T20:31:31.383 に答える
8

これは正しい方法ではないかもしれませんが、これはログにあまり入力せずに要求と応答を印刷するための最も簡単なアプローチだと思います。

以下に2行を追加することにより、application.propertiesはすべての要求と応答をログに記録します。1行目は要求をログに記録し、2行目は応答をログに記録します。

logging.level.org.springframework.web.client.RestTemplate=DEBUG
logging.level.org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor=DEBUG
于 2018-05-29T15:37:29.857 に答える
6

HttpClient 4.xを使用するように構成されている場合は、ここでHttpClientのログドキュメントをRestTemplate確認できます。ロガーは、他の回答で指定されているものとは異なります。

HttpClient3.xのログ設定はこちらから入手できます。

于 2014-11-13T15:13:49.910 に答える
5

ここでの非常に多くの応答には、コーディングの変更とカスタマイズされたクラスが必要であり、実際には必要ありません。fiddlerなどのデバッグプロキシを取得し、コマンドライン(-Dhttp.proxyHostおよび-Dhttp.proxyPort)でプロキシを使用するようにJava環境を設定してから、fiddlerを実行すると、要求と応答全体を確認できます。また、サーバーの変更をコミットする前に実験を実行するために送信される前後の結果と応答をいじくり回す機能など、多くの補助的な利点があります。

発生する可能性のある問題の最後のビットは、HTTPSを使用する必要がある場合、SSL証明書をフィドラーからエクスポートしてJavaキーストア(cacerts)ヒントにインポートする必要があることです。デフォルトのJavaキーストアパスワードは通常「changeit」です。

于 2018-10-08T19:12:09.710 に答える
5

Apache HttpClientの助けを借りてLogbackにログを記録するには:

クラスパスにApacheHttpClientが必要です。

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.5.10</version>
</dependency>

RestTemplateHttpClientを使用するように構成します。

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

要求と応答をログに記録するには、ログバック構成ファイルに追加します。

<logger name="org.apache.http.wire" level="DEBUG"/>

または、さらにログに記録するには:

<logger name="org.apache.http" level="DEBUG"/>
于 2019-10-01T14:57:45.283 に答える
2

上記の議論に加えて、これは幸せなシナリオを表すだけです。エラーが発生した場合、おそらく応答をログに記録することはできません。

この場合と上記のすべての場合では、DefaultResponseErrorHandlerをオーバーライドして、以下のように設定する必要があります

restTemplate.setErrorHandler(new DefaultResponseErrorHandlerImpl());
于 2016-04-07T13:43:28.243 に答える
2

不思議なことに、RestTemplateは一部のクライアントおよびサーバーの500xエラーで応答を返さないようであるため、これらのソリューションはいずれも機能しません。この場合、次のようにResponseErrorHandlerを実装することで、それらもログに記録します。これがドラフトコードですが、要点は次のとおりです。

エラーハンドラと同じインターセプタを設定できます。

restTemplate.getInterceptors().add(interceptor);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
restTemplate.setErrorHandler(interceptor);

そして、インターセプトは両方のインターフェースを実装します:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus.Series;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.ResponseErrorHandler;

public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor, ResponseErrorHandler {
    static final Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);
    static final DefaultResponseErrorHandler defaultResponseErrorHandler = new DefaultResponseErrorHandler();
    final Set<Series> loggableStatuses = new HashSet();

    public LoggingRequestInterceptor() {
    }

    public LoggingRequestInterceptor(Set<Series> loggableStatuses) {
        loggableStatuses.addAll(loggableStatuses);
    }

    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        this.traceRequest(request, body);
        ClientHttpResponse response = execution.execute(request, body);
        if(response != null) {
            this.traceResponse(response);
        }

        return response;
    }

    private void traceRequest(HttpRequest request, byte[] body) throws IOException {
        log.debug("===========================request begin================================================");
        log.debug("URI         : {}", request.getURI());
        log.debug("Method      : {}", request.getMethod());
        log.debug("Headers     : {}", request.getHeaders());
        log.debug("Request body: {}", new String(body, "UTF-8"));
        log.debug("==========================request end================================================");
    }

    private void traceResponse(ClientHttpResponse response) throws IOException {
        if(this.loggableStatuses.isEmpty() || this.loggableStatuses.contains(response.getStatusCode().series())) {
            StringBuilder inputStringBuilder = new StringBuilder();

            try {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"));

                for(String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) {
                    inputStringBuilder.append(line);
                    inputStringBuilder.append('\n');
                }
            } catch (Throwable var5) {
                log.error("cannot read response due to error", var5);
            }

            log.debug("============================response begin==========================================");
            log.debug("Status code  : {}", response.getStatusCode());
            log.debug("Status text  : {}", response.getStatusText());
            log.debug("Headers      : {}", response.getHeaders());
            log.debug("Response body: {}", inputStringBuilder.toString());
            log.debug("=======================response end=================================================");
        }

    }

    public boolean hasError(ClientHttpResponse response) throws IOException {
        return defaultResponseErrorHandler.hasError(response);
    }

    public void handleError(ClientHttpResponse response) throws IOException {
        this.traceResponse(response);
        defaultResponseErrorHandler.handleError(response);
    }
}
于 2017-10-18T02:11:20.147 に答える
1

を使用している場合は、を使用して構成するトリックは機能RestTemplateBufferingClientHttpRequestFactoryませんClientHttpRequestInterceptor。インターセプターを介してログに記録しようとしている場合は機能します。これは、InterceptingHttpAccessorRestTemplateサブクラスが)機能する方法によるものです。

簡単に言うと...代わりにこのクラスをRestTemplate使用してください(これはSLF4JロギングAPIを使用していることに注意してください。必要に応じて編集してください):

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.RestTemplate;

/**
 * A {@link RestTemplate} that logs every request and response.
 */
public class LoggingRestTemplate extends RestTemplate {

    // Bleh, this class is not public
    private static final String RESPONSE_WRAPPER_CLASS = "org.springframework.http.client.BufferingClientHttpResponseWrapper";

    private Logger log = LoggerFactory.getLogger(this.getClass());

    private boolean hideAuthorizationHeaders = true;
    private Class<?> wrapperClass;
    private Constructor<?> wrapperConstructor;

    /**
     * Configure the logger to log requests and responses to.
     *
     * @param log log destination, or null to disable
     */
    public void setLogger(Logger log) {
        this.log = log;
    }

    /**
     * Configure the logger to log requests and responses to by name.
     *
     * @param name name of the log destination, or null to disable
     */
    public void setLoggerName(String name) {
        this.setLogger(name != null ? LoggerFactory.getLogger(name) : null);
    }

    /**
     * Configure whether to hide the contents of {@code Authorization} headers.
     *
     * <p>
     * Default true.
     *
     * @param hideAuthorizationHeaders true to hide, otherwise false
     */
    public void setHideAuthorizationHeaders(boolean hideAuthorizationHeaders) {
        this.hideAuthorizationHeaders = hideAuthorizationHeaders;
    }

    /**
     * Log a request.
     */
    protected void traceRequest(HttpRequest request, byte[] body) {
        this.log.debug("xmit: {} {}\n{}{}", request.getMethod(), request.getURI(), this.toString(request.getHeaders()),
          body != null && body.length > 0 ? "\n\n" + new String(body, StandardCharsets.UTF_8) : "");
    }

    /**
     * Log a response.
     */
    protected void traceResponse(ClientHttpResponse response) {
        final ByteArrayOutputStream bodyBuf = new ByteArrayOutputStream();
        HttpStatus statusCode = null;
        try {
            statusCode = response.getStatusCode();
        } catch (IOException e) {
            // ignore
        }
        String statusText = null;
        try {
            statusText = response.getStatusText();
        } catch (IOException e) {
            // ignore
        }
        try (final InputStream input = response.getBody()) {
            byte[] b = new byte[1024];
            int r;
            while ((r = input.read(b)) != -1)
                bodyBuf.write(b, 0, r);
        } catch (IOException e) {
            // ignore
        }
        this.log.debug("recv: {} {}\n{}{}", statusCode, statusText, this.toString(response.getHeaders()),
          bodyBuf.size() > 0 ? "\n\n" + new String(bodyBuf.toByteArray(), StandardCharsets.UTF_8) : "");
    }

    @PostConstruct
    private void addLoggingInterceptor() {
        this.getInterceptors().add(new ClientHttpRequestInterceptor() {
            @Override
            public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
              throws IOException {

                // Log request
                if (LoggingRestTemplate.this.log != null && LoggingRestTemplate.this.log.isDebugEnabled())
                    LoggingRestTemplate.this.traceRequest(request, body);

                // Perform request
                ClientHttpResponse response = execution.execute(request, body);

                // Log response
                if (LoggingRestTemplate.this.log != null && LoggingRestTemplate.this.log.isDebugEnabled()) {
                    final ClientHttpResponse bufferedResponse = LoggingRestTemplate.this.ensureBuffered(response);
                    if (bufferedResponse != null) {
                        LoggingRestTemplate.this.traceResponse(bufferedResponse);
                        response = bufferedResponse;
                    }
                }

                // Done
                return response;
            }
        });
    }

    private ClientHttpResponse ensureBuffered(ClientHttpResponse response) {
        try {
            if (this.wrapperClass == null)
                this.wrapperClass = Class.forName(RESPONSE_WRAPPER_CLASS, false, ClientHttpResponse.class.getClassLoader());
            if (!this.wrapperClass.isInstance(response)) {
                if (this.wrapperConstructor == null) {
                    this.wrapperConstructor = this.wrapperClass.getDeclaredConstructor(ClientHttpResponse.class);
                    this.wrapperConstructor.setAccessible(true);
                }
                response = (ClientHttpResponse)this.wrapperConstructor.newInstance(response);
            }
            return response;
        } catch (Exception e) {
            this.log.error("error creating {} instance: {}", RESPONSE_WRAPPER_CLASS, e);
            return null;
        }
    }

    private String toString(HttpHeaders headers) {
        final StringBuilder headerBuf = new StringBuilder();
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            if (headerBuf.length() > 0)
                headerBuf.append('\n');
            final String name = entry.getKey();
            for (String value : entry.getValue()) {
                if (this.hideAuthorizationHeaders && name.equalsIgnoreCase(HttpHeaders.AUTHORIZATION))
                    value = "[omitted]";
                headerBuf.append(name).append(": ").append(value);
            }
        }
        return headerBuf.toString();
    }
}

これを行うだけでこれだけの作業が必要になるのはばかげていることに同意します。

于 2016-04-05T22:29:04.470 に答える
1

@MilacHが指摘したように、実装にエラーがあります。statusCode> 400が返された場合、errorHandlerが呼び出されないため、インターセプターからIOExceptionがスローされます。例外は無視して、ハンドラーメソッドで再度キャッチできます。

package net.sprd.fulfillment.common;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import static java.nio.charset.StandardCharsets.UTF_8;

public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

    final static Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

    @SuppressWarnings("HardcodedLineSeparator")
    public static final char LINE_BREAK = '\n';

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        try {
            traceRequest(request, body);
        } catch (Exception e) {
            log.warn("Exception in LoggingRequestInterceptor while tracing request", e);
        }

        ClientHttpResponse response = execution.execute(request, body);

        try {
            traceResponse(response);
        } catch (IOException e) {
            // ignore the exception here, as it will be handled by the error handler of the restTemplate
            log.warn("Exception in LoggingRequestInterceptor", e);
        }
        return response;
    }

    private void traceRequest(HttpRequest request, byte[] body) {
        log.info("===========================request begin================================================");
        log.info("URI         : {}", request.getURI());
        log.info("Method      : {}", request.getMethod());
        log.info("Headers     : {}", request.getHeaders());
        log.info("Request body: {}", new String(body, UTF_8));
        log.info("==========================request end================================================");
    }

    private void traceResponse(ClientHttpResponse response) throws IOException {
        StringBuilder inputStringBuilder = new StringBuilder();
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), UTF_8))) {
            String line = bufferedReader.readLine();
            while (line != null) {
                inputStringBuilder.append(line);
                inputStringBuilder.append(LINE_BREAK);
                line = bufferedReader.readLine();
            }
        }

        log.info("============================response begin==========================================");
        log.info("Status code  : {}", response.getStatusCode());
        log.info("Status text  : {}", response.getStatusText());
        log.info("Headers      : {}", response.getHeaders());
        log.info("Response body: {}", inputStringBuilder);
        log.info("=======================response end=================================================");
    }

}
于 2018-09-14T11:03:09.523 に答える
1

org.apache.http.wire読み取り不能なログが表示されるため、logbookを使用して、アプリケーションのサーブレットおよびRestTemplateの要求と応答をペイロードとともにログに記録します。

build.gradle

compile group: 'org.zalando', name: 'logbook-spring-boot-starter', version: '2.6.2'

またはMavenの依存関係:

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-spring-boot-starter</artifactId>
    <version>2.6.2</version>
</dependency>

application.properties(またはトラフYAML):

logging.level.org.zalando.logbook = TRACE

RestTemplate.java

import java.util.function.Supplier;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.zalando.logbook.httpclient.LogbookHttpRequestInterceptor;
import org.zalando.logbook.httpclient.LogbookHttpResponseInterceptor;

@Configuration
public class RestTemplateConfiguration {
    private final LogbookHttpRequestInterceptor logbookHttpRequestInterceptor;
    private final LogbookHttpResponseInterceptor logbookHttpResponseInterceptor;

    public RestTemplateConfiguration(LogbookHttpRequestInterceptor logbookHttpRequestInterceptor,
            LogbookHttpResponseInterceptor logbookHttpResponseInterceptor) {
        this.logbookHttpRequestInterceptor = logbookHttpRequestInterceptor;
        this.logbookHttpResponseInterceptor = logbookHttpResponseInterceptor;
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
        return restTemplateBuilder
                .requestFactory(new MyRequestFactorySupplier())
                .build();
    }

    class MyRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> {
        @Override
        public ClientHttpRequestFactory get() {
            // Using Apache HTTP client
            CloseableHttpClient client = HttpClientBuilder.create()
                    .addInterceptorFirst(logbookHttpRequestInterceptor)
                    .addInterceptorFirst(logbookHttpResponseInterceptor)
                    .build();
            return new HttpComponentsClientHttpRequestFactory(client);
        }
    }
}
于 2020-01-29T11:00:32.693 に答える
0

今の最良の解決策は、依存関係を追加するだけです:

<dependency>
  <groupId>com.github.zg2pro</groupId>
  <artifactId>spring-rest-basis</artifactId>
  <version>v.x</version>
</dependency>

これには、RestTemplateにその方法で追加できるLoggingRequestInterceptorクラスが含まれています。

次の方法で、このユーティリティをスプリングRestTemplateにインターセプターとして追加することにより、このユーティリティを統合します。

restTemplate.setRequestFactory(LoggingRequestFactoryFactory.build());

そして、log4jのようなフレームワークにslf4j実装を追加します。

または、「Zg2proRestTemplate」を直接使用します。スプリングRestTemplateを使用する場合、httpclientとすべてのapache.httpライブラリが必ずしもロードされるとは限らないため、@PaulSabouによる「ベストアンサー」はそのように見えます。

于 2017-08-22T08:35:01.760 に答える
0

これの実装も追加したかった。セミコロンが欠落していることをお詫びします。これはGroovyで書かれています。

提供された受け入れられた答えよりも構成可能なものが必要でした。これは非常に機敏で、OPが探しているようにすべてをログに記録するRESTテンプレートBeanです。

カスタムロギングインターセプタークラス:

import org.springframework.http.HttpRequest
import org.springframework.http.client.ClientHttpRequestExecution
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.http.client.ClientHttpResponse
import org.springframework.util.StreamUtils

import java.nio.charset.Charset

class HttpLoggingInterceptor implements ClientHttpRequestInterceptor {

    private final static Logger log = LoggerFactory.getLogger(HttpLoggingInterceptor.class)

    @Override
    ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        logRequest(request, body)
        ClientHttpResponse response = execution.execute(request, body)
        logResponse(response)
        return response
    }

    private void logRequest(HttpRequest request, byte[] body) throws IOException {
        if (log.isDebugEnabled()) {
            log.debug("===========================request begin================================================")
            log.debug("URI         : {}", request.getURI())
            log.debug("Method      : {}", request.getMethod())
            log.debug("Headers     : {}", request.getHeaders())
            log.debug("Request body: {}", new String(body, "UTF-8"))
            log.debug("==========================request end================================================")
        }
    }

    private void logResponse(ClientHttpResponse response) throws IOException {
        if (log.isDebugEnabled()) {
            log.debug("============================response begin==========================================")
            log.debug("Status code  : {}", response.getStatusCode())
            log.debug("Status text  : {}", response.getStatusText())
            log.debug("Headers      : {}", response.getHeaders())
            log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()))
            log.debug("=======================response end=================================================")
        }
    }
}

残りのテンプレートBeanの定義:

@Bean(name = 'myRestTemplate')
RestTemplate myRestTemplate(RestTemplateBuilder builder) {

    RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(10 * 1000) // 10 seconds
            .setSocketTimeout(300 * 1000) // 300 seconds
            .build()

    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager()
    connectionManager.setMaxTotal(10)
    connectionManager.closeIdleConnections(5, TimeUnit.MINUTES)

    CloseableHttpClient httpClient = HttpClients.custom()
            .setConnectionManager(connectionManager)
            .setDefaultRequestConfig(requestConfig)
            .disableRedirectHandling()
            .build()

    RestTemplate restTemplate = builder
            .rootUri("https://domain.server.com")
            .basicAuthorization("username", "password")
            .requestFactory(new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)))
            .interceptors(new HttpLoggingInterceptor())
            .build()

    return restTemplate
}

実装:

@Component
class RestService {

    private final RestTemplate restTemplate
    private final static Logger log = LoggerFactory.getLogger(RestService.class)

    @Autowired
    RestService(
            @Qualifier("myRestTemplate") RestTemplate restTemplate
    ) {
        this.restTemplate = restTemplate
    }

    // add specific methods to your service that access the GET and PUT methods

    private <T> T getForObject(String path, Class<T> object, Map<String, ?> params = [:]) {
        try {
            return restTemplate.getForObject(path, object, params)
        } catch (HttpClientErrorException e) {
            log.warn("Client Error (${path}): ${e.responseBodyAsString}")
        } catch (HttpServerErrorException e) {
            String msg = "Server Error (${path}): ${e.responseBodyAsString}"
            log.error(msg, e)
        } catch (RestClientException e) {
            String msg = "Error (${path})"
            log.error(msg, e)
        }
        return null
    }

    private <T> T putForObject(String path, T object) {
        try {
            HttpEntity<T> request = new HttpEntity<>(object)
            HttpEntity<T> response = restTemplate.exchange(path, HttpMethod.PUT, request, T)
            return response.getBody()
        } catch (HttpClientErrorException e) {
            log.warn("Error (${path}): ${e.responseBodyAsString}")
        } catch (HttpServerErrorException e) {
            String msg = "Error (${path}): ${e.responseBodyAsString}"
            log.error(msg, e)
        } catch (RestClientException e) {
            String msg = "Error (${path})"
            log.error(msg, e)
        }
        return null
    }
}
于 2018-04-20T17:55:59.793 に答える
0

HttpInputStreamで複数の読み取りを有効にして、残りのテンプレートの要求と応答をログに記録するためのQ/Aを参照してください

応答が空のカスタムClientHttpRequestInterceptorを使用する理由

于 2018-04-27T03:21:07.280 に答える
0

問題を解決する簡単な方法:

  1. RestTemplateBuilderを使用してRestTemplateのBeanを作成します。これにより、接続時間と読み取り時間をより細かく制御できます。
@Configuration
public class RestTemplateConfig {
  @Bean
  public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
      .setConnectTimeout(Duration.ofMillis(60000))
      .setReadTimeout(Duration.ofMillis(60000))
      .build();
  }

}
  1. resources/application.propertiesこの行をファイルに追加します: logging.level.org.springframework.web.client.RestTemplate=DEBUG
    問題が解決されることを願っています!
于 2022-01-14T09:05:25.803 に答える
-1

ClientHttpInterceptorを使用した応答に関連して、ファクトリをバッファリングせずに応答全体を保持する方法を見つけました。応答本体の入力ストリームを、その配列を本体からコピーするutilsメソッドを使用してバイト配列内に格納するだけですが、重要なのは、応答が空の場合(リソースアクセス例外の原因)に破損するため、このメソッドをtrycatchで囲んでください。 catchでは、空のバイト配列を作成するだけでなく、その配列と元の応答からの他のパラメーターを使用して、ClientHttpResponseの匿名の内部クラスを作成するだけではありません。その新しいClientHttpResponseオブジェクトを残りのテンプレート実行チェーンに戻すことができ、以前に保存されたbodyバイト配列を使用して応答をログに記録できます。そうすれば、実際の応答でInputStreamを消費することを回避し、RESTテンプレート応答をそのまま使用できます。ノート、

于 2018-03-02T04:32:35.463 に答える
-3

私のロガー設定はxmlを使用しました

<logger name="org.springframework.web.client.RestTemplate">
    <level value="trace"/>
</logger>

次に、次のようなものが表示されます。

DEBUG org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:92) : Reading [com.test.java.MyClass] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@604525f1]

HttpMessageConverterExtractor.java:92を介して、デバッグを続行する必要があります。私の場合、これを取得しました。

genericMessageConverter.write(requestBody, requestBodyType, requestContentType, httpRequest);

この:

outputMessage.getBody().flush();

outputMessage.getBody()には、http(post type)が送信するメッセージが含まれています

于 2017-01-19T02:36:56.740 に答える