URL的编解码

注意:这里所说的URL和URI是针对Servlet进行描述的,也就是request.getRequestURL()和request.getRequestURL()返回的URL和URI结果。
       解析请求的URL是在org.apache.coyote.HTTP11.InternalInputBuffer的parseRequestLine方法中进行的,这个方法把传过来的URL的byte[]设置到org.apache.coyote.Request的相应属性中。这里的URL仍然是byte格式,转成char是在org.apache.catalina.connector.CoyoteAdapter的converURI方法中完成的。
       对URL的URI部分进行解码的字符集是在connector的<Connector URIEncoding="UTF-8" />中定义的,如果没有定义,那么将以默认编码ISO-8859-1解析。所以有中文URL时最好把URIEncoding设置成UTF-8编码。
       下面介绍对QueryString(请求参数)的解析过程。以GET方式HTTP请求的QueryString与以POST方式HTTP请求的表单参数都是作为Parameters保存的,都通过request.getParameter获取参数值。对他们的解码是在request.getParameter方法第一次被调用时进行的。request.getParameter方法被调用时将会调用org.apache.catalina.connector.Request的parseParameters方法。这个方法将会对GET和POST方式传递的参数进行解码,但是他们的解码字符集有可能不一样。QueryString的解码字符集是在哪里定义的呢。他本身是通过HTTP的Header传到服务端的,并且也在URL中,但是否和URI的解码字符集一样呢。从前面浏览器对PathInfo(请求的具体的Servlet)和QueryString的编码采取不同的编码格式可以猜测到解码字符集肯定不会一致。的确是这样,QueryString的解码字符集要么是Header中ContentType定义的Charset,要么是默认的ISO-8859-1,要使用ContentType中定义的编码,就要将connector的<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true" />中的useBodyEncodingForURI设置为true。这个配置项的名字容易让人产生混淆,他并不是对整个URL都采用BodyEncoding进行解码,而仅仅是对QueryString使用BodyEncoding解码,对这一点还要特别注意。

       从上面的URL编码和解码过程来看 ,比较复杂,而且编码和解码并不是我们在应用程序中能完全控制的,所以在我们的应用程序中,应该尽量避免在URL中使用非ASCII字符,不然很可能会碰到乱码问题。当然在我们的服务器端最好设置<Connector/>的URIEncoding和useBodyEncodingForURI两个参数。

HTTP Header的编解码

当客户端发起一个HTTP请求时,除上面的URL外还可能会在Header中传递其他参数,如Cookie、redirectPath等,这些用户设置的值很可能也会存在编码问题,Tomcat对他们又是怎么解码的呢。
    对Header中的项进行解码也是在调用request.getHeader时进行的。如果请求的Header项没有解码则调用MessageBytes的toString方法,这个方法从byte到char的转化使用的默认编码也是ISO-8859-1,而我们也不能设置Header的其他解码格式,所以如果你设置的Header中有非ASCII字符,解码中肯定会有乱码。
    我们在添加Header时也是同样的道理,不要在Header中传递非ASCII字符,如果一定要传递,可以先将这些字符用org.apache.catalina.util.URLEncoder编码,再添加到Header中,这样在从浏览器到服务器的传递过程中就不会丢失信息了,我们要访问这些项时再按照相应的字符集解码即可。

POST表单的编解码

前面提到了POST表单提交的参数的解码是在第一次调用request.getParameter时发生的,POST表单的参数传递方式与QueryString不同,他是通过HTTP的BODY传递到服务端的。当我们在页面上单击提交按钮时浏览器首先将根据ContentType的Charset编码格式对在表单中填入的参数进行编码,然后提交到服务器端,在服务器端同样也是用ContentType中的字符集进行解码的。所以通过POST表单提交的参数一般不会出现问题,而且这个字符集编码是我们自己设置的,可以通过request.setCharacterEncoding(charset)来设置。
    注意,你一定要在第一次调用request.getParameter方法之前就设置request.setCharacterEncoding(charset),否则你的POST表单提交上来的数据也可能出现乱码。发现了一个奇怪的现象,就是Tomcat在解析Parameter参数集合之前会获取Header的content-type请求头,并且检查这个content-type中的charset值。在默认情况下浏览器在提交form表单时,提交的content-type是不会含有charset信息。
    所以如果没有设置request.setCharacterEncoding(charset),那么表单提交的数据将会按照系统的默认编码方式解析。
    另外,针对multipart/form-data类型的参数,也就是上传的文件编码,同样也使用ContentType定义的字符集编码。值得注意的地方是,上传文件是用字节流的方式传输到服务器的本地临时目录,这个过程并没有涉及字符编码,而真正编码是在文件内容添加到parameters中时,如果用这个不能编码,则将会使用默认编码ISO-8859-1来编码。

HTTP Body的编解码

当用户请求的资源已经成功获取后,这些内容将通过Response返回给客户端浏览器。这个过程要先经过编码,再到浏览器进行解码。编解码字符集可以通过response.setCharacterEncoding来设置,他将会覆盖request.getCharactorEncoding的值,并且通过Header的Content-Type返回客户端,浏览器接收到返回的Socket流时将通过Content-Type的charset来解码。如果返回的HTTP Header中Content-Type没有设置charset,那么浏览器将根据HTML的<meta HTTP-equiv="Content-Type" content="text/html; charset=GBK" />中的charset来解码。如果也没有定义,那么浏览器将使用默认的编码来解码。
    访问数据库都是通过客户端JDBC驱动来完成的,用JDBC来存取数据时要和数据内置编码保持一致,可以通过设置JDBC URL来指定,如MySQL:url="jdbc:mysql://localhost:3306/DB?useUnicode=true&characterEncoding=GBK"。

一次HTTP请求的编解码。相关推荐

  1. 关于Tomcat上请求的编解码问题

    最近翻阅<深入分析 Java Web 技术内幕>(作者:许令波),关于Tomcat上Web请求的编解码问题,少了一个小点,可能影响了部分读者的理解,我特意查证了一下,特总结如下: 1. 请 ...

  2. 视频编解码之理论概述 和即时通信

    前言 即时通讯应用中的实时音视频技术,几乎是IM开发中的最后一道高墙.原因在于:实时音视频技术 = 音视频处理技术 + 网络传输技术 的横向技术应用集合体,而公共互联网不是为了实时通信设计的.有关实时 ...

  3. HTTP测试、常用编解码转换工具

    2019独角兽企业重金招聘Python工程师标准>>> Web/HTTP开发常用工具 http://www.24zhutian.com/download/HttpDebuger.ex ...

  4. PHP中文URL编解码(urlencode()rawurlencode()

    PHP中文URL编解码(urlencode()rawurlencode() PHP中对于URL进行编码,可以使用 urlencode() 或者 rawurlencode(),二者的区别是前者把空格编码 ...

  5. Netty实战 IM即时通讯系统(八)服务端和客户端通信协议编解码

    Netty实战 IM即时通讯系统(八)服务端和客户端通信协议编解码 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向通信 数 ...

  6. 从编解码、传输到基础架构 详解Bigo多媒体技术栈

    本文来自Bigo多媒体技术团队的投稿,详细介绍了Bigo多媒体技术的前生今世,通过何种技术手段支撑起了BigoLive.Likee和imo三大业务.技术栈具体涉及编解码.传输.全球基础设施架构等三方面 ...

  7. 下一代编解码标准的抉择

    2018年的第一个月对于编辑码标准生态而言很不平静,Apple加入AOM联盟支持AV1,国产的AVS2宣布开源,MPEG创始人.主席Leonardo Chiariglione发文表示"MPE ...

  8. DAVINCI开发原理之三----达芬奇编解码引擎Codec Engine(CE)

    DaVinci是DSP和ARM 双核架构的SOC芯片.对芯片与外界的交互通过ARM端的Montavista Linux和相关驱动与应用程序来管理, DSP端只处理编解码相关的算法.DSP和ARM之间的 ...

  9. 基于FFMPEG 的跨平台视频编解码研究

    第33卷 第11期 2011年11月 武 汉 理 工 大 学 学 报 JOURNALOF WUHANUNIVERSITYOFTECHNOLOGY Vol.33 No.11 췍췍췍췍췍췍췍췍췍췍췍췍췍췍 ...

最新文章

  1. spring bean的生命周期和创建流程
  2. 区块链正本清源 – 从计算机科学评看区块链的起源和发展
  3. 区块链系列教程之:比特币中的共识
  4. rest framework错误笔记——身份验证和权限
  5. Qt 中pro文件换行注意的问题
  6. 数据归一化 - MinMaxScaler()/MaxAbsScaler() - Python代码
  7. 利用Java-JACOB操作WORD文档2
  8. Endnotex7无法保存修改后的格式
  9. 【图文说明】屏幕录像专家如何安装、录制小文件的录像
  10. matlab如何制造魔方矩阵,【1011】魔方矩阵的学习
  11. 第6章 分支语句和逻辑运算符
  12. win10电源设置选项无效--高级电源选项
  13. VMware SDS之九: VMware软件定义存储鲜为人知的另一部分
  14. 关于OSGI中的Felix热插拔技术
  15. Web前端之CSS层叠样式表相关案例
  16. python-猜数字游戏
  17. 软件测试工资直追开发,是我的错觉吗?
  18. 住建部《城市信息模型(CIM)基础平台技术标准》正式发布,6月1日起实施
  19. epoch和iteration的区别
  20. Java 小明同学最近开发了一个网站,在用户注册账户的时候,需要设置账户的密码

热门文章

  1. 如何打造特色小镇的夜游可玩性
  2. Django的搭建和小项目处理的过程(二)
  3. 人工智能开发神器是什么 为何多人用Python入门
  4. 信息学奥赛一本通(C++版)continue
  5. Blender全新开源动画短片官方灯光渲染教程,文末附高清参数截图+专家级灯光渲染建议
  6. 生产制造|数字化车间生产如何进行高效管理?
  7. 这些年,这些挖掘机算法,这些反思 - 推酷
  8. Linux服务器运行状况全面监测
  9. 群晖挂pt 路由器虚拟服务器设置,设置远程唤醒NAS要几步?用群晖路由只要4步!...
  10. axure 8.0 中继器数据绑定详细过程