mjibson mjibson - 5 months ago 90
Android Question

Why does volley's response string use an encoding different from that in the response headers?

When doing a volley request (either

StringRequest
or
JsonObjectRequest
), using the OkHttp stack, the response string's encoding is set to ISO-8995-1, which is the default encoding. The response has a header:
content-type=text/html; charset=utf-8
, which should be detected. Why isn't it?

Answer

Both of those request types call HttpHeaderParser.parseCharset, which is able to determine the charset from the headers. However, it requires that the header be Content-Type, not content-type: it is case sensitive. (I'm not sure of the behavior if using the default HurlStack, it's possible this is an implementation detail difference with the OkHttp stack.)

Solution 1: copy the original request type, but manually override the charset

Solution 2: copy the original request type, but force the expected header to exist

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonRequest;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;

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

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            // solution 1:
            String jsonString = new String(response.data, "UTF-8");
            // solution 2:
            response.headers.put(HTTP.CONTENT_TYPE,
                response.headers.get("content-type"));
            String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            //
            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));
        }
    }
}