Подтвердить что ты не робот

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: [email protected] <-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] 
4b9b3361

Ответ 1

Ответ Николы не помог мне. Я предполагаю, что реализация 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 и возвращает строку.

который должен быть тем, что вы хотите.

Ответ 2

Я попытался прокомментировать правильный ответ от @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";
        }
}

Ответ 3

EDIT

Потому что я вижу, что есть еще некоторые люди, заинтересованные этим сообщением, вот окончательная версия (до следующего улучшения) моего перехватчика. Надеюсь, это спасет некоторых из вас, ребята, время.

Обратите внимание, что этот код использует OkHttp 2.2.0Retrofit 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;
}
}

Ответ 4

Версия, которая обрабатывает запросы с телом или без него:

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 "";
}

Ответ 5

В текущей версии OkHttp вы можете использовать HTTP Interceptor 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 могут привести к утечке конфиденциальной информации, такой как заголовки "Авторизация" или "Cookie" и содержимое тел запросов и ответов. Эти данные должны регистрироваться только контролируемым образом или в непроизводственной среде.

Вы можете редактировать заголовки, которые могут содержать конфиденциальную информацию, вызывая redactHeader().

logging.redactHeader("Authorization");
logging.redactHeader("Cookie");