Android Volley中的http状态码,当error.networkResponse为null时

我在Android平台上使用Google Volley。 我有一个onErrorResponseerror参数返回一个空的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.networkResponseonErrorResponse是非空的?

或者,如何确保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(); } 

我手动处理这个问题:

  1. 从github下载Volley库并添加到AndroidStudio项目中

  2. 转到com.android.volley.toolbox.HurlStack

  3. 查找setConnectionParametersForRequest(connection, request);performRequest方法里面

  4. 最后添加setConnectionParametersForRequest(connection, request);这段代码setConnectionParametersForRequest(connection, request); 行:

 // for avoiding this exception : No authentication challenges found try { connection.getResponseCode(); } catch (IOException e) { e.printStackTrace(); }