文档详情

Web容器的编码问题

jin****ng
实名认证
店铺
DOCX
25.29KB
约11页
文档ID:166947051
Web容器的编码问题_第1页
1/11

Web容器的编码问题一、 概述基于Java编程语言进行应用开发时,不可避免地要处理中文Java编程语 言默认的编码方式是UNICODE,而我们通常使用的数据库及文件都是基于 GBK 编码的,我们经常碰到这样的情况:浏览基于 JSP 技术的网站看到的是乱 码,文件打开后看到的也是乱码,被 Java 修改过的数据库的内容在别的场合应 用时无法继续正确地提供信息本文针对Web应用中常见的编码问题,就如何在OnceAS Web Container上 正确使用和传递中文信息做一个较为全面的比较与分析,并给出了相应的解决方 案本文将从编码基本知识,Java对字符的处理,以及常见问题的解决三个方面 对问题进行阐述二、 编码基本知识最早的编码是ISO-8859-1,和ASCII编码相似但为了方便表示各种各样 的语言,逐渐出现了很多标准编码,重要的有如下几个1、ISO-8859-1属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列比如, 字母'a'的编码为0x61=97很 明显, ISO-8859-1 编码表示的字符范围很窄,无法表示中文字符但是, 由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用 ISO-8859-1 编码来表示。

而且在很多协议上,默认使用该编码比如,虽然"中 文"两个字不存在ISO-8859-1编码,以gb2312编码为例,应 该是"d6d0 cec4"两 个字符,使用ISO-8859-1编码的时候则将它拆开为4个字节来表示:"d6 d0 ce c4" (事实上,在进行存储的 时候,也是以字节为单位处理的)而如果是 UTF 编 码,则是6个字节"e4 b8 ad e6 96 87"很明显,这种表示方法还需要以另一种编 码为 基础2、GB2312/GBK这就是汉子的国标码,专门用来表示汉字,是双字节编码,而英文字母和ISO-8859-1 一致(兼容ISO-8859-1编码)其中GBK编码能够用来同时表示繁 体字和简体字,而gb2312只能表示简体字,GBK是兼容gb2312编码的3、UNICODE这是最统一的编码,可以用来表示所有语言的字符,而且是定长双字节(也 有四字节的)编码,包括英文字母在内所以可以说它是不兼容 ISO-8859-1 编 码的,也不兼容任何编码不过,相对于ISO-8859-1编码来说,UNICODE编 码只是在前面增加了一个0字节,比如字母'a'为"00 61"需要说明的是,定长编码便于计算机处理(注意 GB2312/GBK 不是定长编 码),而 UNICODE 又可以用来表示所有字符,所以在很多软件内部是使用 UNICODE 编码来处理的,比如 java。

4、UTF -8考虑到UNICODE编码不兼容ISO-8859-1编码,而且容易占用更多的空间: 因为对于英文字母,UNICODE也需要两个字节来表示所以UNICODE不便于 传输和存储因此而产生了 UTF-8 编码, UTF-8 编码兼容 ISO-8859-1 编码,同 时也可以用来表示所有语言的字符,不过, UTF-8 编码 是不定长编码,每一个 字符的长度从1-6个字节不等另外,UTF-8编码自带简单的校验功能一般来 讲,英文字母都是用一个字节表示,而汉字使用三个字节注意,虽然说 UTF-8 是为了使用更少的空间而使用的,但那只是相对于 UNICODE 编码来说,如果已经知道是汉字,则使用 GB2312/GBK 无疑是最节 省的不过另一方面,值得说明的是,虽然 UTF-8 编码对汉字使用 3 个字节, 但即使对于汉字网页, UTF-8 编码也会比 UNICODE 编码节省,因为网页中包 含了很多的英文字符三、 java 对字符的处理在 java 应用软件中,会有多处涉及到字符集编码,有些地方需要进行正确 的设置,有些地方需要进行一定程度的处理1、 getBytes(charset)这是 java 字符串处理的一个标准函数,其作用是将字符串所表示的字符按 照 char set 编码,并以字节方式表示。

注意字符串在 java 内存中总是按 UNICODE 编码存储的比如"中文",正常情况下(即没有错误的时候)存储为"4e2d 6587", 如果char set为"GBK",则被编码为"d6d0 cec4",然后返回字节"d6 d0 ce c4" 如果 char set 为"UTF-8"则最后是"e4 b8 ad e6 96 87"如果是"ISO-8859-1",则 由于无法编码,最后返回"3f 3f"(两个问号)3、new String(charset)这是 java 字符串处理的另一个标准函数,和上一个函数的作用相反,将字 节数组按照 charset 编码进行组合识别,最后转换为 UNICODE 存储参考上述 getBytes的例子,"GBK"和"UTF-8"都可以得出正确的结果"4e2d 6587",但 ISO-8859-1最后变成了 "003f 003f"(两个问号)因 为 UTF-8 可 以 用 来 表 示 / 编 码 所 有 字 符 , 所 以 new String( str.getBytes( "UTF-8" ), "UTF-8" ) ==str,即完全可逆4、setCharacterEncoding()该函数用来设置 http 请求或者相应的编码。

