Spring MVC POST 请求乱码:原因与完整解决方案

Spring MVC POST 请求乱码:原因与完整解决方案

POST 请求中文乱码是 Spring MVC 开发中的高频问题。前端提交的中文到了后端变成问号、乱码,或者后端返回给前端的中文显示异常,本质原因通常只有一个:请求体、响应体在编码和解码时使用的字符集不一致。

Tomcat 默认使用 ISO-8859-1 解码请求体,而前端通常使用 UTF-8 编码。两边不统一,中文就会乱码。解决思路是让整条链路统一使用 UTF-8:前端请求、Spring 过滤器、Tomcat 连接器、JVM、响应转换器、数据库连接,每一环都要确认。

下面按项目类型和问题环节分别说明。

一、Spring Boot 项目:优先使用配置

Spring Boot 提供了开箱即用的编码配置,在 application.properties 或 application.yml 中添加:

properties 复制代码
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

force=true 是关键,它会强制把请求和响应的编码覆盖为 UTF-8。

注意旧版本中的 spring.http.encoding.* 已经废弃,不要继续使用。

如果使用 YAML:

yaml 复制代码
server:
  servlet:
    encoding:
      charset: UTF-8
      enabled: true
      force: true

对于大多数 Spring Boot 项目,这一组配置就能解决 POST 表单和普通请求的乱码问题。

二、传统 Spring MVC 项目:注册 CharacterEncodingFilter

传统 Spring MVC 项目需要手动注册 CharacterEncodingFilter。

方式一:web.xml

xml 复制代码
<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>

这个过滤器必须配置在其他过滤器之前,否则可能被其他过滤器提前读取请求参数,导致编码设置失效。

方式二:Java Config

java 复制代码
@Bean
public FilterRegistrationBean<CharacterEncodingFilter> encodingFilter() {
    FilterRegistrationBean<CharacterEncodingFilter> bean = new FilterRegistrationBean<>();
    CharacterEncodingFilter filter = new CharacterEncodingFilter();
    filter.setEncoding("UTF-8");
    filter.setForceEncoding(true);
    bean.setFilter(filter);
    bean.addUrlPatterns("/*");
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}

setOrder(Ordered.HIGHEST_PRECEDENCE) 保证它在过滤器链最前面执行。

三、Tomcat 与 JVM 层面

如果过滤器已经配置,仍然有乱码,检查 Tomcat 的 conf/server.xml 中 <Connector> 配置:

xml 复制代码
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="UTF-8"
           useBodyEncodingForURI="true" />
  • URIEncoding="UTF-8":统一 URI 的解码字符集,影响 GET 参数。
  • useBodyEncodingForURI="true":让请求体使用 request.setCharacterEncoding() 设置的编码。

同时建议给 JVM 加上默认编码参数。Linux/macOS 在 bin/setenv.sh 中:

bash 复制代码
export JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"

Windows 在 catalina.bat 中:

bat 复制代码
set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8

这可以避免日志、文件路径等出现乱码。

四、JSON 请求体乱码

如果乱码发生在 @RequestBody 接收的 JSON 参数上,先检查客户端请求头:

http 复制代码
Content-Type: application/json;charset=UTF-8

如果客户端无法修改,可以在服务端强制 Jackson 使用 UTF-8:

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                MappingJackson2HttpMessageConverter jacksonConverter =
                        (MappingJackson2HttpMessageConverter) converter;
                jacksonConverter.setDefaultCharset(StandardCharsets.UTF_8);
            }
        }
    }
}

这样即使客户端没有在 Content-Type 中声明 charset,Jackson 也会按 UTF-8 读取请求体。

五、响应乱码

如果后端返回的 JSON 或字符串乱码,可以从两个方向处理。

1. 指定 produces

java 复制代码
@RequestMapping(value = "/api", produces = "application/json;charset=UTF-8")

2. 调整 StringHttpMessageConverter

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    }
}

将 UTF-8 的 StringHttpMessageConverter 放在最前面,避免默认转换器使用其他编码。

六、数据库连接乱码

如果数据到了数据库才乱码,检查 JDBC URL:

复制代码
jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=UTF-8

同时确认数据库和表的字符集:

sql 复制代码
SHOW CREATE TABLE your_table;

推荐使用 utf8mb4,兼容中文和 emoji。

七、排查清单

出现 POST 乱码时,按下面顺序排查:

检查位置 关键点
前端请求 Content-Type 是否包含 charset=UTF-8
Spring Boot 配置 server.servlet.encoding.force=true
传统项目过滤器 CharacterEncodingFilter 是否生效,是否在最前面
Tomcat 连接器 URIEncoding="UTF-8"、useBodyEncodingForURI="true"
JVM 参数 -Dfile.encoding=UTF-8
JSON 请求体 Jackson 是否按 UTF-8 读取
响应转换器 StringHttpMessageConverter 或 produces
数据库 JDBC URL 编码、库表字符集

八、总结

POST 请求乱码不是单一配置能覆盖所有场景的问题,它涉及前端、Spring、Tomcat、JVM、数据库多个环节。解决的核心原则是:保证请求、处理、响应、存储每一环都使用 UTF-8。

实际项目中可以按这个优先级处理:

  1. Spring Boot 项目先加 server.servlet.encoding.* 配置。
  2. 传统项目优先检查 CharacterEncodingFilter。
  3. 仍有问题时检查 Tomcat 连接器和 JVM 编码。
  4. JSON 乱码单独处理 Jackson 的默认字符集。
  5. 响应乱码检查 StringHttpMessageConverter 和 produces。
  6. 数据库乱码检查 JDBC URL 和库表字符集。

按这个顺序排查,绝大多数 POST 中文乱码都能定位并解决。

相关推荐
xys_6784 分钟前
JavaEE通关手册:初识Java
java·开发语言
文丑颜不良啊4 分钟前
LeetCode2461~2480题目解析
java·leetcode
文丑颜不良啊1 小时前
LeetCode2441~2460题目解析
java·leetcode
阿屿2 小时前
从零手搓 AI 伴侣(二):好感度通胀危机,与它的「货币政策」
java·人工智能
灿飞2 小时前
Kotlin与Java虚拟机十一:类与属性:构造顺序、backing field 与显式 backing field
java·后端·kotlin
aiks_yuan2 小时前
40亿个QQ号 1G内存怎么去重:Java BitSet 装不下,long 数组位图 512MB 实测 46 秒(JDK 17)
java
文丑颜不良啊2 小时前
LeetCode2521~2540题目解析
java·leetcode
杨凯凡2 小时前
Spring Framework 7 HTTP Interface 实战:声明式 RestClient、超时与测试
java·spring·http
吴名氏.3 小时前
Java转AI Agent教程(第十二周)检索与切分
java·开发语言·人工智能·ai·ai agent
瑞雪兆丰年兮3 小时前
JavaWeb-day10-SpringBootWeb案例
java·开发语言·javaweb·web