URIEncoding与useBodyEncodingForURI 在tomcat中文乱码处理上的区别及CharacterEncodingFilter...

本文探讨了Tomcat中处理中文乱码的问题,主要聚焦于GET请求中的中文字符乱码现象。介绍了通过设置URIEncoding和useBodyEncodingForURI参数来解决乱码的方法,并解释了这两个参数的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家知道tomcat5.0开始,对网页的中文字符的post或者get,经常会出现乱码现象。

 

具体是因为Tomcat默认是按ISO-8859-1进行URL解码,ISO-8859-1并未包括中文字符,这样的话中文字符肯定就不能被正确解析了。

 

常见的解决方法是在tomcat的server.xml下的connetor属性中增加URIEncoding或者useBodyEncodingForURI属性。

 

但是,这两种方式有什么区别呢?

 

我简单谈一下自己的理解:

 

按照tomcat-docs/config/http.html文档的说明

 

URIEncoding:This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used. 

useBodyEncodingForURI:This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding.

 

 

 

也就是说,

 

 useBodyEncodingForURI参数表示是否用request.setCharacterEncoding 
参数对URL提交的数据和表单中GET方式提交的数据进行重新编码,在默认情况下,该参数为false。

 

URIEncoding参数指定对所有GET方式请求进行统一的重新编码(解码)的编码。

 

 

 

URIEncoding和useBodyEncodingForURI区别是,

 

URIEncoding是对所有GET方式的请求的数据进行统一的重新编码,

 

而useBodyEncodingForURI则是根据响应该请求的页面的request.setCharacterEncoding参数对数据进行的重新编码,不同的页面可以有不同的重新编码的编码

 

 

 

 

 

再详细点的======================================================================================================

 

本文章会从tomcat的源码角度来解析Tomcat的两个参数设置URIEncoding和useBodyEncodingForURI。 

对于一个请求,常用的有两种编码方式,如下:
 

 

Java代码  收藏代码
  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta charset="utf-8" />  
  5.         <title></title>  
  6.     </head>  
  7.     <body>  
  8.         <form action="http://127.0.0.1:8080/string?name=中国" method="post">  
  9.             <input type="text" name="user" value="张三"/>  
  10.             <input type="submit" value="提交"/>  
  11.         </form>  
  12.     </body>  
  13. </html>  


首先说说结论: 
上述请求有两处含有中文,一处是请求参数中,即?name='中国',另一处是请求体中,即user='张三'。对于这两处tomcat7是分两种编码方式的。URIEncoding就是针对请求参数的编码设置的,而filter的request.setCharacterEncoding('UTF-8')或者请求header中的content-type中的编码都是针对请求体的。不要把他们搞混了。 

useBodyEncodingForURI=true是说,请求参数的编码方式要采用请求体的编码方式。当useBodyEncodingForURI=true时,若请求体采用utf-8解析,则请求参数也要采用utf-8来解析。这两个属性值的设置在tomcat的conf/server.xml文件中配置,如下:
 

Java代码  收藏代码
  1. <Service name="Catalina">  
  2.   
  3.    <!--The connectors can use a shared executor, you can define one or more named thread pools-->  
  4.    <!--  
  5.    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"  
  6.        maxThreads="150" minSpareThreads="4"/>  
  7.    -->  
  8.   
  9.   
  10.    <!-- A "Connector" represents an endpoint by which requests are received  
  11.         and responses are returned. Documentation at :  
  12.         Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)  
  13.         Java AJP  Connector: /docs/config/ajp.html  
  14.         APR (HTTP/AJP) Connector: /docs/apr.html  
  15.         Define a non-SSL HTTP/1.1 Connector on port 8080  
  16.    -->  
  17.    <Connector port="8080" protocol="HTTP/1.1"  
  18.               connectionTimeout="20000"  
  19.               redirectPort="8443" useBodyEncodingForURI='true' URIEncoding='UTF-8' />  
  20.    <!-- A "Connector" using the shared thread pool-->  


这样写只是说明这两者的配置位置,并不是两个属性要同时配置,不要理解错了。 
继续说说CharacterEncodingFilter的作用。 
使用方式,将如下代码加入web.xml文件中:
 

