Tomat &servlet字符集编码问题

1.字符编码的原由

1.1 request和response的默认编码是?

如果未指定字符编码,则Servlet规范要求使用ISO-8859-1的编码。 HTTP消息正文(请求或响应)的字符编码在Content-Type头字段中指定。 如Content-Type:text / html; charset = ISO-8859-1明确声明正在使用默认值(ISO-8859-1)。见HTTP 1.1 Specification, Section 3.7.1最后一段。

JSP规范进一步指定了JSP页面的行为。 请求字符编码处理是相同的,但响应字符编码的行为略有不同。 请参阅“JSP.4.2响应字符编码”一章。 对于标准语法中的JSP页面,默认响应字符集是通常的ISO-8859-1,但对于XML语法中的字符串,它是UTF-8。

1.2 request和response的默认编码为什么是它们?

从容器角度:

先说请求编码,目前许多浏览器不会随着Content-Type发送字符编码,即Content-Type没有"charset=utf-8"这样的字段。因此,怎么对请求进行解码,Servlet 3.1和Servlet 4.0都对此进行了说明。

Servlet 3.1

在没有charset限定符的情况下,容器对请求的解码将使用ISO-8859-1字符集进行解码。为了显示Content-Type没有指定charset,request.getCharaterEncoding()将返回null;

Servlet4.0

在没有charset限定符的情况下,如果Content-Type是application / x-www-form-urlencoded,则容器用于创建请求阅读器和解析POST数据的默认编码必须是US-ASCII,任何%nn编码值必须解码为ISO-8859-1。

如何Content-Type是任何其他类型,如果客户端请求,Web应用程序(在web.xml中没有指定)或容器供应商特定配置(对于容器中的所有Web应用程序)都没有指定,则默认编码为请求容器用于创建请求读取器和解析POST数据必须是ISO-8859-1。

从上述的两个规范看出,如客户端没有设置字符编码,servlet无法知道编码,如果请求数据使用与上述默认编码不同的编码进行编码,则可能发生破坏。

——————————————————————————————————————————————————————————

从浏览器角度:

GET的默认编码:

HTTP查询字符串的编码规范(即GET请求的参数 )RFC 3986 在2.1和2.2节有说明。字符集定义为US-ASCII。任何未映射到US-ASCII的字符都必须以某种方式(也就是说没有指定)进行编码。 URI语法规范的2.1节说明US-ASCII之外的字符必须使用%转义序列进行编码:每个字符编码为文字%,后跟两个十六进制代码,表示其字符代码。因此,(字符”中“)等同于%E4%B8%AD。虽然URI规范没有强制要求URI的默认编码,但它建议使用UTF-8,特别是对于新的URI方案,并且大多数现代用户代理已经确定UTF-8用于编码URI字符。

注意:1. ISO-8859-1和ASCII兼容字符代码0x20至0x7E,因此它们通常可互换使用。
           2. 使用UTF-8编码URI的现代浏览器。某些浏览器似乎使用当前页面的编码来编码链接的URI,Chrome使用UTF-8。
           3. HTML 4.0建议使用UTF-8对查询字符串进行编码。

POST的默认编码:

  较早版本的HTTP / 1.1规范(例如RFC 2616)表明,如果没有指示字符集,ISO-8859-1是基于文本的HTTP请求和响应主体的默认字符集。尽管RFC 7231删除了此缺省值,但servlet规范仍然适用。因此,servlet规范指示如果POST请求不指示编码,则必须将其处理为ISO-8859-1,但application / x-www-form-urlencoded除外,默认情况下应将其解释为US-ASCII(因为它根据定义应该只包含ASCII范围内的字符开头)。

关于POST请求的字符编码的一些注意事项:

RFC 2616第3.4.1节规定,如果请求有"charset=charsetName",HTTP消息的接收者必须遵守Content-Type头中发件人指定的字符编码。丢失的字符允许收件人“猜测”适当的编码。

今天的大多数Web浏览器都没有指定请求的字符集,即使它不是ISO-8859-1。这似乎违反了HTTP规范。大多数Web浏览器似乎使用用页面的编码来发送请求正文(例如,<form>元提交的参数编码是根据页面的编码来编码的)。

ContentType为application / x-www-form-urlencoded的URI编码:

