2013-10-09 7 views
17

При выполнении запроса волейбола (либо StringRequest, либо JsonObjectRequest), используя стек OkHttp, кодировка строки ответа устанавливается в ISO-8995-1, которая является кодировкой по умолчанию. Ответ имеет заголовок: content-type=text/html; charset=utf-8, который должен быть обнаружен. Почему не так?Почему строка ответа волейбола отличается от кодировки в заголовках ответа?

ответ

32

Оба этих типа запросов вызывают 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)); 
     } 
    } 
} 
+0

спасибо, что это помогло. –

+0

Человек, ты спасаешь мой день! Большое спасибо! – Roman

+0

Это старый вопрос, но если он помогает сегодня, вы можете смешивать оба решения в одном. String jsonString = new String (response.data, HttpHeaderParser.parseCharset (response.headers, «UTF-8»)); Таким образом, вы можете установить кодировку по умолчанию, если она не существует. – hmartinezd

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); 
    } 

Я просто хотел поделиться этим, чтобы другие столкнулись с подобной проблемой. его также важно прочитать метод parseCharset в https://android.googlesource.com/platform/frameworks/volley/+/master/src/com/android/volley/toolbox/HttpHeaderParser.java, чтобы выяснить, почему это работает

3

Переопределить метод parseNetworkResponse класса Request<T>.
Вы можете сделать так:

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

} 
3

Изменение метода с GET на POST для UTF-8 Suppport

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()); 
       } 
      }); 

. , , ,

0

Спасибо @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"; 
     } 
Смежные вопросы