近期在项目中使用Volley作为网络通信框架,却发现在传输中文时会出现乱码。先交代一下项目的软硬件的基础设施
线上:
Django+restful_framework+monogdb
APP:
Android + volley
在使用android端测试之前,我使用了chrome中的Postman这款插件进行了测试,发现,中文读取是正常的。说明服务器返回的是UTF-8字符编码的数据。
但是为什么在Android端会出现乱码的现象呢。
我在想是不是本地端的字符编码出了问题?
我就是用String类的转码功能,发现不起作用。
一筹莫展。
我去网上搜索了一下,大部分都是volley默认采用的是UTF8的字符编码格式。可是服务器返回来的UTF-8的字符串为什么就是显示乱码呢。
接着我就想到了查看volley的源代码。
我发现volley的整个框架的结构是这个样子的,首先Android端构造不同类型的request对象,总得来说有这几大类:
- JSONObjectRequest
- JSONArrayRequest
- StringRequest
它们都有一个共同的基类——Reuqest。所有继承Request的子类都必须覆盖以下两个方法: protected Response<T> parseNetworkResponse(NetworkResponse response);
protected void deliverResponse(T response);
第一个方法是用来解析服务器返回的原始数据。response对象包含了返回数据的body、headers等内容,需要在该方法中对返回数据进行解析。比如JSONObjectRequest就是使用response中的body字符串
构造一个JSONObject对象,传递给监听器的对象。这样的设计默认了消息的发送者必将知道服务器的返回是如何解析的这一潜规则。
接着,我就查看了一下JSONOBjectReuqest类中的parseNetworkResponse方法,看看它在将结果传递给监听器之前做了什么。
源代码如下:@Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { 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)); } }
我们看到了,JSONObjectRequest这个类在将数据返回给监听器之前,是对字符串进行了转码的。我们貌似接近了问题的本质。那就接着查看HttpHeaderParser.parseCacheHeaders(response),是怎么获取字符集的。我猜想里面肯定包含了默认的字符集的定义。
打开代码:/** * Returns the charset specified in the Content-Type of this header, * or the HTTP default (ISO-8859-1) if none can be found. */ public static String parseCharset(Map<String, String> headers) { String contentType = headers.get(HTTP.CONTENT_TYPE); if (contentType != null) { String[] params = contentType.split(";"); for (int i = 1; i < params.length; i++) { String[] pair = params[i].trim().split("="); if (pair.length == 2) { if (pair[0].equals("charset")) { return pair[1]; } } } } return HTTP.DEFAULT_CONTENT_CHARSET; }
看到了注释,一切都水落石出了,原来,如果在服务器的返回数据的header中没有指定字符集那么就会默认使用 ISO-8859-1 字符集。
ISO-8859-1的别名叫做Latin1。这个字符集支持部分是用于欧洲的语言,不支持中文~
很不能理解为什么将这个字符集作为默认的字符集。Volley这个框架可是要用在网络通信的环境中的。
吐槽也没有用,我们来看一下如何来解决中文乱码的问题。有以下几种解决方式:- 在服务器的返回的数据的header的中contentType加上charset=UTF-8的声明。
- 当你无法修改服务器程序的时候,可以定义一个新的子类。覆盖parseNetworkResponse这个方法,直接使用UTF-8对服务器的返回数据进行转码。
好的,写完了。
我们总结一下,从这个问题的解决中,我们能够获取以下的经验:
1.网上的信息不能够全信,要相信自己的判断。
2.看源代码很重要,一般通过源代码找问题解决的办法是最快的。比在网上漫无目的的搜索要来的高效。