Todos os produtos
Search
Central de documentação

ApsaraVideo VOD:Upload de arquivos com o SDK JavaScript

Última atualização: Jul 13, 2026

O ApsaraVideo VOD JavaScript SDK (aliyun-vod-upload-sdk) realiza o upload de arquivos de vídeo e imagem diretamente do navegador para o armazenamento do ApsaraVideo VOD. O SDK gerencia a obtenção de credenciais, o upload multipart, o upload retomável e o acompanhamento de progresso.

Requisitos do navegador

Navegador

Versão mínima

Chrome

60+

Microsoft Edge

79+ (Chromium)

Firefox

55+

Safari

11+

Navegador padrão do Android

60+

Navegador padrão do iOS

11+

Início rápido

Baixe o código-fonte da demonstração para acessar um exemplo completo e funcional.

Instalação

Instale o SDK via npm:

npm install aliyun-vod-upload-sdk

O SDK oferece builds ESM, CJS e UMD, com suporte a todos os empacotadores modernos (Vite, webpack, Rollup e esbuild).

Importação via CDN

Para utilizar o SDK sem um empacotador, importe-o diretamente de uma CDN:

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

Requisitos da API de backend

O SDK não chama diretamente a OpenAPI do Alibaba Cloud. Em vez disso, ele delega essa tarefa ao seu backend por meio do callback getAuth para obter as credenciais de upload. Seu backend deve implementar as seguintes APIs, correspondentes às operações da OpenAPI do VOD:

API de backend

Operação OpenAPI correspondente

Campos de resposta

Criar credencial de upload de vídeo

CreateUploadVideo

{ UploadAuth, UploadAddress, VideoId }

Atualizar credencial de upload de vídeo

RefreshUploadVideo

{ UploadAuth, UploadAddress, VideoId }

Criar credencial de upload de imagem

CreateUploadImage

{ UploadAuth, UploadAddress, ImageId }

O JSON de resposta do backend é repassado tal como está ao SDK. O próprio SDK cuida automaticamente da decodificação base64 e do mapeamento dos campos.

Faça o upload de um arquivo em cinco linhas de código

O exemplo abaixo apresenta o código mínimo necessário para enviar um arquivo:

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

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

// file is a File object, for example from an <input type="file"> element
const { videoId } = await uploader.upload(file);

Recursos básicos

Upload de vídeos

Este exemplo cria um uploader com um callback getAuth que gerencia tanto a criação inicial quanto a atualização das credenciais:

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: 'My Video', cateId: 1000, tags: 'tutorial,example' },
});
console.log('Upload successful, videoId:', result.videoId);

O callback getAuth recebe um parâmetro ctx. O SDK determina automaticamente o valor de ctx.kind conforme o cenário:

  • **create-video** — Primeiro upload. O backend precisa chamar CreateUploadVideo.

  • **refresh-video** — Atualização de credencial durante um upload retomável. O backend precisa chamar RefreshUploadVideo.

  • **create-image** — Upload de imagem. O backend precisa chamar CreateUploadImage.

Upload de imagens

