Le SDK JavaScript ApsaraVideo VOD (aliyun-vod-upload-sdk) permet de téléverser des vidéos et des images depuis un navigateur vers le stockage ApsaraVideo VOD. Le SDK gère la récupération des identifiants, le téléversement en plusieurs parties, la reprise après interruption et le suivi de la progression.
Prérequis navigateurs
| Navigateur | Version minimale |
| Chrome | 60+ |
| Microsoft Edge | 79+ (Chromium) |
| Firefox | 55+ |
| Safari | 11+ |
| Navigateur par défaut Android | 60+ |
| Navigateur par défaut iOS | 11+ |
Démarrage rapide
Téléchargez le code source de démonstration pour obtenir un exemple fonctionnel complet.
Installation
Installez le SDK avec npm :
npm install aliyun-vod-upload-sdk
Le SDK propose des versions ESM, CJS et UMD, et prend en charge tous les bundlers modernes (Vite, webpack, Rollup et esbuild).
Importation via CDN
Pour utiliser le SDK sans bundler, importez-le depuis un 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>
Prérequis API backend
Le SDK n’appelle pas directement les OpenAPI Alibaba Cloud. Il délègue cette tâche à votre backend via le rappel getAuth afin d’obtenir les identifiants de téléversement. Votre backend doit implémenter les API suivantes, qui correspondent aux opérations OpenAPI VOD :
| API backend | Opération OpenAPI correspondante | Champs de réponse |
| Création d’identifiants pour le téléversement vidéo | CreateUploadVideo | { UploadAuth, UploadAddress, VideoId } |
| Actualisation des identifiants pour le téléversement vidéo | RefreshUploadVideo | { UploadAuth, UploadAddress, VideoId } |
| Création d’identifiants pour le téléversement d’image | CreateUploadImage | { UploadAuth, UploadAddress, ImageId } |
La réponse JSON du backend est transmise telle quelle au SDK. Ce dernier gère automatiquement le décodage base64 et le mappage des champs.
Téléversement d’un fichier en cinq lignes de code
L’exemple suivant illustre le code minimal nécessaire pour téléverser un fichier :
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);
Fonctionnalités de base
Téléversement de vidéos
L’exemple ci-dessous crée un téléverseur avec un rappel getAuth qui gère à la fois la création initiale des identifiants et leur actualisation :
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);
Le rappel getAuth reçoit un paramètre ctx. Le SDK détermine automatiquement la valeur de ctx.kind selon le scénario :
**
create-video** — Premier téléversement. Le backend doit appeler CreateUploadVideo.**
refresh-video** — Actualisation des identifiants lors d’une reprise après interruption. Le backend doit appeler RefreshUploadVideo.**
create-image** — Téléversement d’image. Le backend doit appeler CreateUploadImage.
Téléversement d’images
Le téléversement d’images utilise la même méthode upload(). Le SDK détecte automatiquement le type de fichier en se basant sur file.type (les types image/* utilisent le chemin de téléversement dédié aux images) :
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);
Suivi de la progression du téléversement
Utilisez le rappel onProgress pour suivre la progression du téléversement :
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}`);
},
});
Le SDK garantit que percent est égal à 1 lorsque le téléversement est terminé.
Annulation d’un téléversement
Annulez un téléversement soit via la méthode task.abort(), soit à l’aide d’un AbortSignal.
Méthode 1 : task.abort() — Approche la plus simple
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éthode 2 : AbortSignal — Adaptée aux cycles de vie des composants 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');
}
}
Après l’annulation, le point de contrôle est conservé. Le prochain appel à upload(file) reprendra automatiquement le téléversement à partir du point d’interruption.
Reprise après interruption
La reprise après interruption est activée par défaut et ne nécessite aucune configuration supplémentaire. Cette fonctionnalité est prise en charge uniquement pour les téléversements vidéo. Les téléversements d’images n’utilisent pas la reprise après interruption. Le SDK effectue automatiquement les actions suivantes :
Stocke la progression des parties terminées dans
localStorage.Reprend le téléversement là où il a été interrompu lorsque
upload(file)est appelé de nouveau après un rafraîchissement de la page.Associe les points de contrôle selon la règle : même 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);
Pour désactiver la reprise après interruption :
const uploader = createUploader({
getAuth: myGetAuth,
checkpoint: false, // Disable resumable upload
});
Fonctionnalités avancées
Téléversement par lot
Le SDK fournit une API upload() pour un fichier unique. Pour les téléversements par lot, utilisez les primitives asynchrones JavaScript standard.
Téléversement séquentiel (le plus simple)
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}`);
}
Téléversement concurrent (bande passante élevée et fichiers de petite taille)
const results = await Promise.all(
files.map(f => uploader.upload(f)),
);
(Recommandé) Téléversement avec limitation de la concurrence (fichiers volumineux)
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),
}))),
);
Mise en pause et reprise
Le SDK ne dispose pas d’une API explicite de mise en pause. Obtenez cet effet en combinant annulation et reprise :
// Pause: cancel the current upload
task.abort();
// Resume: re-upload the same file, automatically resumes from checkpoint
const result = await uploader.upload(file);
Délai d’expiration et annulation multi-sources
Utilisez AbortSignal.timeout() et AbortSignal.any() pour mettre en œuvre une annulation basée sur un délai d’expiration ou combinée :
// 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),
]),
});
Intégration avec React et Vue
React
Exemple de Hook 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(); // 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
Exemple de Composable 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 };
}
Référence de l’API
createUploader(config)
Crée une instance Uploader.
import { createUploader } from 'aliyun-vod-upload-sdk';
const uploader = createUploader(config);
UploaderConfig
| Paramètre | Type | Obligatoire | Par défaut | Description | |
| getAuth | GetAuth | Oui | — | Rappel de récupération des identifiants. Pour plus d’informations, consultez le rappel getAuth. | |
| retry | RetryPolicy | Non | { count: 3 } | Politique de nouvelle tentative automatique en cas d’échec du téléversement en plusieurs parties OSS. | |
| checkpoint | false \ | { store?: CheckpointStore } | Non | localStorage |
Configuration de la reprise après interruption. Définissez sur |
| parallel | number | Non | 4 | Nombre de parties OSS concurrentes. | |
| partSize | number | Non | 1048576 (1 Mo) | Taille des parties OSS en octets. | |
| timeout | number | Non | 60000 | Délai d’expiration des requêtes réseau en millisecondes. | |
| cname | string | Non | — | Nom de domaine OSS personnalisé. | |
| refreshSTSTokenInterval | number | Non | 300000 (5 min) | Intervalle de vérification de l’actualisation des identifiants STS en millisecondes. |
RetryPolicy
| Champ | Type | Par défaut | Description |
| count | number | 3 | Nombre maximal de nouvelles tentatives. |
uploader.upload(file, options?)
Téléverse un fichier unique. Renvoie une UploadTask, qui est à la fois une Promise<UploadResult> et un objet disposant d’une méthode .abort().
const task = uploader.upload(file, options);
UploadOptions
| Paramètre | Type | Description | |
| meta | VodVideoMeta \ | VodImageMeta |
Métadonnées multimédias (titre, catégorie, tags, etc.). |
| signal | AbortSignal | Signal d’annulation standard Web. | |
| onProgress | (percent, loaded, total) => void | Rappel de progression. La valeur percent varie de 0 à 1. |
|
| partSize | number | Remplace la valeur globale partSize. | |
| parallel | number | Remplace la valeur globale parallel. |
VodVideoMeta (métadonnées vidéo)
| Champ | Type | Description |
| title | string | Titre de la vidéo. |
| description | string | Description de la vidéo. |
| cateId | number | ID de catégorie. |
| tags | string | Tags, séparés par des virgules. |
| templateGroupId | string | ID du groupe de modèles de transcodage. |
| storageLocation | string | Adresse de stockage. |
| coverUrl | string | URL de l’image de couverture. |
| workflowId | string | ID du workflow. |
| appId | string | ID de l’application. |
| userData | Record | Données personnalisées. |
VodImageMeta (métadonnées image)
| Champ | Type | Description | ||
| title | string | Titre de l’image. | ||
| description | string | Description de l’image. | ||
| imageType | 'default' \ | 'cover' \ |
'watermark' |
Type d’image. |
| imageExt | string | Extension du fichier image. | ||
| tags | string | Tags. | ||
| cateId | number | ID de catégorie. | ||
| storageLocation | string | Adresse de stockage. |
UploadResult
| Champ | Type | Description |
| videoId | string? | ID vidéo. Renvoyé pour les téléversements vidéo. |
| imageId | string? | ID image. Renvoyé pour les téléversements d’images. |
| etag | string | ETag OSS. |
| requestId | string | ID de requête OSS. |
| durationMs | number | Durée du téléversement en millisecondes. |
| uploadTaskId | string | ID unique de la tâche de téléversement. Peut être utilisé pour le dépannage avec le support technique. |
UploadTask
L’objet renvoyé par upload() est à la fois une Promise<UploadResult> et un objet disposant d’une méthode .abort().
type UploadTask = Promise<UploadResult> & {
abort(): void;
};
La méthode .abort() est perdue après chaînage. task.then(fn) renvoie une Promise standard. Pour conserver la capacité d’annulation après chaînage, utilisez options.signal.
uploader.dispose()
Libère les ressources : annule tous les téléversements en cours et efface l’état interne.
uploader.dispose();
Après cet appel, l’instance uploader ne peut plus être réutilisée. Appelez cette méthode lors du démontage d’un composant React ou Vue pour éviter les fuites de mémoire.
Rappel getAuth
type GetAuth = (ctx: AuthContext) => Promise<AuthResult>;
AuthContext
Le SDK transmet différentes valeurs de ctx selon le scénario de téléversement :
| ctx.kind | Scénario déclencheur | Champs ctx supplémentaires |
| 'create-video' | Premier téléversement vidéo | file, meta? |
| 'refresh-video' | Actualisation des identifiants lors d’une reprise après interruption | file, videoId |
| 'create-image' | Téléversement d’image | file, meta? |
AuthResult
JSON brut renvoyé par le backend à partir de la réponse OpenAPI. Le SDK le décode automatiquement :
| Champ | Type | Obligatoire | Description |
| UploadAuth | string | Oui | Identifiants STS encodés en base64. |
| UploadAddress | string | Oui | Adresse de téléversement OSS encodée en base64. |
| VideoId | string | Obligatoire pour create-video | ID vidéo. |
| ImageId | string | Obligatoire pour create-image | ID image. |
| ImageURL | string | Non | URL de l’image (transmise telle quelle). |
Implémentation getAuth la plus simple :
// Unified backend route
createUploader({
getAuth: ctx => fetch('/api/vod/auth', {
method: 'POST',
body: JSON.stringify(ctx),
}).then(r => r.json()),
});
Secours automatique en cas d’échec de refresh-video : Lorsque l’actualisation des identifiants lors d’une reprise après interruption échoue, le SDK bascule automatiquement vers create-video pour retéléverser le fichier. Ce processus est totalement transparent pour l’appelant.
Gestion des erreurs
Structure UploadError
Toutes les erreurs de téléversement sont des instances de UploadError (qui étend 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)
}
L’annulation d’un téléversement initiée par l’utilisateur n’est pas une UploadError. Il s’agit d’une DOMException standard (name === 'AbortError').
Codes d’erreur
Format du code d’erreur : UPLOAD.{layer}.{type}
| Code d’erreur | Description | Correction suggérée |
| UPLOAD.AUTH.GET_AUTH_FAILED | Le rappel getAuth a levé une erreur ou renvoyé une structure invalide. | Vérifiez si le rappel getAuth renvoie correctement un JSON contenant les champs UploadAuth et UploadAddress. Assurez-vous que le service backend est disponible et que le format de la réponse est correct. |
| UPLOAD.OSS.ACCESS_DENIED | Erreur d’autorisation OSS (403). | Vérifiez si les identifiants de téléversement (jeton STS) sont valides et n’ont pas expiré, et si la stratégie RAM accorde les autorisations d’écriture OSS. |
| UPLOAD.OSS.NO_SUCH_BUCKET | Le bucket n’existe pas. | Vérifiez si le nom du bucket dans l’adresse de téléversement est correct et assurez-vous que le bucket a bien été créé dans la région correspondante. |
| UPLOAD.OSS.NO_SUCH_UPLOAD | La session de téléversement en plusieurs parties a expiré. | La session de téléversement en plusieurs parties a expiré (éventuellement après plus de 24 heures). Le SDK retéléverse automatiquement le fichier. Aucune action manuelle n’est requise. |
| UPLOAD.OSS.UNKNOWN | Erreur OSS inconnue. | Consultez la console du navigateur pour obtenir des détails sur l’erreur ou contactez le support technique. |
| UPLOAD.NETWORK.TIMEOUT | La requête a expiré. | Ouvrez le panneau Network dans les outils de développement du navigateur pour afficher les détails de la requête ayant échoué. Vérifiez si la connexion réseau est stable ou essayez d’augmenter la valeur du délai d’expiration. |
| UPLOAD.NETWORK.ERROR | Erreur de connexion réseau. | Ouvrez le panneau Network dans les outils de développement du navigateur pour afficher le code d’état et la réponse de la requête ayant échoué. Assurez-vous que le navigateur peut accéder à l’adresse du service OSS. Vérifiez si un proxy ou un pare-feu bloque la requête. |
| UPLOAD.NETWORK.OFFLINE | Le navigateur est hors ligne. | Vérifiez l’état du réseau et retentez le téléversement après reconnexion. |
| UPLOAD.FILE.EMPTY | La taille du fichier est de 0. | La taille du fichier est de 0. Les fichiers vides ne peuvent pas être téléversés. Vérifiez si le fichier sélectionné est correct. |
| UPLOAD.INTERNAL.DISPOSED | L’instance Uploader a été libérée. | Appelez de nouveau createUploader() pour créer une nouvelle instance. |
Utilisation des constantes de code d’erreur
(Il est recommandé) d’utiliser les constantes ErrorCode plutôt que des littéraux de chaîne :
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}`);
}
}
}
Dépannage
Chaque UploadError contient un uploadTaskId, qui constitue un ID de trace global pour l’ensemble du téléversement. Vous pouvez fournir cet ID au support technique Alibaba Cloud pour identifier rapidement le problème :
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);
}
}
Le champ UploadResult.uploadTaskId peut également être utilisé pour corréler les journaux après un téléversement réussi :
const result = await uploader.upload(file);
myLogger.info('Upload successful', { videoId: result.videoId, uploadTaskId: result.uploadTaskId });