web-dev-qa-db-fra.com

OkHttp comment enregistrer le corps de la requête

J'utilise un intercepteur et je voudrais enregistrer le corps d'une demande que je fais mais je ne vois aucun moyen de le faire.

C'est possible ?

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

et le résultat:

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
Mathieu de Brito

La réponse de Nikola n'a pas fonctionné pour moi. Je suppose que la mise en œuvre de ByteString#toString() a été modifiée. Cette solution a fonctionné pour moi:

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

De la documentation de readUtf8():

Supprime tous les octets de cela, les décode en UTF-8 et renvoie la chaîne.

qui devrait être ce que vous voulez.

116
msung

J'ai essayé de commenter la bonne réponse de @msung, mais ma réputation n'est pas assez bonne.

Voici la modification que j'ai faite pour imprimer RequestBody avant d'en faire une demande complète. Il fonctionne comme un charme. Merci

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

Parce que je vois qu'il y a toujours des gens intéressés par ce post, voici la version finale (jusqu'à la prochaine amélioration) de mon intercepteur de journaux. J'espère que cela vous fera gagner du temps.

Veuillez noter que ce code utilise OkHttp 2.2.0 (et 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
Mathieu de Brito

Version qui traite les demandes avec ou sans corps:

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

Avec une version actuelle d'OkHttp, vous pouvez utiliser le HTTP Logging Interceptor et définir le niveau sur BODY

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

Avec cela, vous ne pouvez pas configurer la sortie de manière granulaire pour différentes méthodes HTTP, mais cela fonctionne également pour d'autres méthodes pouvant avoir un corps.

Voici un exemple montrant la sortie d'une requête PATCH (peu expurgée):

--> 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)

Comme vous pouvez le constater, cela imprime également les en-têtes et, comme l'indique la documentation, vous devez prendre les précautions suivantes:

Les journaux générés par cet intercepteur lors de l'utilisation des niveaux HEADERS ou BODY risquent de laisser échapper des informations sensibles telles que les en-têtes "Authorization" ou "Cookie" et le contenu des corps de la requête et de la réponse. Ces données ne doivent être enregistrées que de manière contrôlée ou dans un environnement non productif.

Vous pouvez rédiger des en-têtes pouvant contenir des informations sensibles en appelant redactHeader().

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