hyperf json-rpc 参数丢失主因是 requestdto 字段名、访问修饰符(须 public)、类型声明三者未与请求 json key 严格一致,框架静默跳过不匹配字段且不报错。

Hyperf 的 JsonRpc 调用中参数丢失,90% 以上不是网络或配置问题,而是 RequestDTO 定义与实际传参结构不匹配导致的反序列化失败——框架静默丢弃字段,不报错也不警告。
为什么 DTO 字段会“消失”而不是报错
Hyperf 默认使用 Hyperf\Utils\Codec\Json 解析请求体,再通过反射 + 属性赋值填充 RequestDTO 实例。它只处理 public 属性或带 @var 注解且有 setter 方法的属性;private/protected 属性、未声明类型、拼写不一致的 key 全部被跳过,且无日志提示。
-
RequestDTO中字段名必须与 JSON 请求中的 key 完全一致(区分大小写) - 没有
public访问修饰符,也没有对应setXxx()方法时,该字段不会被赋值 - 类型声明缺失(如
int $userId写成$userId)会导致类型推断失败,反序列化后为null - 数组嵌套结构需显式声明为
array或具体对象数组,如array|UserDto[] $users
检查 RequestDTO 的三个关键点
以常见错误为例:前端传 {"user_id": 123, "tags": ["a", "b"]},但服务端 RequestDTO 定义如下:
class UserRequest
{
public int $userId; // ❌ 键是 user_id,不是 userId → 值为 0
public array $tags; // ✅ 正确,但若没加 @var 或没 setter,仍可能为空
}
- 确认字段命名:用
user_id就写public int $user_id;,别依赖驼峰转换(Hyperf 默认不开启自动映射) - 确认访问控制:必须是
public,protected或private一律忽略 - 确认类型注解:PHP 8.0+ 推荐用 PHP 原生类型(
int,string),否则需补@var,例如/** @var string */ public $name;
如何快速验证 DTO 是否生效
在 RPC 方法入口加一行调试输出,绕过业务逻辑直接看原始数据:
public function getUserInfo(UserRequest $request)
{
var_dump($request->toArray()); // 看实际塞进去了哪些字段
// 或更底层:
$raw = $this->container->get(\Psr\Http\Message\ServerRequestInterface::class)->getParsedBody();
var_dump($raw); // 看原始 JSON 解析结果
}
- 如果
$raw里有user_id,但$request->toArray()里没有,说明 DTO 映射失败 - 如果两者都有
user_id但值为null,检查字段是否为public且类型兼容(比如传字符串给int字段) - 不要依赖 IDE 自动补全的 setter —— Hyperf 不调用它们,只靠属性直赋
Hyperf JsonRpc 的参数绑定不走 Laravel 风格的表单请求验证流程
很多人误以为加了 @Validated 注解或继承 AbstractRequest 就能触发验证和字段映射,其实不能。Hyperf 的 JsonRpc 参数绑定是独立于 HTTP 中间件链的,它由 Hyperf\JsonRpc\Contract\ParserInterface 实现,默认就是直解析 + 直赋值。
- 验证逻辑(如
@Validate)只在控制器层或手动调用Validator时生效,不影响 DTO 构造 - 想强制校验字段存在性,得在 DTO 中加
__construct()并抛异常,或改用Hyperf\Validation\Request+ 手动解析(不推荐,破坏 RPC 语义) - 真正可靠的方案是:DTO 字段名、类型、可见性三者严格对齐请求体结构,不依赖任何“自动转换”机制
最易被忽略的是字段命名一致性——Hyperf 不做下划线转驼峰,也不会因为接口文档写了 userId 就自动把 user_id 映射过去。你看到的空值,大概率是字段根本没被识别到,而不是“传了但丢了”。











