诡异的EOF Exception

近日在写一个简单的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:

诡异的EOF Exception_第1张图片

很疑惑,百思不得解,这是一个简单的GET请求,却抛出了这样难以理解的异常.于是去Google,发现都认为是Android本身的问题,要加上connection close

1
conn.setRequestProperty("Connection", "close");

比如,这个讨论,以及这个讨论. 尝试了,但仍没有解决掉抛出的EOFException.

分析与解决

这个时候就要冷静的分析下,先从根本开始,怀疑一切,把请求的每一句都打印出来,突然发现URL竟然含有一个CRLF换行符(\r\n). 感觉奇怪,于是查阅文档,发现Base64在编码的时候会默认给结果加上CRLF以换行,于是再加一个Flag, NO_WRAP后,问题解决:

1
 String ep = Base64.encodeToString(payload.getBytes(), Base64.URL_SAFE | Base64.NO_WRAP);

深入分析

问题是解决了,但感觉没有完全弄明白.于是做了多次尝试,发现只要URL中部含有换行(\n或\r\n)都会引发此问题,而在尾部则没事.

诡异的EOF Exception_第2张图片

这是请求包

诡异的EOF Exception_第3张图片

这是Server回应

通过抓包可以看出,换行符会导致发送的HTTP请求包不完整,Server返回也认为HTTP是trunk的,所以期待更多的数据,因此这个时候是没有response的,任何对response的读操作(getResponseCode(), getResponseMessage(), getInputStream())都会立即抛出EOFException.

总结

虽然这个问题不大,但是也还值得总结一下:

  1. 遇到问题先检查没犯低级错误

    也就是说,当遇到诡异的问题时,先查看文档,检查参数,确保是否是在按正确的方式在做事情,这很关键,因为很多时候都是我们犯了低级错误,比如拼写错误,或者没传正确的参数,或者解错了API等.因为越是简单的错误越容易被忽略.

  2. 问Google和其他人

    Google一下或者问下身边的人,可能会很有帮助

  3. 如果还搞不定,那就真的是遇到难题了,这个时候只能去查阅源码和书籍,定位出问题,分析原因,解不解得了,就看造化了.
  4. 找Plan B

    不用认死理儿,一条路不通,可走另外的路,或者搭个桥什么的.

你可能感兴趣的:(android)