值得注意的是这个函数只设置 了 Http协议body里面的编码,而对请求连接和Http头无效因此,该指定只对 POST方法有效,对GET方法无效对于request,是指提交内容的编码,指定后可以通过getParameter()则直接 获得正确的字符串,如果不指定,则默认使用 ISO-8859-1 编码,需要进一步处 理值得注意的是在执行setCharacterEncoding()之前,不能执行任何 getParameter()对于response,则是指定输出内容的编码,同时,该设置会传递 给浏览器,告诉浏览器输出内容所采用的编码5、几处设置对于 web 应用程序,和编码有关的设置或者函数如下• JSP编译指定文件的存储编码,很明显,该设置应该置于文件的开头例如:v%@page pageEncoding="GBK"%>另外,对于一般class文件,可以在编译的 时候指定编码• JSP输出指定文件输出到browser是使用的编码,该设置也应该置于文件的开头例 如 : <%@ page contentType="text/html;charset= GBK" %> 该 设 置 和 response.setCharacterEncoding("GBK")等效。

• META 设置 指定网页使用的编码,该设置对静态网页尤其有作用因为静态网页无法采用 JSP 的设置, 而且也无法执行 response.setCharacterEncoding() 例如: 如果同时采用了 JSP输出和meta设置两种编码指定方式,则JSP指定的优 先因为JSP指定的直接体现在response中常见问题的解决常见的编码问题大致可以分为四类:第一类是在编译期间造成,原因在于编 写代码的编码格式和编译器使用的编译格式不一致;第二类是在运行时由于编码 设置的不正确造成,主要因为没有正确设置request和response的字符集编码格 式,输入与输出使用了不同的编码格式第三类是使用URL传输数据时造成, 由于HTTP协议规范并没有考虑多国文字,因此URL信息并不包含编码格式信 息,编码格式只能依靠约定的形式来确定第四类由引入资源文件造成,因为引 入的资源文件编码格式与页面输出格式不同或没有指定引入资源的编码格式,使 得引入的资源文件不能正确的确定编码格式。

下面将针对 OnceAS Web Container 介绍常见的问题,以及解决方案4.1 编译问题4.1.1 编译器字符集指定对于 Java 类文件的编译问题并不常见,但是错误的本地编码可能会引起这 类问题编译Java文件时会使用Javac (标准Java编译器)进行编译,它使用 的字符集为操作系统默认的字符集,比如在中文 Windows 操作系统上是 GBK/GB18030 ,而在英文UNIX操作系统上就是ISO-8859-1因此开发人员会发 现在 英文 UNIX 操作系统上编译的类,其中双字节(中文)字符都成了乱码或 者问号解决方案是在编译时添加 encoding 参数,就可以做到与平台无关语 法为:javac -encoding GBK对于JSP文件,情况就不太一样了,应为容器在运行时才会对JSP做出解析, 生成相应的 class 文件如果不对文件做出编码的指定,容器则会使用默认的方 式进行编码此时,编码问题就有可能出现解决的方法是指定页面使用的编码 方式,如:v%@page pageEncoding="GBK"%>这样,容器便会知道使用何种编 码对文件进行解析,运行环境发生改变后也不会出现编码的异常。

4.2.3 使用 Include 引入可以使用v%@include%>和vjsp:include>两种方法引入另一个JSP页面这 两种方法引入的机制不同,前者使用的是静态引入的方式,在编译时它会将带引 入的 JSP 页面同时生成在同一个 class 文件中而后者是采用的动态引入方式, 只有在页面请求时才会动态的调用另一个JSP页面因为,它们引入的方式不同, 因此,在处理这两种情况时解决的方法也不相同使用vjsp:include>时,由于引入的JSP页面是一个独立页面,因此可以和普 通JSP页面一样进行编码和输出的指定但是在使用v%@ include %>时,被引入的文件不能像被vjsp:include>引入的 文件一样通过加入指定页面和输出编码的代码片段,因为,如果加入这段代码在 解析 JSP 文件时就会因为 contentType 内容重复而报错但是,可以通过仅指定 页面编码格式 “v%@ page language="java" pageEncoding="GBK"%>” 来解决中 文问题此时只指定了页面采用的编码方式,而没有制定页面 contentType 的内 容,不会和主页面冲突。

