我会从最常见的场景(Web 应用)讲起,并提供详细的解决方案和排查思路。

问题根源
乱码问题的根源几乎总是 编码不一致。
- 编码:一方(通常是浏览器或客户端)用一种编码(如
UTF-8)将中文字符转换成字节流。 - 传输:字节流在网络中传输。
- 解码:另一方(通常是你的服务器)用另一种错误的编码(如
ISO-8859-1,即latin1)来解读这些字节流。 - 结果:由于编码和解码的“密码本”不一样,最终显示出来就是一堆看不懂的乱码(如 )。
我们的目标就是确保从客户端到服务器,再到数据库,整个链条都使用同一种编码,业界公认的最佳选择是 UTF-8。
GET 请求乱码
GET 请求的参数通常在 URL 中,http://yourdomain.com/search?name=张三&city=北京
问题原因
URL 的编码方式比较复杂,但服务器在解析 URL 时,如果没有正确配置,可能会用错误的编码来解析查询字符串。

解决方案(以主流技术栈为例)
Java (Spring Boot / Spring MVC)
Spring Boot 默认已经处理得很好,但如果出现乱码,可以尝试以下方法:
配置 application.properties 或 application.yml (推荐)
这是最简单、最优雅的方式,Spring Boot 会自动应用这些配置。
application.properties

# 解决 GET 请求乱码 server.servlet.encoding.enabled=true server.servlet.encoding.charset=UTF-8 server.servlet.encoding.force=true
application.yml
server:
servlet:
encoding:
enabled: true
charset: UTF-8
force: true
enabled=true: 开启编码支持。charset=UTF-8: 指定字符集为 UTF-8。force=true: 强制所有请求都使用此字符集,覆盖客户端的请求。
使用 @WebFilter (如果上述方法无效)
创建一个编码过滤器,这是一种更底层的 Servlet 解决方案。
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@WebFilter("/*") // 拦截所有请求
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 强制设置请求和响应的编码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 将请求包装一下,以便后续获取参数时能正确解码
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
chain.doFilter(new EncodingRequestWrapper(httpServletRequest), response);
}
// 内部类,用于包装 HttpServletRequest
private static class EncodingRequestWrapper extends HttpServletRequestWrapper {
public EncodingRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value != null) {
try {
// 先用 ISO-8859-1 解码,再用 UTF-8 重新编码,解决乱码
return new String(value.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
}
return value;
}
}
}
Node.js (Express)
Express 默认使用 qs 或 querystring 解析查询字符串,它们默认使用 utf8 编码,如果出现乱码,通常是服务器本身或其依赖的配置问题。
解决方案:确保你的应用文件和服务器环境都是 UTF-8。
// 1. 确保你的 .js 文件保存为 UTF-8 编码。
// 2. 在应用启动时,设置环境变量(对某些系统有效)
process.env.NODE_ENV = 'production'; // 或 'development'
// 3. 使用 express 内置的中间件
const express = require('express');
const app = express();
// 这会解析 URL 中的查询字符串,并放到 req.query 中
app.use(express.urlencoded({ extended: true }));
app.get('/search', (req, res) => {
console.log(req.query.name); // 应该能正确输出 "张三"
res.send(`你好, ${req.query.name}!`);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
POST 请求乱码
POST 请求的参数在请求体中,乱码问题通常出在服务器读取请求体时没有使用正确的编码。
解决方案
Java (Spring Boot / Spring MVC)
配置 application.properties (同 GET 请求)
上面提到的 Spring Boot 配置对 POST 请求同样有效。
使用 @WebFilter (同 GET 请求)
上面编写的 EncodingFilter 同时也能解决 POST 请求的乱码问题,因为它在 chain.doFilter() 之前设置了 request.setCharacterEncoding("UTF-8")。
Node.js (Express)
Express 的 express.urlencoded() 中间件就是专门用来解析 POST 请求体的(application/x-www-form-urlencoded 格式),它默认就是 UTF-8。
const express = require('express');
const app = express();
// 这个中间件会自动解析 POST 请求体,并处理 UTF-8 编码
app.use(express.urlencoded({ extended: true }));
app.post('/submit', (req, res) => {
console.log(req.body.name); // 应该能正确输出 "李四"
console.log(req.body.message); // 应该能正确输出 "你好,世界!"
res.send('数据接收成功');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
JSON 请求乱码 (常见于前后端分离项目)
现在很多前端使用 fetch 或 axios 发送 JSON 数据到后端。
前端代码示例 (JavaScript):
fetch('/api/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8' // 明确指定字符集
},
body: JSON.stringify({ name: '王五', city: '上海' })
});
问题原因
后端框架在解析 JSON 请求体时,如果没有正确识别 Content-Type 头中的 charset,可能会使用默认的编码。
解决方案
Java (Spring Boot / Spring MVC)
Spring Boot 的 @RequestBody 注解默认会使用 Jackson 库来解析 JSON,Jackson 非常智能,会优先使用 Content-Type 头中指定的 charset。
解决方案:
- 确保前端在
Content-Type中明确指定了charset=UTF-8(如上例所示)。 - 确保后端依赖了 Jackson,Spring Boot Web Starter 会自动包含它。
如果仍然有问题,可以手动配置 ObjectMapper:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
// 确保使用 UTF-8
ObjectMapper objectMapper = builder.build();
return objectMapper;
}
}
Node.js (Express)
Express 的 express.json() 中间件默认也是 UTF-8。
const express = require('express');
const app = express();
// 这个中间件会自动解析 JSON 请求体
app.use(express.json());
app.post('/api/user', (req, res) => {
console.log(req.body.name); // 应该能正确输出 "王五"
res.json({ status: 'success', data: req.body });
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
数据库乱码
如果数据从你的应用正确无误地进入了数据库,但查询出来时是乱码,那么问题出在数据库连接上。
解决方案
确保你的数据库连接 URL 中指定了字符集。
MySQL / JDBC 示例:
// 错误的 URL,可能导致乱码 String url = "jdbc:mysql://localhost:3306/mydb"; // 正确的 URL,明确指定了 useUnicode 和 characterEncoding String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8";
Node.js (mysql2 驱动示例):
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb',
// 关键在这里!
charset: 'utf8mb4' // 推荐使用 utf8mb4,它支持更广的字符集,包括 emoji
});
总结与排查步骤
当你遇到中文乱码时,请按照以下步骤排查:
- 确认根源:是 GET 乱码、POST 乱码、JSON 乱码还是数据库乱码?
- 检查前端:
- 确保你的 HTML 文件头部有
<meta charset="UTF-8">。 - 发送请求时,检查
Content-Type请求头是否包含了charset=UTF-8。
- 确保你的 HTML 文件头部有
- 检查后端(最关键):
- 对于 Java/Spring:优先在
application.properties中添加全局编码配置,如果不行,再考虑使用@WebFilter。 - 对于 Node.js/Express:确保正确使用了
express.urlencoded()和express.json()中间件。 - 打印日志:在服务器端,打印出接收到的原始请求参数或请求体,如果原始日志就是乱码,那问题出在请求发送阶段;如果原始日志正常,但处理后或存入数据库前变成乱码,那问题就在服务器处理逻辑或数据库连接上。
- 对于 Java/Spring:优先在
- 检查数据库:
- 确认数据库表和字段的字符集是
utf8mb4(MySQL) 或UTF8(PostgreSQL等)。 - 确认数据库连接字符串中指定了正确的字符集参数。
- 确认数据库表和字段的字符集是
遵循以上原则,99% 的中文乱码问题都能迎刃而解,核心思想就是 “统一战线”,让整个请求处理链都使用 UTF-8 这一种编码。
