
当 JWT Token 被篡改(如增删字符)导致解析失败时,CI4 抛出 FormatException: Failed to parse json string 并返回 500 错误页,而非预期的 401 JSON 响应——根本原因在于命名空间下未正确引用全局 Exception 类,导致自定义错误处理逻辑被跳过。
当 jwt token 被篡改(如增删字符)导致解析失败时,ci4 抛出 `formatexception: failed to parse json string` 并返回 500 错误页,而非预期的 401 json 响应——根本原因在于命名空间下未正确引用全局 `exception` 类,导致自定义错误处理逻辑被跳过。
在 CodeIgniter 4 中编写自定义 Auth 过滤器时,若使用 namespace App\Filters; 声明命名空间,则所有未加前缀的类名(如 Exception)都会被自动解析为当前命名空间下的类(即 \App\Filters\Exception),而该类并不存在。因此,catch (Exception $ex) 实际无法捕获任何异常——包括 JWT 解析失败抛出的 DomainException、InvalidArgumentException 或后续 JSON 格式化阶段触发的 FormatException。未被捕获的异常将穿透至框架全局异常处理器,最终由 JSONFormatter 尝试格式化包含非法 UTF-8 字符(如 PHP 错误堆栈中的 HTML 实体
)的响应内容,从而引发二次崩溃并输出原始 PHP Fatal Error。
✅ 正确做法:显式引入或使用全限定类名
推荐在过滤器顶部添加 use 语句,明确导入所需异常类型:
<?php namespace App\Filters; use CodeIgniter\Filters\FilterInterface; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use Firebase\JWT\JWT; use Firebase\JWT\Key; use Exception; // ← 关键:引入全局 Exception use DomainException; // 可选:JWT 更可能抛出此类型 use InvalidArgumentException; // 可选:更精准捕获 JWT 异常
随后更新 catch 块,优先捕获 JWT 相关异常,再兜底捕获通用异常:
try {
JWT::decode($token, new Key($key, 'HS256'));
} catch (DomainException | InvalidArgumentException $ex) {
// Token 无效、过期、签名错误等 JWT 特定异常
$response = [
'status' => 401,
'error' => true,
'message' => 'Invalid or expired token.',
'data' => []
];
header('Content-Type: application/json; charset=utf-8');
http_response_code(401);
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit();
} catch (Exception $ex) {
// 兜底:捕获其他未预期异常(如配置错误、密钥为空等)
log_message('error', 'Auth filter exception: ' . $ex->getMessage());
$response = [
'status' => 500,
'error' => true,
'message' => 'Authentication service error.',
'data' => []
];
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit();
}⚠️ 注意事项与最佳实践
- 禁止直接 echo + exit():CI4 推荐通过 ResponseInterface 返回响应。但过滤器 before() 中尚未初始化完整 Response 对象,此时手动设置 header() 和 http_response_code() 是安全且必要的。
- JSON 输出需指定 UTF-8:始终添加 charset=utf-8 头,并使用 JSON_UNESCAPED_UNICODE 避免中文乱码。
- 日志记录不可少:对非 JWT 异常(如 $key 为空)务必记录,便于排查生产环境问题。
- 避免裸 catch (Exception) 在生产环境:应尽量细化异常类型(如 DomainException, UnexpectedValueException),提高可维护性。
- 验证 Token 前先校验格式:可在 JWT::decode() 前增加简单正则校验(如 /^[A-Za-z0-9\-_]+?\.[A-Za-z0-9\-_]+?\.[A-Za-z0-9\-_]+?$/),提前拦截明显非法字符串,减少 JWT 库内部解析开销。
修复后,篡改 Token 将稳定返回结构化 JSON 响应(如 {"status":401,"error":true,"message":"Invalid or expired token.","data":[]}),前端可统一处理,不再触发 500 内部错误与控制台堆栈污染。











