为什么volley的响应字符串使用的编码与响应头中的编码不同?

mji*_*son 18 android character-encoding android-volley

当使用OkHttp堆栈执行一个排球请求(StringRequest或者JsonObjectRequest)时,响应字符串的编码设置为ISO-8995-1,这是默认编码.响应有一个标题:content-type=text/html; charset=utf-8,应该被检测到.为什么不呢?

mji*_*son 34

这两种请求类型HttpHeaderParser.parseCharset都可以调用,它可以从头文件中确定字符集.但是,它要求标题Content-Type不是content-type:它区分大小写.(如果使用默认的HurlStack,我不确定行为,这可能是与OkHttp堆栈的实现细节差异.)

解决方案1:复制原始请求类型,但手动覆盖字符集

解决方案2:复制原始请求类型,但强制存在预期的标头

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Sim*_*mon 12

首先,非常感谢@mjibson在这里发布的2个解决方案,我遇到了类似的问题,在我的情况下,内容类型总是丢失,所以做了以下事情:

    protected static final String TYPE_UTF8_CHARSET = "charset=UTF-8";

    @Override
    protected Response<String> parseNetworkResponse(
            NetworkResponse response) {
        try {
            String type = response.headers.get(HTTP.CONTENT_TYPE);
            if (type == null) {
                Log.d(LOG_TAG, "content type was null");
                type = TYPE_UTF8_CHARSET;
                response.headers.put(HTTP.CONTENT_TYPE, type);
            } else if (!type.contains("UTF-8")) {
                Log.d(LOG_TAG, "content type had UTF-8 missing");
                type += ";" + TYPE_UTF8_CHARSET;
                response.headers.put(HTTP.CONTENT_TYPE, type);
            }
        } catch (Exception e) {
            //print stacktrace e.g.
        }
        return super.parseNetworkResponse(response);
    }
Run Code Online (Sandbox Code Playgroud)

我只想分享这个让其他人遇到类似的问题.在https://android.googlesource.com/platform/frameworks/volley/+/master/src/com/android/volley/toolbox/HttpHeaderParser.java中阅读parseCharset方法也很重要,以了解其工作原理