收藏 分享(赏)

HTTP协议及浏览器编码行为.docx

上传人:myw993772 文档编号:5518778 上传时间:2019-03-06 格式:DOCX 页数:19 大小:54.51KB
下载 相关 举报
HTTP协议及浏览器编码行为.docx_第1页
第1页 / 共19页
HTTP协议及浏览器编码行为.docx_第2页
第2页 / 共19页
HTTP协议及浏览器编码行为.docx_第3页
第3页 / 共19页
HTTP协议及浏览器编码行为.docx_第4页
第4页 / 共19页
HTTP协议及浏览器编码行为.docx_第5页
第5页 / 共19页
点击查看更多>>
资源描述

1、6.1 HTTP 协议及浏览器编码行为HTTP 协议和浏览器是 Web 国际化的基础,在进入 Java 服务器端之前,必须先对它们的编码行为有所了解。6.1.1 HTTP 协议HTTP 协议是 B/S 体系结构应用程序的基础,只有了解了 HTTP 协议,才能理解如何在B/S 体系结构下实现应用程序的国际化。1HTTP 请求当用户在浏览器的地址栏中输入一个 URL 并按回车键之后,浏览器会向 HTTP 服务器发送 HTTP 请求。HTTP 请求主要分为“Get”和“Post”两种方法。2采取“Get”方法的 HTTP 请求“Get”请求的典型用途是从 HTTP 服务器获取指定的资源,这样的请求不

2、包含请求体。在浏览器中输入一个 URL 并按回车键后,浏览器就会生成这种类型的请求。HTTP 服务器根据该请求所包含 URL 中的参数来动态产生响应内容,即“Get”请求的参数是 URL 的一部分。例如:http:/ URL 是一个使用百度搜索关键字“Chinese”的 URL,参数 “wd”包含在 URL 中,一起发送到 HTTP 服务器,参数的值是“Chinese”。当参数名和参数值都是 ASCII 字符时不会出现问题,但当参数名或参数值中包含非 ASCII 字符时就有可能出现问题。由于 URL 通过网络传递,因此,为了保证信息的兼容性和通用性,当 URL 包含非 ASCII字符时,必须对

3、其进行转义。如果将上例中的参数值改为“中文” ,则 URL 变为:http:/ Firefox2.0)的地址栏中输入上述 URL 并按回车键后,可以看到浏览器会自动对 URL 进行转义,得到的是:http:/ ,它们是汉字“中文”的GBK 编码对应的转义形式。另外,不同的浏览器对 URL 进行转义的行为是不同的,具体内容请参阅 6.1.2 节的介绍。当 HTTP 服务器收到这样的请求时,必须先将转义的字符解释为有效的字符,再对 URL进行处理。但是,HTTP 协议中并没有指定使用何种编码和字符集来解释 URL 中的非ASCII 字符(细节可参阅 RFC2396,2.1 节),因此,是否能成功解

4、析就完全取决于 URL中非 ASCII 内容的编码是否与 HTTP 服务器的解析编码一致。例如,如果我们希望在Google 中也搜索“中文” ,构造如下 URL:http:/ URL 并按回车键后,会发现搜索结果页面查询的关键字并不是“中文”而是一个不能识别的乱码。这是因为 Google 的 HTTP 服务器使用 UTF8 编码来解释URL 中的非 ASCII 字符。如果使用下面以 UTF8 编码的 URL 就能得到正确的结果:http:/ 在不同区域的服务器可能会使用不用的编码方式来解析 URL。例如 可以正确解析:http:/ 只能正确解析:http:/ Google 可以根据用户浏览器的

5、区域设置自动将用户重定向到某个特定区域的服务器上,因此在 Firefox 中,如果浏览器的首选区域是 zh-cn,那么访问如下url: http:/ 会被自动重定向到http:/ /search?q=%D6%D0%CE%C4,因此,显示的结果是正确的。3采取“Post”方法的 HTTP 请求“Post”请求通常用来向 HTTP 服务器提交量比较大的数据(比如请求中包含许多参数或者文件上传操作等),它与“Get” 方法的主要区别在于请求的参数包含在消息体而非 URL 中,服务器同样需要获得正确的编码信息才能够正确解析在消息体中的请求参数。在 “Post”方法的 HTTP 请求中,通常包含一个“C

