使用JavaScript SDK上传文件

更新时间:
复制 MD 格式

本文介绍如何使用JavaScript SDK将媒体文件从本地上传至点播存储。

浏览器要求

浏览器

版本

Chrome

66+

Microsoft Edge

79+(Chromium内核)

Firefox

57+

Safari

12.1+

Android系统默认浏览器

66+

iOS系统默认浏览器

12.2+

Demo下载地址

快速集成

安装

npm install aliyun-vod-upload-sdk

SDK提供ESM、CJS、UMD三种构建产物,支持所有现代打包工具(Vite/webpack/Rollup/esbuild)。

CDN 引入

<script src="https://g.alicdn.com/apsara-media-box/imp-web-vod-upload/2.1.0/vod-upload.umd.js"></script>
<script>
  const { createUploader, UploadError } = window.AliyunVodUpload;
</script>

5 行代码上传

import { createUploader } from 'aliyun-vod-upload-sdk';

const uploader = createUploader({
  getAuth: () => fetch('/api/vod/auth').then(r => r.json()),
});

const { videoId } = await uploader.upload(file);

后端接口要求

在getAuth模式下,SDK不直接调用阿里云OpenAPI,而是通过getAuth回调委托你的后端获取上传凭证。后端需实现以下接口(对应VOD OpenAPI):

后端接口

对应 OpenAPI

返回字段

创建视频上传凭证

CreateUploadVideo

{ UploadAuth, UploadAddress, VideoId }

刷新视频上传凭证

RefreshUploadVideo

{ UploadAuth, UploadAddress, VideoId }

创建图片上传凭证

CreateUploadImage

{ UploadAuth, UploadAddress, ImageId }

创建辅助媒资上传凭证

CreateUploadAttachedMedia

{ UploadAuth, UploadAddress, MediaId }

后端返回的JSON原样透传给SDK即可,SDK 内部自动完成base64解码和字段映射。

如果服务端仅提供STS临时凭证,可以使用STS直传模式getSTS:SDK 会在浏览器中直接签名调用上述VOD OpenAPI,无需实现这些接口。

基础功能

视频上传

import { createUploader } from 'aliyun-vod-upload-sdk';

const uploader = createUploader({
  getAuth: async (ctx) => {
    switch (ctx.kind) {
      case 'create-video':
        return fetch('/api/vod/create-auth', {
          method: 'POST',
          body: JSON.stringify({ fileName: ctx.file.name, ...ctx.meta }),
        }).then(r => r.json());
      case 'refresh-video':
        return fetch(`/api/vod/refresh-auth?videoId=${ctx.videoId}`)
          .then(r => r.json());
    }
  },
});

const result = await uploader.upload(file, {
  meta: { title: '我的视频', cateId: 1000, tags: '教程,示例' },
});
console.log('上传成功,videoId:', result.videoId);

getAuth回调接收一个ctx参数,SDK会根据场景自动决定ctx.kind:

  • create-video— 首次上传,需后端调用CreateUploadVideo。

  • refresh-video—续传或凭证过期时刷新,需后端调用RefreshUploadVideo。

  • create-image—上传图片,需后端调用CreateUploadImage。

  • create-attached-media—上传辅助媒资,需后端调用CreateUploadAttachedMedia。

图片上传

