| name | upload-via-oss |
| description | 上传图片/视频/文件到 echotechoss 时触发。引导:scene 枚举选择 → 获取签名 → FormData 上传(file 字段必须最后)→ 拼 echotechoss:// 地址 → eros 拦截器渲染。覆盖发图、发视频、发头像、上传反馈附件等场景。同时含失败排查(FormData 字段顺序、签名过期)。 |
| allowed-tools | ["Read","Bash","Edit"] |
通过 echotechoss 上传文件
触发场景
- 上传图片 / 上传视频 / 上传文件 / 发图 / 发视频
- 处理用户选择的本地文件
- echotechoss:// 协议地址生成
- 上传失败排查("图片上传失败 / 上传不上去 / 显示不出来")
- 加新的上传场景(如自定义表情、个人头像)
步骤 1:先 Read 字典
Read .ai/knowledge/oss-upload.md 拿完整的:
- echotechoss:// 协议格式
- scene 枚举完整列表
- 签名请求/响应字段
- FormData 上传代码模板
- 已知坑(FormData 字段顺序:file 必须最后)
步骤 2:选择正确的 scene
| 场景 | scene | 何时用 |
|---|
| IM 聊天图片/视频 | im | 聊天中发送的所有媒体(90% 场景) |
| 表情贴纸 | sticker | 自定义表情包 |
| 用户/客服头像 | avatar | 头像设置 |
| 反馈附件 | feedback | 工单截图 / 报障图 |
新场景需求:如果用户要新 scene(如 chat-bg 聊天背景),先确认后端 OSS bucket 是否已配置——前端只补枚举但后端没建 bucket 会上传失败。
步骤 3:标准上传流程
3 步:
const sigRes = await fetch('/oss/v1/signature', {
method: 'POST',
body: JSON.stringify({ scene: 'im', fileName: file.name, contentType: file.type }),
});
const { uploadUrl, ossKey, formData } = (await sigRes.json()).data;
const form = new FormData();
Object.entries(formData).forEach(([k, v]) => form.append(k, v as string));
form.append('file', file);
await fetch(uploadUrl, { method: 'POST', body: form });
const echotechossUrl = `echotechoss://${ossKey.split('/')[0]}/${ossKey}`;
关键约束:
file 字段必须是 FormData 的最后一个,否则 OSS 拒绝(最常见的"上传失败"根因)
- 签名有时效(一般 5-10 分钟),过期重新获取
contentType 不传后端会基于文件名推断,但显式传更稳
步骤 4:渲染时使用
<img> / <video> 直接用 echotechoss:// 地址:
<img src="echotechoss://im/2024/01/15/abc123.jpg" />
@frontend/eros 的全局拦截器会自动转 https URL。不需要手动调 resolveOssUrl(),除非:
- 在邮件 / 第三方平台引用(拦截器不在那个环境,需手动转 https)
- 复制链接给非 IM 场景使用
步骤 5:失败排查
按以下顺序:
| 症状 | 排查 |
|---|
| 上传 200 但拒绝(HTTP 400 类) | 90% 是 FormData 字段顺序错(file 不在最后) |
| 签名接口返回但上传 403 | 签名过期或 contentType 不匹配 |
| 上传成功但渲染不出 | echotechoss:// URL 拼错(scene 与实际不符) / eros 拦截器没装 |
| 在邮件 / 外部链接打不开 | echotechoss:// 协议外部环境无法解析,需调 resolveOssUrl() 转 https |
| 大文件超慢/超时 | 当前是单次 PUT,无分片;大文件需后端先支持分片上传协议 |
| 上传中无进度 | fetch 无原生进度回调,需改用 XHR + onprogress 或服务端分片 |
反模式
- ❌ FormData 先 append
file 再 append 签名字段(顺序错,OSS 拒绝)
- ❌ 把签名接口的整个 response 当 formData(要取
.data.formData,不是顶层)
- ❌ 在
<img> 用 https URL 跳过 eros(写死后 OSS 域名变更要改全部代码)
- ❌ 给新 scene 直接加枚举不和后端确认(可能后端没配 bucket,上传必失败)