当前位置: 首页
数据库
RuoYi-Vue-Plus Docker部署踩坑:MySQL中文双重编码根因与修复

RuoYi-Vue-Plus Docker部署踩坑:MySQL中文双重编码根因与修复

热心网友 时间:2026-07-18
转载

RuoYi-Vue-PlusDocker部署中,MySQL初始化客户端字符集默认latin1,导致UTF-8字节被双重编码,中文显示乱码。在SQL文件首行添加SETNAMESutf8mb4;并重新初始化即可修复。

问题现象:RuoYi-Vue-Plus Docker 部署后菜单中文乱码

使用 docker-compose 部署完 RuoYi-Vue-Plus 项目后,打开前端页面时发现——菜单和面包屑中的中文全部变成了类似这样的乱码:系统管ç†ç§Ÿæˆ·ç®¡ç†。但页面按钮上的「新增」「修改」「删除」以及表头中的「角色名称」「权限字符」却显示正常。看到这种模式,第一时间判断是编码问题,但具体出在哪个环节呢?

RuoYi-Vue-Plus Docker 部署踩坑:MySQL 中文双重编码的根因与修复

详细排查流程

Step 1:排除 Nginx 的干扰

首先检查 Nginx 响应头,Content-Type 明确标注了 charset=utf-8,这里没有问题,直接跳过。

 复制代码curl -sI 
# Content-Type: text/html; charset=utf-8 

Step 2:确认前端 JS 编码无误

接着检查编译产物的字符串字节。以「系统」为例,其 UTF-8 编码应为 e7 b3 bb,通过 xxd 命令搜索,发现前端 JS 文件中保存的 UTF-8 字节完全正确。前端层面没有问题。

 复制代码# "系统" 的 UTF-8 编码应该是 e7 b3 bb
xxd /usr/share/nginx/html/assets/index-*.js | grep "e7b3"
# 确认找到了,前端 JS 中的 UTF-8 字节是正确的

Step 3:检测 API 原始响应字节

这一步是关键。使用 Python 直接读取 API 返回的原始字节,不经过任何解码:

 复制代码import urllib.request
# ... 登录逻辑省略 ...
resp = urllib.request.urlopen(req)
raw = resp.read()
print(repr(raw[:200]))

输出结果:

 复制代码b'{"meta":{"title":"\xc3\xa7\xc2\b3\xc2\xbb...'

问题暴露了!正常的「系统管理」UTF-8 字节应该是:

 复制代码xe7xb3xbbxe7xbbx9fxe7xaexa1xe7x90x86

而实际返回的却是:

 复制代码xc3xa7xc2xb3xc2xbbxc3xa7xc2xbb...

每个原始 UTF-8 字节前面都多了一个 xc3xc2。这正是经典的 Mojibake(双重编码)现象:

 复制代码原始 UTF-8:  E7 B3 BB     "系"
被当作 Latin-1: ç ³ »       3  Latin-1 字符
再以 UTF-8 编码: C3 A7  C2 B3  C2 BB  6 个字节

Step 4:确认问题出在数据库层

直接查询 MySQL 表验证:

 复制代码SELECT menu_name, HEX(menu_name), LENGTH(menu_name), CHAR_LENGTH(menu_name)
FROM sys_menu WHERE menu_id = 1;
 复制代码+----------+----------------------------------------------+--------+----------------+
| menu_name| HEX(menu_name)                               | LENGTH | CHAR_LENGTH    |
+----------+----------------------------------------------+--------+----------------+
| 系统管理  | C3A7C2B3C2BBC3A7C2BBC5B8C3A7C2AEC2A1C3A7... | 25     | 12             |
+----------+----------------------------------------------+--------+----------------+
  • CHAR_LENGTH = 12:MySQL 认为这是 12 个「字符」(实际是 12 个 Latin-1 字符)
  • LENGTH = 25:实际存储了 25 个字节
  • 正确的「系统管理」应该是 CHAR_LENGTH = 4LENGTH = 12,HEX 为 E7B3BBE7BB9FE7AEA1E79086

数据库里存储的就是双重编码的数据!

Step 5:定位 MySQL 初始化时的 charset 问题

检查 MySQL 连接的字符集:

 复制代码SHOW SESSION VARIABLES LIKE 'character_set%';
 复制代码| character_set_client     | latin1 |
| character_set_connection | latin1 |
| character_set_results    | latin1 |
| character_set_server     | utf8mb4 |

虽然 character_set_server = utf8mb4,但 character_set_client = latin1!问题链路非常清晰:

 复制代码SQL 文件 (UTF-8: 系统管理 = E7B3BB E7BB9F E7AEA1 E79086)
    ↓
mysql 客户端 (character_set_client = latin1)
    ↓
MySQL 服务器认为输入是 Latin-1,按 Latin-1 存储
    ↓
每个 UTF-8 字节被当成独立的 Latin-1 字符
    ↓
存储结果变成双重编码: C3A7C2B3C2BB...

为什么只设置 --character-set-server=utf8mb4 不够?

你的 docker-compose.yml 可能已经配置了:

 复制代码mysql:
  image: mysql:8.0
  command:
    --character-set-server=utf8mb4
    --collation-server=utf8mb4_general_ci

但这只设置了服务端(server)的默认字符集。当 docker-entrypoint-initdb.d 执行 SQL 文件时,使用的是 mysql 客户端连接,而 mysql 客户端的 character_set_client 默认值取决于 操作系统的 locale

MySQL 官方 Docker 镜像基于 Oracle Linux 或 Debian,默认 locale 是 CPOSIX,映射到 MySQL 后就是 latin1。因此,即使你配置了 --character-set-server=utf8mb4,initdb 阶段的 mysql 客户端连接仍然是 latin1,导致中文数据被错误编码。

