跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何修复Hyperf中JsonRpc调用时的参数丢失_检查RequestDTO定义

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 方法入口加一行调试输出,绕过业务逻辑直接看原始数据: php版微信js-sdk支付接口类 php版微信js-sdk支付接口类 下载
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
映射过去。你看到的空值,大概率是字段根本没被识别到,而不是“传了但丢了”。

相关文章