• Java Web中涉及的编解码


    一次http请求涉及的编解码

    URL的编解码

    URL的组成部分


    以Tomcat服务器为例子,其中Port,ContextPath在Server.xml中配置
    <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
    <Context docBase="examples" path="/examples" reloadable="true" source="org.eclipse.jst.jee.server:examples"/>

    ServletPath在Web应用的web.xml中的<url-pattern>中配置,PathInfo 是我们请求的具体的 Servlet,QueryString 是要传递的参数,注意这里是在浏览器里直接输入 URL 所以是通过 Get 方法请求的,如果是 POST 方法请求的话,QueryString 将通过表单方式提交到服务器端。

    通过浏览器的请求过程,我们可知两个“君山”的编码结果是不同的:e5 90 9b e5 b1 b1,be fd c9 bd。说明了PathInfo和QueryString是由不同的逻辑代码处理的。

    PathInfo的处理取决于Server.xml中的Connector标签中的定义,如果没有定义,那么将以默认编码 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 方式传递的参数进行解码,但是它们的解码字符集有可能不一样。POST 表单的解码将在后面介绍,QueryString 的解码字符集要么是 Header 中 ContentType 中定义的 Charset 要么就是默认的 ISO-8859-1,要使用 ContentType 中定义的编码就要设置 connector 的  中的 useBodyEncodingForURI 设置为 true。这个配置项的名字有点让人产生混淆,它并不是对整个 URI 都采用 BodyEncoding 进行解码而仅仅是对 QueryString 使用 BodyEncoding 解码,这一点还要特别注意。

    所以在我们的应用程序中应该尽量避免在 URL 中使用非 ASCII 字符,不然很可能会碰到乱码问题,当然在我们的服务器端最好设置  中的 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.getParamter(name)时发生的,通过POST表单方式提交的参数与QueryString不同,他是通过Http Body传递到服务端的,编码为Header中的Content-Type,解码也使用Content-Type,也可以通过request.setCharsetEncoding(charset)设置(必须在第一次调用getParamter前)。若没有指定编码,将使用系统默认编码进行编码,Content-Type为空,tomcat将使用系统默认编码进行解码。

    HTTP BODY的编解码

    当用户请求的资源已经成功获取后,这些内容将通过 Response 返回给客户端浏览器,这个过程先要经过编码再到浏览器进行解码。这个过程的编解码字符集可以通过 response.setCharacterEncoding 来设置,它将会覆盖 request.getCharacterEncoding 的值,并且通过 Header 的 Content-Type 返回客户端,浏览器接受到返回的 socket 流时将通过 Content-Type 的 charset 来解码,如果返回的 HTTP Header 中 Content-Type 没有设置 charset,那么浏览器将使用<meta HTTP-equiv="Content-Type", content="text/html; charset=utf-8">中的编码进行解码。如果也没有定义的话,那么浏览器将使用默认的编码来解码。

    参考文章:

  • 相关阅读:
    李航统计学习方法(第二版)(六):k 近邻算法实现(kd树(kd tree)方法)
    ActiveMQ的安装和启动
    HTML select autofocus 属性
    macpath (File & Directory Access) – Python 中文开发手册
    Java Bitset类
    Linux zip命令
    HTML DOM Keygen 对象
    tanh (Numerics) – C 中文开发手册
    no-shadow (Rules) – Eslint 中文开发手册
    require-await (Rules) – Eslint 中文开发手册
  • 原文地址:https://www.cnblogs.com/huangzefeng/p/10771600.html
Copyright © 2020-2023  润新知