Android 注释记录拦截器输入结束错误

Android Annotations Logging Interceptor end-of-input error

我正在使用 Android 注释向服务器发出请求。我根据这个

的答案创建了以下拦截器
public class LoggingInterceptor implements ClientHttpRequestInterceptor {

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    ClientHttpResponse response = execution.execute(request, body);

    //It works after removing these two lines
    String responseString = stringOf(response.getBody());
    Log.d("RESPONSE", responseString);

    return response;
}

public static String stringOf(InputStream inputStream) {
    inputStream.mark(Integer.MAX_VALUE);
    BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder strBuilder = new StringBuilder();
    String line;
    try {
        while ((line = r.readLine()) != null)
            strBuilder.append(line);
    } catch (IOException ignored) {}
    try {
        inputStream.reset();
    } catch (IOException ignored) {}
    return strBuilder.toString();
 }
}

但是,这会产生以下异常:org.springframework.http.converter.HttpMessageNotReadableException:无法读取 JSON:由于输入结束,没有要映射的内容

当我从拦截器中删除以下行时:

 String responseString = stringOf(response.getBody());
 Log.d("RESPONSE", responseString);

一切正常。

这是我的 RestClient 界面:

 @Rest(rootUrl= "http://107.206.158.62:1337/api/", converters={MappingJackson2HttpMessageConverter.class}, interceptors = { LoggingInterceptor.class })
 public interface IRestClient {

     @Post("users/register/")
     @Accept(MediaType.APPLICATION_JSON)
     User register(@Body User user);

}

用户模型:

public class User implements Serializable {

    String first_name;

    String last_name;

    String email;

    String password;

    public User(){}

    public User(String first_name, String last_name, String email, String password) {
       this.first_name = first_name;
       this.last_name = last_name;
       this.email = email;
       this.password = password;
    }

    //Getters and Setters
}

在我的 Activity

中调用 RestClient
@Click(R.id.bRegister)
@Background
void createAccount() {
    User u = restClient.register(new User("Test Fname", "Test Lname", "test@test.com", "testpass"));
    Log.d("User last name", u.getLast_name());
 }

服务器生成以下 json:

{"first_name":"Test Fname","last_name":"Test Lname","email":"test@test.com"}

我希望能够记录每个响应的正文,然后 return 响应对象。但似乎首先从响应中读取 InputStream 会导致一些问题。

 Log.d("RESPONSE", responseString);

正在生成正确的服务器响应,但是当 MappingJackson2HttpMessageConverter 启动时,我 运行 进入上述异常。

如有任何帮助,我们将不胜感激!新年快乐! :)

我认为这是因为当您阅读响应时,您使用了它然后它是空的。拦截器在内容解析之前起作用,所以你使用你的响应来记录它,然后解析器发现它是空的。

仅在阅读响应内容时记录响应并不是执行此操作的最佳方式。我不知道最好的技术,但我会保留评论响应日志记录,然后当我遇到问题时,我会在拦截方法中停止调试并通过监视面板记录请求,写类似

Log.d("RESPONSE", stringOf(response.getBody())) 

然后您可以将记录的数据读入Android 监控面板。 显然这个响应现在是空的,所以它不会被解析和处理,但是当你需要的时候你可以记录你的响应而不用重建你的项目

正如 firegloves 所说,问题是您在记录期间消耗了输入流。我通过将原始 ClientHttpResponse 对象包装到带有缓冲输入流的自定义对象中解决了这个问题,您可以在记录

后重置
@Throws(IOException::class)
fun intercept(request: HttpRequest, body: ByteArray, execution: ClientHttpRequestExecution): ClientHttpResponse {
    val response = BufferedClientHttpResponse(execution.execute(request, body))

    response.body.mark(0)
    val responseString = StreamUtils.copyToString(response.body, defaultCharset())
    Log.d("RESPONSE", responseString)
    response.body.reset()

    return response
}


class BufferedClientHttpResponse(val originalHttpResponse: ClientHttpResponse) : ClientHttpResponse {
    val bufferedBody: BufferedInputStream = originalHttpResponse.body.buffered()

    override fun getHeaders(): HttpHeaders = originalHttpResponse.headers
    override fun getStatusCode(): HttpStatus = originalHttpResponse.statusCode
    override fun getRawStatusCode(): Int = originalHttpResponse.rawStatusCode
    override fun close() = originalHttpResponse.close()
    override fun getStatusText() = originalHttpResponse.statusText
    override fun getBody(): InputStream = bufferedBody
}