HTML 4.01规范指出应该使用US-ASCII字节序列执行application / x-www-form-urlencoded(HTML表单提交的默认内容类型)的任何非字母数字字符的百分比编码。但是HTML 5将其更改为使用UTF-8字节序列,匹配URL的现代URI编码。因此,现代浏览器在使用application / x-www-form-urlencoded提交表单时用UTF-8对其进行编码。

但是,servlet规范要求servlet容器将ContentType为application / x-www-form-urlencoded的请求正文用ISO-8859-1解码,在默认配置中,由于字符集不匹配,将导致内容损坏。请参阅下文,了解如何在Tomcat中重新配置它。

HTTP Header的编码。

ARPA Internet文本消息规范的第3.1节规定Header始终采用US-ASCII编码。除此之外的任何东西都需要编码,参阅上面有关URI中查询字符串的部分。

 

1.3 URIEncoding&useBodyEncodingForURI是什么?

两者都是Http connector的属性。见apache-tomcat-9.0.16-src\java\org\apache\catalina\connector\Connector.java中的源码。

URIEncoding:

指定用于解码URI所用的字符集。 如果未指定,Tomat 9.0将使用UTF-8,除非org.apache.catalina.STRICT_SERVLET_COMPLIANCE系统属性设置为true,在这种情况下将使用ISO-8859-1

useBodyEncodingForURI

这指定了contentType中指定的编码是否应该用于URI查询参数,而不是使用URIEncoding。 此设置用于与Tomcat 4.1.x兼容,其中在contentType中指定的编码或使用Request.setCharacterEncoding方法显式设置的编码也用于URL中的参数。 默认值为false。

注意:1)此设置仅应用于请求的查询字符串。 与URIEncoding不同,它不会影响请求URI的路径部分。 2)如果请求字符编码未知(由浏览器提供并且未由SetCharacterEncodingFilter或使用Request.setCharacterEncoding方法的类似过滤器设置),则默认编码始终为“ISO-8859-1”。 URIEncoding设置对此默认设置没有影响。

怎么处理字符编码问题

 2.1 怎样改变GET参数的解码?

  Tomcat将使用ISO-8859-1作为整个URL的默认字符编码,包括查询字符串(“GET参数”)。
  有两种方法可以指定如何解释GET参数:

  1. 将server.xml中<Connector>元素上的URIEncoding属性设置为特定的(例如URIEncoding =“UTF-8”)。

  2. 将server.xml中<Connector>元素的useBodyEncodingForURI属性设置为true。 这将导致Connector使用请求正文的GET参数编码。

  从Tomat 8开始,<Connector>元素上的URIEncoding属性的默认值取决于“strict servlet compliance”设置。 URIEncoding的默认值是UTF-8(strict servlet compliance=false)。 如果启用了“strict servlet compliance=true”,则默认值为ISO-8859-1。

2.2 怎样改变POST参数的解码

  POST请求应指定它们发送的参数和值的编码。由于许多客户端没有显式编码,因此当ContentType为application-x-www-form-urlencoded时,使用US-ASCII解码POST请求,当ContentType为其它类型时,使用ISO-8859-1解码POST请求。

  然而,servlet规范要求,ContentType 为application / x-www-form-urlencoded的请求,URI默认解释为ISO-8859-1。但是,HTML 5 推荐使用UTF-8对URI进行编码,并且很多的浏览器都是用UTF-8对URI进行编码的。可见,servlet规范与实际的实现存在冲突。

尽管如此,servlet规范要求servlet容器对ContentType为application / x-www-form-urlencoded的URI的解释遵循任何已配置的字符编码。因此,通过将请求字符编码设置为UTF-8,可以实现对application / x-www-form-urlencoded字节序列的适当解释(见Servlet 4.0 3.12节)。

  即在应用程序中的web.xml中设置  <request-character-encoding>UTF-8<request-character-encoding>

或设置一个charsetEncoding 的filter,指定request的解码方式。也可以在Tomcat安装配置文件conf / web.xml中定义这样的过滤器,该文件将在所有Web应用程序中设置请求字符编码,而无需任何web.xml修改。事实上,最新的Tomcat版本附带了conf / web.xml中的部分,这些部分已经配置了一个过滤器,用于将请求字符编码设置为UTF-8。只需编辑conf / web.xml并取消注释名为setCharacterEncodingFilter的过滤器的定义和映射。

tips: setCharacterEncodingFilter.java源码在apache-tomcat-9.0.16-src\java\org\apache\catalina\filters。

