web-dev-qa-db-ja.com

OkHttpリクエスト本文のログ方法

インターセプターを使用しています。作成しているリクエストの本文を記録したいのですが、これを行う方法がわかりません。

出来ますか ?

public class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        long t1 = System.nanoTime();
        Response response = chain.proceed(request);
        long t2 = System.nanoTime();

        double time = (t2 - t1) / 1e6d;

        if (request.method().equals("GET")) {
            Logs.info(String.format("GET " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), response.code(), response.headers(), response.body().charStream()));
        } else if (request.method().equals("POST")) {
            Logs.info(String.format("POST " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), request.body(), response.code(), response.headers(), response.body().charStream()));
        } else if (request.method().equals("PUT")) {
            Logs.info(String.format("PUT " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), request.body().toString(), response.code(), response.headers(), response.body().charStream()));
        } else if (request.method().equals("DELETE")) {
            Logs.info(String.format("DELETE " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITHOUT_BODY, request.url(), time, request.headers(), response.code(), response.headers()));
        }

        return response;
    }
}

そして結果:

POST  [some url] in 88,7ms
    ZoneName: touraine
    Source: Android
    body: retrofit.client.OkClient$1@1df53f05 <-request.body().toString() gives me this, but I would like the content string
    Response: 500
    Date: Tue, 24 Feb 2015 10:14:22 GMT
    body: [some content] 
59

ニコラの答えは私にはうまくいきませんでした。私の推測では、ByteString#toString()の実装が変更されました。このソリューションは私のために働いた:

_private static String bodyToString(final Request request){

    try {
        final Request copy = request.newBuilder().build();
        final Buffer buffer = new Buffer();
        copy.body().writeTo(buffer);
        return buffer.readUtf8();
    } catch (final IOException e) {
        return "did not work";
    }
}
_

readUtf8()のドキュメントから:

これからすべてのバイトを削除し、それらをUTF-8としてデコードし、文字列を返します。

あなたが望むものでなければなりません。

116
msung

@msungからの正しい答えについてコメントしようとしましたが、私の評判は十分に高くありません。

次に、完全なリクエストを作成する前にRequestBodyを印刷するために行った変更を示します。それは魅力のように機能します。ありがとう

private static String bodyToString(final RequestBody request){
        try {
            final RequestBody copy = request;
            final Buffer buffer = new Buffer();
            copy.writeTo(buffer);
            return buffer.readUtf8();
        } 
        catch (final IOException e) {
            return "did not work";
        }
}
13
Unu

[〜#〜] edit [〜#〜]

この投稿にまだ興味がある人がいるので、ログインターセプターの最終バージョン(次の改善まで)を示します。皆さんの時間を節約できることを願っています。

このコードはOkHttp 2.2.0(およびRetrofit 1.9.0)を使用していることに注意してください

import com.squareup.okhttp.*;
import okio.Buffer;
import Java.io.IOException;

public class LoggingInterceptor implements Interceptor {

private static final String F_BREAK = " %n";
private static final String F_URL = " %s";
private static final String F_TIME = " in %.1fms";
private static final String F_HEADERS = "%s";
private static final String F_RESPONSE = F_BREAK + "Response: %d";
private static final String F_BODY = "body: %s";

private static final String F_BREAKER = F_BREAK + "-------------------------------------------" + F_BREAK;
private static final String F_REQUEST_WITHOUT_BODY = F_URL + F_TIME + F_BREAK + F_HEADERS;
private static final String F_RESPONSE_WITHOUT_BODY = F_RESPONSE + F_BREAK + F_HEADERS + F_BREAKER;
private static final String F_REQUEST_WITH_BODY = F_URL + F_TIME + F_BREAK + F_HEADERS + F_BODY + F_BREAK;
private static final String F_RESPONSE_WITH_BODY = F_RESPONSE + F_BREAK + F_HEADERS + F_BODY + F_BREAK + F_BREAKER;

@Override
public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    long t1 = System.nanoTime();
    Response response = chain.proceed(request);
    long t2 = System.nanoTime();

    MediaType contentType = null;
    String bodyString = null;
    if (response.body() != null) {
        contentType = response.body().contentType();
        bodyString = response.body().string();
    }

    double time = (t2 - t1) / 1e6d;

    if (request.method().equals("GET")) {
        System.out.println(String.format("GET " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), response.code(), response.headers(), stringifyResponseBody(bodyString)));
    } else if (request.method().equals("POST")) {
        System.out.println(String.format("POST " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), stringifyRequestBody(request), response.code(), response.headers(), stringifyResponseBody(bodyString)));
    } else if (request.method().equals("PUT")) {
        System.out.println(String.format("PUT " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), request.body().toString(), response.code(), response.headers(), stringifyResponseBody(bodyString)));
    } else if (request.method().equals("DELETE")) {
        System.out.println(String.format("DELETE " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITHOUT_BODY, request.url(), time, request.headers(), response.code(), response.headers()));
    }

    if (response.body() != null) {
        ResponseBody body = ResponseBody.create(contentType, bodyString);
        return response.newBuilder().body(body).build();
    } else {
        return response;
    }
}


private static String stringifyRequestBody(Request request) {
    try {
        final Request copy = request.newBuilder().build();
        final Buffer buffer = new Buffer();
        copy.body().writeTo(buffer);
        return buffer.readUtf8();
    } catch (final IOException e) {
        return "did not work";
    }
}

public String stringifyResponseBody(String responseBody) {
    return responseBody;
}
}
10

ボディの有無にかかわらずリクエストを処理するバージョン:

private String stringifyRequestBody(Request request) {
  if (request.body() != null) {
      try {
          final Request copy = request.newBuilder().build();
          final Buffer buffer = new Buffer();
          copy.body().writeTo(buffer);
          return buffer.readUtf8();
      } catch (final IOException e) {
          Log.w(TAG, "Failed to stringify request body: " + e.getMessage());
      }
  }
  return "";
}
2
Mr. Bungle

OkHttpの現在のバージョンでは、 HTTP Logging Interceptor を使用して、レベルをBODYに設定できます。

_HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BODY);
_

これを使用すると、さまざまなHTTPメソッドの出力を細かく構成することはできませんが、本文を持つ可能性のある他のメソッドでも機能します。

PATCHリクエストの出力を示す例(最小限の編集):

_--> PATCH https://hostname/api/something/123456 HTTP/1.1
Content-Type: application/json-patch+json; charset=utf-8
Content-Length: 49
Authorization: Basic YWRtaW46c2VjcmV0Cg==
Accept: application/json

[ { "op": "add", "path": "/path", "value": true }]
--> END PATCH (xx-byte body)
_

ご覧のとおり、これによりヘッダーも出力され、ドキュメントに記載されているように、実際に注意する必要があります。

HEADERSまたはBODYレベルの使用時にこのインターセプターによって生成されたログには、「Authorization」または「Cookie」ヘッダーなどの機密情報とリクエストおよびレスポンス本文の内容が漏洩する可能性があります。このデータは、管理された方法または非実稼働環境でのみログに記録する必要があります。

redactHeader()を呼び出すことにより、機密情報を含む可能性のあるヘッダーを編集できます。

_logging.redactHeader("Authorization");
logging.redactHeader("Cookie");
_
0
Kariem