6、ontent-Type”消息头指明该消息体的媒体类型和编码,如“Text/XML; charset=gb2312”,指明该请求的消息体中包含的是纯文本的 XML 类型的数据,字符编码采用“gb2312”。使用一些 Firefox 插件可以辅助开发人员分析请求的消息头和消息体,较常用的有 Firebug等。4HTTP 响应HTTP 响应是 HTTP 服务器在接收请求之后向客户端返回的信息。一个 HTTP 响应通常由状态行、消息头和消息体组成。HTTP 响应消息的第一行是状态行,表示服务器对请求的应答。常见的应答有:“200:OK”、“404:Not Found”、“500:Internal Se

7、rver Error”等。与 HTTP 请求类似,HTTP 响应消息也包含一个“Content-Type”消息头,它指定了消息体中内容的类型和编码,例如“text/html; charset=UTF-8”。只有正确指定了 “Content-Type”消息头,浏览器才能正确解析收到响应消息体中的数据并呈现页面。6.1.2 浏览器行为分析浏览器是发送 HTTP 请求和接收 HTTP 响应的客户端,HTTP 协议保证了大多数情况下浏览器行为的一致性,但不同浏览器之间仍有许多差异。这些差异经常导致 B/S 体系结构应用程序的开发变得困难。本节着重解释不同浏览器在涉及国际化方面的不同行为。1发送请求使用

8、浏览器发送 HTTP 请求有多种方式:在浏览器地址栏中直接输入 URL;在页面中通过点击“提交”按钮提交表单;用户在页面中点击超链接产生的请求;使用 JavaScript 脚本的 XMLHTTPRequest 对象发送请求。(1)在浏览器地址栏中直接输入 URL当 URL 中包含非 ASCII 码字符时,Firefox 会自动将这些字符进行转义,转义使用的编码由浏览器的语言版本决定。例如,“http:/ 6-1 Firefox 中的 URL 编码选项默认情况下,中文 Windows 平台上的 IE 浏览器将 URL 分为两个部分,“?”之前的部分URL 使用 UTF8 进行转义,而“?”之后的

9、参数部分,则不进行转义而直接使用 GBK 编码发送。例如 URL“http:/localhost/中文.jsp?test=中文”,前一个“中文”将按照 UTF8 编码的转义形式“%E4%B8%AD%E6%96%87”发送,而参数部分的“ 中文”则直接以 GBK 编码发送,因此,最终发送的 URL 如图 6-2 所示。图 6-2 URL 编码图解(1 )在 IE 的 “Internet 选项”的“ 高级”选项卡页中有一个选项“总是以 UTF-8 发送 URL”,在缺省情况下该选项是选中的。如果去掉这个选项,IE 将会以系统当前的代码页来对 URL 进行编码。在中文 Windows 中整个 URL

10、 都将以 GBK 编码发送,如图 6-3 所示。图 6-3 URL 编码图解(2 )(2)在页面中通过单击“提交”按钮来提交表单在表单中属性“method”用来指定提交表单时所使用的 HTTP 请求方法,可以选择 Post 或者 Get。用户不指定时,默认采用 Get 方法。而表单所提交内容采用的编码则由页面当前的编码决定。例如,在一个 JSP 中包含以下表单代码:=formencoding.jsp=在 IE 或 Firefox 浏览器中打开该页面,在“中文” 输入框中填入“中文” 并单击“提交”按钮,会产生一个 Get 请求,所使用的 URL 为:http:/localhost:8080/j

