java看完了 不会编码_java中的编码问题

此处对于开发中的编码问题做一个小集结,首先看下下面几个:

1、几种编码介绍

在jsp、servlet中有如下几种形式编码:

A、pageEncoding="UTF-8":表示jsp被编译成为servlet时使用的编码,话句话说就是pageEncoding是用来告诉jsp编译器将jsp编译成servlet时使用什么编码。

案例:发现定义在jsp中的内容(非提交请求时提交的数据)发生乱码,那一定是由于pageEncoding引起的。

例如,你的JSP文件是以GBK为编码保存的,而在JSP中却指定pageEncoding="UTF-8",就会引起JSP内部定义的字符串为乱码。 (读者可以自己试试)

contentType="text/html;charset=UTF-8"、

request.setCharacterEncoding("UTF-8")、response.setCharacterEncoding("UTF-8")

B、contentType="text/html;charset=UTF-8"的作用是指定对服务器响应进行重新编码的编码

在不使用response.setCharacterEncoding方法时,用该参数指定对服务器响应进行重新编码的编码。

服务器在将数据发送到浏览器前,对数据进行重新编码时,使用的就是该编码。

C、request.setCharacterEncoding("UTF-8")的作用是设置对客户端请求进行重新编码的编码,

该方法用来指定对浏览器发送来的数据进行重新编码(或者称为解码)时使用的编码。

D、esponse.setCharacterEncoding("UTF-8")的作用是指定对服务器响应进行重新编码的编码。

服务器在将数据发送到浏览器前,对数据进行重新编码时,使用的就是该编码。

2、浏览器对请求与响应的处理

response.setCharacterEncoding("UTF-8")的作用是指定对服务器响应进行重新编码的编码。同时,

浏览器也是根据这个参数来对其接收到的数据进行重新编码(或者称为解码),其实这种方式是间接的设置浏览器的编码方式。

读者可以做个实验,

在JSP中设置response.setCharacterEncoding("UTF-8"),在IE中显示该页面时,在IE的菜单中

选择"查看(V)"à"编码(D)"中可以查看到是"Unicode(UTF-8)",而在在JSP中设置response.setCharacterEncoding("GBK"),

在IE中显示该页面时,在IE的菜单中选择"查看(V)"à"编码(D)"中可以查看到是"简体中文(GB2312)"。

浏览器在发送数据时,对URL和参数会进行URL编码,对参数中的中文,浏览器也是使用response.setCharacterEncoding参数来进行URL编码的。

浏览器在接收服务器数据和发送数据到服务器时所使用的编码是相同的,默认情况下均为JSP页面的 response.setCharacterEncoding参数。

浏览器在发送数据时,对URL和参数会进行URL编码,对参数中的中文,浏览器也是使用response.setCharacterEncoding参数来进行URL编码的。

3、服务器(app server)对资源的编码处理

发送:服务器按照response.setCharacterEncoding—contentType—pageEncoding的优先顺序,对要发送的数据进行编码。

接收:对于接收数据,要分三种情况。一种是浏览器直接用URL提交的数据,另外两种是用表单的GET和POST方式提交的数据。

无论使用那种方式提交,如果参数中包含中文,浏览器都会使用当前浏览器编码对其进行URL编码。

4、jsp编译过程

JSP要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8,第三阶段就是由Tomcat出来的网页, 用的是contentType。

第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8 JAVA源码(即.java),

如果pageEncoding设定错了,或没有设定,出来的就是中文乱码。

第二阶段是由JAVAC的JAVA源码至java byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。

第三阶段是Tomcat(或其的application container)载入和执行阶段二的来的JAVA二进制码,输出的结果,也就是在客户端见到的,

这时隐藏在阶段一和阶段二的参数contentType就发挥了功效。

=============================================================

下表是三种浏览器的编码情况。其中IE的URI编码可以调整为UTF8。

默认URI编码            默认查询参数编码

谷歌        UTF8                    UTF8

火狐        UTF8                    GBK

IE            GBK                         GBK

=============================================================

实验得出的结论是

1.URIEncoding和useBodyEncodingForURI都可以处理中文乱码的问题

2.浏览器对于URI和查询参数可能使用两种不同的编码方式,这种情况下,可以使用  tomcat的useBodyEncodingForURI调整查询参数的编码。

===================================

以下为常见乱码情况:

乱码场景

1、代码库检出后乱码 :

原因分析:主要是由于代码库的编码与自己本地的环境(IDE——eclipse)的编码不一致造成

解决方案:

1)、修改IDE工作空间的编码:右键项目名称——properties,在弹出的页面右侧修改对应编码

2)、修改具体的某一个文件的编码:右击具体的文件——properties,修改对应编码,主要针对乱码文件比较少的情况

3)、在IDE中,window——preference,在弹出的界面中顶部输入:content type,

在右侧选择具体的文件类型,填写编码格式,然后单击“update”可以更新这一类文件的编码

2、本地新建文件乱码

原因分析:主要是由于IDE中预先设置的项目的编码、工作空间的编码或者某一类文件的编码与新建文件的编码不一致。

