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(); }