11、sbook/formencoding.jsp?%D6%D0%CE%C4=%D6%D0%CE%C4即使用 GBK 编码对 URL 进行转义。如果将该页面的 contentType 重置为 contentType=“text/html; charset=UTF-8“,则该表单所产生的 URL 为:http:/localhost:8080/jsbook/formencoding.jsp? %E4%B8%AD%E6%96%87= %E4%B8%AD%E6%96%87%即使用 UTF-8 编码对 URL 进行转义。如果表单使用 Post 方法,则提交的参数将放在请求的消息体中,而使用的编码方式仍将由该页

12、面的编码方式决定。(3)在页面中单击超链接产生的请求用户单击页面中的超链接时,浏览器将会产生一条“Get” 请求。这个请求的 URL 使用的编码方式由当前页面使用的编码及使用的浏览器共同决定。我们仍然使用前文的例子“http:/localhost/中文.jsp?test= 中文” 来说明。在 IE 中,页面编码为 UTF8 时,这一请求中“?”前的部分将以 UTF8 编码转义,而“ ?”后的参数部分将直接使用 UTF8 编码发送;当页面编码为 GBK 时,请求中“ ?”前的部分仍以UTF8 编码转义,而“?”后的参数部分将直接使用 GBK 编码发送。在 Firefox 中,页面编码为 UTF8

13、 时,整个 URL 将以 UTF8 编码转义。如果页面编码为GBK,则请求以 GBK 编码转义。如果在 IE 中禁用了 “总是以 UTF-8 发送 URL”选项,那么当页面编码为 UTF8 时,这一请求中“?” 前的部分将以 UTF8 编码转义,而“?” 后的参数部分将直接使用 UTF8 编码发送;当页面编码为 GBK 时,整个请求都将直接使用 GBK 编码发送。(4)使用 XMLHTTPRequest 对象发送请求最后,我们来看一下使用 JavaScript 脚本来发送请求的情形。 XMLHTTPRequest 对象(下面简称 XHR)是构成 Ajax 应用程序的基础,它允许 JavaScr

14、ipt 脚本直接向服务器发送 HTTP 请求,在页面不刷新的前提下与服务器通信,提交和获取数据。使用 XHR 对象发送请求也分为 Get 和 Post 两种。IE 中使用 XHR 对象发送“Get” 请求时,对 URL 所使用的编码规则和在地址栏中输入 URL是一致的。Firefox 中使用 XHR 对象发送“Get”请求时始终使用 UTF-8 编码对 URL 进行转义,而发送“Post”请求时,参数和 URL 分离,参数部分在消息体中,使用 UTF-8 编码。要使 Web 服务器能够正确识别,最好在 Content-type 消息头中添加“Charset”信息,如以下代码段所示:/创建 XH

15、R 对象,并准备 URL 和请求参数xmlHttp.open(“Post“,url,true);xmlHttp.setRequestHeader(“Content-type“, “application/x-www-form-urlencoded;charset=UTF-8“);xmlHttp.setRequestHeader(“Content-length“, params.length);xmlHttp.setRequestHeader(“Connection“, “close“);xmlHttp.send(params);请注意,设置上述请求的消息头只能用来告知服务器该消息体所使用的编码

16、,并不能通过修改此消息头的值来改变该请求所使用的编码。2接受响应前文描述了浏览器在发送 HTTP 请求时选取编码的行为。那么从服务器端返回 HTTP 响应时,浏览器又是如何判断该响应使用了何种编码的呢?浏览器判断返回的 HTTP 响应消息所使用的编码遵循以下一系列规则。首先,浏览器会检查 HTTP 响应中的“Content-type”消息头。如“text/html; charset=UTF-8”,表明该消息所包含的内容是纯文本的 HTML 文档,采用 UTF-8 编码。但在很多情况下,服务器返回的 Content-type 消息头并不包含“charset”信息。当响应消息不包含“charset