注意:request编码设置仅在解析参数之前完成时才有效。一旦解析发生,就没有办法回来了。参数解析由请求参数名称或值的第一个方法触发。确保过滤器位于要求请求参数的任何其他过滤器之前。定位取决于WEB-INF / web.xml文件中过滤器映射声明的顺序,但是由于Servlet 3.0规范还有其他选项来控制顺序。要检查实际的顺序,可以从页面中抛出异常并检查其堆栈跟踪以获取过滤器名称。

2.3 如何在任何地方使用UTF-8。

  使用UTF-8作为一切的字符编码是一个安全的选择。 这应该适用于几乎所有情况。

  1. 在server.xml中的<Connector>上设置URIEncoding =“UTF-8”。

  2. 在Tomcat conf / web.xml文件或web app web.xml文件中设置默认请求字符编码;通过设置<request-character-encoding>或使用字符编码过滤器。

  3. 更改所有JSP以在其contentType中包含charset名称。例如,对于通常的JSP页面使用<%@ page contentType =“text / html; charset = UTF-8”%>,使用<jsp:directive.page contentType =“text / html; charset = UTF-8”/>对于XML语法中的页面。

  4. 更改所有servlet以设置响应的内容类型,并在内容类型中包含charset name为UTF-8。使用response.setContentType(“text / html; charset = UTF-8”)或response.setCharacterEncoding(“UTF-8”)。

  5. 更改您使用的任何内容生成库(Velocity,Freemarker等)以使用UTF-8并在其生成的响应的内容类型中指定UTF-8。

  6. 在字符编码过滤器或jsp页面有机会将编码设置为UTF-8之前,禁用可能读取请求参数的任何Valves或filter。

2.4 怎样测试配置是否正常工作?

<%@ page contentType="text/html; charset=UTF-8" %>
<!-- 表单的数据编码与页面的编码相同, 对于这个JSP,是UTF-8-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <title>Character encoding test page</title>
</head>
<body>
<p>Data posted to this form was:
    <%
        /* 在解码参数前,设置用什么字符集解码参数 */
        request.setCharacterEncoding("UTF-8");
        /* 解码数据 */
        out.print(request.getParameter("mydata"));
    %>
</p>
<form method="POST" action="testEncoding.jsp">
    <input type="text" name="mydata">
    <input type="submit" value="Submit" />
    <input type="reset" value="Reset" />
</form>
</body>
</html>

 

URI编码总结
==========================

在URI中有两种情况使用非US-ASCII字符:
- GET方法中的查询字符串
- Servlet的路径

URI的标准编码在 (https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_in_a_URI) ,但是这个标准并不是所有客户端一贯遵循的,因此导致很多问题。

Tomcat提供五一些功能解决这种不太理想的情况

1. Coyote HTTP/1.1连接器具有useBodyEncodingForURI属性,如果设置为true,则使用请求主体编码来解码URI查询参数。  -Tomat9.0.16的默认值为false;

2. Coyote HTTP/1.1 connector 有一个URIEncoding属性,默认值是UTF-8。
3. 关于请求的类(o.a.t.u.http.Parameters)有一个queryStringEncoding 属性,默认值是UTF-8的值。
必须在解码参数前设置此字段方可生效。

servlet API中需要注意的问题:
1. HttpServletRequest.setCharacterEncoding()只能应用于request的实体正文request body)而不是URI。
2. HttpServletRequest.getPathInfo() 由Web容器解码。
3. HttpServletRequest.getRequestURI() 不是由容器解码。

tips:
1. 在表单中使用POST提交参数,这样参数就会是请求正文的一部分

原文地址:https://www.cnblogs.com/yvkm/p/10551484.html

时间: 2024-11-16 17:25:09

Tomat &servlet字符集编码问题的相关文章

Servlet字符编码过滤器

在Java Web程序开发中,由于Web容器内部使用编码格式并不支持中文字符集,所以,处理浏览器请求中的中文数据就会出现乱码的现象.由于Web容器使用了ISO-8859-1的编码格式,所以在Web应用的业务处理中也会使用ISO-8859-1编码格式.虽然浏览器提交的请求使用的是中文编码格式UTF-8,但经过业务处理中的ISO-8859-1编码,仍然会出现中文乱码现象.解决此问题的方法非常简单,在业务处理中重新指定中文字符集进行编码即可解决.在实际的开发过程中,如果通过每一个业务处理指定中文字符集

