getResponseCode 抛异常了 没有返回码 ? 为啥
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了getResponseCode 抛异常了 没有返回码 ? 为啥相关的知识,希望对你有一定的参考价值。
android开发中,我们经常会使用HttpURLConnection类来发出网络请求,请求发出后,一般都会使用getResponseCode()来获取服务器返回的HTTP状态码,以便判断请求是否成功,诸如200、500、404之类的状态码使用getResponseCode()来获取是没有问题的,但是如果状态码是401,同时你使用的又是4.1.x/4.2.x/4.3.x的安卓系统的话,那么getResponseCode()可能会抛出IOException异常:Java.io.IOException: No authentication challenges found
之所以会出现这个问题,是因为服务器在返回401的时候,没有同时在header中设置“WWW-Authenticate”响应头,这个响应头的作用是告诉客户端,服务器需要哪种类型的认证(Basic或者Digest),通常这个响应头对客户端来说没什么作用,但是标准就是这么规定的。如果服务器没返回这个响应头,那么客户端在解析的时候就会找不到这个header而导致抛出异常。
解决这个问题的方法有两种:
1)从服务器入手,在返回信息的时候,服务器设置一个假的“WWW-Authenticate”响应头,比如:WWW-Authenticate: Basic realm="fake",或者遇到未授权的请求时,直接返回403,而不是返回401;
2)从客户端入手,修改代码,在获取响应码的时候捕捉异常:
[java] view plain copy
HttpURLConnection connection = ...;
try
connection.getResponseCode();
catch (IOException e)
int responsecode = connection.getResponseCode();
如果getResponseCode()抛出IOException,那么在捕获异常后,再次获取响应码,这时候就可以正常获取到了,so,就是这么简单。 参考技术A ogcat显示的异常信息您没有发出来,所以我只能猜测是请求没有放在单独线程而是放在主线程了。解决方法,吧http的请求单独放在一个新线程中,或者加一个这个方法本回答被提问者采纳 参考技术B 设置超时时间长一点,服务器还没有响应回数据
conn.setReadTimeout(15000);//设置连接主机超时(单位:毫秒)
conn.setConnectTimeout(15000);//设置从主机读取数据超时(单位:毫秒)
HttpURLConnection.getResponseCode() 在第二次调用时返回 -1
【中文标题】HttpURLConnection.getResponseCode() 在第二次调用时返回 -1【英文标题】:HttpURLConnection.getResponseCode() returns -1 on second invocation 【发布时间】:2010-11-29 06:48:09 【问题描述】:当我使用的库 (signpost 1.1-SNAPSHOT) 与远程服务器建立两个连续连接时,我似乎在 Android 1.5 上遇到了一个特殊问题。第二个连接总是以HttpURLConnection.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。如果我只从输入流中读取一个字符,似乎不会发生故障。
请注意,任何 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);
我发现references 在其他地方似乎是类似的问题,但到目前为止还没有解决方案。如果它们确实是同一个问题,那么问题可能不在于路标,因为其他参考文献没有提及它。
有什么想法吗?
【问题讨论】:
【参考方案1】:您能否在阅读完响应之前验证连接没有关闭?也许 HttpClient 会立即解析响应代码,并将其保存以供将来查询,但是一旦连接关闭,HttpURLConnection 可能会返回 -1?
【讨论】:
【参考方案2】:尝试设置此属性,看看是否有帮助,
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;
【讨论】:
有趣。在测试用例开头添加System.setProperty("http.keepAlive", "false")
完全解决了问题。有关如何进行 http 跟踪的任何建议?我是否需要使用日志代理,或者我可以直接在客户端上做些什么?
确认这是一个安卓漏洞,我们正在这里追踪它:code.google.com/p/android/issues/detail?id=7786
谢谢。这让我们在最后一天发疯了。
顺便说一句,设置“连接:关闭”标题不起作用 - 它 必须 是 System.setProperty("http.keepAlive", "false") 作为 emmby上面指定。【参考方案3】:
我在关闭 InputStream 并打开第二个连接之前没有从 InputStream 中读取所有数据时遇到了同样的问题。也可以使用System.setProperty("http.keepAlive", "false");
修复它,或者只是循环,直到我读完 InputStream 的其余部分。
与您的问题不完全相关,但希望这可以帮助其他有类似问题的人。
【讨论】:
【参考方案4】: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");
参照。 http://android-developers.blogspot.ca/2011/09/androids-http-clients.html
【讨论】:
完美工作。对我来说,这件事发生在 api 4.1.1 中使用 Stripe。【参考方案5】:或者,您可以在连接中设置HTTP头(HttpUrlConnection):
conn.setRequestProperty("Connection", "close");
【讨论】:
以上是关于getResponseCode 抛异常了 没有返回码 ? 为啥的主要内容,如果未能解决你的问题,请参考以下文章
为啥 ConnectException:连接被拒绝:从 HttpURLConnection.getResponseCode() 抛出连接? [复制]
Android之通过HttpURLConnection.getResponseCode状态码抛出异常的问题以及解决方法
为啥,如果 `$q.all` 没有返回一个 promise 数组,那么不会抛出异常?