17、” 信息时,浏览器会尝试自动探测编码。第一个步骤是检查响应消息体的开头是否包含 UTF-8 的 BOM(字节顺序标记,Byte Order Marker)。BOM 是一种用来判断文件编码的特定字节标记,如果一个文件的开头几个字节包含了 UTF-8 的BOM,那么浏览器就可以断定这个 HTML 文件是采用 UTF-8 编码的。如果该 HTML 中不包含 BOM,那么,浏览器就会尝试寻找 HTML 页面中的标记,如:如果页面中又不包含标记,那么,浏览器将采用默认的编码来解析。在中文的 IE和 Firefox 里就是采用 GBK 或 GB2312 编码。因此,要使服务器端返回的响应消息能够正确地被浏

18、览器解析,最简单有效的方法就是在响应的“Content-type”消息头中设置 charset 属性。在 Servlet 编程中可以在 doGet()或doPost()方法中调用:response.setCharacterEncoding(“UTF-8“)在 JSP 编程中可以在页面开头指定响应的编码:6.1.3 简单总结本节描述了 HTTP 协议中数据传输时需要考虑的编码问题,以及在浏览器中发送请求时所使用的不同编码设置。由于编码设置在整个 B/S 体系结构的“ 请求处理响应”各个环节中无处不在,其中任何一个环节的错误设置都会导致最终呈现给用户的数据出现乱码,因此,理解这些编码设置的原理将有

19、助于我们在遇到问题时检测和判断究竟是哪个环节设置错误。而避免这些错误和复杂的编码设置的最好办法,就是在所有的环节都统一使用 UTF-8 编码,这也可以说是在设计 B/S 体系结构的 Web 应用程序时需要贯穿始终的设计原则。6.2 HTML/JSP/Servlet 的编码设置6.2.1 HTML 的编码设置浏览器需要使用恰当的字符编码来解释 HTML 文档,以使网页可以用正确的语言、字符集和字体显示。为了保证这一点,HTML 文档应当包含明确的信息来表明所使用的字符编码,这可以通过设置 META 标记实现。网站管理员还可以通过配置 IBM HTTP Server 来为每一个响应加上合适的 HT

20、TP 消息头,从而确保在 META 标记缺失的情况下网页也能正常显示。1在 HTML 文档中使用 META 标记来标识字符编码META 标记的作用是什么?META 标记在 W3C HTML 规范中定义,嵌入在 HEAD 标记中,用于标识关于 HTML 文档的元信息,这些元信息可以被浏览器和 Web 服务器所解析和使用。在 META 中设置 HTTP-EQUIV 属性,可以告诉浏览器该 META 信息与 HTTP 信息头等价。如果 HTTP-EQUIV 属性缺失,那就需要设置 NAME 属性来标识该元信息,并且不应将这个元信息作为 HTTP 信息头来解析。如果 NAME 属性缺失,但 HTTP-

21、EQUIV 存在,那么会假设 NAME 与 HTTP-EQUIV 相同。而 CONTENT 属性用来保存与 HTTP-EQUIV或 NAME 相关的值,以构成一个“键/值对”(key-value pair)。设置 META 标记最简单也是最安全的做法是将 HTML 以 UTF-8 编码保存,并且在 HEAD中加入名称为 Content-Type 的 META 信息。.这是网页的标题.如果 HTML 整体显示正确,但只有标题为乱码,那是什么问题?这在多数情况下是因为TITLE 标记出现在 META 标记之前,浏览器顺序解读 HTML 时首先遇到 TITLE,而在那时还不曾确定应当用什么字符编码解

22、析,比如下面就是一个错误的例子。回页首.这是网页的标题 .2配置 IBM HTTP Server这是一种自动防错机制,即便个别 HTML 文档因为这样或那样的原因,没有用 META 标记声明字符编码,IBM HTTP Server 仍能够自动地在 HTTP 响应消息头中提供编码信息,帮助浏览器正确解读 HTML 文档。具体的配置方法是修改 IBM HTTP Server 的配置文件 httpd.conf(默认情况下位于 conf 目录下),如下面的代码片段所示。.AddType text/html; charset=UTF-8 html htm.这样,服务器就会为每一个后缀为 html 和 h

