一、遇到的问题:
客户端发送get请求,参数在url中,服务器能正常解析。但如果用post请求访问接口,数据放在body里面,即使参数utf-8编码,从body里面取出的中文参数也是乱码。

二、服务端代码:

@RequestMapping(value = "/api/entry", produces = "application/json;charset=utf-8")
public DeferredResult<Object> sign(HttpServletRequest request,HttpServletResponse response) {    
    DeferredResult<Object> deferredResult = new DeferredResult<>();    
    Map<String, String[]> parameterMap = request.getParameterMap();  
    String method = request.getParameter("method");    
   
    return deferredResult;
}

服务端通过Map<String, String[]> parameterMap = request.getParameterMap()取出所有参数,传进来title参数是乱码!!

二、原因

Servlet 3.0规范中有关请求数据编码的解释如下:

当前很多浏览器并不发送带Content-Type头部的字符编码标识符,它会把字符编码的决定留在读取HTTP请求的时候。如果客户端没有指明编码,容器用来创建请求读和解析POST数据的默认编码必须是"ISO-8859-1"。然而,为了提示开发者客户端没有成功发送一个字符编码,容器中getCharacterEncoding方法会返回null。
如果客户端没有设置字符编码,并且请求数据使用了不同编码而不是上述的默认编码,程序将会出现中断。为了纠正这种状态,一个新的方法setCharacterEncoding(String enc) 被添加到ServletRequest接口。开发者调用这个方法能重写容器提供的字符编码。这个方法必须在解析request中任何post数据或者读任何输入之前调用。一旦数据已经被读取,调用这个方法不会影响它的编码。

springmvc post传递参数_字符编码

 

三、3种解决方法

 

  1. 在web.xml中配置编解码Filter
<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>    
    <async-supported>true</async-supported>
 </filter>
 <filter-mapping>    
     <filter-name>encodingFilter</filter-name>    
     <url-pattern>/*</url-pattern>
 </filter-mapping>
  1. 关于这段配置需要强调两点:
  • web.xml中,这段配置要放在所有filter的最前面,否则会不生效,根本原因请见上述第三点的解释。
  • 两个初始化参数的作用,其实看这个Filter的源码就一目了然,这两个参数是用来决定是否要设置request和response中的编码。源码很简洁:
  • public class CharacterEncodingFilter extends OncePerRequestFilter {    
         private String encoding;    
         private boolean forceEncoding = false;    
         public CharacterEncodingFilter() { }    
         public void setEncoding(String encoding) {        
             this.encoding = encoding;    
         }    
         public void setForceEncoding(boolean forceEncoding) {        
             this.forceEncoding = forceEncoding;    
         }    
         protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {        
             if(this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {            
                 request.setCharacterEncoding(this.encoding);            
                 if(this.forceEncoding) {                
                     response.setCharacterEncoding(this.encoding);            
                 }        
              }        
              filterChain.doFilter(request, response);    
         }
     }
  1. 或者直接修改loginFilter
public class LoginFilter implements Filter {
   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
         throws IOException, ServletException {
      HttpServletRequest req = (HttpServletRequest) servletRequest;
      HttpServletResponse resp = (HttpServletResponse) servletResponse;
      servletRequest.setCharacterEncoding("utf-8");
      filterChain.doFilter(servletRequest, servletResponse);
         return;
      }
  1. 设置Content-Type
    如果post请求方式是x-www-form-urlencoded,那么设置如下:
    Content-Type=application/x-www-form-urlencoded;charset=utf-8
    这样通过request对象取body体里面的中文是正常的。
    这种方式有一点需要注意: 如果请求方式是multipart/form-data,如上设置会导致request取不到参数。Content-Type要与传递数据匹配(本文data)
  2. 手动编解码
    比如参数title="测试",这样取出来就是"测试"。
String str = new String(request.getParameter("title").getBytes("iso-8859-1"), "utf-8");

综上所有,最优雅的方式是第一种解决方案--通过框架的Filter去处理。
你仅专注于业务代码就好。

 

参考:http://www.jianshu.com/p/435c13cfc769