Files
competition-website/app
qubiaobiao cf91f6ba34 fix(download): 哨兵旁路改走 Content-Disposition 的 size= 扩展参数(R103 收口)
背景(R103-3 生产实测已定因):
  X-Accel-Redirect 分支下真正吐字节的是 nginx,Node 侧无从得知 nginx 是否吐对
  了内容(内部 location 缺失时会吐前端 index.html)。原实现靠自定义响应头
  X-File-Size 把「服务端 stat 的真实字节数」透出给前端比对,但双通道对照实测
  (.workbuddy/probes/2026-10-12-r103/prod_xfs_passthrough.js)证伪了原注释所称
  「nginx 会保留上游自定义响应头」:
    · 直连后端 :8023 ⇒ 204 空体,响应带 x-file-size: 19009
    · 经 nginx :80  ⇒ 200 / 19009 字节(与磁盘逐字节一致),而 x-file-size **缺失**
    · 对照 /api/health 经 nginx ⇒ 自定义头 x-readtime **保留**
  ⇒ 丢弃只发生在 X-Accel 内部重定向这一条路径。
  影响:该分支下前端哨兵空转(下载完整性校验被静默跳过)。

修法:
  把同一份字节数写成 RFC 6266 §4.1 的 disposition 扩展参数 `size=`(实测
  Content-Disposition 能穿透 X-Accel),前端按 x-file-size → CD size= 顺序回落。
  两通道同源同值;任一缺失只降级不误伤。Node 流分支(absolutePath)不加旁路 ——
  其响应走 nginx 常规转发,自定义头本就保留。

验证(2026-10-12 生产部署后实测):
  · 本地判别力自证 verify_cd_size_channel.js:pass=12 fail=0
    (含 C1 变异测试:修复前旧 CD 形态解不出 ⇒ 判据确判别力)
  · 生产判决点 r106_prod_sentinel.js:pass=11 fail=0
    ARM A(直连) CD 含 size=19009;ARM B(经 nginx) CD 的 size=19009 穿透成功;
    B2 端到端 sha256 与磁盘逐字节一致;C1 对照组佐证丢弃仅限 X-Accel 通道。
2026-10-12 11:05:47 +08:00
..