23、tm 的请求回复中自动加上消息头(如下所示),以达到通知浏览器文档的编码格式的目的。Content-Type: text/html; charset=UTF-8上面的配置适用于整个网站统一采用 UTF-8 编码的情况。那么,如果并没有统一为 UTF-8编码该怎么办呢?IBM HTTP Server 可以根据文档所处目录的不同,自动添加不同的消息头,当然这种配置会复杂一些。假设网站包含不同编码的文档,分布在不同的目录中。/root/-/en/-index.html (encoded in ASCII)| page1.html|-/cn/-index.html (encoded in GB2312

24、)| page1.html|-/ja/-index.html (encoded in Shift_JIS)page1.html那么相应的 httpd.conf 大致如下。.AddType text/html; charset=iso-8859-1 html htm.AddType text/html; charset=GB2312 html htm.AddType text/html; charset=Shift_JIS html htm.有了上面的配置,在目录/root/下的 html 和 htm 就会以相应的 HTTP 消息头返回给浏览器。比如对于/root/cn/index.html,就

25、会返回“Content-Type: text/html; charset=UTF-8”消息头。如果不希望直接修改 httpd.conf,那么,可以通过修改.htaccess 来覆盖 httpd.conf 中的配置,可以达到相同的目的。.htaccess 是一个作用于其所在目录和所有子目录的配置文件,对.htaccess 的修改不需要重新启动 IBM HTTP Server 就能生效,因此被经常使用。要保证.htaccess 中的配置覆盖 httpd.conf,首先需要在 httpd.conf 中对相关目录加上“AllowOverride”参数,如下所示。.AllowOverride All.然

26、后在.htaccess 中关于/root/cn/ 的配置中加入下面一行以使之生效。AddType text/html; charset=GB2312 html htm更多关于 IBM HTTP Server 配置文件和参数的信息,请查阅相关文档。3小结以 UTF-8 编码保存 HTML 文档。在 HTML 文档中加入 META 标记以标识字符编码。配置 IBM HTTP Server 以启用自动防错功能。6.2.2 JSP 的编码设置在当代的网络应用程序中,JSP 常常扮演 MVC 模型中视图的角色,用来生成 HTML 以返回客户端,从而在浏览器中呈现用户界面。对国际化的应用程序来说,JSP

27、文件可能以多种编码(为不同的语言)编写,因此,需要有特定的参数标识 JSP 的字符编码,以保证应用程序服务器能正确地解析和编译 JSP 文件。本节会介绍相关的参数并说明它们的用途,同时再一次强调,采用统一的 UTF-8 编码是最简单和最安全的策略。1设置 JSP 文件的编码在 JSP 能够被执行并响应用户请求之前,首先要经过一个编译的过程,这里 JSP 文件的编码指的是应用程序服务器读取 JSP,进行编译时所使用的字符编码。最通常的做法是将所有 JSP 都保存为 UTF-8 格式,并在文件中使用 pageEncoding 标明字符编码。如上 pageEncoding 就是一个专用于标识 JSP

28、 字符编码的参数,但同时它也是可选的。你也可以不提供 pageEncoding,而通过设置 contentType 参数来指定页面编码。像这样缺少 pageEncoding 的情况下,contentType 中的 charset 部分将用于 JSP 页面的字符编码。如果同时使用了 contentType 和 pageEncoding,哪一个参数优先级更高呢?答案是 pageEncoding 优先。在 contentType 和 pageEncoding 中使用不同的编码是一种非常少见的情况,后面的章节会具体讨论。但一般而言,字符编码在 contentType 和pageEncoding 中应当

29、保持一致。除了上述在每一个 JSP 文件中指定字符编码外,从 JSP 2.0 规范开始,也可以在 web.xml中一次声明多个 JSP 文件的编码。For all JSPs*.jspUTF-8如果在 web.xml 中加入上面的配置,那么,所有的 JSP 文件都会采用 UTF-8 编码执行编译,这比在每一个 JSP 文件中加入声明要简洁得多,当然,这首先要求应用程序服务器支持 JSP 2.0 规范。在 JSP 2.0 规范中, JSP 文件的编码声明和查询次序的定义如下。(1)首先,寻找 web.xml 中 url-pattern 匹配的 jsp-config 声明。(2)其次,寻找 JSP

