Android Volley library not working with 204 and empty body response
Asked Answered
K

2

5

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.

Kbp answered 10/12, 2014 at 3:21 Comment(4)
entityToBytes appears to return a 0-length byte[] when there is no contentAim
Sorry this is late, but I had the same issue and the real problem was in my implementation of the HttpStack. I am using a newer library of Apache and converting between the new and told objects if getEntity() was null I was returning a blank entity. You issue may be similar.Burnham
Look in your performRequest method of your implementation of HttpStack if it's response getEntity returns null then volley should work fine as it is. If like me you are converting between old and new apache libraries or doing other processing, you may be adding an empty entity.Burnham
204 because the function in web service return "void", IMO, you don't need to process the response data.Arron
H
7

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.

Harveyharvie answered 2/4, 2015 at 7:14 Comment(0)
I
3

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));
    }
}
Ilo answered 30/9, 2015 at 22:34 Comment(1)
I spent 3 day about this issue, you solved my problem! I love you broOvervalue

© 2022 - 2024 — McMap. All rights reserved.