当响应代码为304和200时,Volley出现异常错误。

8

在使用Volley库时,我注意到当进行POST JsonObjectRequest请求时,如果服务器返回304或者200状态码,但响应结果中没有数据(response.data),Volley会将其解释为错误响应而不是成功。

我通过在JsonObjectRequest.java中的方法Response<JSONObject> parseNetworkResponse(NetworkResponse response)加入了几行代码来解决这个问题。

@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
    try {
        if (!response.notModified) {// Added for 304 response
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            return Response.success(new JSONObject(jsonString),
                    HttpHeaderParser.parseCacheHeaders(response));
        } else // Added for 304 response
            return Response.success(new JSONObject(),HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
        Log.v("Volley", "UnsupportedEncodingException " + response.statusCode);
        if (response.statusCode == 200)// Added for 200 response
            return Response.success(new JSONObject(), HttpHeaderParser.parseCacheHeaders(response));
        else
            return Response.error(new ParseError(e));
    } catch (JSONException je) {
        Log.v("Volley", "JSONException " + response.statusCode);
        if (response.statusCode == 200)// Added for 200 response
            return Response.success(new JSONObject(),HttpHeaderParser.parseCacheHeaders(response));
        else
            return Response.error(new ParseError(je));
    }
}

这是解决问题的最佳方案吗?

谢谢!

编辑

检查BasicNetwork.java类,我发现Volley通过询问httpResponse.getEntity() != null来检查响应是否没有数据。

// Some responses such as 204s do not have content. We must check.
    if (httpResponse.getEntity() != null) {
        responseContents = entityToBytes(httpResponse.getEntity());         
    } else {// Add 0 byte response as a way of honestly representing a
    // no-content request.
        responseContents = new byte[0];
    }

但问题仍然是在Volley尝试使用response.data == new byte[0]创建新字符串时出现的JSONException,此处需要在parseNetworkResponse方法中处理。

1个回答

6

米格尔- 如果是成功响应,这个方法只会被调用一次,对吗?

对于所有状态码<200或状态码>200,Volley会调用parseNetworkError(VolleyError volleyError)方法,而不是parseNetworkResponse(NetworkResponse response)方法。在这里看 -

https://android.googlesource.com/platform/frameworks/volley/+/master/src/com/android/volley/toolbox/BasicNetwork.java

行号 -118-120

  if (statusCode < 200 || statusCode > 299) {
                throw new IOException();
   }

以及相应的捕获块 行号-128-151

catch (IOException e) {
            int statusCode = 0;
            NetworkResponse networkResponse = null;
            if (httpResponse != null) {
                statusCode = httpResponse.getStatusLine().getStatusCode();
            } else {
                throw new NoConnectionError(e);
            }
            VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
            if (responseContents != null) {
                networkResponse = new NetworkResponse(statusCode, responseContents,
                        responseHeaders, false);
                if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
                        statusCode == HttpStatus.SC_FORBIDDEN) {
                    attemptRetryOnException("auth",
                            request, new AuthFailureError(networkResponse));
                } else {
                    // TODO: Only throw ServerError for 5xx status codes.
                    throw new ServerError(networkResponse);
                }
            } else {
                throw new NetworkError(networkResponse);
            }
        }

如果你想覆盖这种行为,可以在BasicNetwork.java->performRequest方法中添加特定于状态码的实现。
编辑: 所以不是因为状态码,而是因为空响应。我认为你正在正确地实现自定义请求类。 Volley带有一些预定义的流行请求类型,以方便使用,但你始终可以创建自己的请求类型。 与基于状态码的实现相比,我更愿意在反序列化之前检查以下字符串是否为空-
String jsonString = new String(response.data,
                HttpHeaderParser.parseCharset(response.headers));
if (!jsonString .isEmpty()) {
                 return Response.success(new JSONObject(jsonString),
                HttpHeaderParser.parseCacheHeaders(response));
}
else {
return Response.success(new JSONObject(),
                    HttpHeaderParser.parseCacheHeaders(response));
}

**我没有测试过这个,但你明白我的意思 :)


问题在于当代码200或代码304(未修改)没有返回数据时,我编辑了帖子。 - Miguel
你使用的是哪个版本的Volley?主分支https://android.googlesource.com/platform/frameworks/volley/+/master/src/com/android/volley/toolbox/BasicNetwork.java中没有任何会在响应中没有数据时引发错误的内容。相反,他们在这种情况下添加了一个0字节的响应。行号为106-112。 - Gaurav
当您尝试从0字节对象创建的字符串中创建JSONObject时,它会抛出一个JSONException。 - Miguel
是的,问题不在于状态码,而在于空响应。那么为什么要基于状态码实现,而不是空响应呢? - Gaurav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接