30、文件中的 pageEncoding 参数,如果 pageEncoding 参数与 jsp-config 中的配置不符,将产生一个 JSP 编译错误。(3)再次,寻找 contentType 中的 charset 声明,这仅当 jsp-config 和 pageEncoding 参数都不存在时才有效。(4)最后,如果上述所有设置都不存在,那么,采用 ISO-8859-1 作为默认编码。2设置 JSP 响应字符编码JSP 响应字符编码是指 JSP 生成的 HTTP 响应所使用的字符编码,也就是 JSP 运行后生成的 HTML 文档的字符编码,该编码由 contentType 参数指定。在每一个 J

31、SP 文件中都加入合适的 contentType 声明是推荐的做法。比如:这样会调用 ServletResponse.setContentType()方法,从而设置 HTTP 响应的字符编码。如果缺少 contentType,那么会继续查询 pageEncoding 参数及 web.xml 中的 jsp-config配置。如果其中任意一个存在,那么其字符编码将作用于 HTTP 响应,如果都不存在,那么最终会使用 ISO-8859-1 字符编码。3符合 XML 语法的 JSP 文件JSP 规范从 V2.0 开始支持完全符合 XML 语法的 JSP 文件,对于这类符合 XML 语法的JSP 文件,

32、上述的文件字符编码和响应字符编码的设置会略有不同。对于 JSP 文件编码,它取决于 XML 文件第一行的编码声明。文件中 pageEncoding 和 web.xml 中的 jsp-config 设置仍然有效,但仅起到一个复查的作用。如果任意一处有不一致的编码声明,都将导致 JSP 编译时出错。例如,可以如下声明pageEncoding。对于 HTTP 响应字符编码,仍然使用 contentType 参数,当然语法有所不同,以便符合XML 规范。如果 contentType 参数不存在,那么默认的字符编码将为 UTF-8,而不再是 ISO-8859-1。4一些不推荐的方法对所有 JSP 统一使

33、用 UTF-8 编码是最好的策略。如果非要在 JSP 中使用和语言相关的编码格式,那么,对于国际化的应用程序来说将是一场噩梦,因为这将导致同一个网页有多个对应的 JSP 文件,每个文件对应一种语言。如果要支持 10 种语言,那就有网页数乘以10 的 JSP 文件,其中任意一个网页需要变更,都要改变 10 个 JSP 文件,这几乎是无法管理的。另一种不推荐的情形是对一个 JSP 使用不同的文件编码和响应编码。比如,下面的声明表示 JSP 文件本身的编码是 GB2312,而生成的 HTML 内容则使用 UTF-8。这种做法虽然存在理论上的可能性,但实际操作中却很容易把两种编码混淆,从而产生错误。调

34、试这类编码错误是非常复杂的,因为有太多的配置可能对其产生影响。5小结最好以 UTF-8 编码保存 JSP 文档。在 JSP 中使用 pageEncoding 参数声明文件字符编码,使用 contentType 参数声明响应字符编码。如果应用程序服务器支持 JSP 2.0 规范,也可以在 web.xml 中使用 jsp-config 标记统一声明 JSP 文件编码。6.2.3 Servlet 的编码设置对于一个国际化的应用程序而言,仅设置 HTML 和 JSP 编码是远远不够的,除了考虑服务器端输出内容的字符编码外,还要考虑如何正确解析来自全球范围内不同地域和语言的用户输入。本节将讨论如何设置编

