聊天图片与文件
本地实现,尚未开通线上附件
本页描述新增的通用附件上传。网关、Widget、工作台和 SDK 必须配套更新,并配置私有 R2 与安全扫描服务、完成真实文件验收后再启用。不要因页面存在上传按钮就认为已生产可用。之前发布的会话列表和文本聊天不受此限制。
支持范围
| 类型 | 扩展名 | 展示方式 |
|---|---|---|
| 图片 | PNG、JPG/JPEG、WebP | 扫描通过后预览与下载 |
| 文档 | PDF、TXT、DOC/DOCX、XLS/XLSX、PPT/PPTX | 扫描通过后下载,不内嵌执行 |
| 压缩包 | ZIP | 扫描通过后下载,不在线解压 |
单文件 1 字节至 10 MiB。TXT 只接受 UTF-8。拒绝 SVG、HTML、可执行文件和宏专用扩展名。扩展名和文件签名必须匹配;Office/ZIP 的容器签名检查不等于病毒扫描,也不保证内部格式有效。扫描器须拒绝加密文件、宏告警、损坏媒体和超过解压扫描限制的内容。
商户需要做什么
沿用已有的短期 Widget/Workbench Session,不把 API Key 交给浏览器。用户进入一个已授权的会话后,Widget 的上传入口会发送附件消息;工作台先上传,再选择接收人或内部备注并发送。用户列表 Token 本身不能上传,必须先进入具体会话。
用户只可下载自己有权限看到的公开消息附件。内部备注附件不能进入用户端。客服工作台继续受会话范围、角色和租户限制。文件存储桶不能开启公开访问。
两步接口
| 端 | 上传 | 下载 |
|---|---|---|
| Widget 短期 Session | POST /v1/apps/bot/widget/uploads?filename=receipt.pdf | GET /v1/apps/bot/widget/attachments/{id} |
| 工作台 Session / 商户后端 Key / 管理员 | POST /v1/conversations/{id}/uploads?filename=receipt.pdf | GET /v1/conversations/{id}/attachments/{attachmentId} |
使用 Authorization: Bearer <凭据>。上传请求体为原始文件字节,Content-Type: application/octet-stream,不是 multipart。后端 Key 上传需要 conversation:write,下载需要 conversation:read,仍须限制为当前商户授权的会话。
第一步上传成功返回 201:
{"data":{"storage_key":"workbench/...","filename":"receipt.pdf","mime_type":"application/pdf","byte_size":1234,"scan_status":"pending"}}第二步把 data 放入现有消息接口的 attachments 数组,用稳定的 client_message_id 发送。Widget 使用 /v1/apps/bot/widget/send,工作台或商户后端使用 /v1/conversations/{id}/messages。仅上传并不会创建消息或启动附件消息的扫描。
消息响应丢失时重试同一消息 ID 和同一附件描述,不重新上传。Widget 已实现这种重试。上传接口本身暂不提供 Idempotency-Key 合同;上传响应丢失后再次上传可能产生独立对象,未关联消息的对象七天后进入清理。不得对上传接口宣称 exactly-once。
常见状态码:400 类型、文件名或内容无效;401/403 凭据或权限不足;404 附件不可见、过期或尚未通过扫描;413 超过 10 MiB;429 限流;503 存储未配置或临时失败。继承当前 Widget/Key 的额度,重试应遵守 Retry-After。进度 100% 仅表示传输完成,不表示消息送达或扫描通过。
扫描与数据保留
pending:隔离中,不可下载。扫描未配置、不可用或结果哈希不符时不放行。clean:扫描通过,但下载时仍重新检查用户、会话、可见性及过期时间。blocked:被拦截,不可下载。- 当前扫描沿用后台定时任务,不能保证即时完成。失败最多尝试八次;耗尽后仍保持隔离,需运维调查。
- 附件可在发送时指定
expires_at;到期先拒绝读取,再由定时任务删除对象。未指定过期时间时按租户会话保留政策处理,不存在默认永久保存承诺。 - 删除会话会清除关联对象;未关联的上传保留七天以便重试。清理依赖正常运行的定时任务。
- 普通文件不会从任意用户 URL 抓取。既有外部图片导入仍受精确 HTTPS 来源白名单限制。
SDK
浏览器自有 UI 可使用交付包 ./upload 的 uploadOpen4XAttachment({url, token, file, signal, onProgress})。只传短期 Session。服务端使用 uploadAttachment(conversationId, filename, blob) 和 downloadAttachment(conversationId, attachmentId)。SDK 仍是确认版本交付,不代表已发布公共 npm 包。
AI 接入提示词
请检查当前项目的 Open4X 客服集成,并增加图片和文件上传。
先阅读 /zh/guide/chat-attachments 和 OpenAPI,确认目标环境是否开通附件。
只使用当前会话的短期 Token;API Key 永远留在服务端。
上传原始字节,保存返回的附件描述,再用稳定的 client_message_id 发送消息。
实现进度、取消、失败重试、pending/clean/blocked 状态;扫描未通过不展示下载入口。
文件只下载,只有 PNG/JPEG/WebP 可以预览。退出或切换账户时取消请求、清除缓存和 Blob URL。
测试跨用户/跨租户拒绝、内部备注隔离、超限、断线重试、重复消息和过期附件。
默认使用本地 mock;没有授权和环境确认,不上传真实客户文件或部署生产。平台开通清单
- 网关绑定私有
MEDIA_BUCKET,不开放 R2 公共域名。 - 部署仓库
services/conversation-scanner的扫描适配器和 ClamAV。为扫描器提供 HTTPS,配置CONVERSATION_SCANNER_URL与通过 Secret 保存的CONVERSATION_SCANNER_TOKEN。禁止在聊天和仓库中填写密钥。 - staging 还需配置
CONVERSATION_SCANNER_TENANT_ALLOWLIST,确认外部副作用开关不会阻止扫描。 - 固定并记录容器镜像摘要、病毒库更新时间;确认限制和加密告警已生效。配置依据:ClamAV 配置、官方 clamd 配置参考。
- 使用无客户数据的图片/PDF、标准病毒测试样本、加密包、超限包完成真实引擎验收,再测试 Widget 与客服工作台双向收发、撤权与删除。适配器 mock 测试不能替代真实引擎验收。
附件存储和扫描产生的费用、容量、保留期限需在商户条款中确认;本页不新增免费额度或 SLA 承诺。