Java HttpURLConnection.getResponseCode() 在第二次调用时返回 -1
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1440957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HttpURLConnection.getResponseCode() returns -1 on second invocation
提问by emmby
I seem to be running into a peculiar problem on Android 1.5 when a library I'm using (signpost 1.1-SNAPSHOT), makes two consecutive connections to a remote server. The second connection always fails with a HttpURLConnection.getResponseCode()
of -1
当我使用的库(路标 1.1-SNAPSHOT)连续两次连接到远程服务器时,我似乎在 Android 1.5 上遇到了一个奇怪的问题。第二个连接始终失败了HttpURLConnection.getResponseCode()
的-1
Here's a testcase that exposes the problem:
这是一个暴露问题的测试用例:
// 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);
}
}
Basically, if I sign the request and then consume the entire input stream, the next request will fail with a resultcode of -1. The failure doesn't seem to happen if I just read one character from the input stream.
基本上,如果我签署请求然后使用整个输入流,下一个请求将失败,结果码为 -1。如果我只是从输入流中读取一个字符,则似乎不会发生故障。
Note that this doesn't happen for any url -- just specific urls such as the one above.
请注意,这不会发生在任何 url 上——只是特定的 url,例如上面的那个。
Also, if I switch to using HttpClient instead of HttpURLConnection, everything works fine:
此外,如果我切换到使用 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);
}
}
I've found referencesto what seems to be a similar problem elsewhere, but so far no solutions. If they're truly the same problem, then the problem probably isn't with signpost since the other references make no reference to it.
我在其他地方找到了对类似问题的引用,但到目前为止还没有解决方案。如果它们确实是相同的问题,那么问题可能不在于路标,因为其他参考文献没有提及它。
Any ideas?
有任何想法吗?
采纳答案by ZZ Coder
Try set this property to see if it helps,
尝试设置此属性以查看是否有帮助,
http.keepAlive=false
I saw similar problems when server response is not understood by UrlConnection and client/server gets out of sync.
当 UrlConnection 不理解服务器响应并且客户端/服务器不同步时,我看到了类似的问题。
If this solves your problem, you have to get a HTTP trace to see exactly what's special about the response.
如果这解决了您的问题,您必须获得 HTTP 跟踪以准确查看响应的特殊之处。
EDIT: This change just confirms my suspicion. It doesn't solve your problem. It just hides the symptom.
编辑:此更改仅证实了我的怀疑。它不能解决你的问题。它只是隐藏了症状。
If the response from first request is 200, we need a trace. I normally use Ethereal/Wireshark to get the TCP trace.
如果第一个请求的响应是 200,我们需要跟踪。我通常使用 Ethereal/Wireshark 来获取 TCP 跟踪。
If your first response is not 200, I do see a problem in your code. With OAuth, the error response (401) actually returns data, which includes ProblemAdvice, Signature Base String etc to help you debug. You need to read everything from error stream. Otherwise, it's going to confuse next connection and that's the cause of -1. Following example shows you how to handle errors correctly,
如果您的第一个响应不是 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;
}
}
}
回答by esac
Can you verify that the connection is not getting closed before you finish reading the response? Maybe HttpClient parses the response code right away, and saves it for future queries, however HttpURLConnection could be returning -1 once the connection is closed?
在阅读完响应之前,您能否验证连接没有关闭?也许 HttpClient 会立即解析响应代码,并将其保存以备将来查询,但是一旦连接关闭,HttpURLConnection 可能会返回 -1?
回答by kwogger
I've encountered the same problem when I did not read in all the data from the InputStream before closing it and opening a second connection. It was also fixed either with System.setProperty("http.keepAlive", "false");
or simply just looping until I've read the rest of the InputStream.
当我在关闭 InputStream 并打开第二个连接之前没有从 InputStream 读取所有数据时,我遇到了同样的问题。它也被修复或者System.setProperty("http.keepAlive", "false");
只是循环,直到我阅读了 InputStream 的其余部分。
Not completely related to your issue, but hope this helps anyone else with a similar problem.
与您的问题不完全相关,但希望这可以帮助其他有类似问题的人。
回答by Murphy
Google provided an elegant workaround since it's only happening prior to Froyo:
Google 提供了一个优雅的解决方法,因为它只发生在 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");
}
}
Cf. http://android-developers.blogspot.ca/2011/09/androids-http-clients.html
参见 http://android-developers.blogspot.ca/2011/09/androids-http-clients.html
回答by Yar
Or, you can set HTTP header in the connection (HttpUrlConnection):
或者,您可以在连接中设置 HTTP 标头 (HttpUrlConnection):
conn.setRequestProperty("Connection", "close");