另外,如果使用vjsp:include >包含文件时同时传递了包含汉字的参数,也有 可能出现编码问题解决这个问题的方法将在4.2.2节“Forward中问题”中进 行介绍4.2 编码设置问题编码设置问题产生的主要问题是没有正确设置 request 和 response 的字符集 编码方式解决的办法很多,可以在有可能产生问题的地方插入设置字符编码的 代码片段,也可以通过使用Filter设置字符编码本节首先介绍此类问题中常见 的情况,以及它们的解决方法,最后介绍如何使用Filter统一解决编码设置问题4.2.1 显示问题JSP 页面能正确地被编译并不意味着最终显示给用的内容是正确的因为生 成的页面内容还必须经过网络传输才能到达用户的浏览器,而这个过程中也存在 着编码的转换问题如果不对response进行设置,容器会使用默认的编码方式进 行传送,而客户端浏览器也可能获取不到编码信息,最终用户看到的可能就是无 法辨识的乱码此时,用户可以通过调整浏览器的字符集来进行调整,但是这决 不是用户所希望的解决的方法很简单,只要指定JSP页面输出格式便可语法为:v%@ page language="java" contentType="text/html; charset=GBK"%> 。

此 标 签 与 使 用 response.setCharacterEncoding ()是等效的综合前两个问题,对于一个JSP页面如果需要解决编译和显示的问题可以通 过同时指定页面的编码格式和输出格式达到语法为: v%@ page language="java" contentType="text/html; charset= GBK" pageEncoding="GBK"%>需要指出的是 charset 和 pageEncoding 并一定需要指定为相同的字符集,可以根据具体需要决 定比如说一个页面需要使用GBK编写,同时又希望以UTF-8的格式输出,就 可以指定为<%@ page language="java" contentType="text/html; charset= UTF-8" pageEncoding="GBK"%>4.2.2 Form 提交问题当浏览器提交表单的时候, 可以指定相应的编码 例如: <form method="POST" accept-charset= "GBK">一般不必不使用该设置,使用 POST 方法时浏览器会直接使用网页的编码Form 一般推荐使用 POST 方法提交请求。

因为这种方法相比 GET 方法可以 提交更多的内容,它不会受到请求参数的限制,而且更容易解决编码问题对于 如何解决GET方法里面的编码问题留在RUL编码一节介绍4.2.3 Forward 中文问题使用“ jsp:forward ”标签进行页面跳转,如果没有指定request的 charcterEncoding 则很有可能发生编码问题在处理 Forward 请求时,如果 request 的encoding为空,容器便会使用ISO-8859-1的默认编码方式GBK格式保存得 数据并不能直接转换为ISO-8859-1格式,因为GBK是双字节编码,而ISO-8859-1 是单字节编码,所以转换的过程中会丢失必要的信息比如“中文”的GBK编 码应该为“%d6%d0%ce%c4”,UTF-8 编码为“%e4%b8%ad%e6%96%87 ",但如果直接 用 ISO-8859-1 编码格式进行转换,那么转换的结果为 “%3f%3f ”, 丢失掉了必要 信息,无法进行反编码操作解决问题的方式只能是重定向前首先设置 request 的编码格式,如 request.setCharacterEncoding("GBK")。

值得注意的是在跳转后的页面便可以直接获得真确的编码,但是如果在获取 参数前将字符集改为另外的格式,则同样会引起编码异常因为改变编码集后, 造成了编码前的字符集和解编码的字符集不匹配4.2.4 使用 Filter在每个有可能产生编码问题的地方设置字符集编码,既不便于页面的编码与 设计,也不利于后期的维护由于Filter会在servlet调用前被调用,所以可以使用 Filter 统一解决编码设置的问题,这将大大减轻编码和维护的工作量用于设置请求字符集编码的Filter的功能可以设计得非常简单,只需要为每 个请求设置特定的编码格式便可,当然,可以根据应用的需要设计的相对比较复 杂,也可以对不同的模块使用不同的过滤器,解决多国语言问题其核心逻辑可 以简化为如下形式:public void doFilter(...) throws IOException, ServletException { request.setCharacterEncoding( “GBK”)}4.3 URL 编码问题URL的信息会先于HTTP请求中的其它信息被解析,所以即便使用4.2节中 的方法进行了正确的设置仍有可能会产生编码问题。

URL 中包含请求的路径信息和参数信息两个部分,通过设置服务器的 URI 解析的默认编码或重构字符串都可以解决这类问题不过,参数的处理和路径的 处理在不同的浏览器间会存在细微的差别,因此将会分开介绍它们各自的解决方 法4・3・1 URL参数问题URL 请求所包含的参数只能使用 容器的默认字 符集解析, request 的 setCharacterEncoding 函数所设置的编码格式并不能影响到参数的读取,所以当请 求中包含汉字等信息时便会出现乱码的现象可以通过设置服务器的 URIEncoding 属性解决这个问题在 OnceAS 的配置 文件 webcontainer-means.xml 中,为 Entry 条目指定属性“URIEncoding "为合适 的字符集即可但是这种解决方法和下一节所介绍的URL路径问题可能存在一 定的冲突,下一节将详细分析这种情况另外,也可以通过程序代码显示的对数据进行解编码此时需要确定容器的 默认编码方法和待转化的目标编码方式在不设置容器默认编码的情况下,容器 会使用ISO-8859-1编码格式作为默认编码格式如果应用使用的是GBK的编码 格式,编码转化代码可以写为:new String(request.getParameter(name).getBytes(“ISO-8859-1”),”GBK”)。