解决方案:需要先确定整个工程的编码(大环境编码),然后参考1中的方案。

3、ide中文件编码、文件内容编码:参考1

4、jvm、tomcat编码、servlet编码、浏览器编码

1)、jvm编码:jvm默认会使用本地操作系统的编码格式作为自己的编码方案,

e.g. 经常使用的getBytes()在不指定参数的情况下的作用是使用系统默认或者指定的字符集编码方式

获取jvm编码: Charset.defaultCharset()可以获取到当前jvm的默认字符集

System.getProperty("file.encoding")

修改jvm编码(从eclipse中修改):window——preference——“java”——installed jre——edit,

然后在default JVM Arguments中添加参数:-Dfile-encoding=utf-8

此种方式是会针对引用该JRE的所有情况,当然也可以修改具体的某个server的JVM字符集参数,修改方式基本一致。

2)、tomcat编码:

a、修改conf中的server.xml文件,在连接器(connector,一般是http连接器而非ajp)中添加:URIEncoding=“编码”

b、参考1)中的修改server的jvm编码

=======================================

========================================================

22665ae655d37a51e3db4517675f0de3.png

上图中 PathInfo 和 QueryString 出现了中文,当我们在浏览器中直接输入这个 URL

时,在浏览器端和服务端会如何编码和解析这个 URL 呢?为了验证浏览器是怎么编码 URL 的我们选择 FireFox 浏览器并通过

HTTPFox 插件观察我们请求的 URL 的实际的内容,以下是

URL:HTTP://localhost:8080/examples/servlets/servlet/ 君山 ?author= 君山在中文

FireFox3.6.12 的测试结果

君山的编码结果分别是:e5 90 9b e5 b1 b1,be fd c9 bd,查阅上一届的编码可知,PathInfo 是 UTF-8 编码而

QueryString 是经过 GBK 编码,至于为什么会有“%”?查阅 URL 的编码规范 RFC3986 可知浏览器编码 URL 是将非

ASCII 字符按照某种编码格式编码成 16 进制数字然后将每个 16 进制表示的字节前加上“%”,所以最终的 URL 就成了上图的格式了。

从上面测试结果可知浏览器对 PathInfo 和 QueryString 的编码是不一样的,不同浏览器对 PathInfo

也可能不一样,这就对服务器的解码造成很大的困难,下面我们以 Tomcat 为例看一下,Tomcat 接受到这个 URL 是如何解码的。

从上面的代码中可以知道对 URL 的 URI 部分进行解码的字符集是在 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 方式传递的参数进行解码,但是它们的解码字符集有可能不一样。POST 表单的解码将在后面介绍,QueryString

的解码字符集是在哪定义的呢?它本身是通过 HTTP 的 Header 传到服务端的,并且也在 URL 中,是否和 URI

的解码字符集一样呢?从前面浏览器对 PathInfo 和 QueryString

的编码采取不同的编码格式不同可以猜测到解码字符集肯定也不会是一致的。的确是这样 QueryString 的解码字符集要么是 Header 中

ContentType 中定义的 Charset 要么就是默认的 ISO-8859-1,要使用 ContentType 中定义的编码就要设置

connector 的

useBodyEncodingForURI=”true”/> 中的 useBodyEncodingForURI 设置为

true。这个配置项的名字有点让人产生混淆,它并不是对整个 URI 都采用 BodyEncoding 进行解码而仅仅是对 QueryString

使用 BodyEncoding 解码,这一点还要特别注意。

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

传递到服务端的。当我们在页面上点击 submit 按钮时浏览器首先将根据 ContentType 的 Charset

编码格式对表单填的参数进行编码然后提交到服务器端,在服务器端同样也是用 ContentType 中字符集进行解码。所以通过 POST

表单提交的参数一般不会出现问题,而且这个字符集编码是我们自己设置的,可以通过

request.setCharacterEncoding(charset) 来设置。

另外针对

multipart/form-data 类型的参数,也就是上传的文件编码同样也是使用 ContentType

定义的字符集编码,值得注意的地方是上传文件是用字节流的方式传输到服务器的本地临时目录,这个过程并没有涉及到字符编码,而真正编码是在将文件内容添加

到 parameters 中,如果用这个编码不能编码时将会用默认编码 ISO-8859-1 来编码。

HTTP BODY 的编解码

当用户请求的资源已经成功获取后,这些内容将通过 Response

返回给客户端浏览器,这个过程先要经过编码再到浏览器进行解码。这个过程的编解码字符集可以通过

response.setCharacterEncoding 来设置,它将会覆盖 request.getCharacterEncoding

的值,并且通过 Header 的 Content-Type 返回客户端,浏览器接受到返回的 socket 流时将通过 Content-Type 的

charset 来解码,如果返回的 HTTP Header 中 Content-Type 没有设置 charset,那么浏览器将根据 Html

/> 中的 charset 来解码。如果也没有定义的话,那么浏览器将使用默认的编码来解码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值