我有一个Android应用程序,它给了我这个例外:
org.apache.http.MalformedChunkCodingException: CRLF expected at end of chunk
此方法抛出异常:(目的是将从服务器收到的响应写出到文件中。)
public static void getResponseBodyForServerData(
final HttpEntity entity) throws IOException, ParseException {
if (entity == null) {
throw new IllegalArgumentException("HTTP entity may not be null");
}
InputStream instream = entity.getContent();
if (instream == null) {
return;
}
File file = new File(Environment.getExternalStorageDirectory() +
"/foo/Response.txt");
if (!file.exists()) {
file.createNewFile();
}
OutputStream out = new FileOutputStream(file);
byte buf[] = new byte[1024];
int len;
while ((len = instream.read(buf)) > 0)
out.write(buf, 0, len);
out.flush();
out.close();
}
然后我将上面的代码修改为:
public static void getResponseBodyForServerData(
final HttpEntity entity) throws IOException, ParseException {
if (entity == null) {
throw new IllegalArgumentException("HTTP entity may not be null");
}
InputStream instream = entity.getContent();
InputStreamReader inputStreamReader = new InputStreamReader(
instream, "UNICODE") ;
if (instream == null) {
return;
}
File file = new File(Environment.getExternalStorageDirectory() +
"/foo/Response.txt");
if (!file.exists()) {
file.createNewFile();
}
BufferedReader bufferedReader = new BufferedReader(inputStreamReader) ;
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(file),"UNICODE")) ;
String singleLine = null ;
while((singleLine = bufferedReader.readLine()) != null) {
bufferedWriter.write(singleLine) ;
}
bufferedWriter.flush() ;
bufferedWriter.close() ;
}
然后代码工作,导致错误的原因是什么导致原始代码有什么问题?
答案 0 :(得分:1)
当我搜索MalformedChunkCodingException时,我看到问题相当陈旧,但它出现了。所以这里有一些提示会发生什么。
我只能猜出你的问题是什么,因为你没有告诉我们发生了哪一行的异常以及你使用的org.apache.http.HttpEntity版本。
首先MalformedChunkCodingException: CRLF expected at end of chunk
确实是问题所在。
当您拥有chunked http transfer并且该转移中至少缺少一个\r\n
时,就会发生这种情况。
有两种可能的错误。首先,服务器不发送它们或客户端丢失它们。
检查服务器是否正常检查请求响应是否正常。例如,您可以使用curl以十六进制查看响应:
curl -ivs --raw http://host:port/somePath/toResource --trace /dev/stdout
以下是一些示例输出:
00a0: 30 31 22 7d 5d 0d 0a 30 0d 0a 0d 0a 01"}]..0....
在输出中看\r\n
为0d 0a
?
这意味着服务器实际上发送了正确的消息。
所以你在读取响应时可能会丢失一些字节。
我使用了调试器并为MalformedChunkCodingException(Eclipse中的Java异常断点)设置了断点。我查看了第一次处理传入响应的堆栈,实际上缓冲区中只有一半的响应。
分块消息是流式消息。所以可能是在InputStream读取完整消息之前关闭套接字。 例如,这发生在jersey apache connector。
他们有这个代码:
return new FilterInputStream(inputStream) {
@Override
public void close() throws IOException {
response.close();
super.close();
}
失败了:
JulijanasJezov于2016年10月18日
此更改不适用于org.apache.httpcomponents: httpclient:4.5.1+使用分块传输编码时。这是 因为他们改变了他们关闭连接的方式。
在这种情况下,当调用response.close()时,连接将被关闭 并清除输入流的缓冲区,然后执行super.close()函数 无法关闭ChunkedInputStream并导致结果 org.apache.http.ConnectionClosedException:块的过早结束 编码消息正文:关闭预期的块。
发生异常的原因是在结束时 ChunkedInputStream,close()函数读取其余部分 chunked消息,它失败,因为流的缓冲区已经 在response.close()调用中关闭连接时清除。 参考: https://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/ChunkedInputStream.html#close()
解决此问题的方法是先放置super.close()代码行 response.close()。这允许关闭流 在其缓冲区被清除之前正确。
所以当我发现在我们的项目中我们在maven pom中使用jersey-apache-connector(旧)和http-client(新)的不兼容版本时,我的问题就解决了。 (Depenency Hierachy说:httpclient:4.5.3 (managed from 4.5) (ommitted for conflict with 4.5.3)
)