ApsaraVideo VOD JavaScript SDK (aliyun-vod-upload-sdk) は、ブラウザから ApsaraVideo VOD ストレージに動画および画像ファイルをアップロードします。SDK は、認証情報の取得、マルチパートアップロード、再開可能なアップロード、進捗状況の追跡を処理します。
ブラウザの要件
| ブラウザ | 最小バージョン |
| Chrome | 60+ |
| Microsoft Edge | 79+ (Chromium) |
| Firefox | 55+ |
| Safari | 11+ |
| Android デフォルトブラウザ | 60+ |
| iOS デフォルトブラウザ | 11+ |
クイックスタート
完全に動作するサンプルとして、デモのソースコードをダウンロードできます。
インストール
npm を使用して SDK をインストールします。
npm install aliyun-vod-upload-sdkSDK は ESM、CJS、UMD ビルドを提供し、すべての最新のバンドラー (Vite、webpack、Rollup、esbuild) をサポートしています。
CDN からのインポート
バンドラーを使用せずに SDK を利用するには、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>バックエンド API の要件
SDK は Alibaba Cloud OpenAPI を直接呼び出しません。代わりに、getAuth コールバックを介してバックエンドにデリゲートし、アップロード認証情報を取得します。バックエンドは、VOD OpenAPI オペレーションに対応する以下の API を実装する必要があります。
| バックエンド API | 対応する OpenAPI オペレーション | 応答フィールド |
| 動画アップロード認証情報の作成 | CreateUploadVideo | { UploadAuth, UploadAddress, VideoId } |
| 動画アップロード認証情報のリフレッシュ | RefreshUploadVideo | { UploadAuth, UploadAddress, VideoId } |
| 画像アップロード認証情報の作成 | CreateUploadImage | { UploadAuth, UploadAddress, ImageId } |
バックエンドの応答 JSON は、そのまま SDK に渡されます。SDK は Base64 デコードとフィールドマッピングを自動的に処理します。
5行のコードでファイルをアップロード
次の例は、ファイルをアップロードするための最小限のコードを示しています。
import { createUploader } from 'aliyun-vod-upload-sdk';
const uploader = createUploader({
getAuth: () => fetch('/api/vod/auth').then(r => r.json()),
});
// file は File オブジェクトです。例えば <input type="file"> 要素から取得します
const { videoId } = await uploader.upload(file);基本機能
動画のアップロード
次の例では、初回の認証情報作成と認証情報のリフレッシュの両方を処理する getAuth コールバックを持つアップローダーを作成します。
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);getAuth コールバックは ctx パラメーターを受け取ります。SDK はシナリオに基づいて ctx.kind を自動的に決定します。
create-video— 初回アップロード。バックエンドは CreateUploadVideo を呼び出す必要があります。refresh-video— 再開可能なアップロード中の認証情報のリフレッシュ。バックエンドは RefreshUploadVideo を呼び出す必要があります。create-image— 画像のアップロード。バックエンドは CreateUploadImage を呼び出す必要があります。
画像のアップロード
画像のアップロードには、同じ 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('Image upload successful, imageId:', result.imageId);アップロード進捗の追跡
onProgress コールバックを使用して、アップロードの進捗状況を追跡します。
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() メソッドまたは AbortSignal を使用してアップロードをキャンセルできます。
方法 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('Upload canceled by user');
}
}方法 2: 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('Upload canceled');
}
}キャンセル後、チェックポイントは保持されます。次に upload(file) を呼び出すと、ブレークポイントから自動的に再開されます。
再開可能なアップロード
再開可能なアップロードはデフォルトで有効になっており、追加の設定は不要です。この機能は動画のアップロードでのみサポートされています。画像のアップロードでは再開可能なアップロードは使用されません。SDK は自動的に以下を実行します。
完了したパートの進捗を
localStorageに保存します。ページのリフレッシュ後に再度
upload(file)が呼び出されると、アップロードが中断された場所から再開します。同じ file.name + file.size + file.lastModified というルールを使用してチェックポイントを照合します。
// 初回アップロード (ユーザーが進捗 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} complete, 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();
// 再開: 同じファイルを再アップロードし、チェックポイントから自動的に再開
const result = await uploader.upload(file);タイムアウトと複数ソースからのキャンセル
AbortSignal.timeout() と AbortSignal.any() を使用して、タイムアウトベースおよび組み合わせたキャンセルを実装します。
// 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),
]),
});React と Vue の統合
React
React フックの例
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(); // アンマウント時に解放
}, []);
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
Vue 3 コンポーザブルの例
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 | はい | — | 認証情報取得コールバック。詳細については、getAuth コールバックをご参照ください。 |
| retry | RetryPolicy | いいえ | { count: 3 } | OSS マルチパートアップロード失敗時の自動リトライポリシー。 |
| checkpoint | false | { store?: CheckpointStore } | いいえ | localStorage | 再開可能なアップロードの設定。false に設定すると無効になります。{ store } に設定すると、カスタムストアを注入します。 |
| parallel | number | いいえ | 4 | 同時 OSS パート数。 |
| partSize | number | いいえ | 1048576 (1 MB) | OSS パートサイズ (バイト単位)。 |
| timeout | number | いいえ | 60000 | ネットワークリクエストのタイムアウト (ミリ秒単位)。 |
| cname | string | いいえ | — | カスタム OSS ドメイン名。 |
| refreshSTSTokenInterval | number | いいえ | 300000 (5 分) | STS 認証情報のリフレッシュチェック間隔 (ミリ秒単位)。 |
RetryPolicy
| フィールド | タイプ | デフォルト | 説明 |
| count | number | 3 | 最大リトライ回数。 |
uploader.upload(file, options?)
単一のファイルをアップロードします。UploadTask を返します。これは Promise<UploadResult> であり、かつ .abort() メソッドを持つオブジェクトです。
const task = uploader.upload(file, options);UploadOptions
| パラメーター | タイプ | 説明 |
| meta | VodVideoMeta | VodImageMeta | メディアメタデータ (タイトル、カテゴリ、タグなど)。 |
| 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 | カスタムデータ。 |
VodImageMeta (画像メタデータ)
| フィールド | タイプ | 説明 |
| title | string | 画像のタイトル。 |
| description | string | 画像の説明。 |
| imageType | 'default' | 'cover' | 'watermark' | 画像タイプ。 |
| imageExt | string | 画像ファイルの拡張子。 |
| tags | string | タグ。 |
| cateId | number | カテゴリ ID。 |
| storageLocation | string | ストレージアドレス。 |
UploadResult
| フィールド | タイプ | 説明 |
| videoId | string? | 動画 ID。動画のアップロード時に返されます。 |
| imageId | string? | 画像 ID。画像のアップロード時に返されます。 |
| 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? |
AuthResult
バックエンドが OpenAPI 応答から返した生の JSON。SDK はそれを自動的にデコードします。
| フィールド | タイプ | 必須 | 説明 |
| UploadAuth | string | はい | Base64 エンコードされた STS 認証情報。 |
| UploadAddress | string | はい | Base64 エンコードされた OSS アップロードアドレス。 |
| VideoId | string | create-video に必須 | 動画 ID。 |
| ImageId | string | create-image に必須 | 画像 ID。 |
| ImageURL | string | いいえ | 画像 URL (パススルー)。 |
最も簡単な getAuth の実装:
// 統一されたバックエンドルート
createUploader({
getAuth: ctx => fetch('/api/vod/auth', {
method: 'POST',
body: JSON.stringify(ctx),
}).then(r => r.json()),
});refresh-video 失敗時の自動フォールバック: 再開可能なアップロード中に認証情報のリフレッシュが失敗した場合、SDK は自動的に create-video にフォールバックしてファイルを再アップロードします。これは呼び出し元に対して完全に透過的です。
エラーハンドリング
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.{layer}.{type}
| エラーコード | 説明 | 推奨される修正 |
| UPLOAD.AUTH.GET_AUTH_FAILED | getAuth コールバックがエラーをスローしたか、無効な構造を返しました。 | getAuth コールバックが UploadAuth および UploadAddress フィールドを含む JSON を正しく返すか確認してください。バックエンドサービスが利用可能で、応答フォーマットが正しいことを確認してください。 |
| UPLOAD.OSS.ACCESS_DENIED | OSS 権限エラー (403)。 | アップロード認証情報 (STS トークン) が有効で期限切れでないか、RAM ポリシーが OSS の書き込み権限を付与しているか確認してください。 |
| UPLOAD.OSS.NO_SUCH_BUCKET | バケットが存在しません。 | アップロードアドレスのバケット名が正しいか確認し、対応するリージョンにバケットが作成されていることを確認してください。 |
| UPLOAD.OSS.NO_SUCH_UPLOAD | マルチパートアップロードセッションが期限切れになりました。 | マルチパートアップロードセッションが期限切れになりました (おそらく 24 時間以上経過)。SDK は自動的にファイルを再アップロードします。手動での操作は不要です。 |
| UPLOAD.OSS.UNKNOWN | 不明な OSS エラー。 | ブラウザのコンソールで詳細なエラー情報を確認するか、テクニカルサポートにお問い合わせください。 |
| UPLOAD.NETWORK.TIMEOUT | リクエストがタイムアウトしました。 | ブラウザの開発者ツールのネットワークパネルを開き、失敗したリクエストの詳細を確認してください。ネットワーク接続が安定しているか確認するか、タイムアウト設定値を増やしてみてください。 |
| UPLOAD.NETWORK.ERROR | ネットワーク接続エラー。 | ブラウザの開発者ツールのネットワークパネルを開き、失敗したリクエストのステータスコードと応答を確認してください。ブラウザが OSS サービスアドレスにアクセスできることを確認してください。プロキシやファイアウォールがリクエストをブロックしていないか確認してください。 |
| UPLOAD.NETWORK.OFFLINE | ブラウザがオフラインです。 | ネットワークの状態を確認し、再接続後にアップロードを再試行してください。 |
| UPLOAD.FILE.EMPTY | ファイルサイズが 0 です。 | ファイルサイズが 0 です。空のファイルはアップロードできません。正しいファイルが選択されているか確認してください。 |
| UPLOAD.INTERNAL.DISPOSED | 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 です。この ID を Alibaba Cloud のテクニカルサポートに提供することで、迅速な問題特定が可能になります。
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('Upload successful', { videoId: result.videoId, uploadTaskId: result.uploadTaskId });