Webman无内置统一Response类,需用Result工具类封装标准JSON响应;继承support\Response无效,因不参与json()流程;异常和中间件也须手动构造标准结构。

Webman 没有内置的「统一 Response 类」机制,所有标准化输出必须靠显式封装或中间件兜底。直接继承 support\Response 并重写方法是无效的——它不参与 JSON 响应构造流程,也不被框架自动调用。
为什么不能继承 support\Response 自定义类
Webman 的 response()->json() 底层走的是 support\Response 构造 + json_encode() 输出,但这个类本身不提供可覆盖的「序列化入口」。你继承它、重写 __toString() 或 output(),对 response()->json($data) 完全无影响。
- 常见错误:新建
app\response\JsonResponse继承support\Response,以为 return new JsonResponse(...) 就能自动套结构 —— 实际返回仍是裸数组或原始字符串 -
support\Response是一个低阶响应容器,只管状态码、头、体三元组,不做业务结构包装 - 真正控制 JSON body 格式的,只有控制器里写的
return json([...])、return response()->json(...),或你封装的工具函数
正确做法:用 Result 工具类替代 Response 类
推荐在 app/result/Result.php 封装静态方法,所有控制器统一调用 Result::Success() 或 Result::ErrorCode(),而非碰原生 response() 或 json()。
-
Result::Success($data)内部调用response()->json(['code' => 0, 'msg' => 'success', 'data' => $data]),并确保Content-Type和 HTTP 状态码(默认 200)正确 -
Result::ErrorCode(4001, '用户名为空')同样走response()->json(),但固定code字段为业务码,HTTP 状态码仍为 200(除非显式传第 3 个参数) - 避免在类里做自动字段过滤(如删
password),那是 Controller 层职责;Result 只负责把传入数据干净地包进标准结构 - 若需非 200 状态码(如 422 表单失败),显式写
Result::ErrorCode(422, '验证失败')->withStatus(422)
全局异常必须走 render() 手动构造 JSON
Webman 默认异常响应是 HTML 页面,不是 JSON。想让 throw new \Exception('xxx') 也返回标准结构,必须配置自定义异常处理器,并在 render() 方法里手动输出。
立即学习“PHP免费学习笔记(深入)”;
- 注册路径必须是
config/exception.php中的空键:'' => app\exception\ExceptionHandler::class,不能写成'default'或带注释 -
render()内必须写header('Content-Type: application/json; charset=utf-8'),且返回值必须是support\Response实例,不能直接return ['code'=>500] - 最稳妥写法:
return response()->json(['code' => 500, 'msg' => $e->getMessage(), 'data' => null])->withStatus(500) - 别依赖
http_response_code(500),它对 Webman 无效;也别在render()里echo+exit,会破坏中间件链
中间件中修改响应体要绕过框架自动处理
比如限流中间件返回 429,但默认 body 为空。想补上标准 JSON 结构,不能简单 $response->withStatus(429),得重写整个响应体。
- 错误写法:
return $response->withStatus(429)—— body 还是空的,前端 fetch().json() 会报错 - 正确写法:
return response()->json(['code' => 429, 'msg' => '请求过于频繁', 'data' => null])->withStatus(429) - 如果中间件已拿到原始
$response实例(比如来自$next($request)),不能直接改它的 body,要用新response()替换 - 注意中间件执行顺序:你的统一封装中间件必须在限流、鉴权等之后,但在最终输出前,否则会被后续中间件覆盖
真正难的不是写一个 Result 类,而是让所有分支——正常返回、参数校验失败、数据库异常、未捕获异常、中间件拦截——都经过同一出口。漏掉任意一环,前端就要多写一个 if 判断,长期维护成本就上去了。



















