精华内容
下载资源
问答
  • 本文章会从tomcat的源码角度来解析Tomcat的两个参数设置URIEncoding和useBodyEncodingForURI。对于一个请求,常用的有两种编码方式,如下: Java代码 <!DOCTYPE html>  <...

    本文章会从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的请求体。

    以上的结论说完了,下面就要看看源代码了。不想看的就算了不影响使用,想看看原理的请继续:

    首先是三个名词:
    org.apache.coyote.Request:这是一个最底层的request,包含各种参数信息。暂且称为coyoteRequest。
    org.apache.catalina.connector.Request:实现了HttpServletRequest接口,称它为request,同时包含了一个coyoteRequest,一个connector,待会你就会发现这个connector的编码传递作用。
    org.apache.catalina.connector.RequestFacade:同样实现了HttpServletRequest接口,它仅仅是一个装饰类,称它为requestFacade,构造函数为:

    Java代码   收藏代码
    1. /** 
    2.      * Construct a wrapper for the specified request. 
    3.      * 
    4.      * @param request The request to be wrapped 
    5.      */  
    6.     public RequestFacade(Request request) {  
    7.   
    8.         this.request = request;  
    9.   
    10.     }  


    该构造函数将一个org.apache.catalina.connector.Request传进来,requestFacade的工作全是靠它内部的org.apache.catalina.connector.Request来完成的,org.apache.catalina.connector.Request又是依据它所包含的org.apache.coyote.Request这个最底层的类来完成的。通过org.apache.catalina.connector.Request,我们可以设定org.apache.coyote.Request的一些工作方式,如通过什么编码来解析数据。

    org.apache.coyote.Request含有的属性:
    String charEncoding:针对请求体的编码(在第一次解析参数时会传递给Parameters的encoding)
    Parameters :用于处理和存放请求参数和请求体参数的类
                (1)含String encoding:针对请求体的编码
                (2)含String queryStringEncoding:针对请求参数的编码
                (3)含Map<String,ArrayList<String>> paramHashValues:存放解析后的参数
    Parameters的两个编码是最最重要的编码,直接参与解析数据的编码,不像其他对象的编码大部分都是起传递作用,最终作用到Parameters的两个编码上

    Java代码   收藏代码
    1. public class MyCharacterEncodingFilter extends CharacterEncodingFilter{  
    2.   
    3.     @Override  
    4.     protected void doFilterInternal(HttpServletRequest request,  
    5.             HttpServletResponse response, FilterChain filterChain)  
    6.             throws ServletException, IOException {  
    7.         request.setCharacterEncoding("UTF-8");  
    8.         String name=request.getParameter("user");  
    9.         System.out.println(name);  
    10.         request.setCharacterEncoding("UTF-8");  
    11.         String name1=request.getParameter("user");  
    12.         System.out.println(name1);  
    13.         super.doFilterInternal(request, response, filterChain);  
    14.     }  
    15. }  


    传给过滤器filter的HttpServletRequest request其实是org.apache.catalina.connector.RequestFacade类型的,我们看下获取参数的具体过程:
    requestFacade.getParameter("user")会传递到org.apache.catalina.connector.Request的相应方法,如下:

    Java代码   收藏代码
    1. public String getParameter(String name) {  
    2.   
    3.         if (!parametersParsed) {  
    4.             parseParameters();  
    5.         }  
    6.   
    7.         return coyoteRequest.getParameters().getParameter(name);  
    8.   
    9.     }  


    parametersParsed是org.apache.catalina.connector.Request的属性,用于标示是否已经解析过参数,如果解析过,便不再解析,直接从coyoteRequest的Parameters参数中取出。所以当已经解析过后,你再去设置编码,会无效的,因为它会直接返回第一次的解析结果。并且解析过程仅仅发生在第一次获取参数的时候。
    我们来看下parseParameters()这个解析参数的过程:

    Java代码   收藏代码
    1. /** 
    2.      * Parse request parameters. 
    3.      */  
    4.     protected void parseParameters() {  
    5.   
    6.         //解析发生后,便将是状态置为已解析  
    7.         parametersParsed = true;  
    8.   
    9.         Parameters parameters = coyoteRequest.getParameters();  
    10.         boolean success = false;  
    11.         try {  
    12.             // Set this every time in case limit has been changed via JMX  
    13.             parameters.setLimit(getConnector().getMaxParameterCount());  
    14.   
    15.             // getCharacterEncoding() may have been overridden to search for  
    16.             // hidden form field containing request encoding  
    17.             //重点1  
    18.             String enc = getCharacterEncoding();  
    19.             //重点2  
    20.             boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();  
    21.             if (enc != null) {  
    22.                 parameters.setEncoding(enc);  
    23.                 if (useBodyEncodingForURI) {  
    24.                     parameters.setQueryStringEncoding(enc);  
    25.                 }  
    26.             } else {  
    27.                 parameters.setEncoding  
    28.                     (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);  
    29.                 if (useBodyEncodingForURI) {  
    30.                     parameters.setQueryStringEncoding  
    31.                         (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);  
    32.                 }  
    33.             }  
    34.             //重点3  
    35.             parameters.handleQueryParameters();  
    36.   
    37.             if (usingInputStream || usingReader) {  
    38.                 success = true;  
    39.                 return;  
    40.             }  
    41.   
    42.             if( !getConnector().isParseBodyMethod(getMethod()) ) {  
    43.                 success = true;  
    44.                 return;  
    45.             }  
    46.   
    47.             String contentType = getContentType();  
    48.             if (contentType == null) {  
    49.                 contentType = "";  
    50.             }  
    51.             int semicolon = contentType.indexOf(';');  
    52.             if (semicolon >= 0) {  
    53.                 contentType = contentType.substring(0, semicolon).trim();  
    54.             } else {  
    55.                 contentType = contentType.trim();  
    56.             }  
    57.   
    58.             if ("multipart/form-data".equals(contentType)) {  
    59.                 parseParts();  
    60.                 success = true;  
    61.                 return;  
    62.             }  
    63.   
    64.             if (!("application/x-www-form-urlencoded".equals(contentType))) {  
    65.                 success = true;  
    66.                 return;  
    67.             }  
    68.   
    69.             int len = getContentLength();  
    70.   
    71.             if (len > 0) {  
    72.                 int maxPostSize = connector.getMaxPostSize();  
    73.                 if ((maxPostSize > 0) && (len > maxPostSize)) {  
    74.                     if (context.getLogger().isDebugEnabled()) {  
    75.                         context.getLogger().debug(  
    76.                                 sm.getString("coyoteRequest.postTooLarge"));  
    77.                     }  
    78.                     checkSwallowInput();  
    79.                     return;  
    80.                 }  
    81.                 byte[] formData = null;  
    82.                 if (len < CACHED_POST_LEN) {  
    83.                     if (postData == null) {  
    84.                         postData = new byte[CACHED_POST_LEN];  
    85.                     }  
    86.                     formData = postData;  
    87.                 } else {  
    88.                     formData = new byte[len];  
    89.                 }  
    90.                 try {  
    91.                     if (readPostBody(formData, len) != len) {  
    92.                         return;  
    93.                     }  
    94.                 } catch (IOException e) {  
    95.                     // Client disconnect  
    96.                     if (context.getLogger().isDebugEnabled()) {  
    97.                         context.getLogger().debug(  
    98.                                 sm.getString("coyoteRequest.parseParameters"), e);  
    99.                     }  
    100.                     return;  
    101.                 }  
    102.                //重点4  
    103.                 parameters.processParameters(formData, 0, len);  
    104.             } else if ("chunked".equalsIgnoreCase(  
    105.                     coyoteRequest.getHeader("transfer-encoding"))) {  
    106.                 byte[] formData = null;  
    107.                 try {  
    108.                     formData = readChunkedPostBody();  
    109.                 } catch (IOException e) {  
    110.                     // Client disconnect or chunkedPostTooLarge error  
    111.                     if (context.getLogger().isDebugEnabled()) {  
    112.                         context.getLogger().debug(  
    113.                                 sm.getString("coyoteRequest.parseParameters"), e);  
    114.                     }  
    115.                     return;  
    116.                 }  
    117.                 if (formData != null) {  
    118.                     parameters.processParameters(formData, 0, formData.length);  
    119.                 }  
    120.             }  
    121.             success = true;  
    122.         } finally {  
    123.             if (!success) {  
    124.                 parameters.setParseFailed(true);  
    125.             }  
    126.         }  
    127.   
    128.     }  


    上面有四处我们需要关注的重点。

    重点1:getCharacterEncoding()其实是通过底层的coyoteRequest来获取header content-type中的编码。
    如下:

    Java代码   收藏代码
    1. /** 
    2.      * Return the character encoding for this Request. 
    3.      */  
    4.     @Override  
    5.     public String getCharacterEncoding() {  
    6.       return coyoteRequest.getCharacterEncoding();  
    7.     }  

     

    Java代码   收藏代码
    1. public String getCharacterEncoding() {  
    2.   
    3.        if (charEncoding != null)  
    4.            return charEncoding;  
    5.   
    6.        charEncoding = ContentType.getCharsetFromContentType(getContentType());  
    7.        return charEncoding;  
    8.   
    9.    }  


    若无,则返回空。

    重点2:
    boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();这里就是我们在tomcat的server中配置的useBodyEncodingForURI属性的值。

    常量值org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING="ISO-8859-1";

    当重点1中的enc为空时,则会设置底层coyoteRequest的parameters对象的encoding=s上述"ISO-8859-1",即请求体采用"ISO-8859-1"来解析。当useBodyEncodingForURI=true时,请求参数和请求体的编码设置的都是同一个值,即"ISO-8859-1"。当useBodyEncodingForURI=false时,不改变queryStringEncoding即请求参数的编码,queryStringEncoding默认是为null的,当解析时碰见queryStringEncoding也会采用默认的编码"ISO-8859-1",然而我们可以通过org.apache.catalina.connector.Request所包含的connector配置来给queryStringEncoding赋值。如下:
    当你在tomcat的server.xml文件中加入URIEncoding="UTF-8"时,它将会为queryStringEncoding赋值此值。
    在tomcat的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" URIEncoding='UTF-8'/>  


    connector将这个值为queryStringEncoding赋值的过程如下:

    Java代码   收藏代码
    1. public void log(org.apache.coyote.Request req,  
    2.            org.apache.coyote.Response res, long time) {  
    3.   
    4.        Request request = (Request) req.getNote(ADAPTER_NOTES);  
    5.        Response response = (Response) res.getNote(ADAPTER_NOTES);  
    6.   
    7.        if (request == null) {  
    8.            // Create objects  
    9.            request = connector.createRequest();  
    10.            request.setCoyoteRequest(req);  
    11.            response = connector.createResponse();  
    12.            response.setCoyoteResponse(res);  
    13.   
    14.            // Link objects  
    15.            request.setResponse(response);  
    16.            response.setRequest(request);  
    17.   
    18.            // Set as notes  
    19.            req.setNote(ADAPTER_NOTES, request);  
    20.            res.setNote(ADAPTER_NOTES, response);  
    21.   
    22.            // Set query string encoding  
    23.            //重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点  
    24.            req.getParameters().setQueryStringEncoding  
    25.                (connector.getURIEncoding());  
    26.        }  


    connector.getURIEncoding()便是我们配置的URIEncoding值
    req.getParameters().setQueryStringEncoding
                    (connector.getURIEncoding());
    这句代码便是将我们在tomcat的server.xml文件中配置的URIEncoding值设置进最重要的Parameters的queryStringEncoding中。

    当重点1中的enc不为空时,为Parameters请求体的的编码encoding设置为enc。
    至此,Parameters的encoding和queryStringEncoding都有相应的值了,然后便按照对应的编码来解析字节数组。

    重点3和4:有个相应的编码方式,分别执行请求参数的解析过程和请求体的解析过程。

    总结下一些设置的作用:

    request.setCharacterEncoding(encoding) :暴漏给我们的request为requestFacade,最终调用request->调用coyoteRequest->设置到coyoteRequest的charEncoding,所以coyoteRequest的charEncoding有两种来源,一种可能是content-type中的编码,另一种就是调用request.setCharacterEncoding(encoding) 方法。此方法最好在第一次解析参数之前调用,不然就无效。

    URIEncoding:直接设置Parameters的queryStringEncoding的值。即针对请求参数的编码。

    useBodyEncodingForURI:设置queryStringEncoding的值=encoding的值,即请求参数采用请求体的编码方式。 

    展开全文
  • 大家知道tomcat5.0开始,对网页的中文字符的post或者get,经常会出现乱码现象。...常见的解决方法是在tomcat的server.xml下的connetor属性中增加URIEncoding或者useBodyEncodingForURI属性。但是,这两...

    大家知道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的两个参数设置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的请求体。 

    展开全文
  • http://blog.itpub.net/29254281/viewspace-775925/http://blog.itpub.net/29254281/viewspace-1063133/Tomcat解决请求乱码可以使用URIEncoding和useBodyEncodingForURI.下面是两个参数的具体说明,参见ApacheTomc.....
    之前关于编码的问题已经总结过两次了,有些地方写的很粗略。
    http://blog.itpub.net/29254281/viewspace-775925/
    http://blog.itpub.net/29254281/viewspace-1063133/

    Tomcat解决请求乱码可以使用URIEncoding和useBodyEncodingForURI.下面是两个参数的具体说明,参见ApacheTomcat官方手册。
    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. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitly set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false.
    http://tomcat.apache.org/tomcat-7.0-doc/config/http.html


    在上图可以看到,中文乱码容易出现在两个地方。一个是所请求的资源名称为中文,一个是查询参数的内容包括中文。
    更复杂的是,不同的浏览器可能使用两种编码分别处理URL和查询参数。
    useBodyEncodingForURI只是针对图上"author=君山"的 查询参数(QueryString )有效,他的设置对于URL和URI无效。
    下面以Windows环境为例,分别测试谷歌、火狐和IE浏览器请求中文资源和中文参数的乱码情况。

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

    默认URI编码默认查询参数编码
    谷歌UTF8UTF8
    火狐UTF8GBK
    IEGBKGBK

    1.Tomcat的URIEncoding设置为UTF8
    谷歌正常
    火狐可以请求到资源,但是查询参数的中文为乱码
    IE不能请求到资源

    测试代码如下

    测试结果如下:


    2.将IE的URI编码设置为UTF8,开启useBodyEncodingForURI,并设置request的字符集为GBK。

    针对URI和查询参数使用两种编码的情况,可以使用useBodyEncodingForURI。他会根据http body设置的字符集解码。
    将IE设置为"发送UTF8的URL"之后,三种浏览器都使用UTF8作为URI编码,但是IE和火狐的 查询参数使用GBK编码,而谷歌的查询参数使用UTF8编码。所以在这种情况下,IE和火狐的访问都是正常的,而使用谷歌浏览器,可以访问资源,但是中文的查询参数则是乱码。

    测试结果:


    实验得出的结论是
    1.URIEncoding和useBodyEncodingForURI都可以处理中文乱码的问题
    2.浏览器对于URI和查询参数可能使用两种不同的编码方式,这种情况下,可以使用 useBodyEncodingForURI调整查询参数的编码。

    参考:
    http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
    展开全文
  • 本文章会从tomcat的源码角度来解析Tomcat的两个参数设置URIEncoding和useBodyEncodingForURI。  对于一个请求,常用的有两种编码方式,如下:  Java代码  <!DOCTYPE html>         ...

    继续上一章节的乱码问题。上一篇文章仅仅说了设置Tomcat的URIEncoding可以解决乱码问题,这篇文章便会讲述这一背后的内容。首先说明下,光看是没用的,要多实验实验。 

    目前我的tomcat版本为:7.0.55,spring所有文章的版本始终为4.0.5 

    本文章会从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的请求体。 

    以上的结论说完了,下面就要看看源代码了。不想看的就算了不影响使用,想看看原理的请继续: 

    首先是三个名词: 
    org.apache.coyote.Request:这是一个最底层的request,包含各种参数信息。暂且称为coyoteRequest。 
    org.apache.catalina.connector.Request:实现了HttpServletRequest接口,称它为request,同时包含了一个coyoteRequest,一个connector,待会你就会发现这个connector的编码传递作用。 
    org.apache.catalina.connector.RequestFacade:同样实现了HttpServletRequest接口,它仅仅是一个装饰类,称它为requestFacade,构造函数为: 

    Java代码  收藏代码

    1. /** 
    2.      * Construct a wrapper for the specified request. 
    3.      * 
    4.      * @param request The request to be wrapped 
    5.      */  
    6.     public RequestFacade(Request request) {  
    7.   
    8.         this.request = request;  
    9.   
    10.     }  


    该构造函数将一个org.apache.catalina.connector.Request传进来,requestFacade的工作全是靠它内部的org.apache.catalina.connector.Request来完成的,org.apache.catalina.connector.Request又是依据它所包含的org.apache.coyote.Request这个最底层的类来完成的。通过org.apache.catalina.connector.Request,我们可以设定org.apache.coyote.Request的一些工作方式,如通过什么编码来解析数据。 

    org.apache.coyote.Request含有的属性: 
    String charEncoding:针对请求体的编码(在第一次解析参数时会传递给Parameters的encoding) 
    Parameters :用于处理和存放请求参数和请求体参数的类 
                (1)含String encoding:针对请求体的编码 
                (2)含String queryStringEncoding:针对请求参数的编码 
                (3)含Map<String,ArrayList<String>> paramHashValues:存放解析后的参数 
    Parameters的两个编码是最最重要的编码,直接参与解析数据的编码,不像其他对象的编码大部分都是起传递作用,最终作用到Parameters的两个编码上 
     

    Java代码  收藏代码

    1. public class MyCharacterEncodingFilter extends CharacterEncodingFilter{  
    2.   
    3.     @Override  
    4.     protected void doFilterInternal(HttpServletRequest request,  
    5.             HttpServletResponse response, FilterChain filterChain)  
    6.             throws ServletException, IOException {  
    7.         request.setCharacterEncoding("UTF-8");  
    8.         String name=request.getParameter("user");  
    9.         System.out.println(name);  
    10.         request.setCharacterEncoding("UTF-8");  
    11.         String name1=request.getParameter("user");  
    12.         System.out.println(name1);  
    13.         super.doFilterInternal(request, response, filterChain);  
    14.     }  
    15. }  


    传给过滤器filter的HttpServletRequest request其实是org.apache.catalina.connector.RequestFacade类型的,我们看下获取参数的具体过程: 
    requestFacade.getParameter("user")会传递到org.apache.catalina.connector.Request的相应方法,如下: 

    Java代码  收藏代码

    1. public String getParameter(String name) {  
    2.   
    3.         if (!parametersParsed) {  
    4.             parseParameters();  
    5.         }  
    6.   
    7.         return coyoteRequest.getParameters().getParameter(name);  
    8.   
    9.     }  


    parametersParsed是org.apache.catalina.connector.Request的属性,用于标示是否已经解析过参数,如果解析过,便不再解析,直接从coyoteRequest的Parameters参数中取出。所以当已经解析过后,你再去设置编码,会无效的,因为它会直接返回第一次的解析结果。并且解析过程仅仅发生在第一次获取参数的时候。 
    我们来看下parseParameters()这个解析参数的过程: 

    Java代码  收藏代码

    1. /** 
    2.      * Parse request parameters. 
    3.      */  
    4.     protected void parseParameters() {  
    5.   
    6.         //解析发生后,便将是状态置为已解析  
    7.         parametersParsed = true;  
    8.   
    9.         Parameters parameters = coyoteRequest.getParameters();  
    10.         boolean success = false;  
    11.         try {  
    12.             // Set this every time in case limit has been changed via JMX  
    13.             parameters.setLimit(getConnector().getMaxParameterCount());  
    14.   
    15.             // getCharacterEncoding() may have been overridden to search for  
    16.             // hidden form field containing request encoding  
    17.             //重点1  
    18.             String enc = getCharacterEncoding();  
    19.             //重点2  
    20.             boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();  
    21.             if (enc != null) {  
    22.                 parameters.setEncoding(enc);  
    23.                 if (useBodyEncodingForURI) {  
    24.                     parameters.setQueryStringEncoding(enc);  
    25.                 }  
    26.             } else {  
    27.                 parameters.setEncoding  
    28.                     (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);  
    29.                 if (useBodyEncodingForURI) {  
    30.                     parameters.setQueryStringEncoding  
    31.                         (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);  
    32.                 }  
    33.             }  
    34.             //重点3  
    35.             parameters.handleQueryParameters();  
    36.   
    37.             if (usingInputStream || usingReader) {  
    38.                 success = true;  
    39.                 return;  
    40.             }  
    41.   
    42.             if( !getConnector().isParseBodyMethod(getMethod()) ) {  
    43.                 success = true;  
    44.                 return;  
    45.             }  
    46.   
    47.             String contentType = getContentType();  
    48.             if (contentType == null) {  
    49.                 contentType = "";  
    50.             }  
    51.             int semicolon = contentType.indexOf(';');  
    52.             if (semicolon >= 0) {  
    53.                 contentType = contentType.substring(0, semicolon).trim();  
    54.             } else {  
    55.                 contentType = contentType.trim();  
    56.             }  
    57.   
    58.             if ("multipart/form-data".equals(contentType)) {  
    59.                 parseParts();  
    60.                 success = true;  
    61.                 return;  
    62.             }  
    63.   
    64.             if (!("application/x-www-form-urlencoded".equals(contentType))) {  
    65.                 success = true;  
    66.                 return;  
    67.             }  
    68.   
    69.             int len = getContentLength();  
    70.   
    71.             if (len > 0) {  
    72.                 int maxPostSize = connector.getMaxPostSize();  
    73.                 if ((maxPostSize > 0) && (len > maxPostSize)) {  
    74.                     if (context.getLogger().isDebugEnabled()) {  
    75.                         context.getLogger().debug(  
    76.                                 sm.getString("coyoteRequest.postTooLarge"));  
    77.                     }  
    78.                     checkSwallowInput();  
    79.                     return;  
    80.                 }  
    81.                 byte[] formData = null;  
    82.                 if (len < CACHED_POST_LEN) {  
    83.                     if (postData == null) {  
    84.                         postData = new byte[CACHED_POST_LEN];  
    85.                     }  
    86.                     formData = postData;  
    87.                 } else {  
    88.                     formData = new byte[len];  
    89.                 }  
    90.                 try {  
    91.                     if (readPostBody(formData, len) != len) {  
    92.                         return;  
    93.                     }  
    94.                 } catch (IOException e) {  
    95.                     // Client disconnect  
    96.                     if (context.getLogger().isDebugEnabled()) {  
    97.                         context.getLogger().debug(  
    98.                                 sm.getString("coyoteRequest.parseParameters"), e);  
    99.                     }  
    100.                     return;  
    101.                 }  
    102.                //重点4  
    103.                 parameters.processParameters(formData, 0, len);  
    104.             } else if ("chunked".equalsIgnoreCase(  
    105.                     coyoteRequest.getHeader("transfer-encoding"))) {  
    106.                 byte[] formData = null;  
    107.                 try {  
    108.                     formData = readChunkedPostBody();  
    109.                 } catch (IOException e) {  
    110.                     // Client disconnect or chunkedPostTooLarge error  
    111.                     if (context.getLogger().isDebugEnabled()) {  
    112.                         context.getLogger().debug(  
    113.                                 sm.getString("coyoteRequest.parseParameters"), e);  
    114.                     }  
    115.                     return;  
    116.                 }  
    117.                 if (formData != null) {  
    118.                     parameters.processParameters(formData, 0, formData.length);  
    119.                 }  
    120.             }  
    121.             success = true;  
    122.         } finally {  
    123.             if (!success) {  
    124.                 parameters.setParseFailed(true);  
    125.             }  
    126.         }  
    127.   
    128.     }  


    上面有四处我们需要关注的重点。 

    重点1:getCharacterEncoding()其实是通过底层的coyoteRequest来获取header content-type中的编码。 
    如下: 

    Java代码  收藏代码

    1. /** 
    2.      * Return the character encoding for this Request. 
    3.      */  
    4.     @Override  
    5.     public String getCharacterEncoding() {  
    6.       return coyoteRequest.getCharacterEncoding();  
    7.     }  

     

    Java代码  收藏代码

    1. public String getCharacterEncoding() {  
    2.   
    3.        if (charEncoding != null)  
    4.            return charEncoding;  
    5.   
    6.        charEncoding = ContentType.getCharsetFromContentType(getContentType());  
    7.        return charEncoding;  
    8.   
    9.    }  


    若无,则返回空。 

    重点2: 
    boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();这里就是我们在tomcat的server中配置的useBodyEncodingForURI属性的值。 

    常量值org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; 

    当重点1中的enc为空时,则会设置底层coyoteRequest的parameters对象的encoding=s上述"ISO-8859-1",即请求体采用"ISO-8859-1"来解析。当useBodyEncodingForURI=true时,请求参数和请求体的编码设置的都是同一个值,即"ISO-8859-1"。当useBodyEncodingForURI=false时,不改变queryStringEncoding即请求参数的编码,queryStringEncoding默认是为null的,当解析时碰见queryStringEncoding也会采用默认的编码"ISO-8859-1",然而我们可以通过org.apache.catalina.connector.Request所包含的connector配置来给queryStringEncoding赋值。如下: 
    当你在tomcat的server.xml文件中加入URIEncoding="UTF-8"时,它将会为queryStringEncoding赋值此值。 
    在tomcat的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" URIEncoding='UTF-8'/>  


    connector将这个值为queryStringEncoding赋值的过程如下: 

    Java代码  收藏代码

    1. public void log(org.apache.coyote.Request req,  
    2.            org.apache.coyote.Response res, long time) {  
    3.   
    4.        Request request = (Request) req.getNote(ADAPTER_NOTES);  
    5.        Response response = (Response) res.getNote(ADAPTER_NOTES);  
    6.   
    7.        if (request == null) {  
    8.            // Create objects  
    9.            request = connector.createRequest();  
    10.            request.setCoyoteRequest(req);  
    11.            response = connector.createResponse();  
    12.            response.setCoyoteResponse(res);  
    13.   
    14.            // Link objects  
    15.            request.setResponse(response);  
    16.            response.setRequest(request);  
    17.   
    18.            // Set as notes  
    19.            req.setNote(ADAPTER_NOTES, request);  
    20.            res.setNote(ADAPTER_NOTES, response);  
    21.   
    22.            // Set query string encoding  
    23.            //重点重点重点重点重点重点重点重点重点重点重点重点重点重点重点  
    24.            req.getParameters().setQueryStringEncoding  
    25.                (connector.getURIEncoding());  
    26.        }  


    connector.getURIEncoding()便是我们配置的URIEncoding值 
    req.getParameters().setQueryStringEncoding 
                    (connector.getURIEncoding()); 
    这句代码便是将我们在tomcat的server.xml文件中配置的URIEncoding值设置进最重要的Parameters的queryStringEncoding中。 

    当重点1中的enc不为空时,为Parameters请求体的的编码encoding设置为enc。 
    至此,Parameters的encoding和queryStringEncoding都有相应的值了,然后便按照对应的编码来解析字节数组。 

    重点3和4:有个相应的编码方式,分别执行请求参数的解析过程和请求体的解析过程。 

    总结下一些设置的作用: 

    request.setCharacterEncoding(encoding) :暴漏给我们的request为requestFacade,最终调用request->调用coyoteRequest->设置到coyoteRequest的charEncoding,所以coyoteRequest的charEncoding有两种来源,一种可能是content-type中的编码,另一种就是调用request.setCharacterEncoding(encoding) 方法。此方法最好在第一次解析参数之前调用,不然就无效。 

    URIEncoding:直接设置Parameters的queryStringEncoding的值。即针对请求参数的编码。 

    useBodyEncodingForURI:设置queryStringEncoding的值=encoding的值,即请求参数采用请求体的编码方式。 

    转载于:https://my.oschina.net/u/2820842/blog/1839806

    展开全文
  • URIEncoding和UseBodyEncodingForURI的解释

    千次阅读 2017-03-15 19:44:54
    UseBodyEncodingForURI为TRUE,就是对queryString的解码会采用请求头中content-type中指定的编码或者在request.setsetCharacterEncoding(charsetName)中指定的编码(默认这个方法只对post有用)。但是如果既没有...
  • 经过一段时间在网络上的搜索,发现将Tomcat目录下的server.xml文件的useBodyEncodingForURI设置为"true"可能可以解决问题,于是在  connectionTimeout="20000" redirectPort="8443" />中加入...
  • Spring MVC中解决中文乱码问题时useBodyEncodingForURI="true"的作用。
  • Tomcat解决请求乱码可以使用URIEncoding和useBodyEncodingForURI.下面是两个参数的具体说明,参见ApacheTomcat官方手册。 URIEncoding This specifies the character encoding used to decode the URI ...
  • 转自:... Tomcat解决请求乱码可以使用URIEncoding和useBodyEncodingForURI.下面是两个参数的具体说明,参见ApacheTomcat官方手册。 URIEncoding This specifies the character encoding
  • 大家知道tomcat5.0开始,对网页的中文字符的post或者get,经常会出现乱码现象。 具体是因为Tomcat默认是按ISO-...常见的解决方法是在tomcat的server.xml下的connetor属性中增加URIEncoding或者useBodyEncodingForURI
  • 2> 在tomcat的server.xml设置<Connector useBodyEncodingForURI="true" /> 能够解决query String的乱码问题。 useBodyEncodingForURI=true -> 使用http header中指定charset进行decode(例如:Content-Type: ...
  • 大家知道tomcat5.0开始,对网页的中文字符的post或者get,经常会出现乱码现象。...常见的解决方法是在tomcat的server.xml下的connetor属性中增加URIEncoding或者useBodyEncodingForURI属性。但是,这两种
  • URIEncoding和useBodyEncodingForURI区别是,URIEncoding是对所有GET方式的请求的数据进行统一的重新编码(解码),而useBodyEncodingForURI则是根据响应该请求的页面的request.setCharacterEncoding参数对数据进行...
  • 在Tomcat的通道(Connector)配置中,除了URIEncoding之外,还有一个影响编码的参数useBodyEncodingForURI,关于这个参数,官方文档说明如下: This specifies if the encoding specified in contentType should be ...
  • useBodyEncodingForURI:This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. 也就是说, useBodyEncodingForURI参数表示...
  • 大家知道tomcat5.0开始,对网页的中文字符的post或者get,经常会出现乱码现象。 ...常见的解决方法是在tomcat的server.xml下的connetor属性中增加URIEncoding或者useBodyEncodingForURI属性。...
  • 本文章会从tomcat的源码角度来解析Tomcat的两个参数设置URIEncoding和useBodyEncodingForURI。  对于一个请求,常用的有两种编码方式,如下:   Java代码  <!DOCTYPE html>   ...
  • useBodyEncodingForURI="true"解决Tomcat乱码问题

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,208
精华内容 2,483
关键字:

usebodyencodingforuri