我正在使用一个拦截器,我想记录我正在制作的请求的正文,但我看不到这样做的任何方法。
有可能吗?
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]
答案 0 :(得分:108)
尼古拉的回答对我不起作用。我的猜测是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,并返回字符串。
应该是你想要的。
答案 1 :(得分:12)
我试图评论@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";
}
}
答案 2 :(得分:10)
编辑
因为我看到仍有一些人对这篇文章感兴趣,这里是我的日志拦截器的最终版本(直到下一次改进)。我希望它可以节省你们一些人的时间。
请注意,此代码使用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;
}
}
答案 3 :(得分:2)
处理有或没有正文的请求的版本:
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 "";
}
答案 4 :(得分:1)
科特林版本:
val buf = okio.Buffer()
requestBody.writeTo(buf)
Log.d("AppXMLPostReq", "reqBody = ${buf.readUtf8()}")
答案 5 :(得分:0)
使用OkHttp的当前版本,您可以使用HTTP Logging Interceptor并将级别设置为"onclick": function() {
chrome.tabs.query({
currentWindow: true,
active: true
}, function(tab) {
var parser = document.createElement('a');
parser.href = tab[0].url;
chrome.cookies.get({
"url": parser.origin,
"name": "tooken"
}, function(cookie) {
if (cookie && cookie.value) {
var newURL = "http://localhost?token=" + cookie.value;
chrome.tabs.update(tab[0].id, {
url: newURL
});
} else {
console.log("Not found", parser.origin);
}
});
});
BODY
使用此方法,您不能为不同的HTTP方法精细地配置输出,但它也适用于可能具有主体的其他方法。
以下示例显示了HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BODY);
请求的输出(已最小编辑):
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
级别时,此拦截器生成的日志有可能泄漏敏感信息,例如“授权”或“ Cookie”标头以及请求和响应主体的内容。只能以受控方式或在非生产环境中记录此数据。您可以通过调用
BODY
来删除可能包含敏感信息的标头。redactHeader()
答案 6 :(得分:0)
创建一个单独的新类并实现拦截器。
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
var logInfo = ""
val requestBody=loggerUtil.getRequestBody
return response
}
yourOkHttpClient.addInterceptor(yourInstance)
GetRequestBody
var requestContent = ""
val requestBody = request.body
val buffer = Buffer()
if (requestBody != null) {
requestBody.writeTo(buffer)
}
val contentType = requestBody?.contentType()
val charset: Charset =
contentType?.charset(StandardCharsets.UTF_8) ?:StandardCharsets.UTF_8
if (buffer.isProbablyUtf8()) {
requestContent = buffer.readString(charset)
}
扩展查找缓冲区数据是否为UT8格式
fun Buffer.isProbablyUtf8(): Boolean {
try {
val prefix = Buffer()
val byteCount = size.coerceAtMost(64)
copyTo(prefix, 0, byteCount)
for (i in 0 until 16) {
if (prefix.exhausted()) {
break
}
val codePoint = prefix.readUtf8CodePoint()
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
return false
}
}
return true
} catch (_: EOFException) {
return false // Truncated UTF-8 sequence.
}
}