2009-09-17 39 views
28

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

下面是暴露问题的测试用例:

// 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); 
    } 
} 

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

请注意,这不会发生任何网址 - 只是具体的网址,如上面的一个。

另外,如果我切换到使用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); 
    } 
} 

我发现references什么似乎是一个类似的问题在其他地方,但至今没有解决方案。如果他们真的是同一个问题,那么问题可能不是路标,因为其他参考文献没有提及它。

任何想法?

回答

28

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

http.keepAlive=false 

我看到了类似的问题,当服务器响应不是由URLConnection的和客户机/服务器可以理解得到了同步的。

如果这样可以解决您的问题,您必须获取HTTP跟踪以确切了解响应的特殊性。

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

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

如果您的第一个响应不是200,我确实在您的代码中看到了问题。使用OAuth,错误响应(401)实际上会返回数据,其中包括ProblemAdvice,Signature Base String等,以帮助您进行调试。您需要从错误流中读取所有内容。否则,它会混淆下一个连接,这是-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; 
     } 
    } 
} 
+4

有趣。在测试用例的开头添加'System.setProperty(“http.keepAlive”,“false”)'完全解决了这个问题。 有关如何执行http跟踪的任何建议?我是否需要使用日志记录代理,或者我可以直接在客户端上做些什么? – emmby 2009-09-17 22:10:59

+0

查看我的编辑.............. – 2009-09-17 23:25:57

+1

确认它是一个android bug,我们在这里跟踪它: http://code.google.com/p/android/issues/详细信息?id = 7786 – 2010-05-13 21:03:00

0

在读完响应之前,您能否验证连接没有关闭?也许HttpClient马上解析响应代码,并保存它以备将来查询,但是一旦连接关闭,HttpURLConnection可能会返回-1。

10

我遇到了同样的问题时,我并没有从InputStream中的所有数据将其关闭,并打开第二连接前仔细阅读。它也被固定为System.setProperty("http.keepAlive", "false");或者只是循环直到我读完了其余的InputStream。

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

5

谷歌提供了一个优雅的解决办法,因为这只是之前的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

+0

完美的工作。对我来说,这个事情发生在使用Stripe的api 4.1.1上。 – 2016-01-29 11:37:56

2

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

conn.setRequestProperty("Connection", "close"); 
相关问题