中文参数乱码,如何解决?

99ANYc3cd6
预计阅读时长 27 分钟
位置: 首页 参数 正文

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

request 中文参数乱码
(图片来源网络,侵删)

问题根源

乱码问题的根源几乎总是 编码不一致

  1. 编码:一方(通常是浏览器或客户端)用一种编码(如 UTF-8)将中文字符转换成字节流。
  2. 传输:字节流在网络中传输。
  3. 解码:另一方(通常是你的服务器)用另一种错误的编码(如 ISO-8859-1,即 latin1)来解读这些字节流。
  4. 结果:由于编码和解码的“密码本”不一样,最终显示出来就是一堆看不懂的乱码(如 )。

我们的目标就是确保从客户端到服务器,再到数据库,整个链条都使用同一种编码,业界公认的最佳选择是 UTF-8


GET 请求乱码

GET 请求的参数通常在 URL 中,http://yourdomain.com/search?name=张三&city=北京

问题原因

URL 的编码方式比较复杂,但服务器在解析 URL 时,如果没有正确配置,可能会用错误的编码来解析查询字符串。

request 中文参数乱码
(图片来源网络,侵删)

解决方案(以主流技术栈为例)

Java (Spring Boot / Spring MVC)

Spring Boot 默认已经处理得很好,但如果出现乱码,可以尝试以下方法:

配置 application.propertiesapplication.yml (推荐)

这是最简单、最优雅的方式,Spring Boot 会自动应用这些配置。

application.properties

request 中文参数乱码
(图片来源网络,侵删)
# 解决 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 默认使用 qsquerystring 解析查询字符串,它们默认使用 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 请求乱码 (常见于前后端分离项目)

现在很多前端使用 fetchaxios 发送 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

解决方案:

  1. 确保前端在 Content-Type 中明确指定了 charset=UTF-8 (如上例所示)。
  2. 确保后端依赖了 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
});

总结与排查步骤

当你遇到中文乱码时,请按照以下步骤排查:

  1. 确认根源:是 GET 乱码、POST 乱码、JSON 乱码还是数据库乱码?
  2. 检查前端
    • 确保你的 HTML 文件头部有 <meta charset="UTF-8">
    • 发送请求时,检查 Content-Type 请求头是否包含了 charset=UTF-8
  3. 检查后端(最关键)
    • 对于 Java/Spring:优先在 application.properties 中添加全局编码配置,如果不行,再考虑使用 @WebFilter
    • 对于 Node.js/Express:确保正确使用了 express.urlencoded()express.json() 中间件。
    • 打印日志:在服务器端,打印出接收到的原始请求参数或请求体,如果原始日志就是乱码,那问题出在请求发送阶段;如果原始日志正常,但处理后或存入数据库前变成乱码,那问题就在服务器处理逻辑或数据库连接上。
  4. 检查数据库
    • 确认数据库表和字段的字符集是 utf8mb4 (MySQL) 或 UTF8 (PostgreSQL等)。
    • 确认数据库连接字符串中指定了正确的字符集参数。

遵循以上原则,99% 的中文乱码问题都能迎刃而解,核心思想就是 “统一战线”,让整个请求处理链都使用 UTF-8 这一种编码。

-- 展开阅读全文 --
头像
戴尔U2412MB拆机步骤有哪些?
« 上一篇 今天
Lumia 920参数如何?值得买吗?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

最近发表

标签列表

目录[+]