4・3・2 URL路径问题处理 URL 路径中的汉字就不像处理参数那么容易了,不是简单的对服务器 进行设置或者编写字符集转化代码就可以解决问题的由于IE浏览器有一个选项“总是以UTF-8发送URL”,并且在默认的情况 下是选中的因此,使用IE浏览页面时,无论用户使用什么样的编码,URL路 径默认都会以 UTF-8 的编码格式处理但是, URL 中参数信息的编码格式并不 一定是 UTF-8 的格式,而是根据用户使用的编码确定的这样,如果试图通过 设置服务器的URIEncoding解决编码问题就很可能会和URL参数中的编码冲突 用户可能希望使用GBK读取参数信息,同时又希望使用UTF-8读取路径信息 这种设置几乎是不可能的,况且,其它浏览器对路径信息编码的格式与 IE 存在 着差异,即便某种服务器具有这种功能也很难彻底解决这种冲突如果希望通过服务器的设置彻底解决 URL 的编码问题,应用就必须约定使 用 UTF-8 的格式输出,好在这种格式对多国语言的支持是很有利的,便于应用 的国际化操作,同时也可以避免因为 IE 浏览器的特殊默认设置造成的影响值 得注意的是输出格式为 UTF-8,并不影响使用 GBK编写页面,可以通过contentType和pageEncoding连个不同的属性进行指定。

请求Servlet和JSP的路径一般都不会出现中文,也几乎没有人这么设计程序, 虽说 Java 支持这种编写方式有可能出现汉字的地方大部分情况下是访问某些 资源文件,比如说一个 word 文件这种情况下如果仍然希望使用 GBK 作为应 用输出,可以编写一个特殊的servlet来处理这类请求Servlet 中需要处理的核心问题是如何确定 URL 中使用的编码方式直接通 过字符串精确判断字符编码格式几乎是不可能的考虑到请求的是应用中能找到 的资源,因此可以通过编码转换加上搜索资源是否存在来确定编码的格式确定 编码格式的代码如下:for (int i = 0; i < encoding.length; i++) {String path = new String(pathInfo.getBytes(defaultEncoding),encoding[i]);if (context.getResource(path) != null) {pathInfo = path;break;}}其中,pathinfo是当前访问的路径信息,defaultEncoding是服务器使用的默 认编码格式, encoding 是一个待搜索的字符集数组。

当 context.getResource(path) 不为空时说明当前的路径有对应的资源存在,也就是说找到了合适的字符集对请 求路径进行转换4.4 JavaScript 问题浏览器获取JavaScript文件(js文件),是通过与http请求不同的链接实现的(新 的规范在这方有有所改进),因此两个请求的编码格式有可能不同,出现乱码也 就很好理解了使用GBK格式保存的js文件,在使用UTF-8格式输出的页面显 示肯定就会出现乱码解决JavaScript的乱码问题相对来说就简单很多了,下面 介绍几种可行的解决方案一种方法是通过 native2ascii 工具对 js 文件进行转换,因为转换后的文件以 UNICODE的格式保存数据,因此不出现是编码转换的问题但是这种方法相对 繁琐,转换后的编码不直观,而且不宜修改除非特别需求,并不推荐使用另一种方法是将js文件的编码格式设置的和应用输出一致比如,如果应用 使用GBK格式输出,那么js文件以GBK格式保存,如果应用以UTF-8格式输 出则 js 文件以 UTF-8 格式保存经过这样处理的 js 文件因为和页面输出编码格 式保持一致,所以不会出现乱码的问题。

最后,如果希望使用GBK保存js文件,而希望适用UTF-8格式输出页面的 话可以通过设置script标签的charset属性办到,不过这种设置在一些低版本的浏 览中可能得不到支持指定charset的格式为:vscript…charset=”GBK” src=”...”x/script>五、总的说来,使用UTF-8作为应用的同一编码格式是一个很好的选择这 种格式并不影响本地化应用的编写,同时对应用的国际化和多语言支持具有很大 优势,更重要的是它能避免某些潜在的造成编码问题的可能一个应用需要设置的关键点包括, JSP 页面的 contentType 和 pageEncoding 属性,服务器的 URIEncoding 属性, request 的 characterEncoding 属性和资源文 件的保存和引入编码格式等。

下载提示
相关文档
正为您匹配相似的精品文档