美文网首页JavaWeb中文乱码工作中源代码学习
JavaWeb乱码---Spring后端乱码问题

JavaWeb乱码---Spring后端乱码问题

作者: ___TheOne___ | 来源:发表于2018-04-19 15:49 被阅读22次

    1.场景:

    使用Apache的HttpClient+Spring控制器,来探究Java后端Http请求中容易出现的乱码。关于Apache的HttpClient发送请求可以查看我的Apache-HttpClient请求

    心法:乱码解决,从根入手。

    2.Post请求

    2.1 HttpClient发送请求时乱码

    HttpClient发送post请求有两种方式:请求参数key-value键值对 或 请求参数为字符串。

    这个步骤是Http请求源头,我们首先要保证源头处中文被显式设置为指定编码 eg:UTF-8

    1>请求参数是key-value键值对

    HttpEntity request= new UrlEncodedFormEntity(params, "UTF-8");
    

    2>请求参数为字符串

    StringEntity stringEntity = new StringEntity(requestBody, "UTF-8");
    

    2.2 Spring控制器获取请求时乱码

    Spring一般会在web.xml设置一个CharacterEncodingFilter过滤器,处理获取过程中文乱码问题,代码如下:

    <!--对请求参数使用UTF-8强制编码,否则请求中文会出现乱码-->
        <filter>
            <filter-name>encodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
            <init-param>
                <param-name>forceEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    

    后来了解CharacterEncodingFilter本质作用:

    request.setCharacterEncoding("UTF-8");
    response.setCharacterEncoding("UTF-8");
    

    1>获取key-value键值对请求参数

    使用上述web.xml中CharacterEncodingFilter编码配置。

    2>获取字符串请求参数:以流的方式获取,且显式设置UTF-8编码

    public String getReqeustData(HttpServletRequest request) {
            String data = null;
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8")); 
                String line = null;
                StringBuilder sb = new StringBuilder();
    
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
                data = sb.toString();
    
                if (StringUtils.isEmpty(data)) {
                    return null;
                }
    
            } catch (Exception e) {
                logger.error("read Inputstream for httpReqeust error", e);
            }
            return data;
        }
    

    2.3 Spring控制器响应时乱码

    Spring控制器有两种常见方式,对请求进行响应:

    1>使用 HttpServletResponse response响应
      为了避免中文乱码,要么配置上述web.xml中CharacterEncodingFilter配置编码;要么response显式设置响应编码。两者必须有一个,否则响应信息中文会乱码。

    response.setCharacterEncoding("UTF-8");
    

    2>使用@ResponseBody标签响应
      @ResponseBody会将内容或对象作为 HTTP 响应正文返回,使用@ResponseBody将会跳过视图处理部分,而是调用适合的HttpMessageConverter,将返回值写入输出流。如果返回String,则使用StringHttpMessageConverter,但这个convert使用的是字符集是ISO-8859-1,而且是final的。响应乱码的万恶之源啊!

    部分源码如下:

    public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
    
        public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
    }
    

    解决方案有两种:
    方法一:对于需要返回字符串的方法添加注解: produces = "application/json;charset=UTF-8"。但是这个方法,需要在每个需要的方法都加上此注解,比较麻烦,所以就有了下面的方法二和三。

       @RequestMapping(value = "/testStringParams", produces = "application/json;charset=UTF-8")
       @ResponseBody
        public String testStringReqParams(HttpServletRequest request){
    
            String stringReqParams = getReqeustData(request);
    
            return stringReqParams;
    
        }//end method
    

    方法二:
    在mvc配置文件中,修改StringHttpMessageConverter使用字符集

       <mvc:annotation-driven>
            <mvc:message-converters>
                <!-- StringHttpMessageConverter编码为UTF-8,防止乱码 -->
               <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <constructor-arg value="UTF-8"/>
                    <property name="writeAcceptCharset" value="false"/>  <!--用于避免响应头过大-->
                </bean>
            </mvc:message-converters>
        </mvc:annotation-driven>
    

    方法三:
    在mvc配置文件中,使用MappingJackson2HttpMessageConverter转换字符串

       <mvc:annotation-driven>
            <mvc:message-converters>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                 <property name="supportedMediaTypes">
                  <list>
                      <value>text/html;charset=UTF-8</value>
                      <value>application/json;charset=UTF-8</value>
                  </list>
                </property>
               </bean>
            </mvc:message-converters>
        </mvc:annotation-driven>
    

    2.4 HttpClient接收响应时乱码

    显式设置接收信息编码格式:

    String result = EntityUtils.toString(entity, "UTF-8");
    

    3.Get请求

    3.1 获取Get请求查询参数时乱码

    可以去设置URIEncoding="utf-8"

      <Connector connectionTimeout="20000" port="8084" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="utf-8"/>
    

    3.2 Tomcat7和Tomcat8之于乱码

    可是有时候你会发现,同样的项目,A本地解析get查询参数中文正常,但是B本地解析中文乱码。这个是由于Tomcat8和Tomcat7,对URIEncoding默认编码是不一样的:Tomcat8默认是UTF-8,而Tomcat7是ISO-8895-1。详见Tomcat7和Tomcat8编码

    个人总结,助人助己。

    相关文章

      网友评论

        本文标题:JavaWeb乱码---Spring后端乱码问题

        本文链接:https://www.haomeiwen.com/subject/tpywkftx.html