Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/182.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android OkHttp如何记录请求正文_Android_Okhttp - Fatal编程技术网

Android OkHttp如何记录请求正文

Android OkHttp如何记录请求正文,android,okhttp,Android,Okhttp,我正在使用一个拦截器,我想记录我正在发出的请求的主体,但我看不到任何方法可以做到这一点 可能吗 public class LoggingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); long t1 = Syste

我正在使用一个拦截器,我想记录我正在发出的请求的主体,但我看不到任何方法可以做到这一点

可能吗

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] 
以88,7ms的速度发布[一些url]
ZoneName:touraine
资料来源:安卓

正文:reformation.client.OkClient$1@1df53f05尼古拉的回答对我不起作用。我猜
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,并返回字符串


这应该是你想要的。

我试图对@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";
        }
}
编辑

因为我看到仍然有一些人对这篇文章感兴趣,这里是我的日志拦截器的最终版本(直到下一次改进)。我希望这能节省你们一些人的时间

请注意,此代码正在使用
OkHttp 2.2.0
(和
改装1.9.0


处理带或不带正文的请求的版本:

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

对于OkHttp的当前版本,您可以使用并将级别设置为
BODY

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BODY);
使用这种方法,您无法为不同的HTTP方法粒度配置输出,但它也适用于可能有正文的其他方法

下面的示例显示了
补丁
请求的输出(最小编辑):

如您所见,这也会打印出标题,正如文档中所述,您应该特别注意:

此拦截器在使用
标题
正文
级别时生成的日志有可能泄漏敏感信息,如“授权”或“Cookie”标题以及请求和响应正文的内容。此数据只能以受控方式或在非生产环境中记录

您可以通过调用
redactHeader()
来编辑可能包含敏感信息的标题


创建一个单独的新类并实现拦截器

  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.
    }
}
Kotlin版本:

val buf = okio.Buffer()
requestBody.writeTo(buf)
Log.d("AppXMLPostReq", "reqBody = ${buf.readUtf8()}")

@MathieudBrito try
response.body().string()
@aga谢谢,但这不会复制响应正文,因此当我稍后尝试读取正文时(在拦截器之后),它会告诉我responsebody为null并且已经被读取。您使用哪个“缓冲区”来执行此操作
writeTo()
仅对java.nio.Buffer未实现的BufferedSink对象执行。@Graeme Use okio.Buffer^希望看到此类示例中提到的正确导入语句只返回一组随机字符串。不工作你有没有序列化过它?没有,我没有序列化过它…你能不能编辑你的答案,以精确的方式打印请求正文?很抱歉,我不记得它从内存打印了什么,我会在我处理那个项目时添加它。为什么我们需要创建副本?如果你能够将导入内容上传到顶部,这将是非常有帮助的,因为有多个版本的OKHttp,我正在玩猜测和检查,以找出您在这里有哪些版本。谢谢你完成了,希望有帮助;)是的,非常感谢您对Mathieu的澄清。如何仅从请求对象获取[{“op”:“add”,“path”:“/path”,“value”:true})?
            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)
            }
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.
    }
}
val buf = okio.Buffer()
requestBody.writeTo(buf)
Log.d("AppXMLPostReq", "reqBody = ${buf.readUtf8()}")