Filter过滤器(自动登陆、通用的字符集编码的过滤【处理不同请求的乱码问题】、。。。)

Filter过滤器:可以过滤(拦截)从客户端向服务器发送的请求. 过滤器的作用: 进行ip的过滤,脏话敏感词语的过滤,自动登陆,响应压缩... 过滤器的使用: 1.编写类实现Filter接口. destroy()销毁 doFilter(servletRequest request,ServletResponse response,FilterChain chain)拦截过滤 eg:chain.doFilter(request,response);//执行此代码表示放行到下一个过滤器中,如果没有下

Linux下MySQL5.6的修改字符集编码为UTF8

一.登录MySQL查看用SHOW VARIABLES LIKE 'character%';下字符集,显示如下: +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_conn

12月30日作业-&lt;转&gt;字符集编码

1.基础知识 计算机中储存的信息都是用二进制数表示的:而我们在屏幕上看到的英文.汉字等字符是二进制数转换之后的结果.通俗的说,按照何种规则将字符存储在计算机中,如'a'用什么表示,称为"编码":反之,将存储在计算机中的二进制数解析显示出来,称为"解码",如同密码学中的加密和解密.在解码过程中,如果使用了错误的解码规则,则导致'a'解析成'b'或者乱码. 字符集(Charset):是一个系统支持的所有抽象字符的集合.字符是各种文字和符号的总称,包括各国家文字.标点符号

MySQL字符集编码

MySQL字符集编码总结 之前内部博客上凯哥分享了一篇关于mysql字符集的文章,之前我对mysql字符集一块基本没有深究过,看到凯哥文章后有些地方有点疑惑,遂自己去看了mysql的官方文档,并参考了凯哥的文章,总结了这篇博文.本文主要是对mysql常见的字符集问题进行整理,如有错误,请大家指正. 1.MySQL字符集编码简介 谈到字符集,总会跟编码扯上关系,有关字符集和编码的理论知识请参见我之前的文章.MySQL内部是支持多种字符集的,这里就不再严格区分字符集和编码的概念了.同时,MySQL中

字符编码乱码问题(servlet底层 编码大揭秘)

好多初学者会遇到,请求过去的信息内包含中文(一般会是get方式提交过去的请求会出现).好郁闷,这是为什么呢.有下面分析下,说的不好可以吐槽 话说我们能遇到这种编码的问题,归根结底就是这  这 web开发不是中国人开发的,中国文化博大精深,四大发明渊源流传,可惜,我们太自己为是了,来了个闭关锁国政策,弄得中国跟不上时代的步伐,不潮了,落伍了,互联网时代被西方人抢了个先,发明了,我们只能用别人的了.我们也知道,西方讲的是英语,所以他们采用的编码格式是iso-8895-1.而这  这种编码方式只占两个

JavaScript字符集编码与解码

一.字符集 1)字符与字节(Character) 字符是各种文字和符号的总称,包括乱码:一个字符对应1~n个字节,一字节对应8位,每位用0或1表示. 2)字符集(Character Set) 字符集是多个字符的集合,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集.GB2312字符集.Unicode字符集等. 3)字符集编码(Character Encoding) 字符集编码就是将符号转换为计算机可读的二进制,解码就是把二进制转换为人类可读的符号. 字符集大多对应一种编码方式(例如

linux 之字符集编码

1.linux系统上有时会遇到字符集乱码问题,常用的也就是英文和中文的转换而已 [[email protected] ~]# echo $LANG zh_CN.UTF-8 [[email protected] ~]# export LANG=en_us #这样修改只是暂时有效 #若长期有效需在配置文件中修改 [[email protected] ~]# cat /etc/sysconfig/i18n LANG="zh_CN.UTF-8" linux系统支持的字符集可以用locale指令

你不知道的 字符集和编码(编码字符集与字符集编码)

我的上篇文章,有朋友提出字符集和编码的区别,我在此立文和大家讨论下 常说的字符集和编码区别,其实就是编码字符集和字符集编码的区别,其实,单单如果只是说字符集,没有任何编码的概念的话,那么字符集其实仅仅是一个简单的字符的集合,或者说是一个抽象的字符的集合,包括文字,符号等等,不参与任何存储形式,只是存在这么各种各样标准的字符的集合 如果仅仅是抽象的字符集,我们是无需拿出讨论的,因为没有任何异议,通俗易懂,而常说的字符集指的编码字符集,比如常见的 unicode.ascii.gb2312.gbk等,