深入分析java Web技术内幕 - 编码(3)

2019-08-26  本文已影响0人  attentionYSF
为什么要编码?

计算机存储信息的最小单位是1byte,即8bit,所能表示的字符个数为255个,但是人类要表示的符号太多,远远不止255个,西欧字符、中文等等符号。

解决这个问题,就必须要有一个新的数据结构,在java中就是char,从char到byte必须编码(可以理解为翻译)

常见编码格式(字典)
  1. ASCⅡ
    由于计算机最早是由美国发明的,根据他们的语言习惯,用1个字节可以表示128个字符,可以通过键盘输入并且能够显示出来
  2. ISO-8859-1
    应用最广泛的编码格式,占用2个字节可以表示256个字符,涵盖大部分的西欧语言字符。
  3. 中文编码
    • GB2312
      包含682个字符和6763个汉字
    • GBK
      总共有23940个码位,能表示21003个汉字,兼容GB2312
    • GB18030
      国家标准,兼容GB2312,但是应用不广泛
  4. Unicode
    统一编码,是计算机科学领域里的一项业界标准,包括字符集、编码方案。
  5. UTF-16
    用两个字节,将Unicode字符转换为字节存储。Java以UTF-16作为内存的字符存储格式
  6. UTF-8
    变长,1-6个字节
Java中的编码场景

磁盘I/O 和 网络I/O

磁盘I/O
 //字符转字节
    @Test
    public void charToByteByDiskIo() {
        String path = CodeProgram.class.getResource("").getPath();
        File file = new File(path, "字符转字节流,通过字符写入磁盘文件.txt");
        FileOutputStream fos = null;
        OutputStreamWriter osw = null;
        try {
            fos = new FileOutputStream(file);
            osw = new OutputStreamWriter(fos, "utf-8");
            osw.write("我爱中国,我爱香港!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(null != osw) {
                    osw.close();
                }
                if(null != fos) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
//字节转字符:打印当前java类的内容到控制台(如果eclipse中的workspace文件编码未改为utf-8或者测试方法所属的java类的文件编码没有改为utf-8,则会乱码)
@Test
    public void byteToCharByDiskIo() {
        File directory = new File("./src");
        File file = new File(directory, "CodeProgram.java");
        FileInputStream fis = null;
        InputStreamReader isr = null;
        try {
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis, "utf-8");
            StringBuffer sb = new StringBuffer();
            char[] cbuf = new char[1024];
            int length = 0;
            while((length = isr.read(cbuf)) != -1) {
                sb.append(cbuf, 0, length);
            }
            System.out.println(sb.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(null != isr) {
                    isr.close();
                }
                if(null != fis) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
网络I/O
  1. URL的编解码
  2. HTTP Header的编解码
  3. POST表单的编解码
  4. HTTP Body的编解码
  5. 外部引入JS文件
  6. JS的URL编码及服务端解码
  7. 其他需要编码的地方
    以Tomcat服务器为例讲解
  1. URL的编解码
    Get请求,URL的pathinfo(路径)和Query String(参数)的编码字符集不同,浏览器将URL中非ASCⅡ码字符按某种字符集转换为16进制到字符加上%。
    tomcat设置URI解码字符集为UTF-8:<Connector URIEncoding="UTF-8" />
    tomcat设置Query String解码字符集为UTF-8:<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true" />
  2. HTTP Header的编解码

    默认为ISO-8859-1,且不提供编码设置到方法,只能用URLEncoder编码,服务端request.getHeader时,再相应到用URLEncoder解码

  3. POST表单的编解码

    手动指定编码格式, request.setCharacterEncoding(charset),post表单提交到数据就是以指定到编码格式编码,再调用request.getParameter(),会自动用设定到编码去解码。
    一定要在调用request.getParameter()方法前调用request.setCharacterEncoding(charset),否则tomcat在解析前会检测HTTP Header中到contentType,一般请求时,这个值是null,根据tomcat源码,为空时,按默认到到字符集ISO-8859-1来编码,导致乱码

  4. HTTP Body的编解码

    请求资源成功获取后,这些内容将通过response返回给客户端浏览器。通过response.setCharacterEncoding(charset)设置编解码字符集,通过response Header的contentType返回给客户端,浏览器根据contentType解码,如果不存在,则根据html <meta/>中到charset来解码,如果都不存在,则用默认到ISO-8859-1解码

  5. 外部引入JS文件

    如果在一个单独到js脚本中包含中文输出,需指定字符集<script src="" charset="gbk" />
    如果被一个页面引入到js脚本,则与外部页面到编码方式一致,若js文件本身到编码格式与外部页面编码格式不一致,则会乱码

  6. JS的URL编码及服务端解码
    • encodeURI()
    • encodeURIComponent()

    除了特殊字符加英文字母不编码加%外,其余到都编码;后者到特殊字符范围缩小,特别是&符号不包含在内,&符号也要编码。所以后者常用来对一个URL传递一个参数值为URL的URL进行编码。后台对应到解码JAVA类为URLDecoder。前端JS两次编码,后端request.getParameter()自动解一次码,URLDecoder.decoder手动解一次码。两次编解码避免了前后端第一次编解码不一致的问题。

  7. 其他需要编码的地方
    • 数据库连接JDBC URL传递characterEncoding=gbk,与数据库内置编码格式要一直
    • XML
    • JSP
上一篇 下一篇

猜你喜欢

热点阅读