图片上传使用同一个 upload() 方法,SDK 根据 file.type 自动识别(image/* 类型走图片链路):

const uploader = createUploader({
  getAuth: async (ctx) => {
    if (ctx.kind === 'create-image') {
      return fetch('/api/vod/image-auth', {
        method: 'POST',
        body: JSON.stringify({ imageType: 'default' }),
      }).then(r => r.json());
    }
  },
});

const result = await uploader.upload(imageFile);
console.log('图片上传成功,imageId:', result.imageId);

辅助媒资上传(水印 / 字幕 / 素材)

水印图、字幕文件(srt / ass / vtt)、素材(zip / 图片 / 视频片段)需调用CreateUploadAttachedMedia - 获取辅助媒资上传地址和凭证:在 meta里带上 businessType 即路由到该链路,其余用法与视频 / 图片完全一致(进度 / 取消 / 超时重试 / 埋点)。

// 字幕:.srt 不带 businessType 会被视频链路接走,生成一条类型错误的视频记录
const r1 = await uploader.upload(srtFile, { meta: { businessType: 'subtitle' } });

// 素材
const r2 = await uploader.upload(materialFile, { meta: { businessType: 'material' } });

// 水印图:走辅助媒资(产物与「图片链路 + imageType: 'watermark'」是两类不同资源)
const r3 = await uploader.upload(logoFile, {
  meta: { businessType: 'watermark', mediaExt: 'png' },
});

console.log('mediaId:', r1.mediaId);   // 三路统一字段:视频 = VideoId、图片 = ImageId、辅助媒资 = MediaId

businessType / mediaExt 等字段说明:

字段

说明

businessType

必填。取值原样透传给 VOD(文档值:watermark / subtitle / material),SDK 不做枚举校验,VOD 新增业务类型时无需升级 SDK

mediaExt

可选。不传时 STS 模式从文件名扩展名派生(sub.srt → srt);文件名没有扩展名(或上传 Blob)时才需要显式传

title / fileName / description / tags / cateIds / storageLocation / appId / userData

可选,与视频 meta 同义;注意 cateIds 是逗号分隔字符串(最多 5 个),与视频的 cateId: number 不同

两点行为差异:

  • 不参与断点续传:视频点播没有该接口的Refresh 版本(凭证约 3000 秒有效,过期只能重新 Create 并拿到新 MediaId),所以 SDK 不为辅助媒资读写 checkpoint,中断后重传是全新一次上传。

  • png 水印有两条官方路径:图片链路(VodImageMeta.imageType = 'watermark')与辅助媒资链路(businessType: 'watermark')产物是两类不同资源,SDK不会自动决定;传 businessType 才走辅助媒资,不传就按文件类型走图片链路。

uploadAuth 模式下getAuth会收到ctx.kind === 'create-attached-media',把ctx.meta.businessType转给后端即可;STS模式(getSTS)下SDK自动完成签名调用,getSTS无需任何改动。

上传进度

const result = await uploader.upload(file, {
  onProgress: (percent, loaded, total) => {
    // percent: 0..1 (如 0.5 表示 50%)
    // loaded:  已上传字节数
    // total:   文件总字节数
    progressBar.value = percent;
    console.log(`${(percent * 100).toFixed(1)}% - ${loaded} / ${total}`);
  },
});

SDK 保证上传完成时 percent 最终一定等于 1。

取消上传

  • 方式一:task.abort() — 最简单

    const task = uploader.upload(file);
    
    cancelBtn.onclick = () => task.abort();
    
    try {
      const result = await task;
    } catch (e) {
      if (e.name === 'AbortError') {
        console.log('用户取消了上传');
      }
    }
  • 方式二:AbortSignal — 适合 React/Vue 组件生命周期

    const ctrl = new AbortController();
    cancelBtn.onclick = () => ctrl.abort();
    
    try {
      const result = await uploader.upload(file, { signal: ctrl.signal });
    } catch (e) {
      if (e.name === 'AbortError') {
        console.log('已取消');
      }
    }

取消后 checkpoint 会保留,下次再upload(file)会自动从断点续传(仅视频;图片与辅助媒资不走断点续传,再次上传是全新一次上传)。

断点续传

断点续传是默认开启的,无需任何额外配置(仅视频上传支持,图片与辅助媒资上传不走断点续传)。SDK 自动:

  1. 将已完成的分片进度存入 localStorage。

  2. 页面刷新后再次 upload(file),自动从上次中断处继续。

  3. 匹配规则:相同 file.name + file.size + file.lastModified → 命中 checkpoint。

// 第一次上传(上传到 40% 时用户关闭页面)
await uploader.upload(file);

// 用户重新打开页面后再次上传同一个文件
// SDK 自动从 40% 继续,不会重复上传
const result = await uploader.upload(file);

关闭断点续传:

const uploader = createUploader({
  getAuth: myGetAuth,
  checkpoint: false,  // 关闭
});

高级功能

批量上传

SDK 提供单文件 upload() API,批量上传使用标准 JavaScript 异步原语组合:

// 串行上传(最简单)
for (const file of files) {
  const result = await uploader.upload(file, {
    onProgress: p => updateProgress(file.name, p),
  });
  console.log(`${file.name} 完成,videoId: ${result.videoId}`);
}
// 并发上传(大带宽 + 小文件)
const results = await Promise.all(
  files.map(f => uploader.upload(f)),
);
// 限并发(推荐,大文件场景)
import pLimit from 'p-limit';

const limit = pLimit(2); // 最多同时上传 2 个文件
const results = await Promise.all(
  files.map(f => limit(() => uploader.upload(f, {
    onProgress: p => updateItemProgress(f, p),
  }))),
);

暂停与恢复

SDK没有显式的暂停API。暂停效果通过取消 + 续传实现:

// 暂停:取消当前上传
task.abort();

// 恢复:重新上传同一文件,自动从 checkpoint 续传
const result = await uploader.upload(file);

超时取消与多源取消

// 60 秒超时自动取消
await uploader.upload(file, {
  signal: AbortSignal.timeout(60_000),
});

// 多源取消:用户手动取消 或 60 秒超时
const userCtrl = new AbortController();
await uploader.upload(file, {
  signal: AbortSignal.any([
    userCtrl.signal,
    AbortSignal.timeout(60_000),
  ]),
});
说明

AbortSignal.timeout需要Chrome103+,AbortSignal.any需要Chrome116+。SDK本身兼容到Chrome60,若要支持更老的浏览器,请使用AbortController+setTimeout组合。

React / Vue 集成

React Hook示例

import { useEffect, useRef, useState } from 'react';
import { createUploader } from 'aliyun-vod-upload-sdk';

function useUploader(getAuth) {
  const uploaderRef = useRef(null);

  // 在 effect 里创建:避免每次渲染都 createUploader;
  // StrictMode 下 effect 会「执行 → 清理 → 再执行」,清理时 dispose 的实例会被重新创建
  useEffect(() => {
    const uploader = createUploader({ getAuth });
    uploaderRef.current = uploader;
    return () => {
      uploader.dispose(); // 组件卸载时释放,同时取消进行中的上传
      uploaderRef.current = null;
    };
  }, []);

  return uploaderRef;
}

function UploadButton({ file }) {
  const uploaderRef = useUploader(myGetAuth);
  const ctrlRef = useRef(null);
  const [progress, setProgress] = useState(0);

  const handleUpload = () => {
    const uploader = uploaderRef.current;
    if (!uploader) return;
    const ctrl = new AbortController();
    ctrlRef.current = ctrl;

    uploader.upload(file, {
      signal: ctrl.signal,
      onProgress: p => setProgress(p),
    }).then(result => {
      console.log('成功', result.videoId);
    }).catch(e => {
      if (e.name !== 'AbortError') {
        console.error('失败', e);
      }
    });
  };

  return (
    <>
      <button onClick={handleUpload}>上传 ({(progress * 100).toFixed(0)}%)</button>
      <button onClick={() => ctrlRef.current?.abort()}>取消</button>
    </>
  );
}

Vue 3 Composable示例

import { onUnmounted, ref } from 'vue';
import { createUploader } from 'aliyun-vod-upload-sdk';

export function useUploader(getAuth) {
  const uploader = createUploader({ getAuth });
  const progress = ref(0);

  onUnmounted(() => uploader.dispose());

  async function upload(file) {
    return uploader.upload(file, {
      onProgress: p => { progress.value = p; },
    });
  }

  return { upload, progress };
}

API文档

createUploader(config)

创建 Uploader 实例。

import { createUploader } from 'aliyun-vod-upload-sdk';

const uploader = createUploader(config);

UploaderConfig

参数

类型

必填

默认值

说明

getAuth

GetAuth

与getSTS二选一

—

凭证获取回调,详见凭证回调 getAuth。

getSTS

GetSTS

与getAuth二选一

—

STS临时凭证回调(前端直传模式)。详见STS直传模式getSTS。

region

string

getSTS模式必填

—

VOD服务地域(如cn-shanghai),决定vod.<region>.aliyuncs.com端点。

retry

RetryPolicy

否

{count: 3}

OSS分片上传失败时的自动重试策略。

checkpoint

false | { store?: CheckpointStore }

否

localStorage

断点续传配置。false关闭;{ store }注入自定义store。

parallel

number

否

4

OSS分片并发数。

partSize

number

否

1048576 (1MB)

OSS分片大小(字节)。

timeout

number

否

60000

网络请求超时(毫秒)。同时作用于OSS上传与STS模式的VOD OpenAPI调用。

cname

string

否

—

OSS自定义域名。

enableMD5

boolean

否

false

开启后每个分片计算并携带Content-MD5,由OSS校验数据完整性(对应ali-oss multipartUpload的disabledMD5: false);会增加CPU开销。

refreshSTSTokenInterval

number

否

300000 (5min)

两次刷新上传凭证之间的最小间隔(毫秒),仅视频上传生效(通过refresh-video刷新),透传给 ali-oss refreshSTSTokenInterval。刷新由请求驱动:只在发起OSS请求前检查,没有请求就不刷新,上传请求很慢时实际刷新间隔会跟着变长。注意它管的是OSS上传凭证,不是用户的 STS 凭证;0/ 负数/NaN会归一化回落默认值。

RetryPolicy

字段

类型

默认值

说明

count

number

3

最大重试次数

uploader.upload(file, options?)

上传单个文件。返回UploadTask:既是Promise<UploadResult>,也带.abort()方法。

const task = uploader.upload(file, options);

UploadOptions

参数

类型

说明

meta

VodVideoMeta | VodImageMeta | VodAttachedMediaMeta

媒资元数据(标题、分类、标签等);出现businessType时走辅助媒资链路。

signal

AbortSignal

Web标准取消信号。

onProgress

(percent, loaded, total) => void

进度回调,percent范围 0到1。

partSize

number

覆盖全局partSize。

parallel

number

覆盖全局parallel。

VodVideoMeta(视频元数据)

字段

类型

说明

title

string

视频标题。

description

string

视频描述。

cateId

number

分类ID。

tags

string

标签(逗号分隔)。

templateGroupId

string

转码模板组ID。

storageLocation

string

存储地址。

coverUrl

string

封面URL。

workflowId

string

工作流ID。

appId

string

应用ID。

userData

Record<string, unknown>

用户自定义数据。

fileName

string

STS模式上传Blob(没有name)时的FileName来源。

transCodeMode

string

STS模式:转码模式(VODTransCodeMode),不传则不发送该参数。

VodImageMeta(图片元数据)

字段

类型

说明

title

string

图片标题

description

string

图片描述

imageType

'default' | 'cover' | 'watermark'

图片类型

imageExt

string

图片扩展名

tags

string

标签

cateId

number

分类 ID

storageLocation

string

存储地址

VodAttachedMediaMeta(辅助媒资元数据)

字段

类型

说明

businessType

string

必填。watermark/subtitle/material等,原样透传不校验;出现该字段即路由到辅助媒资链路。

mediaExt

string

扩展名;不传时STS模式从文件名派生,都拿不到则不发送该参数。

title

string

标题(辅助媒资可选,SDK不派生)。

fileName

string

STS模式上传Blob(没有name)时的FileName来源。

description

string

描述。

tags

string

标签(逗号分隔)。

cateIds

string

分类ID,逗号分隔、最多 5 个(与视频的cateId: number不同)。

storageLocation

string

存储地址。

appId

string

应用ID。

userData

Record<string, unknown>

用户自定义数据。

UploadResult(上传结果)

字段

类型

说明

videoId

string?

视频ID(视频上传时返回)。

imageId

string?

图片ID(图片上传时返回)。

mediaId

string?

三路统一媒资ID:视频=VideoId、图片=ImageId、辅助媒资=MediaId。

etag

string

OSS ETag。

requestId

string

OSS请求ID。

durationMs

number

上传耗时(毫秒)。

uploadTaskId

string

上传任务唯一ID(可用于售后排障)。

UploadTask

upload() 返回的对象同时是 Promise<UploadResult> 和带 .abort() 方法的对象。

type UploadTask = Promise<UploadResult> & {
  abort(): void;
};
重要

链式调用后 .abort() 方法会丢失。task.then(fn) 返回的是普通 Promise。如需链式后仍可取消,请用 options.signal。

uploader.dispose()

释放资源:取消所有进行中的上传并清除内部状态。

uploader.dispose();

调用后该 uploader 实例不可再使用。在 React/Vue 组件卸载时务必调用,避免内存泄漏。

凭证回调 getAuth

type GetAuth = (ctx: AuthContext) => Promise<AuthResult>;

AuthContext

SDK 根据上传场景传入不同的 ctx:

ctx.kind

触发场景

ctx 额外字段

'create-video'

首次视频上传

file, meta?。

'refresh-video'

续传时刷新凭证

file, videoId。

'create-image'

图片上传

file, meta?。

'create-attached-media'

辅助媒资(水印 / 字幕 / 素材)

file, meta?(含businessType)。

AuthResult

后端返回的 OpenAPI 原始 JSON,SDK 内部自动解码:

字段

类型

必填

说明

UploadAuth

string

是

base64编码的STS凭证。

UploadAddress

string

是

base64编码的OSS上传地址。

VideoId

string

create-video 必填

视频ID。

ImageId

string

create-image 必填

图片ID。

MediaId

string

create-attached-media 必填

辅助媒资ID。

ImageURL

string

否

图片URL(透传)。

getAuth 最简实现:

// 后端统一路由。注意 ctx.file 是 File / Blob,JSON.stringify 会把它变成 {},
// 需要把后端用到的文件信息(如 fileName)单独取出来
createUploader({
  getAuth: ({ file, ...rest }) => fetch('/api/vod/auth', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ ...rest, fileName: file.name, fileSize: file.size }),
  }).then(r => r.json()),
});

refresh-video 失败自动降级:当续传凭证刷新失败时,SDK 自动 fallback 到 create-video 重新上传,对调用方完全透明。

STS直传模式getSTS

getAuth模式需要由服务端调用VOD OpenAPI获取UploadAuth/UploadAddress。如果你的服务端仅提供STS 临时凭证,可以使用getSTS模式:SDK会在浏览器中使用该凭证签名调用VOD OpenAPI,获取上传凭证后再上传文件。

type GetSTS = () => Promise<STSCredential>;

interface STSCredential {
  accessKeyId: string;
  accessKeySecret: string;
  securityToken: string;
}
createUploader({
  region: 'cn-shanghai',              // getSTS 模式必填,决定 vod.<region>.aliyuncs.com 端点
  getSTS: async () => {
    const { AccessKeyId, AccessKeySecret, SecurityToken } = await fetch('/api/sts').then(r => r.json());
    return { accessKeyId: AccessKeyId, accessKeySecret: AccessKeySecret, securityToken: SecurityToken };
  },
});

要点:

  • 必须运行在HTTPS或localhost:STS模式的V3签名依赖Web Crypto crypto.subtle,普通HTTP页面不可用;getAuth模式不受此限制。

  • 与getAuth互斥:两者只能传一个。

  • 无参数、不含expiration:SDK 不主动判断STS凭证是否过期;VOD返回InvalidSecurityToken.Expired时自动重新调一次getSTS()并重试一次。

  • 不做缓存、不做并发去重:多个并发upload()会各自调getSTS(),需要缓存请自己实现。

  • Title/FileName由SDK从文件派生:FileName=file.name(Blob时用meta.fileName),Title=meta.title ?? FileName;派生值截断到 128 字符,显式传的meta.title不截断。

  • FileSize由SDK填:每次CreateUploadVideo无条件带上FileSize=file.size(v1要用户自己在userData里传,漏传VOD侧就缺大小)。

  • VOD调用失败时错误码为UPLOAD.VOD.CREATE_FAILED/UPLOAD.VOD.REFRESH_FAILED,suggestion里带VOD的排障链接;VOD原始Message不会进UploadError(可能含明文凭证),只会脱敏后上报到埋点。

  • 超时与重试复用timeout/retry.count配置;4xx/5xx都不重试(只有上面那一处过期码例外)。

错误处理

UploadError 结构

所有上传错误都是UploadError实例(继承自Error):

import { UploadError } from 'aliyun-vod-upload-sdk';

class UploadError extends Error {
  readonly code: string;           // 结构化错误码,如 'UPLOAD.OSS.ACCESS_DENIED'
  readonly message: string;        // 错误描述
  readonly suggestion: string;     // 中文修复建议
  readonly cause?: unknown;        // 底层原始错误
  readonly uploadTaskId?: string;  // 上传任务 ID(可用于售后排障)
}

用户取消上传不是 UploadError,而是标准的 DOMException(name === 'AbortError')。

错误码清单

错误码格式:UPLOAD.{层级}.{类型}

错误码

含义

修复建议

UPLOAD.AUTH.GET_AUTH_FAILED

getAuth回调抛错或返回结构非法

请检查getAuth回调是否正确返回了包含UploadAuth、UploadAddress的JSON。确认后端服务可用且返回格式正确。

UPLOAD.AUTH.GET_STS_FAILED

getSTS回调抛错(STS模式)

STS模式下getSTS回调获取临时凭证失败。请检查getSTS 实现能否正常调用你的STS服务(网络连通性、鉴权、跨域配置),以及返回的 accessKeyId/ accessKeySecret/ securityToken是否完整。

UPLOAD.VOD.CREATE_FAILED

STS模式下CreateUploadVideo/CreateUploadImage/CreateUploadAttachedMedia调用失败

STS模式下SDK调用VOD接口创建上传凭证失败。请检查 createUploader传入的region 是否与账号所属地域一致,getSTS返回的临时凭证是否具备VOD权限(CreateUploadVideo/ CreateUploadImage/ CreateUploadAttachedMedia),以及meta中的媒资参数是否合法。

UPLOAD.VOD.REFRESH_FAILED

STS模式下RefreshUploadVideo调用失败

STS模式下SDK调用VOD接口续期上传凭证失败。请检查 getSTS返回的临时凭证是否有效、是否具备 RefreshUploadVideo权限,以及videoId对应的媒资是否仍然存在。

UPLOAD.CONFIG.INVALID

配置非法:① createUploader的getAuth/getSTS 未二选一,或STS模式缺 region(构建期同步抛出);② meta.businessType键存在但值不是非空字符串(上传期返回 rejected 的 UploadTask)

配置无效。请确认 createUploader的getAuth与 getSTS只传其中一个;STS 模式(传getSTS)时必须提供非空的region,且与账号所属地域一致(如cn-shanghai)。上传辅助媒资时 meta.businessType必须是非空字符串(如watermark / subtitle/material)。

UPLOAD.OSS.ACCESS_DENIED

OSS 权限错误(403)

OSS 访问被拒绝。请检查上传凭证(STS Token)是否有效、是否已过期,以及RAM 策略是否授权了OSS写入权限。

UPLOAD.OSS.NO_SUCH_BUCKET

Bucket不存在

OSS Bucket不存在。请检查上传地址中的Bucket名称是否正确,确认Bucket已在对应区域创建。

UPLOAD.OSS.NO_SUCH_UPLOAD

分片上传会话已失效

分片上传会话已失效(可能已超过24小时)。SDK将自动重新上传,无需手动处理。

UPLOAD.OSS.UNKNOWN

OSS未知错误

OSS上传遇到未知错误。请查看浏览器控制台获取详细错误信息。

UPLOAD.NETWORK.TIMEOUT

请求超时

网络请求超时。请打开浏览器开发者工具的Network面板查看失败请求的详情,检查网络连接是否稳定,或尝试增大timeout配置值。

UPLOAD.NETWORK.ERROR

网络连接错误

网络连接错误。请打开浏览器开发者工具的Network面板查看失败请求的状态码和响应,确认浏览器可以访问OSS服务地址,排查是否有代理或防火墙拦截。

UPLOAD.NETWORK.OFFLINE

浏览器离线

浏览器检测到当前处于离线状态。请打开浏览器开发者工具的 Network 面板确认网络状态,连接网络后重试上传。

UPLOAD.FILE.EMPTY

文件大小为0

文件大小为0,无法上传空文件。请检查文件是否正确选择。

UPLOAD.INTERNAL.DISPOSED

Uploader实例已销毁

Uploader实例已销毁,无法继续使用。请重新调用createUploader创建新实例。

使用错误码常量

推荐使用 ErrorCode 常量而非字符串字面量:

import { ErrorCode, UploadError } from 'aliyun-vod-upload-sdk';

try {
  await uploader.upload(file);
} catch (e) {
  if (e instanceof UploadError) {
    switch (e.code) {
      case ErrorCode.AUTH_GET_AUTH_FAILED:
        showToast('凭证获取失败,请刷新页面重试');
        break;
      case ErrorCode.NETWORK_TIMEOUT:
      case ErrorCode.NETWORK_ERROR:
        showToast('网络异常,请检查网络后重试');
        break;
      case ErrorCode.OSS_ACCESS_DENIED:
        showToast('上传权限不足,请联系管理员');
        break;
      default:
        showToast(`上传失败:${e.suggestion || e.message}`);
    }
  }
}

排障指引

每个 UploadError 都携带 uploadTaskId,这是整次上传的全局串联 ID。提交给阿里云售后时可快速定位问题:

catch (e) {
  if (e instanceof UploadError) {
    // 发给你的技术支持团队
    const diagnostic = {
      code: e.code,
      message: e.message,
      uploadTaskId: e.uploadTaskId,
      suggestion: e.suggestion,
    };
    reportToSupport(diagnostic);
  }
}

UploadResult.uploadTaskId 同样可用于成功上传后的日志关联:

const result = await uploader.upload(file);
myLogger.info('上传成功', { videoId: result.videoId, uploadTaskId: result.uploadTaskId });