一个SpringSecurity引发的表单提交乱码问题

    这个问题困扰了大半个下午,好久没遇到耗时这么久的问题了,所以还是值得一写的。

    最近在做一个工程,前后端交互用的是Spring4.3.1+SpringSecurity4.1.3+thymeleaf3.0.1,版本都比较新,总体还是比较愉快的。今天在做一个form的时候,有一个字段允许填写中文的,但输入中文后提交回显乱码。起初以为是数据库连接编码问题(今天刚换了本地的调试库),但打了个断点发现controller里拿到的对象的desc字段(就是允许输入中文的字段)已经是乱码了,而用

System.out.println(new String(desc.getBytes("iso-8859-1"), "UTF-8"));

这种方法又可以还原成中文。这就奇怪了。

 

    网上搜了下,说法大概有以下三种:

    1,html层面的问题。在页面头部加上,以及在

里加上accept-charset="utf-8"(因为我有用thymeleaf,还试了th:accept-charset="utf-8"),都一样,没用。

 

    2,工程文件的编码问题。我用的是IJ,默认编码就开的UTF-8,前前后后都查了一遍,没用。

 

    3,thymeleaf和拦截器配置问题。这个我觉得是最可疑的,网上的说法是查以下几处(我是java配置方式,另有xml配置方式也可以在网上找到):

    模板解析器设置编码格式:

@Bean
    public ITemplateResolver templateResolver() {
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("HTML5");
        templateResolver.setCharacterEncoding("utf-8");
        templateResolver.setCacheable(false);
        return templateResolver;
    }

    视图解析器设置编码格式:

@Bean
    public ViewResolver springThymeleafViewResolver() {

        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        viewResolver.setOrder(1);
        viewResolver.setCharacterEncoding("utf-8");
        return viewResolver;
    }

    拦截器设置:

    protected String[] getServletMappings() {
        return new String[] { "/*" };
    }

    @Override
    protected Filter[] getServletFilters() {
        final CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding(SpringWebConfig.CHARACTER_ENCODING);
        encodingFilter.setForceEncoding(true);
        return new Filter[] { encodingFilter };
    }

    但是这几处地方我本来就差不多是这么写的,没有任何问题,还是没解决。

 

    4,tomcat问题。我容器用的是tomcat8,而且是在IJ里配置了直接起工程的,网上有说法说这种方法可能读不到配置什么的。在server.xml的里加上:

URIEncoding="UTF-8"

useBodyEncodingForURI="true"

然后重新打war包,手工放到tomcat的wabapps下,手工起tomcat,问题还没解决。

 

    走投无路的时候想起来翻一翻stackoverflow,翻了半天,发现有个老外也遇到类似的问题(http://stackoverflow.com/questions/20863489/characterencodingfilter-dont-work-together-with-spring-security-3-2-0),下面有人给出了解决方法,先贴方法:

@Configuration
@EnableWebMvcSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        http.addFilterBefore(filter,CsrfFilter.class);
        //rest of your code   
    }
//rest of your code
}

    其根本原因是,使用SpringSecurity后会改变原有的拦截次序,改变后最早发生的拦截是CsrfFilter,即在所有请求头上增加CSRF Token,对servlet的拦截则在更晚的时候发生。由于CSRF Token是一个英文数字的串,应该是将其编码定死为iso-8859-1了,因此在servlet拦截器上设置的编码格式未起作用。如果在CsrfFilter拦截之前再拦截一次,来设置编码格式,就可以生效了。我看到有很多无法解决这个问题的人都是一次次调用new String(desc.getBytes("iso-8859-1"),"UTF-8") 这样的代码来转码的,肯定不如一劳永逸的解决方案好。


你可能感兴趣的:(其他)