Exporter efficacement des fichiers vers Microsoft Azure avec cURL
Pour exporter un fichier vers Azure Blob Storage avec cURL, envoyez une requête
PUT authentifiée avec x-ms-blob-type: BlockBlob.
L’exemple ci-dessous signe cette requête avec une clé de compte de stockage existante,
refuse de remplacer un blob existant et télécharge le résultat pour comparer ses octets
à ceux du fichier local.
Vérifier les prérequis
Utilisez un shell Linux avec Node.js et cURL installés. Cet exemple a été testé avec Node.js 26.12.0 et cURL 8.23.0 ; utilisez ces versions pour le reproduire dans les mêmes conditions. Node exécute le programme auxiliaire TypeScript sans compilateur ni installation de paquet. La page de téléchargement de Node.js et les versions de cURL fournissent ces outils.
Vérifiez les deux exécutables avant d’enregistrer le programme :
node --version && curl --version
Vous avez également besoin des éléments suivants :
- Un compte de stockage existant et un conteneur privé accessibles via le point de terminaison
public Azure
https://ACCOUNT.blob.core.windows.net. Pour un nouveau projet, utilisez un compte à usage général v2 pris en charge. La création du compte et du conteneur sort du cadre de ce guide. - L’autorisation d’utiliser Shared Key sur ce compte, ainsi que sa clé de compte en Base64, fournie selon le processus de gestion des secrets de votre organisation. Conservez-la dans un fichier protégé que vous seul pouvez lire. Le programme lit ce fichier via l’entrée standard ; gardez-le hors de votre projet et de votre système de gestion de versions.
- Un fichier ordinaire local d’une taille comprise entre zéro et 8 MiB. Ne le modifiez pas avant la fin de la vérification. Cet exemple pour petits fichiers met en mémoire tampon les octets du fichier d’entrée et ceux téléchargés.
Utilisez des caractères ASCII imprimables dans le chemin local complet. Pour le nom du blob distant, utilisez des segments séparés par des barres obliques, contenant des lettres, des chiffres, des points, des traits de soulignement et des traits d’union. Chaque segment doit commencer par une lettre, un chiffre, un trait de soulignement ou un trait d’union. Le programme auxiliaire rejette délibérément les autres noms plutôt que de tenter de deviner l’échappement d’URL. Un fichier vide est valide.
Signer la requête
Shared Key utilise une signature HMAC-SHA256 calculée à partir de la méthode HTTP, de certains
en-têtes de requête et du chemin de la ressource. La clé de compte est décodée depuis Base64 avant
la signature. L’ordre des en-têtes compte, et un téléversement de zéro octet utilise un champ
content-length vide dans la signature, même si son en-tête HTTP Content-Length
vaut 0. Ces détails suivent la
spécification Shared Key de Microsoft.
Une clé de compte accorde un accès étendu. Microsoft recommande Microsoft Entra ID avec des identités managées lorsque c’est possible ; cette procédure s’adresse spécifiquement à un environnement déjà autorisé à utiliser Shared Key. Un jeton porteur ou un jeton SAS ne peut pas remplacer la clé de compte dans ce programme.
Enregistrez ce programme complet sous le nom azure-upload.mts.
L’extension .mts rend son format de module explicite,
y compris au sein d’un projet CommonJS existant.
import { spawnSync } from 'node:child_process'
import { createHash, createHmac } from 'node:crypto'
import { readFileSync, statSync } from 'node:fs'
import { resolve } from 'node:path'
const maxBytes = 8 * 1024 * 1024
function main(): void {
const [input, account, container, blob, ...extra] = process.argv.slice(2)
if (!input || !account || !container || !blob || extra.length > 0) {
throw new Error('Usage: node azure-upload.mts FILE ACCOUNT CONTAINER BLOB < KEY_FILE')
}
const file = resolve(input)
if (!/^[\x20-\x7e]+$/.test(file)) throw new Error('Use a printable ASCII local path.')
if (!/^[a-z0-9]{3,24}$/.test(account)) throw new Error('Invalid account name.')
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(container) || container.length < 3 || container.length > 63) {
throw new Error('Invalid container name.')
}
if (blob.length > 1024 || !blob.split('/').every((part) => /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(part))) {
throw new Error('Use simple slash-separated blob-name segments.')
}
const info = statSync(file)
if (!info.isFile() || info.size > maxBytes) throw new Error('Use a regular file of at most 8 MiB.')
const original = readFileSync(file)
if (original.length > maxBytes) throw new Error('The input grew beyond 8 MiB.')
const encodedKey = readFileSync(0, 'utf8').trim()
if (!/^[A-Za-z0-9+/]{86}==$/.test(encodedKey)) throw new Error('Expected a Base64 512-bit account key.')
const key = Buffer.from(encodedKey, 'base64')
const url = `https://${account}.blob.core.windows.net/${container}/${blob}`
function request(method: 'PUT' | 'GET'): Buffer {
const uploading = method === 'PUT'
const length = uploading ? original.length : 0
const contentType = uploading ? 'application/octet-stream' : ''
const azureHeaders = [
...(uploading ? ['x-ms-blob-type:BlockBlob'] : []),
`x-ms-date:${new Date().toUTCString()}`,
'x-ms-version:2023-11-03',
]
const fields = [method, '', '', length === 0 ? '' : String(length), '', contentType,
'', '', '', uploading ? '*' : '', '', '']
const stringToSign = `${fields.join('\n')}\n${azureHeaders.join('\n')}\n/${account}/${container}/${blob}`
const signature = createHmac('sha256', key).update(stringToSign).digest('base64')
const headers = [
...azureHeaders,
`Authorization: SharedKey ${account}:${signature}`,
...(uploading ? [`Content-Length: ${length}`, `Content-Type: ${contentType}`, 'If-None-Match: *'] : []),
]
const result = spawnSync('curl', [
'--disable', '--globoff', '--silent', '--show-error', '--fail', '--proto', '=https',
'--request', method, '--header', '@-',
'--write-out', '%{stderr}HTTP:%{http_code}',
...(uploading ? ['--upload-file', file] : []),
'--output', uploading ? '/dev/null' : '-', url,
], { input: `${headers.join('\n')}\n`, maxBuffer: maxBytes + 65536 })
const status = /HTTP:(\d{3})$/.exec(result.stderr?.toString() ?? '')?.[1] ?? 'unknown'
if (result.status !== 0 || status !== (uploading ? '201' : '200')) {
console.error(`${method} failed: HTTP ${status}; cURL exit ${result.status ?? 'unknown'}.`)
throw new Error('Request failed.')
}
return result.stdout
}
request('PUT')
const downloaded = request('GET')
if (!original.equals(downloaded)) throw new Error('Downloaded bytes differ from the input.')
const sha256 = createHash('sha256').update(original).digest('hex')
console.log(`Verified ${original.length} bytes; SHA-256 ${sha256}`)
}
try {
main()
} catch {
console.error('Export failed. Check the input, account key, destination, and connection.')
process.exitCode = 1
}
Le programme auxiliaire transmet l’en-tête d’autorisation à cURL via l’entrée standard avec
--header @-, ce qui évite d’exposer la clé et la signature dans les arguments
de la commande. Il désactive aussi le chargement de .curlrc pour qu’une
configuration cURL enregistrée ne puisse ni ajouter de nouvelles tentatives ni modifier le traitement
de la sortie. Évitez le traçage du shell et les options de traçage ou de sortie détaillée de cURL
lorsque vous manipulez des informations d’authentification. Consultez le
manuel de cURL pour ces options.
Téléverser et vérifier les octets
Remplacez ci-dessous le compte, le conteneur, le nom du blob de destination et le chemin du fichier
contenant la clé. Le conteneur doit déjà exister ; choisissez une destination qui n’existe pas.
Exécutez cette commande depuis le répertoire contenant azure-upload.mts
et votre fichier d’entrée :
node azure-upload.mts ./localfile.bin youraccount yourcontainer exports/localfile.bin < /secure/path/azure-account.key
Une opération Put Blob réussie renvoie le statut HTTP
201. Le programme exige ensuite le statut HTTP
200 lors d’un téléchargement authentifié distinct et compare
l’intégralité de la réponse au fichier d’entrée d’origine. Il affiche
Verified, le nombre d’octets et l’empreinte
SHA-256 uniquement après la réussite des deux vérifications. Un téléversement réussi à lui seul
ne produit pas ce message. Le blob reste dans votre conteneur privé ; ce programme ne le supprime pas.
Gérer un refus ou un résultat incertain
La condition If-None-Match: * limite le téléversement
à la création. Réexécuter la commande avec une destination existante doit échouer et laisser ses
octets intacts. Azure peut signaler 409 avec
BlobAlreadyExists ou un échec de condition 412 ;
ne considérez pas chaque conflit comme un problème d’authentification. Microsoft répertorie les
codes d’erreur de Blob Storage.
Le programme indique uniquement le statut HTTP et le code de sortie de cURL, sans afficher le corps
des réponses d’erreur du fournisseur.
Un statut 403 nécessite une vérification des accès : confirmez que
la clé correspond au compte, que Shared Key est autorisé et que votre réseau peut accéder à ce compte.
Vérifiez le fichier local et le chemin du fichier contenant la clé si le programme échoue avant
d’indiquer un statut HTTP. Aucune nouvelle tentative automatique n’est activée.
Une connexion interrompue peut laisser l’issue de l’écriture incertaine : Azure peut avoir stocké le blob avant la perte de la réponse. L’échec du téléchargement de vérification laisse également le blob téléversé en place. Inspectez cette destination précise avec vos outils habituels d’accès authentifié au stockage et comparez les octets téléchargés avant de choisir de conserver ou de supprimer le blob. Réexécuter cette commande limitée à la création ne permet pas de confirmer le contenu d’un blob existant et ne le remplace pas. Ne supprimez pas une destination existante dans le seul but de faire réussir une nouvelle tentative.
Choisir un autre outil pour les transferts plus volumineux
Le plafond de 8 MiB est propre à cet exemple qui utilise une mise en mémoire tampon ; il ne s’agit
pas de la limite du service Azure. L’exemple utilise une seule requête
Put Blob au lieu de préparer puis de valider des blocs. Pour des fichiers
plus volumineux, des transferts avec reprise ou une automatisation par lots, utilisez un client
de stockage qui gère ces transferts ; cet exemple ne fournit aucune garantie de transfert
multibloc ni de débit. Les bibliothèques clientes Azure Blob
constituent une suite utile lorsque vos besoins dépassent un petit export REST.
