必须使用框架认可的异常类型并重写render()方法返回json,否则前端收不到规范错误码;http状态码与业务码需分层设计,不可混用。

直接 throw new Exception() 不会返回规范错误码
这是最常踩的坑:写 throw new Exception('参数错误'),前端收到的是 HTML 错误页(开发环境)或空白响应(生产环境),code 字段根本不会出现。ThinkPHP 的 app\common\exception\Handler::render() 只处理继承自 think\Exception 或其子类(如 HttpException、ValidateException)的异常,原生 Exception 被 PHP 底层直接捕获,框架无感知。
必须用框架认可的异常类型,例如:
throw new HttpException(400, '参数缺失', ['code' => 1001])throw new ValidateException($errorInfo, 422, ['code' => 1002])- 自定义业务异常类需继承
HttpException,不能只继承Exception
Handler::render() 中必须显式构造 JSON 响应结构
即使抛出的是 HttpException,默认响应仍可能是 HTML(尤其非 AJAX 请求),render() 方法不干预的话,前端收不到统一 code 字段。关键不是调 json(),而是主动覆盖响应体和头:
- 先判断是否为 API 场景:检查
$request->pathinfo()是否以/api/开头,或是否命中api中间件 - 用
response()->json()构造结构:['code' => $e->getCode() ?: 500, 'msg' => $e->getMessage(), 'data' => []] - 必须链式调用
->code($e->getStatusCode() ?: 500)设置 HTTP 状态码 - 必须显式设头:
->header('Content-Type', 'application/json'),不能依赖默认
验证失败时 getError() 返回字符串,要字段级错误得用 getFailMsg()
$validate->getError() 默认只返回中文提示字符串(如“邮箱格式不正确”),没有字段键名,前端无法定位具体哪个字段出错。想返回 { "code": 422, "msg": "验证失败", "errors": { "email": ["邮箱格式不正确"] } } 这类结构,必须:
- 开启 batch 模式:
$validate->batch(true)->check($data) - 关闭
failException(设为false),避免提前中断 - 调用
$validate->getFailMsg()—— 注意:ThinkPHP 6.0+ 才返回带字段键的二维数组,5.1 需手动解析 - 在控制器中手动封装:
return response()->json(['code' => 422, 'msg' => '验证失败', 'errors' => $validate->getFailMsg()])->code(422)
状态码与业务码必须分层设计,别混在一起
HTTP 状态码(如 400、401、422)是通信契约,业务码(如 1001、2002)是领域语义,两者不可替代。前端靠状态码做通用错误处理(比如 401 自动跳登录),靠业务码做具体提示或逻辑分支。
常见错误包括:
- 所有错误都返回 200 +
code: 1001→ 前端无法区分网络失败、服务不可用、还是业务拒绝 - 把业务码当 HTTP 状态码传给
HttpException构造函数 → 导致实际发出去的是 1001 状态码,违反 HTTP 协议 - 在
render()里忽略$e->getStatusCode(),一律用 500 → 验证失败本该是 422,却变成 500,掩盖问题性质
真正要小心的是:HttpException 第二个参数是消息,第三个参数是数据(可放业务码),第四个参数才是 HTTP 状态码 —— 顺序错一个,code 字段就进不了响应体,或者状态码发不出去。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











