android - okhttpclient - okhttp vs retrofit
OkHttp cómo registrar el cuerpo de la solicitud (5)
Estoy usando un interceptor y me gustaría registrar el cuerpo de una solicitud que estoy haciendo, pero no veo ninguna forma de hacerlo.
Es posible ?
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;
}
}
y el resultado:
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]
Con una versión actual de OkHttp, puede usar el
Interceptor de registro HTTP
y establecer el nivel en
BODY
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BODY);
Con esto no puede configurar de forma granular la salida para diferentes métodos HTTP, pero también funciona para otros métodos que pueden tener un cuerpo.
Aquí un ejemplo que muestra la salida de una solicitud
PATCH
(mínimamente redactada):
--> 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)
Como puede ver, esto también imprime los encabezados y, como dice la documentación, realmente debe tener cuidado:
Los registros generados por este interceptor cuando se usan los niveles
HEADERS
oBODY
tienen el potencial de filtrar información confidencial como encabezados de "Autorización" o "Cookie" y el contenido de los cuerpos de solicitud y respuesta. Estos datos solo deben registrarse de forma controlada o en un entorno que no sea de producción.Puede redactar encabezados que pueden contener información confidencial llamando a
redactHeader()
.
logging.redactHeader("Authorization"); logging.redactHeader("Cookie");
La respuesta de Nikola no funcionó para mí.
Mi suposición es que la implementación de
ByteString#toString()
cambió.
Esta solución funcionó para mí:
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 documentación de
readUtf8()
:
Elimina todos los bytes de esto, los decodifica como UTF-8 y devuelve la cadena.
que debe ser lo que quieras
Traté de comentar la respuesta correcta de @msung, pero mi reputación no es lo suficientemente alta.
Aquí está la modificación que hice para imprimir RequestBody antes de hacer una solicitud completa. Funciona a las mil maravillas. Gracias
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";
}
}
Versión que maneja solicitudes con o sin cuerpo:
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 "";
}
EDITAR
Como veo que todavía hay algunas personas interesadas en esta publicación, aquí está la versión final (hasta la próxima mejora) de mi interceptor de registros. Espero que les ahorre tiempo a algunos de ustedes.
Tenga en cuenta que este código está utilizando
OkHttp 2.2.0
(y
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;
}
}