为什么 --init-connect 也不起作用?

你可能尝试过:

 复制代码command:
  --init-connect="SET NAMES utf8mb4"

--init-connectroot 用户不生效(这是 MySQL 的安全策略)。而 docker-entrypoint-initdb.d 中的 SQL 正是用 root 用户执行的,所以这个配置完全无效。

有效修复方案

在每个 SQL 文件的第一行添加 SET NAMES utf8mb4;

 复制代码SET NAMES utf8mb4;
-- ----------------------------
-- 原来的内容...
-- ----------------------------
create table sys_social
(
    ...
);

然后删除数据卷,重新初始化数据库:

 复制代码docker compose down -v    # 删除数据卷
docker compose up -d      # 重新启动,重新执行 initdb.d

验证结果:

 复制代码SELECT menu_name, HEX(menu_name), CHAR_LENGTH(menu_name)
FROM sys_menu WHERE menu_id = 1;
 复制代码+----------+----------------------------------+--------------+
| menu_name| HEX(menu_name)                   | CHAR_LENGTH  |
+----------+----------------------------------+--------------+
| 系统管理  | E7B3BBE7BB9FE7AEA1E79086         | 4            |
+----------+----------------------------------+--------------+

CHAR_LENGTH = 4,HEX 是正确的 UTF-8 编码,问题完美解决。

其他备选方案对比

方案是否有效原因
--character-set-server=utf8mb4只影响 server 层,不影响 client 连接
--init-connect="SET NAMES utf8mb4"root 用户不执行 init_connect
-e LANG=C.UTF-8️ 部分只对 BMP 字符有效,emoji 等扩展字符仍有问题
[client] default-character-set=utf8mb4在 my.cnf 里配置,但需要挂载自定义配置文件
SQL 文件头部加 SET NAMES utf8mb4;最简单、最可靠,不依赖任何外部配置

为什么这个问题难以排查?

  1. 静态文字正常:Vue 模板里写死的按钮中文不受影响,只有数据库返回的动态数据出现乱码
  2. 乱码不是问号:不是典型的 ??? 或方块字符,而是 系统 这种“看起来像编码问题但又不确定”的字符串
  3. server charset 具有误导性SHOW VARIABLES 显示 character_set_server=utf8mb4,让人误以为配置正确
  4. SQL 文件本身是 UTF-8:用 file 命令检查 SQL 文件确实是 UTF-8,但写入时被 mysql 客户端转码了

总结

MySQL Docker 镜像的 docker-entrypoint-initdb.d 机制中,mysql 客户端默认的字符集是 latin1 而不是 utf8mb4。 这是一个从 2016 年就有人报告的问题(docker-library/mysql#131、#708),至今仍作为默认行为存在。

如果你的 SQL 文件包含非 ASCII 字符(中文、日文、韩文、emoji 等),务必在每个 SQL 文件的第一行添加 SET NAMES utf8mb4;,否则数据会被双重编码写入数据库,导致中文乱码。


参考:

  • docker-library/mysql#131 - UTF8 Encoded SQL Scripts in initdb
  • docker-library/mysql#708 - utf8 dump imported as latin1
  • MySQL 8.0 Reference - Character Sets
来源:https://juejin.cn/post/7663295656179073064

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
利用AWR报告诊断表空间碎片对扫描性能的影响

利用AWR报告诊断表空间碎片对扫描性能的影响

通过AWR报告中dbfilesequentialread等待异常、物理读请求次数增幅远超读块数、以及SQL执行计划从索引扫描退化为全表扫描这三类信号交叉验证,可判断表空间碎片是否拖慢扫描性能,避免误判。

时间:2026-07-19 10:46
MySQL第三方审计系统只读系统视图权限配置方法

MySQL第三方审计系统只读系统视图权限配置方法

为审计账号配置MySQL只读权限时,performance_schema必须逐表显式授权,不可使用* *或库级批量授权;认证插件必须指定mysql_native_password;无法通过视图封装,必须直接授权原始表。这是审计账号配置的关键注意事项,必须严格遵守,并遵循最小权限原则。

时间:2026-07-19 10:45
Navicat团队项目自定义图标背景色设置方法

Navicat团队项目自定义图标背景色设置方法

Navicat中设置团队项目图标背景色实为两个独立配置:模型图节点颜色需手动修改navicat ini文件并完全重启;SQL编辑器及主窗口背景色通过主题设置。版本一致、配置路径准确、激活ERD模式是效果一致的关键。修改后必须彻底退出程序。

时间:2026-07-19 10:14
SQL嵌套查询中如何有效利用索引覆盖提升性能

SQL嵌套查询中如何有效利用索引覆盖提升性能

SQL嵌套查询中,子查询字段未被索引覆盖会导致全表扫描,而外层EXPLAIN的Usingindex可能误导优化。需为子查询过滤字段建索引,联合索引将SELECT字段包含在内且顺序正确。PostgreSQL可用INCLUDE或组合索引,MySQL8 0+支持函数索引,物化视图需手动建索引并刷新统计信息。

时间:2026-07-19 10:14
SQL窗口函数快速查找用户多设备登录顺序

SQL窗口函数快速查找用户多设备登录顺序

使用ROW_NUMBER()配合PARTITIONBYuser_id和ORDERBYlogin_time,可快速按用户分组并排序登录顺序。漏掉PARTITIONBY会导致全局编号,且必须用ROW_NUMBER()保证编号连续,避免RANK()或DENSE_RANK()的跳号问题。区分首次登录可嵌套MIN()窗口函数。老版本MySQL用变量模拟易出错,建议升级

时间:2026-07-19 10:14
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