编解码(编码解码)常识

字符编码


字符编码就是以二进制的数字来对应字符集的字符,常见字符编码方式有:ISO-8859-1(不支持中文),GB2312,GBK,UTF-8等.在JavaWeb中, 经常遇到的需要编码/解码的场景有响应编码/请求编码/URL编码:


响应编码


服务器发送数据给客户端由Response对象完成,如果响应数据是二进制流,就无需考虑编码问题.如果响应数据为字符流,那么就一定要考虑编码问题:


response.getWriter()默认使用ISO-889-1发送数据,而该字符集不支持中文,因此遇到中文就一定会乱码.


在需要发送中文时, 需要使用:


response.setCharacterEncoding("UTF-8");

// getWriter() ...


设置编码方式,由于在getWriter()输出前已经设置了UTF-8编码,因此输出字符均为UTF-8编码,但我们并未告诉客户端使用什么编码来读取响应数据,因此我们需要在响应头中设置编码信息(使用Content-Type):


response.setContentType("text/html;charset=UTF-8");

// getWriter() ...


注意: 这句代码不只在响应头中添加了编码信息,还相当于调用了一次response.setCharacterEncoding("UTF-8");


请求编码


1. 浏览器地址栏编码

在浏览器地址栏书写字符数据,由浏览器编码后发送给服务器,因此如果在地址栏输入中文,则其编码方式由浏览器决定:


浏览器编码
IE/FireFoxGB2312
ChromeUTF-8


2. 页面请求

如果通过页面的超链接/表单向服务器发送数据,那么其编码方式由当前页面的编码方式确定:


<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">


3. GET

当客户端发送GET请求时,无论客户端发送的数据编码方式为何,服务端均以ISO-8859-1解码(Tomcat8.x之后改用UTF-8),这就需要我们在request.getParameter()获取数据后再转换成正确的编码:


private Map<String, String> convertToParameterMap(HttpServletRequest request) throws UnsupportedEncodingException {

    Enumeration<String> names = request.getParameterNames();

    Map<String, String> parameters = new HashMap<String, String>();

    if (names != null) {

        while (names.hasMoreElements()) {

            String name = names.nextElement();

            String value = request.getParameter(name);

            parameters.put(name, new String(value.getBytes("ISO-8859-1"), "UTF-8"));

        }

    }

    return parameters;

}


4. POST

当客户端发送POST请求时,服务端也是默认使用iOS-8859-1解码,但POST的数据是通过请求体传送过来,因此POST请求可以通过request.setCharacterEncoding()来指定请求体编码方式:


private Map<String, String> convertToParameterMap(HttpServletRequest request) throws IOException {

    Map<String, String> parameters = new HashMap<String, String>();

    if (request.getMethod().equals("POST")) {

        request.setCharacterEncoding("UTF-8");

        Enumeration<String> names = request.getParameterNames();

        while (names.hasMoreElements()) {

            String key = names.nextElement();

            parameters.put(key, request.getParameter(key));

        }

    } else {

        Enumeration<String> names = request.getParameterNames();

        while (names.hasMoreElements()) {

            String key = names.nextElement();

            String value = request.getParameter(key);

            parameters.put(key, new String(value.getBytes("ISO-8859-1"), "UTF-8"));

        }

    }

 

    return parameters;

}


URL编码


网络标准RFC 1738规定:


“…Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”

“只有字母和数字[0-9a-zA-Z]、一些特殊符号"$-_.+!*'(),"[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。”


如果URL中有汉字,就必须编码后使用, 而URL编码过程其实很简单:


首先需要指定一种字符编码,把字符串解码后得到byte[],然后把小于0的字节+256,再将其转换成16进制,最后前面再添加一个%.


这个编码过程在Java中已经封装成了现成的库, 可直接使用:


URLEncoder描述
static String encode(String s, String enc)Translates a string into application/x-www-form-urlencoded format using a specific encoding scheme.
URLDecoder描述
static String decode(String s, String enc)Decodes a application/x-www-form-urlencoded string using a specific encoding scheme.

注: 在Web中Tomcat容器会自动识别URL是否已经编码并自动解码.





posted @ 2016-06-16 11:22    阅读(273)  评论(0编辑  收藏  举报