【问题标题】:Why does volley's response string use an encoding different from that in the response headers?为什么 volley 的响应字符串使用的编码与响应标头中的编码不同?
【发布时间】:2013-10-09 09:10:26
【问题描述】:

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

【问题讨论】:

    标签: android character-encoding android-volley


    【解决方案1】:

    这两种请求类型都调用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));
            }
        }
    }
    

    【讨论】:

    • 伙计,你救了我的命!非常感谢!
    • 这是一个老问题,但如果它在今天有帮助,您可以将两种解决方案合二为一。 String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers, "UTF-8"));这样,如果不存在,您可以设置默认字符集。
    【解决方案2】:

    首先非常感谢@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);
        }
    

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

    【讨论】:

      【解决方案3】:

      覆盖Request&lt;T&gt; 类的方法parseNetworkResponse。
      你可以这样做:

      /**
       * A canned request for retrieving the response body at a given URL as a String.
       */
      public class StringRequest extends Request<String> {
          private final Listener<String> mListener;
      
      
          /**
           * the parse charset.
           */
          private String charset = null;
      
          /**
           * Creates a new request with the given method.
           *
           * @param method the request {@link Method} to use
           * @param url URL to fetch the string at
           * @param listener Listener to receive the String response
           * @param errorListener Error listener, or null to ignore errors
           */
          public StringRequest(int method, String url, Listener<String> listener,
                  ErrorListener errorListener) {
              super(method, url, errorListener);
              mListener = listener;
          }
      
          /**
           * Creates a new GET request.
           *
           * @param url URL to fetch the string at
           * @param listener Listener to receive the String response
           * @param errorListener Error listener, or null to ignore errors
           */
          public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
              this(Method.GET, url, listener, errorListener);
          }
      
          /**
           * Creates a new GET request with the given Charset.
           *
           * @param url URL to fetch the string at
           * @param listener Listener to receive the String response
           * @param errorListener Error listener, or null to ignore errors
           */
          public StringRequest(String url, String charset, Listener<String> listener, ErrorListener errorListener) {
              this(Method.GET, url, listener, errorListener);
              this.charset = charset;
          }
      
          @Override
          protected void deliverResponse(String response) {
              mListener.onResponse(response);
          }
      
          @Override
          protected Response<String> parseNetworkResponse(NetworkResponse response) {
              String parsed;
              try {
                  if(charset != null) {
                      parsed = new String(response.data, charset);
                  } else {
                      parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                  }
              } catch (UnsupportedEncodingException e) {
                  parsed = new String(response.data);
              }
              return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
          }
      
          /**
           * @return the Parse Charset Encoding
           */
          public String getCharset() {
              return charset;
          }
      
          /**
           * set the Parse Charset Encoding
           * @param charset
           */
          public void setCharset(String charset) {
              this.charset = charset;
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        将方法从 GET 更改为 POST 以支持 UTF-8

        JsonObjectRequest jsonReq = new JsonObjectRequest(Method.POST,
                    URL_FEED, null, new Response.Listener<JSONObject>() {
                        @Override
                        public void onResponse(JSONObject response) {
                            VolleyLog.d(TAG, "Response: " + response.toString());
                            Log.d("SHY", "Response: " + response.toString());
                            if (response != null) {
                                parseJsonFeed(response);
                            }
                        }
                    }, new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            VolleyLog.d(TAG, "Error: " + error.getMessage());
                        }
                    });
        

        。 . . .

        【讨论】:

          【解决方案5】:

          谢谢@Simon Heinen。根据你的回复,我写了一个函数。

          private void addEncodeing2Request(NetworkResponse response) {
              try {
                  String type = response.headers.get(HTTP.CONTENT_TYPE);
                  if (type == null) {
                      //Content-Type:
                      Log.d("RVA", "content type was null");
                      type = TYPE_UTF8_CHARSET;
                      response.headers.put(HTTP.CONTENT_TYPE, type);
                  } else if (!type.contains("charset")) {
                      //Content-Type: text/plain;
                      Log.d("RVA", "charset was null, added encode utf-8");
                      type += ";" + TYPE_UTF8_CHARSET;
                      response.headers.put(HTTP.CONTENT_TYPE, type);
                  } else {
                      //nice! Content-Type: text/plain; charset=utf-8'
                      Log.d("RVA", "charset is " + type);
                  }
          
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          

          用法:

          protected Response<String> parseNetworkResponse(NetworkResponse response) {
                    addEncodeing2Request(response);
                    return super.parseNetworkResponse(response);
                }
          

          此外,覆盖 getParamsEncoding() 也可以工作。

          protected String getParamsEncoding() {
                      return "utf-8";
                  }
          

          【讨论】:

            猜你喜欢
            • 2015-10-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-06-26
            • 1970-01-01
            • 2019-08-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多