Android Volley中的http状态码,当error.networkResponse为null时
我在Android平台上使用Google Volley。 我有一个onErrorResponse的error参数返回一个空的onErrorResponse的问题对于我使用的RESTful API,我需要确定通常以401(SC_UNAUTHORIZED)或500(SC_INTERNAL_SERVER_ERROR)到达的Http状态码,而我偶尔可以通过以下方式查看 
 final int httpStatusCode = error.networkResponse.statusCode; if(networkResponse == HttpStatus.SC_UNAUTHORIZED) { // Http status code 401: Unauthorized. } 
 这将抛出一个NullPointerException因为networkResponse为null。 
 我如何确定函数onErrorResponse的http状态码? 
 或者,如何确保error.networkResponse在onErrorResponse是非空的? 
或者,如何确保error.networkResponse在onErrorResponse中是非空的?
我首先想到的是检查对象是否为空。
 @Override public void onErrorResponse(VolleyError error) { NetworkResponse networkResponse = error.networkResponse; if (networkResponse != null && networkResponse.statusCode == HttpStatus.SC_UNAUTHORIZED) { // HTTP Status Code: 401 Unauthorized } } 
 或者,您也可以尝试通过扩展Request类和覆盖parseNetworkResponse获取状态码。 
 例如,如果扩展了抽象的Request<T>类 
 public class GsonRequest<T> extends Request<T> { ... private int mStatusCode; public int getStatusCode() { return mStatusCode; } ... @Override protected Response<T> parseNetworkResponse(NetworkResponse response) { mStatusCode = response.statusCode; try { Log.d(TAG, "[raw json]: " + (new String(response.data))); Gson gson = new Gson(); String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(gson.fromJson(json, mClazz), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } } ... } 
 或者,如果您正在使用已经扩展了抽象Request<T>类的工具箱类之一,并且不想混淆parseNetworkResponse(NetworkResponse networkResponse) ,请继续覆盖该方法,但通过super.parseNetworkResponse(networkResponse)返回super的实现super.parseNetworkResponse(networkResponse) 
 例如StringResponse 
 public class MyStringRequest extends StringRequest { private int mStatusCode; public MyStringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, listener, errorListener); } public int getStatusCode() { return mStatusCode; } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { mStatusCode = response.statusCode; return super.parseNetworkResponse(response); } } 
用法:
 public class myClazz extends FragmentActivity { private Request mMyRequest; ... public void makeNetworkCall() { mMyRequest = new MyNetworkRequest( Method.GET, BASE_URL + Endpoint.USER, new Listener<String>() { @Override public void onResponse(String response) { // Success } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (mMyRequest.getStatusCode() == 401) { // HTTP Status Code: 401 Unauthorized } } }); MyVolley.getRequestQueue().add(request); } 
当然,也可以select重写内联方法
 public class MyClazz extends FragmentActivity { private int mStatusCode; ... public void makeNetworkCall() { StringRequest request = new StringRequest( Method.GET, BASE_URL + Endpoint.USER, new Listener<String>() { @Override public void onResponse(String response) { // Success } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (mStatusCode == 401) { // HTTP Status Code: 401 Unauthorized } } }) { @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { mStatusCode = response.statusCode; return super.parseNetworkResponse(response); } }; MyVolley.getRequestQueue.add(request); } 
  更新: 
  HttpStatus被弃用。 改用HttpURLConnection 。 请参阅链接 。 
401不受Volley支持
 事实certificate,不可能保证error.networkResponse不为null,因为Volley中的一个错误引发NoConnectionError (134)中的Http状态代码401( NoConnectionError的exceptionNoConnectionError而不修改Google Volley代码。在设置networkResponse的值之前。 
变通
 在这种情况下,我们的解决scheme不是修复Volley代码,而是修改Web服务API,为特定的案例发送Http Error Code 403( HttpStatus.SC_FORBIDDEN )。 
 对于此Http状态代码,在Volleyerror handling程序中, error.networkResponse的值是非空的: public void onErrorResponse(VolleyError error) 。 而且, error.networkResponse.httpStatusCode正确返回error.networkResponse.httpStatusCode 。 
其他-build议
  Rperryng提出的扩展Request<T>类的build议可能提供了一个解决scheme,并且是一个创造性和优秀的想法。 非常感谢你的详细的例子。 我发现我们的案例的最佳解决scheme是使用解决方法,因为我们有幸能够控制Web服务API。 
如果我无法在服务器上进行简单的更改,我可能会select将Volley代码修复到BasicNetwork.java中的一个位置。
Volley支持HTTP 401未经授权的响应。 但是这个响应必须包含“WWW-Authenticate”头域。
 如果没有这个头文件,401响应会导致"com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found"错误。 
有关更多详细信息: https : //stackoverflow.com/a/25556453/860189
如果您使用第三方API并且无权更改响应头,则可能会考虑实施您自己的HttpStack,因为HurlStack引发了此exception。 或者更好,使用OkHttpStack作为HttpStack。
 如果设备没有networking连接,则error.networkResponse将为null (您可以通过启用飞行模式来certificate这一点)。 查看Volley库中相应的代码片段 。 
 如果错误是NoConnectionError的实例,则必须先检查NoConnectionError 。 我不能同意,Volley不支持401错误,我testing了它,并得到了一个带有401状态码的非空networkResponse对象。 看看这里的相应代码。 
networking响应可以通过以下格式接收
 NetworkResponse response = error.networkResponse; if(response != null && response.data != null){ switch(response.statusCode){ case 403: json = new String(response.data); json = trimMessage(json, "error"); if(json != null) displayMessage(json); break; } } 
这是我如何检查和grep错误。
  // TimeoutError => most likely server is down or network is down. Log.e(TAG, "TimeoutError: " + (e instanceof TimeoutError)); Log.e(TAG, "NoConnectionError: " + (e instanceof NoConnectionError)); /*if(error.getCause() instanceof UnknownHostException || error.getCause() instanceof EOFException ) { errorMsg = resources.getString(R.string.net_error_connect_network); } else { if(error.getCause().toString().contains("Network is unreachable")) { errorMsg = resources.getString(R.string.net_error_no_network); } else { errorMsg = resources.getString(R.string.net_error_connect_network); } }*/ Log.e(TAG, "NetworkError: " + (e instanceof NetworkError)); Log.e(TAG, "AuthFailureError: " + (e instanceof AuthFailureError)); Log.e(TAG, "ServerError: " + (e instanceof ServerError)); //error.networkResponse.statusCode // inform dev Log.e(TAG, "ParseError: " + (e instanceof ParseError)); //error.getCause() instanceof JsonSyntaxException Log.e(TAG, "NullPointerException: " + (e.getCause() instanceof NullPointerException)); if (e.networkResponse != null) { // 401 => login again Log.e(TAG, String.valueOf(e.networkResponse.statusCode)); if (e.networkResponse.data != null) { // most likely JSONString Log.e(TAG, new String(e.networkResponse.data, StandardCharsets.UTF_8)); Toast.makeText(getApplicationContext(), new String(e.networkResponse.data, StandardCharsets.UTF_8), Toast.LENGTH_LONG).show(); } } else if (e.getMessage() == null) { Log.e(TAG, "e.getMessage"); Log.e(TAG, "" + e.getMessage()); if (e.getMessage() != null && e.getMessage() != "") Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show(); else Toast.makeText(getApplicationContext(), "could not reach server", Toast.LENGTH_LONG).show(); } else if (e.getCause() != null) { Log.e(TAG, "e.getCause"); Log.e(TAG, "" + e.getCause().getMessage()); if (e.getCause().getMessage() != null && e.getCause().getMessage() != "") Toast.makeText(getApplicationContext(), e.getCause().getMessage(), Toast.LENGTH_LONG).show(); else Toast.makeText(getApplicationContext(), "could not reach server", Toast.LENGTH_LONG).show(); } 
我手动处理这个问题:
- 
从github下载Volley库并添加到AndroidStudio项目中 
- 
转到 com.android.volley.toolbox.HurlStack类
- 
查找 setConnectionParametersForRequest(connection, request);在performRequest方法里面
- 
最后添加 setConnectionParametersForRequest(connection, request);这段代码setConnectionParametersForRequest(connection, request);行:
// for avoiding this exception : No authentication challenges found try { connection.getResponseCode(); } catch (IOException e) { e.printStackTrace(); }