Hyperf控制器中$request->post()无法获取JSON数据,因默认仅解析x-www-form-urlencoded和multipart/form-data;需启用JsonMiddleware或手动解析php://input。

Hyperf 控制器里不能直接用 $request->json() 或 $request->all() 拿 JSON 参数,因为默认不自动解析请求体;必须显式启用 JSON 解析中间件或手动读取原始流。
为什么 $request->post() 拿不到 JSON 数据
Hyperf 的 HttpServer 默认只解析 application/x-www-form-urlencoded 和 multipart/form-data 类型的请求体。application/json 请求体被跳过,$request->post()、$request->all() 均为空数组。
- 现象:
curl -H "Content-Type: application/json" -d '{"id":1}' http://localhost:9501/api/test,控制器中$request->post()返回[] - 根本原因:Hyperf 的核心中间件
CoreMiddleware未对application/json类型做json_decode(file_get_contents('php://input'))处理 - 注意:
$request->getContent()能拿到原始字符串,但需手动json_decode(),且重复调用会失败(php://input 只能读一次)
正确获取 JSON 参数的两种方式
推荐使用第一种,更符合 Hyperf 风格且兼容验证器、注解等能力。
- 方式一:启用
JsonMiddleware(推荐)
在config/autoload/middlewares.php中为对应路由加中间件:return [ 'http' => [ \Hyperf\HttpServer\Middleware\JsonMiddleware::class, ], ];然后在控制器方法参数上用类型提示 + 验证器,例如:public function store(RequestInterface $request, UserRequest $requestValidator) { // $requestValidator->validated() 即解析后的数组 } - 方式二:手动解析
php://input
仅限简单场景,避免与验证器、@Validate注解混用:$raw = $request->getBody()->getContents(); $data = json_decode($raw, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new BadRequestHttpException('Invalid JSON'); }
JsonMiddleware 的行为细节和坑点
它不是“万能 JSON 解析器”,有明确边界和限制。
- 只在
Content-Type: application/json时触发,其他类型(如text/plain、空 header)直接跳过 - 解析结果存入
$request的parsedBody属性,所以$request->all()、$request->input('key')才能取到值 - 如果同时配置了
FormParamsMiddleware(处理表单),二者互斥:JSON 请求不会进 Form 中间件,反之亦然 - 不处理嵌套 JSON(如
{"user":{"name":"a"}}),但$request->input('user.name')仍可用 —— 这是 Hyperf 的InputResolver特性,非中间件本身行为
配合 @Validate 注解使用的注意事项
验证器能否生效,取决于参数是否已进入 parsedBody。所以:
- 必须确保
JsonMiddleware已加载且执行顺序早于验证中间件(默认满足) - 验证器类中的
rules()方法写法与普通表单一致,例如:public function rules(): array { return [ 'id' => 'required|integer', 'name' => 'required|string|max:50', ]; } - 若用
@Validate但没配JsonMiddleware,验证器会收不到数据,报Missing parameter类错误
最常被忽略的是中间件加载顺序和 Content-Type 的严格匹配 —— 少一个字母(比如写成 application/json; charset=utf-8)在某些旧版 Hyperf 中可能失效,建议始终用标准格式发送。


















