larksuite / larksuite/cli

[Bug][im] 经 Latin-1 敏感代理下载非 ASCII 文件名附件时报 HTTP 502

Open
#2,648 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug domain/im
Dominant language
Go
Stars
17.3k
Forks
1.4k
Avg merge
2d 4h
Merged PRs (30d)
105

Description

沙箱/代理环境下,im +messages-resources-download 下载**文件名含非 ASCII 字符(中文)**的群消息附件时失败,CLI 报 HTTP 502: Bad Gateway。同一命令、同一账号、同一文件在无代理环境(本机直连)下一次成功。

环境

  • 触发环境:AI agent 沙箱(出口流量经其内置的 tls-terminate 正向代理,Node 实现),沙箱内 lark-cli 1.0.74
  • 对照环境(成功):本机直连(无代理),lark-cli 1.0.63,同一 user 身份
  • 触发条件:附件文件名含非 ASCII 字符 出口经过会对非 Latin-1 响应头敏感的代理;二者缺一不可

复现命令

(沙箱内执行)

lark-cli im +messages-resources-download \
  --as user \
  --message-id <om_xxx> \
  --file-key <file_v3_xxx> \
  --type file \
  --output ./中文文件名.docx \
  --format json

实际行为

{
  "ok": false,
  "identity": "user",
  "error": {
    "type": "network",
    "subtype": "server_error",
    "code": 502,
    "message": "HTTP 502: Bad Gateway"
  }
}

跨约 1.5 小时间隔多次重试(4 次),结果一致。

根因分析(已在代理侧定位到错误栈)

502 并非来自飞书服务端,而是本地代理转发上游响应时崩溃产生:

TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["content-disposition"]
    at storeHeader (node:_http_outgoing:628:5)
    ...
    at ServerResponse.writeHead (node:_http_server:439:8)
    at .../sandbox-runtime/dist/sandbox/tls-terminate-proxy.js:419:13

完整链路:

  1. lark-cli 按文档约定,下载请求带 Content-Type: application/jsonim/v1/message-resource/get 的请求头要求;同时官方文档写明「If you need the Content-Disposition header, you need to set the
    Content-Type in the header to application/json when initiating the request」);
  2. 飞书正常返回文件字节 + Content-Disposition: attachment; filename="中文文件名.docx"(裸 UTF-8 头值——RFC 7230 obs-text 文法内合法,但非 RFC 5987 推荐形态);
  3. Node 实现的 MITM 代理把该头 writeHead 写回沙箱内客户端时,Node 拒绝非 Latin-1 头值(ERR_INVALID_CHAR),本次转发作废 → CLI 收到 502。

对照组证据(同账号、同一 message/file、同一中文文件名):

环境 lark-cli 结果
沙箱内(经代理) 1.0.74 ❌ 502 ×4
本机直连(无代理) 1.0.63 ✅ 一次成功,完整字节数下载,文件名正常

即:CLI 客户端解析与服务端下载本身均正常,唯一断点是「带非 ASCII Content-Disposition 的响应经过 Latin-1 敏感代理」这一组合。该场景下任意服务端发非 ASCII 头都会踩中,飞书只是常见来源之一。

期望行为与建议

--output 已显式指定时,CLI 并不需要服务端原始文件名(按 Content-Disposition 保留原名的特性仅在省略 --output 时有意义)。建议任一:

  1. --output 显式时,下载请求省略触发 Content-Disposition 的 Content-Type(需验证:不带该头时飞书侧是否仍允许下载——文档只写了正向条件,未说明不带时的行为);
  2. 或提供 --no-content-disposition 类开关;
  3. 或至少在 lark-im 的下载参考文档中标注已知限制:在会对非 Latin-1 响应头敏感的代理/沙箱环境下,非 ASCII 文件名的附件下载会失败,workaround 为改用不经该代理的网络出口。

相关

  • 下载参考文档:Preserves the server's original filename via Content-Disposition (supports RFC 5987 UTF-8 encoding)——解析侧已支持 RFC 5987,但服务端实际发送为裸 UTF-8 头值
  • 飞书开放平台 im/v1/message-resource/get 文档:请求头 Content-Type 必填 application/json; charset=utf-8
  • 代理侧(Anthropic sandbox-runtime)的对应 bug 已在该仓库报 issue:anthropics/sandbox-runtime#490(non-latin1 response header 导致 ERR_INVALID_CHAR),尚未修复;本 issue 关注 CLI 侧可独立采取的缓解

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the im +messages-resources-download command and its handling of --output, then inspect how the im/v1/message-resource/get request sets Content-Type. Verify the explicit-output path through a Latin-1-sensitive proxy and add regression coverage showing that a non-ASCII attachment downloads successfully without requiring Content-Disposition.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.