Java代码  收藏代码
  1. <filter>  
  2.         <filter-name>encoding</filter-name>  
  3.         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
  4.         <init-param>  
  5.             <param-name>encoding</param-name>  
  6.             <param-value>UTF-8</param-value>  
  7.         </init-param>  
  8.         <init-param>  
  9.             <param-name>forceEncoding</param-name>  
  10.             <param-value>true</param-value>  
  11.         </init-param>  
  12.     </filter>  
  13.   
  14.     <filter-mapping>  
  15.         <filter-name>encoding</filter-name>  
  16.         <url-pattern>/*</url-pattern>  
  17.     </filter-mapping>  


作用是,当forceEncoding为false的前提下(默认为false),当request没有指定content-type或content-type不含编码时,该filter将会为这个request设定请求体的编码为filter的encoding值。 
当forceEncoding为true的前提下,就会为request的请求体和response都设定为这个filter的encoding值。 
CharacterEncodingFilter源码如下:
 

Java代码  收藏代码
  1. public class CharacterEncodingFilter extends OncePerRequestFilter {  
  2.   
  3.     private String encoding;  
  4.   
  5.     private boolean forceEncoding = false;  
  6.   
  7.   
  8.     /** 
  9.      * Set the encoding to use for requests. This encoding will be passed into a 
  10.      * {@link javax.servlet.http.HttpServletRequest#setCharacterEncoding} call. 
  11.      * <p>Whether this encoding will override existing request encodings 
  12.      * (and whether it will be applied as default response encoding as well) 
  13.      * depends on the {@link #setForceEncoding "forceEncoding"} flag. 
  14.      */  
  15.     public void setEncoding(String encoding) {  
  16.         this.encoding = encoding;  
  17.     }  
  18.   
  19.     /** 
  20.      * Set whether the configured {@link #setEncoding encoding} of this filter 
  21.      * is supposed to override existing request and response encodings. 
  22.      * <p>Default is "false", i.e. do not modify the encoding if 
  23.      * {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()} 
  24.      * returns a non-null value. Switch this to "true" to enforce the specified 
  25.      * encoding in any case, applying it as default response encoding as well. 
  26.      * <p>Note that the response encoding will only be set on Servlet 2.4+ 
  27.      * containers, since Servlet 2.3 did not provide a facility for setting 
  28.      * a default response encoding. 
  29.      */  
  30.     public void setForceEncoding(boolean forceEncoding) {  
  31.         this.forceEncoding = forceEncoding;  
  32.     }  
  33.   
  34.   
  35.     @Override  
  36.     protected void doFilterInternal(  
  37.             HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
  38.             throws ServletException, IOException {  
  39.   
  40.         if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {  
  41.             request.setCharacterEncoding(this.encoding);  
  42.             if (this.forceEncoding) {  
  43.                 response.setCharacterEncoding(this.encoding);  
  44.             }  
  45.         }  
  46.         filterChain.doFilter(request, response);  
  47.     }  
  48.   
  49. }  


这个filter有两个属性,encoding和forceEncoding,我们可以在web.xml文件中来设定这两个属性值。 
每次request请求到来执行方法doFilterInternal,首先调用request.getCharacterEncoding(),本质就是从请求header content-type中获取编码值,如果没有,则调用request.setCharacterEncoding(this.encoding)将该filter的encoding值设置为请求体的编码方式,记住该编码方式只对请求体,不针对请求参数。当forceEncoding=true时,不管请求header content-type有没有编码方式,始终将该filter的encoding值设置到request和response中,同样只针对request的请求体。 

