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 中文乱码都能定位并解决。

相关推荐
y1su43 分钟前
Leetcode 链表,树,回溯 模板
java·leetcode·链表
qianyuqiye11 小时前
K8s 命名空间与 Pod 入门:从概念到实战
java·docker·kubernetes
牧瀬クリスだ1 小时前
观察者模式:一个对象变化,一群对象自动响应
java·观察者模式·设计模式
小张成长计划..1 小时前
【Linux】26:线程互斥和同步
java·开发语言
邪修king4 小时前
Re:Linux 系统篇(三十五):进程间通信Chapter2:从匿名管道到进程池:Linux 进程间通信实战(深度理解「先描述,再组织」)
java·linux·运维
拆房老料4 小时前
【第四部分:Agentic 智能体设计模式】16. 一个 Prompt 搞不定复杂任务?试试 Prompt Chaining
java·前端·人工智能·设计模式·prompt
张张123y5 小时前
后端第十四课:Agent 记忆系统(让 Agent 记住上下文和用户,跨会话不健忘)
java·大数据·人工智能·python·agent·记忆
曹牧9 小时前
C#:空合并运算符
java·前端·数据库
布吉岛的石头10 小时前
Java 程序员第 50 阶段2:预训练的目标函数:自回归语言建模本质
java·开发语言·人工智能·深度学习·回归·transformer