tp8.0接口返回json中文乱码的根源是响应头缺失charset=utf-8,需在全局中间件中强制设置content-type为application/json;charset=utf-8。

TP8.0 接口返回 JSON 时中文显示为 ??? 或 u5f20u4e09 等 Unicode 转义,前端解析后仍是乱码,不是前端没解码,而是响应流在输出前已被错误编码或未声明字符集,必须从框架底层响应环节拦截并重置编码行为。
确认乱码是否真由 TP8.0 响应头缺失导致
打开浏览器开发者工具 → Network → 点击任意一个返回中文的接口 → 查看 Response Headers → 找到 Content-Type 字段。如果值是 【application/json】 而没有 【;charset=utf-8】 后缀,这就是根源——TP8.0 默认不自动补 charset,即使你 json_encode 用了 JSON_UNESCAPED_UNICODE,没有响应头声明,某些旧版 WebView 或代理网关仍会按 ISO-8859-1 解析。
这一步不能跳过。有些项目启用了 gzip 中间件,压缩后 header 可能被覆盖,必须以原始未压缩响应为准。
全局中间件强制设置 UTF-8 响应头
在 app/middleware 目录下新建文件 ForceUtf8Response.php:
用命令行快速创建:php think make:middleware ForceUtf8Response
编辑该文件,写入以下内容:
```php
namespace appmiddleware;
use thinkResponse;
class ForceUtf8Response
{
public function handle($request, Closure $next)
{
$response = $next($request);
if ($response instanceof Response && strpos($response->getHeader('Content-Type'), 'application/json') === 0) {
$response->header('Content-Type', 'application/json; charset=utf-8');
}
return $response;
}
}
```
注意:不要用 header() 函数硬写,TP8.0 的 Response 对象已接管输出,直接调用 $response->header() 才生效。用 header() 会导致 headers already sent 错误。
注册中间件为全局(仅对 JSON 接口生效)
打开 app/middleware.php 文件,在数组末尾追加一行:
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
'app\middleware\ForceUtf8Response' => ['except' => ['api/upload', 'api/download']]
这个配置表示:对所有路由启用该中间件,但排除上传和下载类接口(它们可能返回二进制流,设成 application/json 会破坏文件)。
如果你的 API 全部集中在 api/ 下,也可以更精准地限定作用域:
在 app/middleware.php 中改用闭包方式注册:
```php
return [
// 其他中间件...
'api/*' => [appmiddlewareFroceUtf8Response::class],
];
```
TP8.0 支持通配符路由绑定中间件,比全局注册更安全,避免干扰后台 HTML 页面或静态资源。
验证是否生效
重启 PHP-FPM 或 Swoole 服务(如使用命令 php think swoole:restart),然后重新请求任意 JSON 接口。
再次打开 Network 面板 → 查看响应头 → 确认 Content-Type 已变为 【application/json; charset=utf-8】。
此时若仍显示 uXXXX,说明前端未调用 JSON.parse();若显示 ???,说明数据库查询结果本身不是 UTF-8 编码——需检查 PDO 连接参数是否含 charset=utf8mb4。










