A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 大山哥哥 于 2018-4-27 22:46 编辑

        上次我们讨论了JavaEE开发中的响应乱码和文件下载时文件名乱码的原因和解决方案。今天我们继续讨论乱码的问题。
        首先是请求的乱码问题,这个问题出现在Tomcat8以前的版本(不包括Tomcat8)。我们还是分情况来讨论,众所周知,我们现在使用的HTTP协议中的请求常用主流的方式有两种,一种是GET;另一种是POST。我们就分别以GET和POST为例来说一下中文参数乱码的问题。
        如果是POST方式请求,请求的参数会在HTTP协议的请求体中携带过来,而表单中的数据默认会以application/x-www-form-urlencoded的格式传输。而这种格式是用类似UrlEncoder.encode()的方式以UTF-8编码的。这样携带的参数会以流的方式直接到达服务器中放入request对象内部的缓冲区中,以二进制的方式存储,可以理解为一个byte数组来存储的0101的二进制数据。而调用request.getParameter()时会把缓冲区的数据拿出来用Url的格式构造成一个字符串,而构造时使用的默认编码就是request的默认编码,而request又是由Tomcat创建的,所以和Tomcat的默认编码一致,也就是ISO-8859-1。所以中文字符串直接乱码了。
        如下图所示:
                                
        而解决的方式就显而易见了,由于request的默认编码是ISO-8859-1才导致这个问题,所以只要把默认编码改掉就行了。而request中正好有这个API。就是request.setCharacterEncoding("UTF-8")。所以直接一句话就能解决request的POST乱码了。
        接下来是request的GET方式的请求。GET方式请求略微复杂一些,我们用画图的方式分析。如下图:
        
        由于GET请求的参数是从URL上拼接,在地址栏上传输的。也就是在HTTP协议的请求行上传输的,所以在这要提一下HTTP协议的规则。HTTP协议中的请求行上是不允许出现中文字符的,所以浏览器对GET请求传递的中文参数做了默认处理,也就是把中文字符转换成了非中文字符。那么它是怎么转换的呢?很简单,还是使用的URLEncoder.encode()方法。用这个方法可以把中文以指定的编码(浏览器默认为UTF-8)转成一串类似"%A3%B5%6F%D3"这样格式的数据,而这个数据虽然表示的还是中文字符,但是显示出来的格式就像是加密了一样成为了全英文的字符。所以可以直接在请求行上传输了。而到达服务器之后,这个字符串会存储到request对象的内部。当我们调用request.getParameter()方法的时候,request会把这个URL格式的字符串再解码回中文字符串。然而由于浏览器上用的是UTF-8的编码转码的,所以需要用UTF-8的方式解码才可以。而在request对象的内部,默认解码的编码是ISO-8859-1。所以虽然"%A3%B5%6F%D3"正确的传输过来了,也在服务器端接收到了,也就是说数据是对的,只不过格式错了。类似于一个txt的文件,非要把后缀名改为jpg然后用图片查看器查看,这样肯定是看到一片乱码。而我们得到的字符串就是这个原因才是乱码。不过字符串虽然是乱码,但是对应的二进制数据是对的,所以我们只需要把这个字符串再还原为二进制数据再重新编码就行了。所以可以调用String的getBytes方法,传参为ISO-8859-1,用这个码重新把字符串还原为二进制的byte数据。然后再用String 的构造器new String(byte[] ,"UTF-8")重新指定UTF-8的编码构造字符串即可。总体来说,GET的乱码解决方式就是String name = new String(req.getParameter("name").getBytes("ISO-8859-1"),"UTF-8");一句话搞定。写起来简单,但是内部的原理却有些绕,所以大家要慢慢的整理思路。
        最后给大家介绍一下cookie中存储中文的问题。cookie中默认是不能存储中文的,原因和上面一样,因为cookie 是用response的响应头设置回浏览器存储的,而响应头中不支持中文字符,所以不能保存cookie。解决方式就是我们手动的编码,把cookie中的中文字符串转码为非中文字符,也就是运用URLEncoder和URLDecoder两个类的编码和解码方法处理。代码如下:
[AppleScript] 纯文本查看 复制代码
Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                        for (Cookie cookie : cookies) {
                                if ("name".equals(cookie.getName())) {
                                        //%E4%B8%AD%E6%96%87
                                        String value = cookie.getValue();
                                        System.out.println("已经存在的cookie的value值:" + value);
                                        System.out.println("解码后的字符串:" + URLDecoder.decode(value, "UTF-8"));
                                }
                        }
                }

                String value = "中文";
                //Cookie cookie = new Cookie("name", value);
                String encode = URLEncoder.encode(value, "UTF-8");
                System.out.println("编码后的字符串:" + encode);
                Cookie cookie = new Cookie("name", encode);
                response.addCookie(cookie);


        好的,本期乱码处理讲解到这里,希望能给大家带来一点帮助。

5 个回复

倒序浏览
写的太详细了,豁然开朗
回复 使用道具 举报
还看不懂,以后看
回复 使用道具 举报

写的太详细了,豁然开朗,666
回复 使用道具 举报
学习一下!!!
回复 使用道具 举报
贤哥威武!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马