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
}
我正在使用 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
}