35、码以确保一个网页上的表单能够接收不同语言的输入,并且在服务器端这些不同语言的字符能够被正确地解析。1使用 UTF-8 编码提交数据要使应用程序能够接收国际化的输入,首先要确保浏览器使用 UTF-8 编码向 Web 服务器提交数据。UTF-8 作为通用编码,可以为全球不同的语言进行统一的编码和解码,这样可以大大简化服务器端为了适应多语言所需的编程。当用户在浏览器单击提交表单时,浏览器会使用当前网页的字符编码提交表单上输入的内容,因此,只要对所有的网页都采用 UTF-8 编码,就可以保证浏览器总是使用 UTF-8 编码提交数据。对网页编码的设置已经在“6.2.1 HTML 的编码设置”和“6.2.

36、2 JSP 的编码设置”中详细讨论过了,可以根据网页输出的具体方式在相应的章节找到编码的设置方法,这里就不重复了。2设置字符编码以正确解析 HTTP 请求当数据提交到服务器端后,一般在 Servlet 中进行字符编码的解析,然后获取用户输入,进行逻辑运算和业务处理。为了正确地解码用户输入,程序在读取 HTTP 请求之前,必须调用 ServletRequest.setCharacterEncoding()方法来设置合适的字符编码,以便将 HTTP请求中包含的字节流解码为字符流。protected final void doPost(HttpServletRequest req, HttpServ

37、letResponse resp)throws ServletException, IOException req.setCharacterEncoding(“UTF-8“);String input = req.getParameter(“order“);如上例所示,在 Servlet 的 doPost()方法中,首先调用 setCharacterEncoding(),以便将UTF-8 设置为字符编码,然后读取名为 order 的输入参数。这里 setCharacterEncoding()设置的编码必须和浏览器提交数据所使用的字符编码一致,上例中即为 UTF-8,否则,就会导致读入的字符串为

38、乱码。关于 setCharacterEncoding()方法,一个需要强调的要点是:必须在读取 HTTP 请求之前设置编码,否则是无效的。这里说的“读取 HTTP 请求” 不仅包括使用 getParameter(), getParameterMap(),getParameterNames()和 getParameterValues()之类的方法,还包括getReader() 方法,比如下面就是一个错误的例子。protected final void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletExc

39、eption, IOException Reader reader = req.getReader();req.setCharacterEncoding(“UTF-8“); / 错误!必须在 getReader() 之前调用!String input = req.getParameter(“order“); / 有可能读入乱码对于一般的程序,要确保在第一时间调用 setCharacterEncoding()可能极为简单,但是,如果使用了比较复杂的 Web 层框架,情形就会不同。因为程序的控制权往往并不直接进入应用程序代码,而是通过框架转发调用再进入应用程序,此时如果在框架内部首先读取了 HTT

40、P 请求,那么在应用程序中调用 setCharacterEncoding()就为时已晚。因此,根据所使用的 Web 框架的不同,调用 setCharacterEncoding()的时机和位置都有可能不同,需要根据具体情况而定。上面的示例仅对最普通的 Servlet 而言,并不适用于所有的 Web 框架。后面的章节会对一些主流的 Web 框架进行与国际化相关的具体分析。3设置 Servlet 的响应字符编码在大多数情况下,Java 应用程序通过 JSP 生成 HTML 文档,作为响应发回浏览器,相关的设置已经在 6.2.2 中的“2 设置 JSP 响应字符编码”中介绍过了。然而,也存在个别特殊情

41、况,程序会选择由 Servlet 直接生成响应,此时就需要在 Servlet 中设置响应的字符编码。在 ServletAPI 中,有三个方法可以用于设置响应字符编码,它们都在 ServletResponse 接口中定义,分别是 setCharacterEncoding(), setContentType()和 setLocale()。一般推荐用 setContentType()或者 setCharacterEncoding()设置编码。它们的用法大致如下:protected final void doPost(HttpServletRequest req, HttpServletRespons

42、e resp)throws ServletException, IOException resp.setCharacterEncoding(“UTF-8“);resp.setContentType(“text/html; charset=UTF-8“);PrintWriter writer = resp.getWriter();writer.println(“.“);两个方法都会在 HTTP 响应头中加入 ContentType 声明,通知浏览器响应内容的字符编码。仅当旧版本的 Servlet 规范不支持 setContentType()和 setCharacterEncoding()时,才会