<think>我们之前提到在Servlet中添加request.setCharacterEncoding("UTF-8")来解决中文乱码问题。下面将详细解释这个问题及其解决方案,并提供完整的代码示例。###问题描述在Web应用中,当客户端(如浏览器)通过POST请求提交表单数据时,如果包含中文字符,服务器端接收到的字符串可能会显示为乱码。这是因为客户端和服务器端在字符编码上不一致导致的。常见的场景包括:-表单提交(method="post")-通过AJAX发送POST请求###原因分析1.**请求编码服务器解码不一致**:-浏览器通常使用UTF-8编码发送数据-服务器默认使用ISO-8859-1解码2.**GET请求POST请求的区别**:-POST请求:参数在请求体中,可以通过`request.setCharacterEncoding("UTF-8")`设置-GET请求:参数在URL中,设置`request.setCharacterEncoding`无效,需要在服务器配置(如Tomcat的server.xml)中设置URIEncoding="UTF-8"###解决方案####1.对于POST请求在获取任何参数之前,设置请求对象的字符编码为UTF-8。**在Servlet中添加:**```javaprotectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{//设置请求字符编码为UTF-8request.setCharacterEncoding("UTF-8");//其他处理逻辑...}```####2.对于GET请求修改Tomcat的配置文件`conf/server.xml`,在Connector标签中添加`URIEncoding="UTF-8"`:```xml<Connectorport="8080"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"URIEncoding="UTF-8"/>```####3.统一设置编码的过滤器(推荐)为了避免在每个Servlet中重复设置,可以使用过滤器统一设置请求和响应的编码。**创建字符编码过滤器:**```javapackagefilter;importjavax.servlet.*;importjavax.servlet.annotation.WebFilter;importjava.io.IOException;@WebFilter("/*")//过滤所有请求publicclassCharacterEncodingFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{//设置请求编码request.setCharacterEncoding("UTF-8");//设置响应编码response.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");chain.doFilter(request,response);}@Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{//初始化代码(可选)}@Overridepublicvoiddestroy(){//销毁代码(可选)}}```**在web.xml中配置(如果使用注解则无需配置):**```xml<filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>filter.CharacterEncodingFilter</filter-class></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>```####4.设置响应编码确保响应也使用UTF-8编码,避免返回给客户端的内容出现乱码。在Servlet中设置响应编码:```javaprotectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{response.setContentType("text/html;charset=UTF-8");//或者分别设置response.setCharacterEncoding("UTF-8");//其他处理逻辑...}```###完整示例:处理表单提交**HTML表单(add.jsp):**```jsp<%@pagecontentType="text/html;charset=UTF-8"language="java"%><html><head><metacharset="UTF-8"><title>添加学生</title></head><body><formaction="students"method="post"><inputtype="hidden"name="action"value="add">姓名:<inputtype="text"name="name"><br>邮箱:<inputtype="email"name="email"><br>课程:<inputtype="text"name="course"><br><inputtype="submit"value="提交"></form></body></html>```**Servlet(StudentServlet.java):**```javaprotectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{//如果使用了过滤器,这里可以不用再设置//request.setCharacterEncoding("UTF-8");Stringname=request.getParameter("name");//此时name应该正确显示中文//设置响应编码response.setContentType("text/html;charset=UTF-8");//其他业务逻辑...}```###测试乱码问题1.在表单中输入中文字符,如“张三”2.提交表单3.在Servlet中获取参数并打印,检查是否为正确的中文###注意事项1.**设置顺序**:`request.setCharacterEncoding("UTF-8")`必须在获取参数之前调用2.**GET请求**:对于GET请求,修改Tomcat配置后需要重启服务器3.**响应编码**:同时设置响应编码,确保返回给浏览器的内容也是UTF-8编码4.**页面编码**:JSP页面顶部添加`<%@pagepageEncoding="UTF-8"%>`和`<metacharset="UTF-8">`###常见问题排查1.**过滤器不生效**:-检查`@WebFilter("/*")`或web.xml中的配置-确保过滤器在第一个位置(可通过web.xml中`<filter-mapping>`的顺序控制)2.**Tomcat配置不生效**:-检查server.xml中Connector的配置是否正确-重启Tomcat3.**JSP页面乱码**:-在JSP顶部添加:`<%@pagecontentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%>`-在HTML中添加:`<metahttp-equiv="Content-Type"content="text/html;charset=UTF-8">`###总结通过统一设置请求和响应的字符编码为UTF-8,可以有效解决中文乱码问题。推荐使用过滤器进行全局设置,这样可以避免在每个Servlet中重复编码,并确保整个Web应用使用统一的编码。§§相关问题§§:1.为什么在GET请求中设置request.setCharacterEncoding无效?2.如何解决URL中包含中文参数时出现的乱码问题?3.在JSP页面中如何正确设置字符编码以避免乱码?4.除了UTF-8,还有哪些常用的字符编码?</think>## 解决 JSP/Servlet 中文乱码问题详解 中文乱码Web 开发中的常见问题,尤其是在处理表单提交和数据库交互时。下面我将详细解释如何通过 `request.setCharacterEncoding("UTF-8")` 解决中文乱码问题,并提供完整的解决方案。 ### 问题原因分析 中文乱码通常由以下原因引起: 1. **请求编码服务器解码不一致**:浏览器使用 UTF-8 发送数据,但服务器默认使用 ISO-8859-1 解码 2. **响应编码未设置**:服务器返回数据时未指定正确编码 3. **数据库连接字符集不匹配**:数据库连接未指定 UTF-8 4. **JSP 页面未声明编码**:页面未设置正确的字符编码 ### 完整解决方案 #### 1. 在 Servlet 中设置请求编码 ```java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置请求字符编码为UTF-8 request.setCharacterEncoding("UTF-8"); // 处理请求参数 String name = request.getParameter("name"); // ...其他业务逻辑 } ``` **关键点**: - 必须在获取任何请求参数**之前**设置编码 - 只对 POST 请求体有效,对 GET 请求无效 #### 2. 设置响应编码 ```java protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应内容类型和编码 response.setContentType("text/html; charset=UTF-8"); // 设置响应字符编码 response.setCharacterEncoding("UTF-8"); // 处理请求... } ``` #### 3. 添加字符编码过滤器(推荐) 创建全局过滤器解决所有请求的编码问题: ```java package filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter("/*") public class CharacterEncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化方法 } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 设置请求编码 request.setCharacterEncoding("UTF-8"); // 设置响应编码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8"); // 传递给下一个过滤器或Servlet chain.doFilter(request, response); } @Override public void destroy() { // 销毁方法 } } ``` 在 `web.xml` 中配置(如果未使用注解): ```xml <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` #### 4. 配置数据库连接使用 UTF-8 在数据库连接 URL 中添加字符集参数: ```java // 在DAO实现类中 private static final String URL = "jdbc:mysql://localhost:3306/student_db?useUnicode=true&characterEncoding=UTF-8"; ``` #### 5. 在 JSP 页面设置编码 在每个 JSP 页面顶部添加: ```jsp <%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> ``` 在 HTML 中设置: ```html <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ``` ### 处理 GET 请求中文乱码 对于 GET 请求中的中文参数,需要额外处理: ```java protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应编码 response.setContentType("text/html; charset=UTF-8"); // 处理GET请求中的中文参数 String name = request.getParameter("name"); if (name != null) { // 对ISO-8859-1编码的字符串进行转换 name = new String(name.getBytes("ISO-8859-1"), "UTF-8"); } // 使用处理后的参数... } ``` ### 完整示例:处理表单提交 #### 表单页面 (add.jsp) ```jsp <%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> <html> <head> <title>添加学生</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <form action="students" method="post"> <input type="hidden" name="action" value="add"> 姓名: <input type="text" name="name"><br> 邮箱: <input type="email" name="email"><br> 课程: <input type="text" name="course"><br> <input type="submit" value="保存"> </form> </body> </html> ``` #### Servlet 处理 (StudentServlet.java) ```java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 由过滤器统一处理编码,此处无需再设置 String action = request.getParameter("action"); if ("add".equals(action)) { // 获取参数(已正确解码) String name = request.getParameter("name"); String email = request.getParameter("email"); String course = request.getParameter("course"); // 创建学生对象 Student student = new Student(name, email, course); // 保存到数据库 studentDAO.addStudent(student); // 重定向到列表页 response.sendRedirect("students"); } } ``` ### 乱码问题排查流程 1. **检查请求编码**: - 确保在获取参数前设置 `request.setCharacterEncoding("UTF-8")` - 使用过滤器统一处理 2. **检查响应编码**: - 设置 `response.setContentType("text/html; charset=UTF-8")` - 检查 JSP 页面的 `pageEncoding` 和 `contentType` 3. **检查数据库连接**: - 确认连接字符串包含 `?useUnicode=true&characterEncoding=UTF-8` - 验证数据库和表的字符集为 UTF-8 4. **检查浏览器设置**: - 确保浏览器使用 UTF-8 编码(右键 > 编码 > UTF-8) - 添加 HTML meta 标签指定编码 5. **检查服务器配置**: - 在 Tomcat 的 `server.xml` 中配置 URI 编码: ```xml <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" /> ``` ### 最佳实践 1. **统一使用 UTF-8 编码**: - 项目文件、数据库、服务器配置全部使用 UTF-8 2. **使用字符编码过滤器**: - 创建全局过滤器处理所有请求响应编码 3. **验证数据库字符集**: ```sql SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'collation%'; ``` 4. **测试中文输入**: - 使用各种边界情况测试(长文本、特殊字符) 5. **日志记录**: ```java System.out.println("原始参数值: " + request.getParameter("name")); ``` ### 常见问题解决 1. **表单提交后仍然是乱码**: - 确认 `request.setCharacterEncoding()` 在获取参数**前**调用 - 检查是否使用了 GET 方法提交表单(改用 POST) 2. **数据库保存后显示乱码**: - 验证数据库连接字符串包含字符集参数 - 检查数据库表的字符集设置 3. **JSP 页面显示乱码**: - 确认页面顶部有 `<%@ page pageEncoding="UTF-8" %>` - 添加 `<meta charset="UTF-8">` 4. **URL 参数中文乱码**: - 在 Tomcat 的 `server.xml` 中配置 `URIEncoding="UTF-8"` - 或者手动解码: ```java String param = new String(request.getParameter("name").getBytes("ISO-8859-1"), "UTF-8"); ``` ### 总结 通过系统性地设置请求编码、响应编码、数据库连接编码和页面编码,可以彻底解决 JSP/Servlet 中的中文乱码问题。推荐使用全局过滤器统一处理编码问题,确保整个应用使用 UTF-8 字符集。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值