近日在写一个简单的HTTP代码中遇到了诡异的EOFException,当读取ResponseCode的时候就抛出了EOF异常,感觉很诡异,下面进行问题还原,以及分析和解决过程.
有问题的代码如下:
private void testEcho() {
String payload = "The quick brown fox jumps over the lazy dog.";
try {
HttpURLConnection conn = null;
BufferedReader br = null;
try {
String ep = Base64.encodeToString(payload.getBytes(), Base64.URL_SAFE);
URL u = new URL("http://httpbin.org/get?p=" + ep + "&key=testEcho");
conn = (HttpURLConnection) u.openConnection();
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setDoOutput(false);
conn.connect();
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.e(TAG, "http res " + conn.getResponseCode() + ", msg : " + conn.getResponseMessage());
return;
}
br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String buf = null;
while ((buf = br.readLine()) != null) {
Log.e(TAG, "HTTP res: " + buf);
}
} finally {
if (br != null) {
br.close();
}
if (conn != null) {
conn.disconnect();
}
}
} catch (IOException e) {
Log.e(TAG, "ioexception ", e);
}
}
这段代码进行后会在getResponseCode()这行抛出EOFException:
很疑惑,百思不得解,这是一个简单的GET请求,却抛出了这样难以理解的异常.于是去Google,发现都认为是Android本身的问题,要加上connection close
1
|
|
比如,这个讨论,以及这个讨论. 尝试了,但仍没有解决掉抛出的EOFException.
这个时候就要冷静的分析下,先从根本开始,怀疑一切,把请求的每一句都打印出来,突然发现URL竟然含有一个CRLF换行符(\r\n). 感觉奇怪,于是查阅文档,发现Base64在编码的时候会默认给结果加上CRLF以换行,于是再加一个Flag, NO_WRAP后,问题解决:
1
|
|
问题是解决了,但感觉没有完全弄明白.于是做了多次尝试,发现只要URL中部含有换行(\n或\r\n)都会引发此问题,而在尾部则没事.
这是请求包
这是Server回应
通过抓包可以看出,换行符会导致发送的HTTP请求包不完整,Server返回也认为HTTP是trunk的,所以期待更多的数据,因此这个时候是没有response的,任何对response的读操作(getResponseCode(), getResponseMessage(), getInputStream())都会立即抛出EOFException.
虽然这个问题不大,但是也还值得总结一下:
遇到问题先检查没犯低级错误
也就是说,当遇到诡异的问题时,先查看文档,检查参数,确保是否是在按正确的方式在做事情,这很关键,因为很多时候都是我们犯了低级错误,比如拼写错误,或者没传正确的参数,或者解错了API等.因为越是简单的错误越容易被忽略.
问Google和其他人
Google一下或者问下身边的人,可能会很有帮助
找Plan B
不用认死理儿,一条路不通,可走另外的路,或者搭个桥什么的.