Android Volley library not working with 204 and empty body response

3.3k views Asked by At

I'm using the latest Volley library and I'm having issues when my api is returning a 204 with no body in the response. It seems that the following code in BasicNetwork.java isn't working as expected:

// 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];
}

the result from getEntity is never null for me, but it is empty. I've made sure that my API is returning nothing by checking curl and postman (just to be extra sure i'm not going crazy). Has anyone else has such an issue?

For now I've just changed that if to:

if (statusCode != HttpStatus.SC_NO_CONTENT && httpResponse.getEntity() != null)

which I know isn't solving the root cause, but I want to make sure that I'm not missing anything obvious before diving deeper into this problem.

Thanks!

EDIT: Sorry, I forgot to mention that the actual problem was that a timeout exception occurs whilst in the method entityToBytes, which is strange since there is no body to retrieve.

Also, i'm not using an actual fully functioning webservice API, as it's not available yet. Instead i'm connecting to a mocked out webservice on apiary, but i don't see how apiary could be the problem.

2

There are 2 answers

0
CharlesA On

This is less an answer than an elaboration on your solution! First off, I use 204 responses from my API and had the exact same issue you had. I used your code in BasicNetwork.java to solve it - the line if (statusCode != HttpStatus.SC_NO_CONTENT && httpResponse.getEntity() != null)

What I also found was that if I use a standard JsonObjectRequest request then the Response.ErrorListener would be triggered because the body was null.

I created a new JsonObjectRequestWithNull which provides a success response in the event of a null or blank body. Code:

public class JsonObjectRequestWithNull extends JsonRequest<JSONObject> {

public JsonObjectRequestWithNull(int method, String url, JSONObject jsonRequest,
                         Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
    super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
            errorListener);
}

public JsonObjectRequestWithNull(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener,
                         Response.ErrorListener errorListener) {
    this(jsonRequest == null ? Request.Method.GET : Request.Method.POST, url, jsonRequest,
            listener, errorListener);
}

@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
    try {
        String jsonString = new String(response.data,
                HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
        //Allow null
        if (jsonString == null || jsonString.length() == 0) {
            return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
        }
        return Response.success(new JSONObject(jsonString),
                HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
        return Response.error(new ParseError(e));
    } catch (JSONException je) {
        return Response.error(new ParseError(je));
    }
}

}

The relevant bit is:

        //Allow null
        if (jsonString == null || jsonString.length() == 0) {
            return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
        }

Hope helpful to someone.

1
Chantell Osejo On

As long as you are using the standard Volley library without any custom HttpStack or modifications to it (gradle dependency: compile 'com.mcxiaoke.volley:library:1.0.15'), then the only change you'll need to include is in the parseNetworkResponse method in your Request class (this is assuming you're using Gson to convert to Json, this comes from a custom GsonRequest class I wrote).

@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
    try {
        final String json = new String(
                response.data, HttpHeaderParser.parseCharset(response.headers));

        if (TextUtils.isEmpty(json)) {
            return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
        }

        return Response.success(gson.fromJson(json, clazz), null);
    } catch (UnsupportedEncodingException e) {
        return Response.error(new ParseError(e));
    } catch (JsonSyntaxException e) {
        return Response.error(new ParseError(e));
    }
}