2009-09-17 41 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"); 
相關問題