43、使用 setLocale()。调用 setLocale()会导致采用和语言相关的默认编码,但仍通过ContentType 响应头通知客户端。这里同样需要注意,设置响应编码必须在输出响应之前执行,否则将起不到预期的效果。下面是一个错误例子。protected final void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException PrintWriter writer = resp.getWriter();writer.println(“.“);resp.setC

44、haracterEncoding(“UTF-8“); / 错误,必须在 getWriter() 之前设置4小结将 UTF-8 设置为网页编码,以 UTF-8 提交数据。调用 ServletRequest.setCharacterEncoding()设置编码解析 HTTP 请求。如果不通过 JSP,而是通过 Servlet 直接生成响应,那么调用 ServletResponse 接口中定义的 setCharacterEncoding()或者 setContentType()来设置响应字符编码。6.2.4 主流 Web 框架的编码设置在实际项目开发中,往往不会直接使用 Servlet/JSP,更多

45、的是在一些 Web 框架的基础上搭建应用程序,这些 Web 框架在带来完善的设计模式的同时,也对 Serlet/JSP 编程接口进行包装和扩展,这在一定程度上造成了不小的学习曲线。习惯在 Servlet/JSP 模式下工作的开发人员有时也会产生困扰:如何在这些框架下写出支持国际化的代码呢?面对更丰富的编程接口和类继承,应该从何处入手,通过什么方法来设置恰当的字符编码呢?本节将尝试回答这些问题。1Struts 框架下的编码设置Struts 可能是时下最流行的 Web 框架,它推荐的 MVC 模式几乎是所有 Web 应用程序的首选。从原理上说,Struts 是基于 Servlet/JSP 的一种扩

46、展,就设置字符编码而言,仍然是通过 Servlet 编程接口来执行,其不同处主要在于设置编码的时机。与 Servlet 不同,在 Struts 框架下,服务器端的程序入口并不在应用程序,而总是经由Struts 框架,再辗转进入应用程序的操作(Action)逻辑,这对需要在第一时间设置的字符编码造成了不小的困扰。更重要的是,Struts 还负责自动从 HTTP 请求读取表单输入,并导入 ActionForm 中,以供应用程序使用。所以,必须寻找到一个时机,在 Struts 读取HTTP 请求之前完成编码设置。纵观 Struts 框架,最合适设置编码的位置是 ActionForm 的 reset(

47、)方法。该方法在每次重置 ActionForm 时调用,紧接着 Struts 就会从 HTTP 请求读取表单输入。下面是一个范例。public class SampleForm extends ActionForm public void reset(ActionMapping mapping, HttpServletRequest request) / 在此设置字符编码request.setCharacterEncoding(“UTF-8“);.具体设置的方法与 Servlet 中的编码设置一样,更详细的内容可以参阅 6.2.3 节中的“2设置字符编码以正确解析 HTTP 请求”。2使用过滤

48、器的通用编码设置方法Java 社区框架种类繁多是出名的。除了 Struts 以外,其他的 Web 框架也如雨后春笋般层出不穷。每一个框架都有自己的个性和特质,实现国际化、设置编码的方法都有可能不同。逐一分析每一个框架,寻找恰当时机和位置来设置字符编码固然可行,但有没有更通用的方法,能够普遍适用于大多数 Web 框架呢?答案是:有。Servlet 规范 V2.3 引入了过滤器(Filter)机制,这是一种非常有用的工具,能够通用地设置 Web 层的字符编码。其原理是,通过恰当的配置,过滤器可以在所有的HTTP 请求进入 Servlet 之前进行拦截,从而保证在调用 Web 框架之前(不论什么框架,其入口总是一个特定的 Servlet)第一时间完成字符编码的设置。关于过滤器的详细说明和使

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 实用文档 > 往来文书

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报