HttpURLConnection.getResponseCode()在第二次调用时返回-1

当我使用一个库(路标1.1-SNAPSHOT)时,我似乎遇到了Android 1.5上的一个特殊问题,它连续连接到远程服务器。 第二个连接始终以-1HttpURLConnection.getResponseCode()失败

这是一个暴露这个问题的testing用例:

 // BROKEN public void testDefaultOAuthConsumerAndroidBug() throws Exception { for (int i = 0; i < 2; ++i) { final HttpURLConnection c = (HttpURLConnection) new URL("https://api.tripit.com/oauth/request_token").openConnection(); final DefaultOAuthConsumer consumer = new DefaultOAuthConsumer(api_key, api_secret, SignatureMethod.HMAC_SHA1); consumer.sign(c); // This line... final InputStream is = c.getInputStream(); while( is.read() >= 0 ) ; // ... in combination with this line causes responseCode -1 for i==1 when using api.tripit.com but not mail.google.com assertTrue(c.getResponseCode() > 0); } } 

基本上,如果我签名请求,然后消耗整个inputstream,下一个请求将失败,结果码为-1。 如果我只是从inputstream中读取一个字符,失败似乎不会发生。

请注意,这不会发生任何url – 只是特定的url,如上面的一个。

另外,如果我切换到使用HttpClient而不是HttpURLConnection,一切工作正常:

 // WORKS public void testCommonsHttpOAuthConsumerAndroidBug() throws Exception { for (int i = 0; i < 2; ++i) { final HttpGet c = new HttpGet("https://api.tripit.com/oauth/request_token"); final CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(api_key, api_secret, SignatureMethod.HMAC_SHA1); consumer.sign(c); final HttpResponse response = new DefaultHttpClient().execute(c); final InputStream is = response.getEntity().getContent(); while( is.read() >= 0 ) ; assertTrue( response.getStatusLine().getStatusCode() == 200); } } 

我发现在其他地方似乎是类似的问题的参考 ,但到目前为止还没有解决scheme。 如果他们真的是同样的问题,那么问题可能不是路标,因为其他参考没有提及它。

有任何想法吗?

尝试设置此属性,看看是否有帮助,

 http.keepAlive=false 

当UrlConnection无法理解服务器响应,并且客户机/服务器不同步时,我看到类似的问题。

如果这解决了你的问题,你必须得到一个HTTP跟踪,以确切地看到什么是响应。

编辑:这个改变只是证实了我的怀疑。 它不能解决你的问题。 它只是隐藏症状。

如果第一个请求的响应是200,我们需要一个跟踪。 我通常使用Ethereal / Wireshark获取TCP跟踪。

如果你的第一个响应不是200,我的确看到你的代码有问题了。 使用OAuth,错误响应(401)实际上会返回数据,其中包括ProblemAdvice,Signature Base String等,以帮助您进行debugging。 您需要从错误stream中读取所有内容。 否则,它会混淆下一个连接,这是-1的原因。 以下示例显示如何正确处理错误,

 public static String get(String url) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); URLConnection conn=null; byte[] buf = new byte[4096]; try { URL a = new URL(url); conn = a.openConnection(); InputStream is = conn.getInputStream(); int ret = 0; while ((ret = is.read(buf)) > 0) { os.write(buf, 0, ret); } // close the inputstream is.close(); return new String(os.toByteArray()); } catch (IOException e) { try { int respCode = ((HttpURLConnection)conn).getResponseCode(); InputStream es = ((HttpURLConnection)conn).getErrorStream(); int ret = 0; // read the response body while ((ret = es.read(buf)) > 0) { os.write(buf, 0, ret); } // close the errorstream es.close(); return "Error response " + respCode + ": " + new String(os.toByteArray()); } catch(IOException ex) { throw ex; } } } 

在closures它并打开第二个连接之前,我没有从InputStream中读取所有数据时遇到同样的问题。 它也被固定与System.setProperty("http.keepAlive", "false"); 或者只是循环,直到我读了其余的InputStream。

不完全与您的问题有关,但希望这可以帮助其他类似问题的人。

谷歌提供了一个优雅的解决方法,因为它只发生在Froyo之前:

 private void disableConnectionReuseIfNecessary() { // HTTP connection reuse which was buggy pre-froyo if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { System.setProperty("http.keepAlive", "false"); } } 

参看 http://android-developers.blogspot.ca/2011/09/androids-http-clients.html

或者,您可以在连接(HttpUrlConnection)中设置HTTP标头:

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

在阅读完回复之前,您能否确认连接没有closures? 也许HttpClient立即parsing响应代码,并将其保存为将来的查询,但是,一旦连接closures,HttpURLConnection可能会返回-1?

Interesting Posts