6.9 KiB
6.9 KiB
前端直传腾讯云 COS(视频大文件)
Goal
让管理后台的视频上传绕开 PHP 服务器的中转通道,由浏览器直接把视频文件分片上传到腾讯云 COS。
解决两类痛点:(1) 服务器双倍带宽消耗(client→server→COS);(2) PHP upload_max_filesize / post_max_size 与 fpm 进程内存对大视频不友好。
首发场景:诊单 CallRecordPanel.vue 上传通话回放视频。
What I already know
- 现有上传链路:
admin/src/components/upload/index.vue→POST /upload/video(UploadController::video)→UploadService::video()→storage/Driver→engine/Qcloud::upload()用putObject。 - 服务端入参依赖
$_FILES,受 PHP 上传上限约束;返回{id, cid, type, name, uri, url},uri经FileService::getFileUrl()拼接 OSS/CDN 域名。 - 存储驱动配置走
dev_config.storage(管理员可在后台「存储配置」切换 local/qiniu/aliyun/qcloud;本任务只对 qcloud 启用直传)。 - composer 已有
qcloud/cos-sdk-v5 ^2.5,但 STS 临时凭证需要再装qcloud/cos-sts-sdk。 - 未提交代码:
CallRecordPanel.vue已加「上传视频」按钮,调用createManualCallRecord+attachLocalCallRecording,依赖上传组件吐出的response.data.uri/url。AuthMiddleware 已为tcm.diagnosis/uploadcallrecording等加白名单 — 直传新接口与之解耦,不需要白名单。
Assumptions (temporary)
- 生产环境默认存储引擎已经是
qcloud;切到local/aliyun/qiniu时 direct 模式需要降级回老链路。 - COS Bucket 已开启跨域 CORS(直传必须)。如未开启,需要运维在 COS 控制台配置
AllowedOrigin = 后台域名 + 本地 dev、AllowedMethod = PUT/POST/HEAD、AllowedHeader = *、ExposeHeader: ETag。 - 后台域名固定(暂无多租户独立域名)。
- 视频文件大小有合理上限(建议 2GB)。
Decisions (locked)
- 视频上限 2 GB(写进 STS policy
numeric_less_than_equal cos:content-length+ 前端file.size预检)。 - 保留
/upload/video老接口;upload/index.vue的directprop 默认false,仅CallRecordPanel.vue这类显式声明的视频场景启用直传。 - STS 凭证有效期 30 分钟(1800 秒)。
- 直传完成后必须等
oss-confirm返回(写完file表 + HEAD 校验通过)才 emitsuccess,保证业务侧拿到的uri/url一定有file_id。
Requirements (evolving)
- [R1] 后端新增
POST /adminapi/upload/oss-credentials,仅当storage.default == qcloud时返回{provider, bucket, region, credentials, expiredTime, key, host, cdn_url_base};其它 driver 返回{provider: '<engine>', fallback: true}让前端自动降级到老链路。 - [R2] 后端新增
POST /adminapi/upload/oss-confirm,HEAD 一下key校验确实存在 + size 在阈值内,写入file表(沿用FileService::getFileUrl),返回与UploadService::video()完全对齐的{id, cid, type, name, uri, url}。 - [R3] 新装 composer 依赖
qcloud/cos-sts-sdk;在engine/Qcloud.php增加getStsCredentials($keyPrefix, $maxSize)方法,复用现有access_key/secret_key/bucket/region。 - [R4] STS policy 限定 action:
name/cos:PostObject、name/cos:PutObject、name/cos:InitiateMultipartUpload、name/cos:UploadPart、name/cos:CompleteMultipartUpload、name/cos:AbortMultipartUpload、name/cos:ListParts;resource 限定qcs::cos:${region}:uid/${appId}:${bucket}/uploads/video/{YYYYMMDD}/*。 - [R5] 前端新增 npm 依赖
cos-js-sdk-v5;upload/index.vue增加direct: booleanprop(默认false),type==='video' && direct===true时走 STS +cos.uploadFile(含SliceSize=5MB、onProgress),仍发出原success事件{ code, data: { uri, url, ... } }保持调用侧兼容。 - [R6]
CallRecordPanel.vue切到<upload type="video" direct :show-progress="true">,并支持上传过程中显示百分比(沿用组件内置el-dialog进度)。 - [R7] 失败/降级路径:STS 接口失败 / response 标记
fallback=true/cos-js-sdk-v5上传报错时,自动降级到老的POST /upload/video,提示「直传失败,已切换到普通上传」。 - [R8] 安全:保留登录鉴权;STS 凭证 30 分钟有效期;前端拒绝不在
accept列表的扩展名(沿用现有.wmv,.avi,...,.mp4,.mkv)。
Acceptance Criteria (evolving)
- 在 storage=qcloud 环境,从
CallRecordPanel.vue上传 1.5GB mp4 文件,浏览器 Network 面板能看到流量直接打到*.cos.*.myqcloud.com,/upload/video没有调用。 - 上传过程中能看到分片进度条(5MB 一片,并发 ≥3)。
- 上传完成后,
call_record表正确写入recording_urls,前端表格recording_urls_list渲染出可播放视频。 file表新增一行,uri形如uploads/video/20260508/xxxxx.mp4,url拼接了 CDN/COS 域名。- 把
dev_config.storage.default改成local,再次上传,自动降级到老/upload/video路径,整体功能正常。 - 凭证接口未登录调用返回 401。
- 上传一个被 STS policy resource 拒绝的 key(人为篡改 prefix),COS 返回 403,前端给出明确错误。
Definition of Done
- 单元/集成测试:暂无 PHPUnit 工程,跳过自动化测试;保证手测覆盖 AC 全部场景。
- 前端
npm run type-check通过、npm run lint无新增告警。 - 后端
php -l通过,新接口在 admin 路由可访问。 - 文档:在
.trellis/spec/(如已有上传相关 spec)补充直传规范;PRD 同步关闭 Open Questions。 - COS CORS / STS 子账号最小权限策略整理为 ops 备忘(写到 prd.md 的 Technical Notes)。
Out of Scope (explicit)
- 不做断点续传(刷新页面不保留 UploadId)。
- 不做 PostObject 回调链路。
- 不做 aliyun / qiniu 直传。
- 不改
upload/image、upload/file链路(图片小文件用老链路即可)。 - 不做客户端 H5/uniapp 端直传(uniapp 本来就不走 admin)。
- 不做并发上传限流 / 全局上传队列。
Technical Notes
- 关键文件:
server/app/common/service/storage/engine/Qcloud.php、server/app/common/service/UploadService.php、server/app/adminapi/controller/UploadController.php、admin/src/components/upload/index.vue、admin/src/views/tcm/diagnosis/components/CallRecordPanel.vue。 - composer 新增:
qcloud/cos-sts-sdk: ^3.0。 - npm 新增:
cos-js-sdk-v5。 - COS CORS 配置(运维):
AllowedOrigin: <admin 域名>、AllowedMethod: PUT,POST,HEAD,GET、AllowedHeader: *、ExposeHeader: ETag,x-cos-request-id,x-cos-version-id。 - STS 子账号最小权限:仅赋予对
${bucket}/uploads/video/*的cos:Get*、cos:Put*、cos:Post*、Multipart 系列动作;STS policy 在此基础上再用 condition + resource 收敛。 - Key 命名:
uploads/video/${YYYYMMDD}/${ulid}.${ext},与现有UploadService::getUploadUrl()的Ymd分日目录保持一致。