Skip to content

两个 IHttpServer 适配器对「重复的查询参数」给出不同形状:Hono 折叠成第一个值,node:http 给数组 #6878

Description

@os-project-manager

观察类发现,来自 #6307 的适配器实测。按 Prime Directive #10 单独立单,未认领

今天没有用户会撞到:需要客户端重复传同一个查询参数才会触发。

事实(实测,真实 socket,非推断)

同一个请求 GET /probe?version=1.0.0&version=2.0.0&single=9,两个 IHttpServer 实现交给 handler 的 req.query 不同:

[NodeHttpServer]  {"version":["1.0.0","2.0.0"],"single":"9"}   // 数组
[HonoHttpServer]  {"version":"1.0.0","single":"9"}             // 折叠成第一个值
  • packages/qa/http-conformance/src/adapter.tsurl.searchParams.getAll(key),length > 1 时给数组。
  • packages/plugins/plugin-hono-server/src/adapter.tsc.req.query(),Hono 该方法每个 key 只返回第一个值(c.req.queries() 才给数组)。实测 hono@4.12.34。

两者都没有违反契约:IHttpRequest.queryRecord<string, string | string[]>,联合的两支都合法,Record<string,string> 可赋值给它。所以这不是某一边的 bug。

为什么仍然值得记

契约允许两支,意味着平台对「重复查询参数」的回答取决于哪个 server 启动了 —— 而 packages/qa/http-conformance 的存在意义正是"经 IHttpServer 注册的一切在非 Hono server 上原样运行"。这条差异恰好落在它的 cross-adapter 套件没有钉住的地方:套件没有任何一个用例传重复参数。

后果是可观察的,而且方向相反:

#6307 的修复(readSingleQueryValue,重复即 400 VALIDATION_ERROR)因此在两个适配器上不等价:node:http 上会拒收,Hono 上根本走不到那条分支。消费方按契约处理声明过的形状是对的,但"同一请求两种答案"这件事本身没有被任何门禁记录。

处置建议(留给分诊)

三条路,都是决策而非实现细节,所以本单不动手:

  1. 给 conformance 套件加一条重复参数用例,把差异钉成已知(最小、最诚实,但不消除差异);
  2. 收紧契约为"重复参数一律是数组",让 Hono 适配器改用 c.req.queries() 并按 length 归一 —— 这会改变 Hono 上现有的、依赖"取第一个"的读取点(需先普查,见 packages/rest 的其它 req.query.* 读取点同样把 string | string[] 当字符串用(#6307 的未扩大部分) #6877);
  3. 收紧契约为"永远是单值,重复取第一个",让 node:http 适配器折叠 —— 代价是消费方再也无法察觉歧义,GET/DELETE /packages/:id 把重复的 ?version= 查询参数(string[])原样交给 PackageService #6307 那类静默错答就不可修了。

倾向 2 或 1;3 与 #6307 已落地的取向冲突。

查重

搜过 open issue 的 IHttpServer / adapter / query,无同题单。#6307 是本单的来源(范围仅 package-routes.ts 两个 handler),#6877 是同批的另一条(rest 内其它 req.query 读取点),三者互不重复。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions