All Products
Search
Document Center

ApsaraVideo VOD:Unggah file menggunakan SDK JavaScript

Last Updated:Jul 14, 2026

SDK JavaScript ApsaraVideo VOD (aliyun-vod-upload-sdk) mengunggah file video dan gambar dari browser ke penyimpanan ApsaraVideo VOD. SDK ini menangani pengambilan kredensial, unggah multi-bagian, unggah yang dapat dilanjutkan, serta pelacakan progres.

Persyaratan browser

BrowserVersi minimum
Chrome60+
Microsoft Edge79+ (Chromium)
Firefox55+
Safari11+
Browser default Android60+
Browser default iOS11+

Mulai cepat

Anda dapat mengunduh kode sumber Demo untuk contoh lengkap yang berfungsi.

Instalasi

Instal SDK menggunakan npm:

npm install aliyun-vod-upload-sdk

SDK menyediakan build ESM, CJS, dan UMD serta mendukung semua bundler modern (Vite, webpack, Rollup, dan esbuild).

Impor melalui CDN

Untuk menggunakan SDK tanpa bundler, impor dari 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>

Persyaratan API backend

SDK tidak memanggil langsung Alibaba Cloud OpenAPI. Sebaliknya, SDK mendelegasikan ke backend Anda melalui callback getAuth untuk memperoleh kredensial unggah. Backend Anda harus mengimplementasikan API berikut, yang sesuai dengan operasi OpenAPI VOD:

API BackendOperasi OpenAPI yang sesuaiBidang respons
Buat kredensial unggah videoCreateUploadVideo{ UploadAuth, UploadAddress, VideoId }
Segarkan kredensial unggah videoRefreshUploadVideo{ UploadAuth, UploadAddress, VideoId }
Buat kredensial unggah gambarCreateUploadImage{ UploadAuth, UploadAddress, ImageId }

Respons JSON backend diteruskan apa adanya ke SDK. SDK secara otomatis menangani decoding Base64 dan pemetaan bidang.

Unggah file dalam lima baris kode

Contoh berikut menunjukkan kode minimal untuk mengunggah file:

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

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

// file adalah objek File, misalnya dari elemen <input type="file">
const { videoId } = await uploader.upload(file);

Fitur dasar

Unggah video

Contoh berikut membuat uploader dengan callback getAuth yang menangani pembuatan kredensial awal dan penyegaran kredensial:

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('Unggah berhasil, videoId:', result.videoId);

Callback getAuth menerima parameter ctx. SDK secara otomatis menentukan ctx.kind berdasarkan skenario:

  • create-video — Unggahan pertama kali. Backend harus memanggil CreateUploadVideo.

  • refresh-video — Penyegaran kredensial selama unggah yang dapat dilanjutkan. Backend harus memanggil RefreshUploadVideo.

  • create-image — Unggahan gambar. Backend harus memanggil CreateUploadImage.

Unggah gambar

Unggah gambar menggunakan metode upload() yang sama. SDK secara otomatis mendeteksi jenis file berdasarkan file.type (jenis image/* menggunakan jalur unggah gambar):

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('Unggah gambar berhasil, imageId:', result.imageId);

Lacak progres unggah

Gunakan callback onProgress untuk melacak progres unggah:

const result = await uploader.upload(file, {
  onProgress: (percent, loaded, total) => {
    // percent: 0..1 (misalnya 0,5 berarti 50%)
    // loaded:  byte yang diunggah
    // total:   ukuran file total dalam byte
    progressBar.value = percent;
    console.log(`${(percent * 100).toFixed(1)}% - ${loaded} / ${total}`);
  },
});

SDK menjamin bahwa percent bernilai 1 saat unggah selesai.

Batalkan unggah

Anda dapat membatalkan unggah dengan menggunakan metode task.abort() atau AbortSignal.

  • Metode 1: task.abort() — Pendekatan paling sederhana

const task = uploader.upload(file);

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

try {
  const result = await task;
} catch (e) {
  if (e.name === 'AbortError') {
    console.log('Unggah dibatalkan oleh pengguna');
  }
}
  • Metode 2: AbortSignal — Cocok untuk siklus hidup komponen 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('Unggah dibatalkan');
  }
}

Setelah pembatalan, checkpoint dipertahankan. Pemanggilan berikutnya ke upload(file) secara otomatis melanjutkan dari titik henti.

Unggah yang dapat dilanjutkan

Unggah yang dapat dilanjutkan diaktifkan secara default dan tidak memerlukan konfigurasi tambahan. Fitur ini hanya didukung untuk unggah video; unggah gambar tidak menggunakan unggah yang dapat dilanjutkan. SDK secara otomatis:

  • Menyimpan progres bagian yang telah selesai di localStorage.

  • Melanjutkan dari tempat unggah terputus ketika upload(file) dipanggil lagi setelah refresh halaman.

  • Mencocokkan checkpoint berdasarkan aturan: file.name + file.size + file.lastModified yang sama.

// Unggah pertama (pengguna menutup halaman pada progres 40%)
await uploader.upload(file);

// Pengguna membuka kembali halaman dan mengunggah file yang sama lagi
// SDK secara otomatis melanjutkan dari 40% tanpa mengunggah ulang
const result = await uploader.upload(file);

Untuk menonaktifkan unggah yang dapat dilanjutkan:

const uploader = createUploader({
  getAuth: myGetAuth,
  checkpoint: false,  // Nonaktifkan unggah yang dapat dilanjutkan
});

Fitur lanjutan

Unggah batch

SDK menyediakan API upload() untuk satu file. Untuk unggah batch, gunakan primitif async JavaScript standar.

Unggah serial (paling sederhana)

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

Unggah konkuren (bandwidth tinggi dan file kecil)

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

(Direkomendasikan) Unggah dengan batas konkurensi (file besar)

import pLimit from 'p-limit';

const limit = pLimit(2); // Unggah maksimal 2 file secara bersamaan
const results = await Promise.all(
  files.map(f => limit(() => uploader.upload(f, {
    onProgress: p => updateItemProgress(f, p),
  }))),
);

Jeda dan lanjutkan

SDK tidak memiliki API eksplisit untuk jeda. Capai efek jeda melalui batalkan + lanjutkan:

// Jeda: batalkan unggah saat ini
task.abort();

// Lanjutkan: unggah ulang file yang sama, secara otomatis dilanjutkan dari checkpoint
const result = await uploader.upload(file);

Timeout dan pembatalan multi-sumber

Gunakan AbortSignal.timeout() dan AbortSignal.any() untuk mengimplementasikan pembatalan berbasis timeout dan gabungan:

// Batalkan otomatis setelah 60 detik
await uploader.upload(file, {
  signal: AbortSignal.timeout(60_000),
});

// Pembatalan multi-sumber: pembatalan manual pengguna ATAU timeout 60 detik
const userCtrl = new AbortController();
await uploader.upload(file, {
  signal: AbortSignal.any([
    userCtrl.signal,
    AbortSignal.timeout(60_000),
  ]),
});

Integrasi React dan Vue

React

Contoh 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(); // Lepaskan saat 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('Berhasil', result.videoId);
    }).catch(e => {
      if (e.name !== 'AbortError') {
        console.error('Gagal', e);
      }
    });
  };

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

Vue 3

Contoh 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 };
}

Referensi API

createUploader(config)

Membuat instans Uploader.

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

const uploader = createUploader(config);

UploaderConfig

ParameterTypeWajibDefaultDeskripsi
getAuthGetAuthYaCallback pengambilan kredensial. Untuk informasi lebih lanjut, lihat callback getAuth.
retryRetryPolicyTidak{ count: 3 }Kebijakan retry otomatis untuk kegagalan unggah multi-bagian OSS.
checkpointfalse | { store?: CheckpointStore }TidaklocalStorageKonfigurasi unggah yang dapat dilanjutkan. Atur ke false untuk menonaktifkan. Atur ke { store } untuk menyuntikkan store kustom.
parallelnumberTidak4Jumlah bagian OSS konkuren.
partSizenumberTidak1048576 (1 MB)Ukuran bagian OSS dalam byte.
timeoutnumberTidak60000Timeout permintaan jaringan dalam milidetik.
cnamestringTidakNama domain OSS kustom.
refreshSTSTokenIntervalnumberTidak300000 (5 menit)Interval pemeriksaan penyegaran kredensial STS dalam milidetik.

RetryPolicy

BidangTipeDefaultDeskripsi
countnumber3Jumlah maksimum percobaan ulang.

uploader.upload(file, options?)

Mengunggah satu file. Mengembalikan UploadTask, yang merupakan Promise<UploadResult> sekaligus objek dengan metode .abort().

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

UploadOptions

ParameterTipeDeskripsi
metaVodVideoMeta | VodImageMetaMetadata media (judul, kategori, tag, dan lainnya).
signalAbortSignalSinyal pembatalan standar web.
onProgress(percent, loaded, total) => voidCallback progres. Nilai percent berkisar dari 0 hingga 1.
partSizenumberMengganti partSize global.
parallelnumberMengganti parallel global.

VodVideoMeta (metadata video)

BidangTipeDeskripsi
titlestringJudul video.
descriptionstringDeskripsi video.
cateIdnumberID kategori.
tagsstringTag, dipisahkan koma.
templateGroupIdstringID grup templat transkoding.
storageLocationstringAlamat penyimpanan.
coverUrlstringURL gambar sampul.
workflowIdstringID alur kerja.
appIdstringID aplikasi.
userDataRecordData kustom.

VodImageMeta (metadata gambar)

BidangTipeDeskripsi
titlestringJudul gambar.
descriptionstringDeskripsi gambar.
imageType'default' | 'cover' | 'watermark'Jenis gambar.
imageExtstringEkstensi file gambar.
tagsstringTag.
cateIdnumberID kategori.
storageLocationstringAlamat penyimpanan.

UploadResult

BidangTipeDeskripsi
videoIdstring?ID video. Dikembalikan untuk unggah video.
imageIdstring?ID gambar. Dikembalikan untuk unggah gambar.
etagstringETag OSS.
requestIdstringID permintaan OSS.
durationMsnumberDurasi unggah dalam milidetik.
uploadTaskIdstringID tugas unggah unik. Dapat digunakan untuk troubleshooting bersama tim dukungan teknis.

UploadTask

Objek yang dikembalikan oleh upload() merupakan Promise<UploadResult> sekaligus objek dengan metode .abort().

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

Metode .abort() hilang setelah chaining. task.then(fn) mengembalikan Promise biasa. Untuk mempertahankan kemampuan membatalkan setelah chaining, gunakan options.signal.

uploader.dispose()

Melepaskan sumber daya: membatalkan semua unggah yang sedang berlangsung dan membersihkan status internal.

uploader.dispose();

Setelah pemanggilan ini, instans uploader tidak dapat digunakan lagi. Panggil metode ini saat komponen React atau Vue di-unmount untuk mencegah kebocoran memori.

Callback getAuth

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

AuthContext

SDK meneruskan nilai ctx yang berbeda berdasarkan skenario unggah:

ctx.kindSkenario pemicuBidang ctx tambahan
'create-video'Unggah video pertama kalifile, meta?
'refresh-video'Penyegaran kredensial selama unggah yang dapat dilanjutkanfile, videoId
'create-image'Unggah gambarfile, meta?

AuthResult

JSON mentah yang dikembalikan oleh backend dari respons OpenAPI. SDK secara otomatis mendecodenya:

BidangTipeWajibDeskripsi
UploadAuthstringYaKredensial STS yang dienkripsi Base64.
UploadAddressstringYaAlamat unggah OSS yang dienkripsi Base64.
VideoIdstringWajib untuk create-videoID video.
ImageIdstringWajib untuk create-imageID gambar.
ImageURLstringTidakURL gambar (dilewatkan).

Implementasi getAuth paling sederhana:

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

Fallback otomatis saat kegagalan refresh-video: Saat penyegaran kredensial selama unggah yang dapat dilanjutkan gagal, SDK secara otomatis fallback ke create-video untuk mengunggah ulang file. Ini sepenuhnya transparan bagi pemanggil.

Penanganan error

Struktur UploadError

Semua error unggah adalah instans UploadError (memperluas Error):

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

class UploadError extends Error {
  readonly code: string;           // Kode error terstruktur, misalnya 'UPLOAD.OSS.ACCESS_DENIED'
  readonly message: string;        // Deskripsi error
  readonly suggestion: string;     // Saran perbaikan
  readonly cause?: unknown;        // Error asli yang mendasari
  readonly uploadTaskId?: string;  // ID tugas unggah (untuk troubleshooting)
}

Pembatalan unggah yang diprakarsai pengguna bukanlah UploadError. Ini adalah DOMException standar (name === 'AbortError').

Kode error

Format kode error: UPLOAD.{layer}.{type}

Kode errorDeskripsiSaran perbaikan
UPLOAD.AUTH.GET_AUTH_FAILEDCallback getAuth melempar error atau mengembalikan struktur yang tidak valid.Periksa apakah callback getAuth mengembalikan JSON yang benar berisi bidang UploadAuth dan UploadAddress. Pastikan layanan backend tersedia dan format respons benar.
UPLOAD.OSS.ACCESS_DENIEDError izin OSS (403).Periksa apakah kredensial unggah (Token STS) valid dan belum kedaluwarsa, serta apakah kebijakan RAM memberikan izin tulis OSS.
UPLOAD.OSS.NO_SUCH_BUCKETBucket tidak ada.Periksa apakah nama bucket dalam alamat unggah benar, dan pastikan bucket telah dibuat di wilayah yang sesuai.
UPLOAD.OSS.NO_SUCH_UPLOADSesi unggah multi-bagian telah kedaluwarsa.Sesi unggah multi-bagian telah kedaluwarsa (mungkin setelah lebih dari 24 jam). SDK secara otomatis mengunggah ulang file. Tidak diperlukan tindakan manual.
UPLOAD.OSS.UNKNOWNError OSS tidak dikenal.Periksa konsol browser untuk informasi error detail, atau hubungi dukungan teknis.
UPLOAD.NETWORK.TIMEOUTPermintaan timeout.Buka panel Network di developer tools browser untuk melihat detail permintaan yang gagal. Periksa apakah koneksi jaringan stabil, atau coba tingkatkan nilai konfigurasi timeout.
UPLOAD.NETWORK.ERRORError koneksi jaringan.Buka panel Network di developer tools browser untuk melihat kode status dan respons permintaan yang gagal. Pastikan browser dapat mengakses alamat layanan OSS. Periksa apakah proxy atau firewall memblokir permintaan.
UPLOAD.NETWORK.OFFLINEBrowser sedang offline.Periksa status jaringan dan coba unggah lagi setelah terhubung kembali.
UPLOAD.FILE.EMPTYUkuran file 0.Ukuran file 0. File kosong tidak dapat diunggah. Periksa apakah file yang benar dipilih.
UPLOAD.INTERNAL.DISPOSEDInstans Uploader telah di-dispose.Panggil createUploader() lagi untuk membuat instans baru.

Gunakan konstanta kode error

(Direkomendasikan) Gunakan konstanta ErrorCode daripada literal 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('Gagal memperoleh kredensial. Refresh halaman dan coba lagi.');
        break;
      case ErrorCode.NETWORK_TIMEOUT:
      case ErrorCode.NETWORK_ERROR:
        showToast('Error jaringan. Periksa koneksi Anda dan coba lagi.');
        break;
      case ErrorCode.OSS_ACCESS_DENIED:
        showToast('Izin unggah tidak mencukupi. Hubungi administrator.');
        break;
      default:
        showToast(`Unggah gagal: ${e.suggestion || e.message}`);
    }
  }
}

Troubleshooting

Setiap UploadError berisi uploadTaskId, yaitu ID jejak global untuk seluruh proses unggah. Anda dapat memberikan ID ini kepada tim dukungan teknis Alibaba Cloud untuk identifikasi masalah cepat:

catch (e) {
  if (e instanceof UploadError) {
    // Kirim ke tim dukungan teknis Anda
    const diagnostic = {
      code: e.code,
      message: e.message,
      uploadTaskId: e.uploadTaskId,
      suggestion: e.suggestion,
    };
    reportToSupport(diagnostic);
  }
}

UploadResult.uploadTaskId juga dapat digunakan untuk korelasi log setelah unggah berhasil:

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