CharacterEncodingFilter 源码解析以及在 SpringBoot 中的配置

SpringMVC 中有这样一个 Filter 专门处理编码问题的,它是CharacterEncodingFilter

比如默认给 response 返回设定编码格式为:UTF-8,则可以通过配置 CharacterEncodingFilter 实现。

CharacterEncodingFilter 源码

查看源码,它是一个OncePerRequestFilter,里面有如下几个配置项:

  1. encoding:设置的编码格式
  2. forceRequestEncoding:是否强制设置请求编码格式为设置的编码格式
  3. forceResponseEncoding:是否强制设置返回编码格式为设置的编码格式

源码也很简单,请求会调用到:doFilterInternal方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class CharacterEncodingFilter extends OncePerRequestFilter {

private String encoding;

private boolean forceRequestEncoding = false;

private boolean forceResponseEncoding = false;

public CharacterEncodingFilter() {
}

public CharacterEncodingFilter(String encoding) {
this(encoding, false);
}

public CharacterEncodingFilter(String encoding, boolean forceEncoding) {
this(encoding, forceEncoding, forceEncoding);
}

public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {
Assert.hasLength(encoding, "Encoding must not be empty");
this.encoding = encoding;
this.forceRequestEncoding = forceRequestEncoding;
this.forceResponseEncoding = forceResponseEncoding;
}

public void setEncoding(String encoding) {
this.encoding = encoding;
}

public String getEncoding() {
return this.encoding;
}

public void setForceEncoding(boolean forceEncoding) {
this.forceRequestEncoding = forceEncoding;
this.forceResponseEncoding = forceEncoding;
}

public void setForceRequestEncoding(boolean forceRequestEncoding) {
this.forceRequestEncoding = forceRequestEncoding;
}

public boolean isForceRequestEncoding() {
return this.forceRequestEncoding;
}

public void setForceResponseEncoding(boolean forceResponseEncoding) {
this.forceResponseEncoding = forceResponseEncoding;
}

public boolean isForceResponseEncoding() {
return this.forceResponseEncoding;
}


@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

String encoding = getEncoding();
if (encoding != null) {
if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
if (isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
filterChain.doFilter(request, response);
}

}

所以在 SpringMVC 项目中使用,可以参考如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

SpringBoot 支持

SpringBoot 对CharacterEncodingFilter 也有支持,在项目启动中可以看到如下日志:

1
2
3
4
5
17:03:55.802  INFO 7980 --- : Mapping servlet: 'dispatcherServlet' to [/]
17:03:55.809 INFO 7980 --- : Mapping filter: 'characterEncodingFilter' to: [/*]
17:03:55.810 INFO 7980 --- : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
17:03:55.810 INFO 7980 --- : Mapping filter: 'httpPutFormContentFilter' to: [/*]
17:03:55.810 INFO 7980 --- : Mapping filter: 'requestContextFilter' to: [/*]

这是因为 SpringBoot 在自动装配时,HttpEncodingAutoConfiguration配置类里配置了该 Filter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class) // 使用 HttpEncodingProperties 接收配置
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class)
// 没有配置:spring.http.encoding.enabled 时,默认为:true
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

private final HttpEncodingProperties properties;

public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}

// 创建 CharacterEncodingFilter Bean
@Bean
@ConditionalOnMissingBean(CharacterEncodingFilter.class)
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}

@Bean
public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
return new LocaleCharsetMappingsCustomizer(this.properties);
}

private static class LocaleCharsetMappingsCustomizer implements EmbeddedServletContainerCustomizer, Ordered {

private final HttpEncodingProperties properties;

LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) {
this.properties = properties;
}

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (this.properties.getMapping() != null) {
container.setLocaleCharsetMappings(this.properties.getMapping());
}
}

@Override
public int getOrder() {
return 0;
}

}

}

使用 SpringBoot 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 设置的编码,默认为:UTF-8
spring.http.encoding.charset=UTF-8

# 是否启用 CharacterEncodingFilter,如果不配置也代表 true
spring.http.encoding.enabled=true

# 是否强制设置请求和响应的编码格式为设置的编码格式
spring.http.encoding.force=

# 是否强制设置请求的编码格式为设置的编码格式
spring.http.encoding.force-request=

# 是否强制设置响应的编码格式为设置的编码格式
spring.http.encoding.force-response=