O envio de imagens utiliza o mesmo método upload(). O SDK detecta automaticamente o tipo de arquivo com base em file.type (tipos image/* seguem o fluxo de upload de imagem):

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('Image upload successful, imageId:', result.imageId);

Acompanhamento do progresso de upload

Utilize o callback onProgress para monitorar o andamento do upload:

const result = await uploader.upload(file, {
  onProgress: (percent, loaded, total) => {
    // percent: 0..1 (e.g. 0.5 means 50%)
    // loaded:  bytes uploaded
    // total:   total file size in bytes
    progressBar.value = percent;
    console.log(`${(percent * 100).toFixed(1)}% - ${loaded} / ${total}`);
  },
});

O SDK garante que percent seja igual a 1 quando o upload for concluído.

Cancelamento de um upload

É possível cancelar um upload utilizando o método task.abort() ou um AbortSignal.

  • Método 1: task.abort() — Abordagem mais simples

const task = uploader.upload(file);

cancelBtn.onclick = () => task.abort();

try {
  const result = await task;
} catch (e) {
  if (e.name === 'AbortError') {
    console.log('Upload canceled by user');
  }
}
  • Método 2: AbortSignal — Ideal para ciclos de vida de componentes 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('Upload canceled');
  }
}

Após o cancelamento, o checkpoint é preservado. A próxima chamada a upload(file) retoma automaticamente o envio a partir do ponto de interrupção.

Upload retomável

O upload retomável vem ativado por padrão e não exige configurações adicionais. Esse recurso é suportado apenas para uploads de vídeo; uploads de imagem não utilizam essa funcionalidade. O SDK executa automaticamente as seguintes ações:

  • Armazena o progresso das partes concluídas no localStorage.

  • Retoma o envio do ponto onde foi interrompido quando upload(file) é chamado novamente após uma atualização da página.

  • Identifica os checkpoints usando a regra: mesmo file.name + file.size + file.lastModified.

// First upload (user closes the page at 40% progress)
await uploader.upload(file);

// User reopens the page and uploads the same file again
// The SDK automatically resumes from 40% without re-uploading
const result = await uploader.upload(file);

Para desativar o upload retomável:

const uploader = createUploader({
  getAuth: myGetAuth,
  checkpoint: false,  // Disable resumable upload
});

Recursos avançados

Upload em lote

O SDK fornece uma API upload() para arquivo único. Para uploads em lote, utilize os primitivos assíncronos padrão do JavaScript.

Upload sequencial (mais simples)

for (const file of files) {
  const result = await uploader.upload(file, {
    onProgress: p => updateProgress(file.name, p),
  });
  console.log(`${file.name} complete, videoId: ${result.videoId}`);
}

Upload simultâneo (alta largura de banda e arquivos pequenos)

const results = await Promise.all(
  files.map(f => uploader.upload(f)),
);

(Recomendado) Upload com limite de concorrência (arquivos grandes)

import pLimit from 'p-limit';

const limit = pLimit(2); // Upload at most 2 files simultaneously
const results = await Promise.all(
  files.map(f => limit(() => uploader.upload(f, {
    onProgress: p => updateItemProgress(f, p),
  }))),
);

Pausar e retomar

O SDK não possui uma API explícita de pause. Obtenha o efeito de pausa combinando cancelamento + retomada:

// Pause: cancel the current upload
task.abort();

// Resume: re-upload the same file, automatically resumes from checkpoint
const result = await uploader.upload(file);

Timeout e cancelamento de múltiplas origens

Utilize AbortSignal.timeout() e AbortSignal.any() para implementar cancelamentos baseados em timeout ou combinados:

// Auto-cancel after 60 seconds
await uploader.upload(file, {
  signal: AbortSignal.timeout(60_000),
});

// Multi-source cancellation: user manual cancel OR 60-second timeout
const userCtrl = new AbortController();
await uploader.upload(file, {
  signal: AbortSignal.any([
    userCtrl.signal,
    AbortSignal.timeout(60_000),
  ]),
});

Integração com React e Vue

React

Exemplo de React Hook

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

function useUploader(getAuth) {
  const uploaderRef = useRef(createUploader({ getAuth }));

  useEffect(() => {
    return () => uploaderRef.current.dispose(); // Release on unmount
  }, []);

  return uploaderRef.current;
}

function UploadButton({ file }) {
  const uploader = useUploader(myGetAuth);
  const [progress, setProgress] = useState(0);

  const handleUpload = () => {
    const ctrl = new AbortController();

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

  return <button onClick={handleUpload}>Upload ({(progress * 100).toFixed(0)}%)</button>;
}

Vue 3

Exemplo de 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 };
}

Referência da API

createUploader(config)

Cria uma instância do Uploader.

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

const uploader = createUploader(config);

UploaderConfig

Parâmetro

Tipo

Obrigatório

Padrão

Descrição

getAuth

GetAuth

Sim

Callback para obtenção de credenciais. Para mais informações, consulte callback getAuth.

retry

RetryPolicy

Não

{ count: 3 }

Política de nova tentativa automática para falhas no upload multipart do OSS.

checkpoint

false

{ store?: CheckpointStore }

Não

localStorage

Configuração de upload retomável. Defina como false para desativar. Defina como { store } para injetar um armazenamento personalizado.

parallel

number

Não

4

Quantidade de partes do OSS enviadas simultaneamente.

partSize

number

Não

1048576 (1 MB)

Tamanho da parte do OSS em bytes.

timeout

number

Não

60000

Timeout de requisição de rede em milissegundos.

cname

string

Não

Nome de domínio personalizado do OSS.

refreshSTSTokenInterval

number

Não

300000 (5 min)

Intervalo de verificação para atualização de credenciais STS em milissegundos.

RetryPolicy

Campo

Tipo

Padrão

Descrição

count

number

3

Número máximo de novas tentativas.

uploader.upload(file, options?)

Envia um único arquivo. Retorna um UploadTask, que funciona simultaneamente como uma Promise<UploadResult> e como um objeto com o método .abort().

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

UploadOptions

Parâmetro

Tipo

Descrição

meta

VodVideoMeta

VodImageMeta

Metadados da mídia (título, categoria, tags, entre outros).

signal

AbortSignal

Sinal de cancelamento padrão da Web.

onProgress

(percent, loaded, total) => void

Callback de progresso. O valor de percent varia de 0 a 1.

partSize

number

Substitui o partSize global.

parallel

number

Substitui o parallel global.

VodVideoMeta (metadados de vídeo)

Campo

Tipo

Descrição

title

string

Título do vídeo.

description

string

Descrição do vídeo.

cateId

number

ID da categoria.

tags

string

Tags separadas por vírgulas.

templateGroupId

string

ID do grupo de modelos de transcodificação.

storageLocation

string

Endereço de armazenamento.

coverUrl

string

URL da imagem de capa.

workflowId

string

ID do fluxo de trabalho.

appId

string

ID da aplicação.

userData

Record

Dados personalizados.

VodImageMeta (metadados de imagem)

Campo

Tipo

Descrição

title

string

Título da imagem.

description

string

Descrição da imagem.

imageType

'default'

'cover'

'watermark'

Tipo de imagem.

imageExt

string

Extensão do arquivo de imagem.

tags

string

Tags.

cateId

number

ID da categoria.

storageLocation

string

Endereço de armazenamento.

UploadResult

Campo

Tipo

Descrição

videoId

string?

ID do vídeo. Retornado em uploads de vídeo.

imageId

string?

ID da imagem. Retornado em uploads de imagem.

etag

string

ETag do OSS.

requestId

string

ID da requisição do OSS.

durationMs

number

Duração do upload em milissegundos.

uploadTaskId

string

ID exclusivo da tarefa de upload. Pode ser usado para solução de problemas junto ao suporte técnico.

UploadTask

O objeto retornado por upload() atua tanto como uma Promise<UploadResult> quanto como um objeto com o método .abort().

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

O método .abort() se perde após o encadeamento. task.then(fn) retorna uma Promise comum. Para manter a capacidade de cancelamento após o encadeamento, utilize options.signal.

uploader.dispose()

Libera recursos: cancela todos os uploads em andamento e limpa o estado interno.

uploader.dispose();

Após essa chamada, a instância uploader não pode mais ser utilizada. Chame este método quando um componente React ou Vue for desmontado para evitar vazamentos de memória.

Callback getAuth

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

AuthContext

O SDK passa diferentes valores de ctx dependendo do cenário de upload:

ctx.kind

Cenário de acionamento

Campos adicionais de ctx

'create-video'

Primeiro upload de vídeo

file, meta?

'refresh-video'

Atualização de credencial durante upload retomável

file, videoId

'create-image'

Upload de imagem

file, meta?

AuthResult

JSON bruto retornado pelo backend a partir da resposta da OpenAPI. O SDK faz a decodificação automaticamente:

Campo

Tipo

Obrigatório

Descrição

UploadAuth

string

Sim

Credencial STS codificada em Base64.

UploadAddress

string

Sim

Endereço de upload do OSS codificado em Base64.

VideoId

string

Obrigatório para create-video

ID do vídeo.

ImageId

string

Obrigatório para create-image

ID da imagem.

ImageURL

string

Não

URL da imagem (repassada tal como está).

Implementação mais simples de getAuth:

// Unified backend route
createUploader({
  getAuth: ctx => fetch('/api/vod/auth', {
    method: 'POST',
    body: JSON.stringify(ctx),
  }).then(r => r.json()),
});

Fallback automático em caso de falha no refresh-video: Quando a atualização de credencial durante um upload retomável falha, o SDK reverte automaticamente para create-video para reenviar o arquivo. Esse processo é totalmente transparente para quem faz a chamada.

Tratamento de erros

Estrutura do UploadError

Todos os erros de upload são instâncias de UploadError (estende Error):

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

class UploadError extends Error {
  readonly code: string;           // Structured error code, e.g. 'UPLOAD.OSS.ACCESS_DENIED'
  readonly message: string;        // Error description
  readonly suggestion: string;     // Fix suggestion
  readonly cause?: unknown;        // Original underlying error
  readonly uploadTaskId?: string;  // Upload task ID (for troubleshooting)
}

O cancelamento de upload iniciado pelo usuário não gera um UploadError. Trata-se de uma DOMException padrão (name === 'AbortError').

Códigos de erro

Formato do código de erro: UPLOAD.{layer}.{type}

Código de erro

Descrição

Correção sugerida

UPLOAD.AUTH.GET_AUTH_FAILED

O callback getAuth lançou um erro ou retornou uma estrutura inválida.

Verifique se o callback getAuth retorna corretamente um JSON contendo os campos UploadAuth e UploadAddress. Certifique-se de que o service de backend está disponível e o formato da resposta está correto.

UPLOAD.OSS.ACCESS_DENIED

Erro de permissão do OSS (403).

Valide se a credencial de upload (STS Token) é válida e não expirou, e se a política do RAM concede permissões de escrita no OSS.

UPLOAD.OSS.NO_SUCH_BUCKET

O bucket não existe.

Confirme se o nome do bucket no endereço de upload está correto e garanta que o bucket foi criado na região correspondente.

UPLOAD.OSS.NO_SUCH_UPLOAD

A sessão de upload multipart expirou.

A sessão de upload multipart expirou (possivelmente após mais de 24 horas). O SDK reenvia o arquivo automaticamente. Nenhuma ação manual é necessária.

UPLOAD.OSS.UNKNOWN

Erro desconhecido do OSS.

Consulte o console do navegador para obter informações detalhadas sobre o erro ou entre em contato com o suporte técnico.

UPLOAD.NETWORK.TIMEOUT

Tempo limite da requisição esgotado.

Abra o painel Network nas ferramentas de desenvolvedor do navegador para visualizar os detalhes da requisição com falha. Verifique se a conexão de rede está estável ou tente aumentar o valor de configuração do timeout.

UPLOAD.NETWORK.ERROR

Erro de conexão de rede.

Abra o painel Network nas ferramentas de desenvolvedor do navegador para verificar o código de status e a resposta da requisição com falha. Garanta que o navegador consegue acessar o endereço do service OSS. Verifique se algum proxy ou firewall está bloqueando a requisição.

UPLOAD.NETWORK.OFFLINE

O navegador está offline.

Verifique o status da rede e tente realizar o upload novamente após reconectar.

UPLOAD.FILE.EMPTY

O tamanho do arquivo é 0.

O tamanho do arquivo é 0. Arquivos vazios não podem ser enviados. Verifique se o arquivo correto foi selecionado.

UPLOAD.INTERNAL.DISPOSED

A instância do Uploader foi descartada.

Chame createUploader() novamente para criar uma nova instância.

Uso de constantes de código de erro

(Recomendado) Utilize as constantes ErrorCode em vez de literais de string:

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('Failed to obtain credentials. Refresh the page and try again.');
        break;
      case ErrorCode.NETWORK_TIMEOUT:
      case ErrorCode.NETWORK_ERROR:
        showToast('Network error. Check your network and try again.');
        break;
      case ErrorCode.OSS_ACCESS_DENIED:
        showToast('Insufficient upload permissions. Contact the administrator.');
        break;
      default:
        showToast(`Upload failed: ${e.suggestion || e.message}`);
    }
  }
}

Solução de problemas

Cada UploadError contém um uploadTaskId, que serve como ID de rastreamento global para todo o upload. Forneça esse ID ao suporte técnico do Alibaba Cloud para agilizar a identificação do problema:

catch (e) {
  if (e instanceof UploadError) {
    // Send to your technical support team
    const diagnostic = {
      code: e.code,
      message: e.message,
      uploadTaskId: e.uploadTaskId,
      suggestion: e.suggestion,
    };
    reportToSupport(diagnostic);
  }
}

O campo UploadResult.uploadTaskId também pode ser usado para correlacionar logs após um upload bem-sucedido:

const result = await uploader.upload(file);
myLogger.info('Upload successful', { videoId: result.videoId, uploadTaskId: result.uploadTaskId });