hyperf 中 return ['data' => $user] 不会自动 json 化,必须显式调用 $response->json() 才能正确设置响应头、编码并保障异常流程兼容性。

Hyperf 默认不区分 API 与 Web 路由,所有控制器方法返回的都是 ResponseInterface 实例,但直接 return ['data' => $user] 不会自动 JSON 化——它会被当成普通数组交给 Swoole 原始响应,最终可能输出裸 PHP 数组或触发不可预期的序列化行为。
用 $response->json() 显式返回 JSON
这是最稳妥、最可控的方式。Hyperf 的 ResponseInterface 提供了 json() 方法,它会自动设置 Content-Type: application/json; charset=utf-8,并调用 json_encode()(含错误检测)。
- 状态码必须显式传入:
$response->json($data, 201),否则默认是 200 - 避免手动
echo json_encode(...):绕过框架响应生命周期,丢失中间件、日志、异常捕获等能力 - 不要在
json()前调用header()或http_response_code():json()内部已处理,重复设置可能被覆盖或报错 - 若需自定义 JSON 编码选项(如中文不转义),可传第四个参数:
$response->json($data, 200, [], JSON_UNESCAPED_UNICODE)
别依赖 return [] 自动转换
Hyperf 没有 Laravel 那样的“API 上下文自动识别”机制。即使你把路由写在 routes/api.php,框架也不会因此给 return [] 加上 JSON 头或编码逻辑——这完全是开发者手动控制的。
-
return ['code' => 0, 'data' => $user]等价于return $response->raw(json_encode([...])),不设头、不校验、不兼容异常流程 - 这种写法在调试时看似正常,但一旦数据含资源句柄、Closure 或循环引用,
json_encode()返回false,响应体变成空字符串或"false"字面量 - 前端收到
text/html类型响应(Swoole 默认 fallback)时,fetch().json()会直接抛错
统一格式建议封装成响应方法
每个接口都写 $response->json(['code' => 200, 'data' => ...], 200) 容易遗漏字段或状态码。推荐在基类控制器或服务中封装:
public function success($data = null, int $code = 200, string $message = 'success')
{
return $this->response->json([
'code' => $code,
'data' => $data,
'message' => $message
], $code);
}
- 避免在封装里硬写状态码常量(如
Response::HTTP_OK),Hyperf 不自带 Laravel 的Illuminate\Http\Response - 业务异常不要用
success(),而应走ExceptionHandler统一拦截并返回$response->json(..., 4xx) - 若使用
Hyperf\ExceptionHandler\ExceptionHandler,确保render()中对$request->header('accept')含application/json的请求才返回 JSON,否则可能干扰管理后台等 HTML 场景
注意中间件顺序和 Accept 头判断
Hyperf 没有内置的 api 中间件组,也不存在 Laravel 那种路由文件级中间件绑定。是否返回 JSON,最终取决于你如何设计中间件链与异常处理器。
- 跨域(CORS)、Token 校验等中间件应放在
json()之前,否则响应头可能被覆盖 - 异常处理器中别只靠
$request->isAjax()判断——Hyperf 没这个方法;改用stripos($request->header('accept', ''), 'application/json') !== false - 测试时务必带
-H "Accept: application/json",浏览器直输地址默认发text/html,容易误判逻辑 - 流式响应(如 SSE)不能混用
json():它会关闭连接,得用$response->withHeader('Content-Type', 'text/event-stream')手动写
真正卡住人的从来不是怎么输出 JSON,而是状态码漏设、Accept 头没校验、异常路径绕过处理器、以及把 json() 当作“语法糖”而非响应契约来对待。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











