zoukankan      html  css  js  c++  java
  • 第三章 深入分析Java Web中的中文编码问题

    3.1 几种常见的编码格式

      3.1.1 为什么要编码

      一个字节 byte只能表示0~255个符号,要表示更多的字符,需要编码。

      3.1.2 如何翻译

      ASCII码:有128个,用一个字节的低7位表示。

      ISO-8859-1,能表示256个,是单字节编码。

      GB2312: 双字节编码,

      GBK:是对GB2312的扩展,加入更多汉字,和GB2312兼容,BG2312编码的汉字可以用GBK来解码,不会乱码。

      GB18030:

              

            UTF-16:Unicode(统一码),ISO创建的全新的超语言字典。Unicode是JAVA和XML基础。 注意: Unicode是编码,也就是码和汉字(或其他国家语言)的对应关系。但是具体如何把这些编码存储,则要采取不同的编码方式,比如UTF-16和UTF-8。UTF-16就用固定两个字节表示一个UNicode编码。因为是固定两个字节的长度,所以操作起来很简单,这也是JAVA以UTF-16作为字符的内存存储格式的原因。

            UTF-8: UTF的缺点是浪费,因为很多字符用一个字节就够了,用不上两个字节。

            UTF-8的编码规则:  如果一个字节最高位为0,XXX

                如果一个字节以11开头,XXX

                    如果一个字节以10开头,XXX   

    3.2 在JAVA中需要编码的场景

         什么场合需要编码

      3.2.1 在I/O操作中存在的编码

        在字符到字节或从字节到字符的转换,而这种转换的场景主要是I/O.  I/O包括磁盘和网络两种I/O.

        Reader类是在JAVA IO读字符的父类,而inputstream类是读字节的父类,InputStreamReader类就是关联字节到字符的桥梁,字节到字符的转换,而对具体字节到字符的编码实现,它又委托StreamDecoder去做,解码过程中必须制定Charset,如果没有制定,则将使用本地环境中的默认字符集,如在中文环境中使用GBK。     

    package ioTest;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.io.UnsupportedEncodingException;
    
    public class decodeTest {
    
        public static void main(String[] args) {
            String file = "XXX.txt";
            String charset = "UTF-8";
            try {
                FileOutputStream outputStream = new FileOutputStream(file);
                try {
                    OutputStreamWriter  writer = new OutputStreamWriter(outputStream, charset);
                    try {
                        writer.write("要保存的中文字符");
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            finally{
                writer.close();
            }
        }
    }

      3.2.2 在内存操作中编码

    字节和字符转换:

    String s = "lfdasjlfjasljfasfa";
    byte[] b = s.getBytes("UTF-8");               
    String n = new String(b, "UTF-8");

    byte[] 和 char[]之间编码和解码:

    String string = "fsdfsd";
    Charset chars = Charset.forName("UTF-9");
    ByteBuffer byteBuffer = chars.encode(string);
    CharBuffer charBuffer = chars.decode(byteBuffer);    

    3.3 在JAVA中如何编码

      3.3.1 按照ISO-8859-1编码

      3.3.2 按照GB2312编码

      3.3.3 按照GBK编码

      3.3.4 按照UTF-16编码

      3.3.5 按照UTF-8编码

      3.3.6 编码UTF-8编码代码片段

      3.3.7 几种编码格式的比较

      GBK是对GB2312扩展,可以表示所有的汉字。

           UTF-8比UTF-16更适合网络传输

    3.4 在JAVA web中编解码

    http请求过程中,存在编码的地方是:

                  前段发过啦来的URL, cookie,  Parameters。

        服务器接收到HTTP请求后,要解析HTTP,其中URL,cookie和POST表单参数需要解码。

        服务器可能读网络和本地的文件和DB,可能存在编码问题。

        当servlet处理完所有请求后,需要将这些数据再编码,发送给浏览器。

       3.4.1 URL的编解码

        URL可能存在中文,所以需要编码。

        浏览器编码URL是将非ASCII字符按照某种编码格式编码成16进制数字后将每个16进制表示的字符前加上%。

        浏览器可以设置编码格式。

        Tomcat是如何解码的?

                     ’URL的URI部分进行解码的字符集是在<Connector URIEncodeing="UTF-8">里设置的。

            QueryString的解析过程:GET方式HTTP请求的querystring和POST方式HTTP请求的表单参数都是作为parameters保存的,都通过request.getParameter();

                                          queryString的解码字符集是在哪定义的呢? 是在HTTP的header的contentType或者是默认的ISO-8859-1,如果要用HTTP的header中

                     中定义的编码需要设置<Connector URIEncoding="UTF-8"      useBodyEncodingForURI='true'>

        

      3.4.2 HTTP Header的编解码

      除了上面的URL外,还可能在header中传递其他参数,如cookie,redirectPath等。这些用户设置的值也可能存在编码问题。

           对Header的解码是在调用request.getHeader()时进行的。默认是按照ISO-8859-1,如果header中有非ASCII,会乱码。

           如果要用header传递中文,可以传之前编码,然后解码:

        1、客户端
        method.addRequestHeader("hello",URLEncoder.encode("中文","UTF-8"));
        2、服务器
        value=URLDecoder.decode(value);

      3.4.3 POST表单的编解码

        POST表单提交的参数的解码是在第一次调用request.getParameter时发生的,与queryString不同,是通过HTTP的body传递的,当提交表单的时候,根据ContentType的charset编码格式对表单中填入的参数编码,然后提交到服务器,在服务器端也用contentType来解码。这个编码、解码的字符集使我们自己设置的。

                  注意一定要在第一次调request.getParameter方法之前就设置request.setCharacterEncoding(charset), 否则会乱码。

      3.4.4 HTTP BODY的编解码

                 response.setCharacterEcoding可以设置编码方式,覆盖request.getCharacterEncoding的值,并且通过contentType返回给客户端。浏览器根据content-Type解码;如果么有这个值,按照HTML中的charset来解码。

                 和JDBC的编码方式要一致。

    3.5 在JS中的编码问题

      3.5.1 外部引入JS文件

              如何js文件本身的编码和JS中使用的字符编码不一致,可能就有乱码。比如*.js文件是UTF-8,而页面是GBK,就会有乱码问题。

      3.5.2 JS的URL编码

      Ajax的http_request('get', url, ture)调用,URL在IE下用OS的默认编码,在Firefox下是UTF-8编码。

      JS有三个函数是和编码解码相关的。

            JAVA是如何来解码的?JAVA端处理URL编码、解码有连个类:   分别是Java.net.URLEncoder和java.net.URLDecoder

      3.5.3 其他需要编码的地方

    3.6 常见问题分析

      3.6.1 中文变成了看不懂的字符

        解码和编码用的字符集不一样,就会出现乱码。

      3.6.2 一个汉字变成一个问号

        ISO-8859-1遇到不认识的用3F表示,是问号。

      3.6.3 一个汉字变成两个问号

      3.6.4 一种不正常的正确编码

    3.7 一种繁简转换的实现方式

    3.8 总结

  • 相关阅读:
    Poj2104-K-th Number(主席树)
    Poj3237-Tree(树链剖分)
    Spoj QTREE(树链剖分)
    字符串算法
    网络流算法
    利用DiDiSoft OpenPGP Library for .NET 程序加密解密文件
    利用GPG4Win加密解密文件
    .NET Standard和.NET Framework的区别【转】
    Aras学习笔记 (6) Aras Client Side代码弹出标准ItemType内容窗口
    WebClient使用DownloadFile下载文件超时的解决办法
  • 原文地址:https://www.cnblogs.com/liufei1983/p/7384317.html
Copyright © 2011-2022 走看看