ThinkPHP伪静态路由本身不导致乱码,根本原因是URL中文参数在传递、解析、数据库写入及模板输出等环节编码不一致;必须全程统一使用UTF-8无BOM,涵盖.htaccess或Nginx配置、路由正则、数据库charset(utf8mb4)、语言包文件编码及htmlspecialchars编码声明。

ThinkPHP 伪静态路由本身不会导致乱码,真正出问题的环节是 URL 中的中文参数在传递、解析、数据库写入或模板输出时,多个环节的编码不一致。关键不是“开启伪静态”,而是确保整个链路都用 UTF-8 无 BOM 贯穿。
伪静态 URL 中的中文参数被截断或显示为问号
这是最典型的表象:比如访问 /article/标题-含中文,控制器里 $this->request->param('title') 拿到的是乱码或空值。
- Apache 用户必须确认
.htaccess文件本身是 UTF-8 无 BOM 编码保存的——否则重写规则里的中文会被 Apache 错误解析 - Nginx 用户需检查
location块中是否遗漏charset utf-8;或设置了冲突的charset GBK; - ThinkPHP 路由正则若手动写了匹配中文的规则(如
[\x{4e00}-\x{9fa5}]+),必须在 PHP 文件顶部加mb_internal_encoding('UTF-8');,否则 PCRE 不识别 Unicode 范围 - 浏览器地址栏输入含中文的伪静态 URL 时,实际已自动做 URL 编码(如
%E4%B8%AD%E6%96%87),ThinkPHP 默认能正确解码;但若中间经过 Nginx 反向代理或 CDN,需确认它们未二次解码或丢弃编码
数据库查出的中文在伪静态页面里显示为
和普通页面一样,但容易被误认为是伪静态导致——其实只是数据库连接层没对齐。
- 检查
config/database.php中'charset' => 'utf8mb4'(注意是utf8mb4,不是utf8) - 确认 MySQL 服务端配置
my.cnf包含:character-set-server = utf8mb4和collation-server = utf8mb4_unicode_ci - 执行
SHOW VARIABLES LIKE 'character_set%';,重点看character_set_client、character_set_connection、character_set_results是否全为utf8mb4 - 如果用了 PDO,在 DSN 后追加
;charset=utf8mb4;如果用了 mysqli,连接后立即调用mysqli_set_charset($conn, 'utf8mb4');
多语言切换时中文变乱码(如 /zh-cn/article/测试)
ThinkPHP 的多语言包(lang/zh-cn.php)若文件编码不对,会导致整个语言变量数组读取失败。
立即学习“PHP免费学习笔记(深入)”;
- 所有
lang/*.php文件必须保存为 UTF-8 无 BOM——VS Code 中右下角点击编码 → “通过编码重新打开” → UTF-8 → 再点编码 → “另存为编码” → UTF-8(不带 BOM) -
config/app.php中的'default_lang' => 'zh-cn'和语言 Cookie 名不能含非 ASCII 字符 - 如果使用了
Lang::get()动态加载语言变量,确保传入的键名是英文,不要把中文当 key 用(如Lang::get('文章标题')是错的,应为Lang::get('article_title')) - 模板中输出语言变量时,避免混用
htmlspecialchars()和原始中文内容——它默认按 ISO-8859-1 处理,应显式指定编码:htmlspecialchars($str, ENT_QUOTES, 'UTF-8')
最容易被忽略的是:伪静态 + 多语言 + 数据库三者叠加时,BOM 头会破坏 header 输出,导致后续所有编码设置失效。哪怕只在一个 lang/zh-cn.php 文件里存在 BOM,整个请求的 Content-Type header 就发不出去,浏览器只能靠猜,一猜一个乱。



















