azure-storage-blob-ts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

@azure/storage-blob (TypeScript/JavaScript)

@azure/storage-blob (TypeScript/JavaScript)

SDK for Azure Blob Storage operations — upload, download, list, and manage blobs and containers.
用于Azure Blob存储操作的SDK —— 上传、下载、列出及管理Blob和容器。

Installation

安装

bash
npm install @azure/storage-blob @azure/identity
Current Version: 12.x
Node.js: >= 18.0.0
bash
npm install @azure/storage-blob @azure/identity
当前版本:12.x
Node.js:>= 18.0.0

Environment Variables

环境变量

bash
AZURE_STORAGE_ACCOUNT_NAME=<account-name>
AZURE_STORAGE_ACCOUNT_KEY=<account-key>
bash
AZURE_STORAGE_ACCOUNT_NAME=<账户名称>
AZURE_STORAGE_ACCOUNT_KEY=<账户密钥>

OR connection string

或使用连接字符串

AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...
undefined
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...
undefined

Authentication

身份验证

DefaultAzureCredential (Recommended)

DefaultAzureCredential(推荐)

typescript
import { BlobServiceClient } from "@azure/storage-blob";
import { DefaultAzureCredential } from "@azure/identity";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  new DefaultAzureCredential()
);
typescript
import { BlobServiceClient } from "@azure/storage-blob";
import { DefaultAzureCredential } from "@azure/identity";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  new DefaultAzureCredential()
);

Connection String

连接字符串

typescript
import { BlobServiceClient } from "@azure/storage-blob";

const client = BlobServiceClient.fromConnectionString(
  process.env.AZURE_STORAGE_CONNECTION_STRING!
);
typescript
import { BlobServiceClient } from "@azure/storage-blob";

const client = BlobServiceClient.fromConnectionString(
  process.env.AZURE_STORAGE_CONNECTION_STRING!
);

StorageSharedKeyCredential (Node.js only)

StorageSharedKeyCredential(仅Node.js)

typescript
import { BlobServiceClient, StorageSharedKeyCredential } from "@azure/storage-blob";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY!;

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  sharedKeyCredential
);
typescript
import { BlobServiceClient, StorageSharedKeyCredential } from "@azure/storage-blob";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY!;

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  sharedKeyCredential
);

SAS Token

SAS令牌

typescript
import { BlobServiceClient } from "@azure/storage-blob";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const sasToken = process.env.AZURE_STORAGE_SAS_TOKEN!; // starts with "?"

const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net${sasToken}`
);
typescript
import { BlobServiceClient } from "@azure/storage-blob";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const sasToken = process.env.AZURE_STORAGE_SAS_TOKEN!; // 以"?"开头

const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net${sasToken}`
);

Client Hierarchy

客户端层级结构

BlobServiceClient (account level)
└── ContainerClient (container level)
    └── BlobClient (blob level)
        ├── BlockBlobClient (block blobs - most common)
        ├── AppendBlobClient (append-only blobs)
        └── PageBlobClient (page blobs - VHDs)
BlobServiceClient(账户级别)
└── ContainerClient(容器级别)
    └── BlobClient(Blob级别)
        ├── BlockBlobClient(块Blob - 最常用)
        ├── AppendBlobClient(追加型Blob)
        └── PageBlobClient(页Blob - 虚拟硬盘)

Container Operations

容器操作

Create Container

创建容器

typescript
const containerClient = client.getContainerClient("my-container");
await containerClient.create();

// Or create if not exists
await containerClient.createIfNotExists();
typescript
const containerClient = client.getContainerClient("my-container");
await containerClient.create();

// 或不存在时创建
await containerClient.createIfNotExists();

List Containers

列出容器

typescript
for await (const container of client.listContainers()) {
  console.log(container.name);
}

// With prefix filter
for await (const container of client.listContainers({ prefix: "logs-" })) {
  console.log(container.name);
}
typescript
for await (const container of client.listContainers()) {
  console.log(container.name);
}

// 带前缀过滤
for await (const container of client.listContainers({ prefix: "logs-" })) {
  console.log(container.name);
}

Delete Container

删除容器

typescript
await containerClient.delete();
// Or delete if exists
await containerClient.deleteIfExists();
typescript
await containerClient.delete();
// 或存在时删除
await containerClient.deleteIfExists();

Blob Operations

Blob操作

Upload Blob (Simple)

上传Blob(简单方式)

typescript
const containerClient = client.getContainerClient("my-container");
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");

// Upload string
await blockBlobClient.upload("Hello, World!", 13);

// Upload Buffer
const buffer = Buffer.from("Hello, World!");
await blockBlobClient.upload(buffer, buffer.length);
typescript
const containerClient = client.getContainerClient("my-container");
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");

// 上传字符串
await blockBlobClient.upload("Hello, World!", 13);

// 上传Buffer
const buffer = Buffer.from("Hello, World!");
await blockBlobClient.upload(buffer, buffer.length);

Upload from File (Node.js only)

从文件上传(仅Node.js)

typescript
const blockBlobClient = containerClient.getBlockBlobClient("uploaded-file.txt");
await blockBlobClient.uploadFile("/path/to/local/file.txt");
typescript
const blockBlobClient = containerClient.getBlockBlobClient("uploaded-file.txt");
await blockBlobClient.uploadFile("/path/to/local/file.txt");

Upload from Stream (Node.js only)

从流上传(仅Node.js)

typescript
import * as fs from "fs";

const blockBlobClient = containerClient.getBlockBlobClient("streamed-file.txt");
const readStream = fs.createReadStream("/path/to/local/file.txt");

await blockBlobClient.uploadStream(readStream, 4 * 1024 * 1024, 5, {
  // bufferSize: 4MB, maxConcurrency: 5
  onProgress: (progress) => console.log(`Uploaded ${progress.loadedBytes} bytes`),
});
typescript
import * as fs from "fs";

const blockBlobClient = containerClient.getBlockBlobClient("streamed-file.txt");
const readStream = fs.createReadStream("/path/to/local/file.txt");

await blockBlobClient.uploadStream(readStream, 4 * 1024 * 1024, 5, {
  // bufferSize: 4MB, maxConcurrency: 5
  onProgress: (progress) => console.log(`已上传 ${progress.loadedBytes} 字节`),
});

Upload from Browser

浏览器端上传

typescript
const blockBlobClient = containerClient.getBlockBlobClient("browser-upload.txt");

// From File input
const fileInput = document.getElementById("fileInput") as HTMLInputElement;
const file = fileInput.files![0];
await blockBlobClient.uploadData(file);

// From Blob/ArrayBuffer
const arrayBuffer = new ArrayBuffer(1024);
await blockBlobClient.uploadData(arrayBuffer);
typescript
const blockBlobClient = containerClient.getBlockBlobClient("browser-upload.txt");

// 从文件输入框
const fileInput = document.getElementById("fileInput") as HTMLInputElement;
const file = fileInput.files![0];
await blockBlobClient.uploadData(file);

// 从Blob/ArrayBuffer
const arrayBuffer = new ArrayBuffer(1024);
await blockBlobClient.uploadData(arrayBuffer);

Download Blob

下载Blob

typescript
const blobClient = containerClient.getBlobClient("my-file.txt");
const downloadResponse = await blobClient.download();

// Read as string (browser & Node.js)
const downloaded = await streamToText(downloadResponse.readableStreamBody!);

async function streamToText(readable: NodeJS.ReadableStream): Promise<string> {
  const chunks: Buffer[] = [];
  for await (const chunk of readable) {
    chunks.push(Buffer.from(chunk));
  }
  return Buffer.concat(chunks).toString("utf-8");
}
typescript
const blobClient = containerClient.getBlobClient("my-file.txt");
const downloadResponse = await blobClient.download();

// 读取为字符串(浏览器 & Node.js)
const downloaded = await streamToText(downloadResponse.readableStreamBody!);

async function streamToText(readable: NodeJS.ReadableStream): Promise<string> {
  const chunks: Buffer[] = [];
  for await (const chunk of readable) {
    chunks.push(Buffer.from(chunk));
  }
  return Buffer.concat(chunks).toString("utf-8");
}

Download to File (Node.js only)

下载到文件(仅Node.js)

typescript
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
await blockBlobClient.downloadToFile("/path/to/local/destination.txt");
typescript
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
await blockBlobClient.downloadToFile("/path/to/local/destination.txt");

Download to Buffer (Node.js only)

下载到Buffer(仅Node.js)

typescript
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
const buffer = await blockBlobClient.downloadToBuffer();
console.log(buffer.toString());
typescript
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
const buffer = await blockBlobClient.downloadToBuffer();
console.log(buffer.toString());

List Blobs

列出Blob

typescript
// List all blobs
for await (const blob of containerClient.listBlobsFlat()) {
  console.log(blob.name, blob.properties.contentLength);
}

// List with prefix
for await (const blob of containerClient.listBlobsFlat({ prefix: "logs/" })) {
  console.log(blob.name);
}

// List by hierarchy (virtual directories)
for await (const item of containerClient.listBlobsByHierarchy("/")) {
  if (item.kind === "prefix") {
    console.log(`Directory: ${item.name}`);
  } else {
    console.log(`Blob: ${item.name}`);
  }
}
typescript
// 列出所有Blob
for await (const blob of containerClient.listBlobsFlat()) {
  console.log(blob.name, blob.properties.contentLength);
}

// 带前缀过滤
for await (const blob of containerClient.listBlobsFlat({ prefix: "logs/" })) {
  console.log(blob.name);
}

// 按层级列出(虚拟目录)
for await (const item of containerClient.listBlobsByHierarchy("/")) {
  if (item.kind === "prefix") {
    console.log(`目录: ${item.name}`);
  } else {
    console.log(`Blob: ${item.name}`);
  }
}

Delete Blob

删除Blob

typescript
const blobClient = containerClient.getBlobClient("my-file.txt");
await blobClient.delete();

// Delete if exists
await blobClient.deleteIfExists();

// Delete with snapshots
await blobClient.delete({ deleteSnapshots: "include" });
typescript
const blobClient = containerClient.getBlobClient("my-file.txt");
await blobClient.delete();

// 存在时删除
await blobClient.deleteIfExists();

// 删除包含快照
await blobClient.delete({ deleteSnapshots: "include" });

Copy Blob

复制Blob

typescript
const sourceBlobClient = containerClient.getBlobClient("source.txt");
const destBlobClient = containerClient.getBlobClient("destination.txt");

// Start copy operation
const copyPoller = await destBlobClient.beginCopyFromURL(sourceBlobClient.url);
await copyPoller.pollUntilDone();
typescript
const sourceBlobClient = containerClient.getBlobClient("source.txt");
const destBlobClient = containerClient.getBlobClient("destination.txt");

// 启动复制操作
const copyPoller = await destBlobClient.beginCopyFromURL(sourceBlobClient.url);
await copyPoller.pollUntilDone();

Blob Properties & Metadata

Blob属性与元数据

Get Properties

获取属性

typescript
const blobClient = containerClient.getBlobClient("my-file.txt");
const properties = await blobClient.getProperties();

console.log("Content-Type:", properties.contentType);
console.log("Content-Length:", properties.contentLength);
console.log("Last Modified:", properties.lastModified);
console.log("ETag:", properties.etag);
typescript
const blobClient = containerClient.getBlobClient("my-file.txt");
const properties = await blobClient.getProperties();

console.log("内容类型:", properties.contentType);
console.log("内容长度:", properties.contentLength);
console.log("最后修改时间:", properties.lastModified);
console.log("ETag:", properties.etag);

Set Metadata

设置元数据

typescript
await blobClient.setMetadata({
  author: "John Doe",
  category: "documents",
});
typescript
await blobClient.setMetadata({
  author: "John Doe",
  category: "documents",
});

Set HTTP Headers

设置HTTP头

typescript
await blobClient.setHTTPHeaders({
  blobContentType: "text/plain",
  blobCacheControl: "max-age=3600",
  blobContentDisposition: "attachment; filename=download.txt",
});
typescript
await blobClient.setHTTPHeaders({
  blobContentType: "text/plain",
  blobCacheControl: "max-age=3600",
  blobContentDisposition: "attachment; filename=download.txt",
});

SAS Token Generation (Node.js only)

SAS令牌生成(仅Node.js)

Generate Blob SAS

生成Blob SAS

typescript
import {
  BlobSASPermissions,
  generateBlobSASQueryParameters,
  StorageSharedKeyCredential,
} from "@azure/storage-blob";

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "my-file.txt",
    permissions: BlobSASPermissions.parse("r"), // read only
    startsOn: new Date(),
    expiresOn: new Date(Date.now() + 3600 * 1000), // 1 hour
  },
  sharedKeyCredential
).toString();

const sasUrl = `https://${accountName}.blob.core.windows.net/my-container/my-file.txt?${sasToken}`;
typescript
import {
  BlobSASPermissions,
  generateBlobSASQueryParameters,
  StorageSharedKeyCredential,
} from "@azure/storage-blob";

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "my-file.txt",
    permissions: BlobSASPermissions.parse("r"), // 仅读取
    startsOn: new Date(),
    expiresOn: new Date(Date.now() + 3600 * 1000), // 1小时
  },
  sharedKeyCredential
).toString();

const sasUrl = `https://${accountName}.blob.core.windows.net/my-container/my-file.txt?${sasToken}`;

Generate Container SAS

生成容器SAS

typescript
import { ContainerSASPermissions, generateBlobSASQueryParameters } from "@azure/storage-blob";

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    permissions: ContainerSASPermissions.parse("racwdl"), // read, add, create, write, delete, list
    expiresOn: new Date(Date.now() + 24 * 3600 * 1000), // 24 hours
  },
  sharedKeyCredential
).toString();
typescript
import { ContainerSASPermissions, generateBlobSASQueryParameters } from "@azure/storage-blob";

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    permissions: ContainerSASPermissions.parse("racwdl"), // 读取、添加、创建、写入、删除、列出
    expiresOn: new Date(Date.now() + 24 * 3600 * 1000), // 24小时
  },
  sharedKeyCredential
).toString();

Generate Account SAS

生成账户SAS

typescript
import {
  AccountSASPermissions,
  AccountSASResourceTypes,
  AccountSASServices,
  generateAccountSASQueryParameters,
} from "@azure/storage-blob";

const sasToken = generateAccountSASQueryParameters(
  {
    services: AccountSASServices.parse("b").toString(), // blob
    resourceTypes: AccountSASResourceTypes.parse("sco").toString(), // service, container, object
    permissions: AccountSASPermissions.parse("rwdlacupi"), // all permissions
    expiresOn: new Date(Date.now() + 24 * 3600 * 1000),
  },
  sharedKeyCredential
).toString();
typescript
import {
  AccountSASPermissions,
  AccountSASResourceTypes,
  AccountSASServices,
  generateAccountSASQueryParameters,
} from "@azure/storage-blob";

const sasToken = generateAccountSASQueryParameters(
  {
    services: AccountSASServices.parse("b").toString(), // Blob
    resourceTypes: AccountSASResourceTypes.parse("sco").toString(), // 服务、容器、对象
    permissions: AccountSASPermissions.parse("rwdlacupi"), // 所有权限
    expiresOn: new Date(Date.now() + 24 * 3600 * 1000),
  },
  sharedKeyCredential
).toString();

Blob Types

Blob类型

Block Blob (Default)

块Blob(默认)

Most common type for text and binary files.
typescript
const blockBlobClient = containerClient.getBlockBlobClient("document.pdf");
await blockBlobClient.uploadFile("/path/to/document.pdf");
最常用于文本和二进制文件。
typescript
const blockBlobClient = containerClient.getBlockBlobClient("document.pdf");
await blockBlobClient.uploadFile("/path/to/document.pdf");

Append Blob

追加Blob

Optimized for append operations (logs, audit trails).
typescript
const appendBlobClient = containerClient.getAppendBlobClient("app.log");

// Create the append blob
await appendBlobClient.create();

// Append data
await appendBlobClient.appendBlock("Log entry 1\n", 12);
await appendBlobClient.appendBlock("Log entry 2\n", 12);
针对追加操作优化(日志、审计追踪)。
typescript
const appendBlobClient = containerClient.getAppendBlobClient("app.log");

// 创建追加Blob
await appendBlobClient.create();

// 追加数据
await appendBlobClient.appendBlock("Log entry 1\n", 12);
await appendBlobClient.appendBlock("Log entry 2\n", 12);

Page Blob

页Blob

Fixed-size blobs for random read/write (VHDs).
typescript
const pageBlobClient = containerClient.getPageBlobClient("disk.vhd");

// Create 512-byte aligned page blob
await pageBlobClient.create(1024 * 1024); // 1MB

// Write pages (must be 512-byte aligned)
const buffer = Buffer.alloc(512);
await pageBlobClient.uploadPages(buffer, 0, 512);
固定大小的Blob,用于随机读写(虚拟硬盘)。
typescript
const pageBlobClient = containerClient.getPageBlobClient("disk.vhd");

// 创建512字节对齐的页Blob
await pageBlobClient.create(1024 * 1024); // 1MB

// 写入页(必须512字节对齐)
const buffer = Buffer.alloc(512);
await pageBlobClient.uploadPages(buffer, 0, 512);

Error Handling

错误处理

typescript
import { RestError } from "@azure/storage-blob";

try {
  await containerClient.create();
} catch (error) {
  if (error instanceof RestError) {
    switch (error.statusCode) {
      case 404:
        console.log("Container not found");
        break;
      case 409:
        console.log("Container already exists");
        break;
      case 403:
        console.log("Access denied");
        break;
      default:
        console.error(`Storage error ${error.statusCode}: ${error.message}`);
    }
  }
  throw error;
}
typescript
import { RestError } from "@azure/storage-blob";

try {
  await containerClient.create();
} catch (error) {
  if (error instanceof RestError) {
    switch (error.statusCode) {
      case 404:
        console.log("容器不存在");
        break;
      case 409:
        console.log("容器已存在");
        break;
      case 403:
        console.log("访问被拒绝");
        break;
      default:
        console.error(`存储错误 ${error.statusCode}: ${error.message}`);
    }
  }
  throw error;
}

TypeScript Types Reference

TypeScript类型参考

typescript
import {
  // Clients
  BlobServiceClient,
  ContainerClient,
  BlobClient,
  BlockBlobClient,
  AppendBlobClient,
  PageBlobClient,

  // Authentication
  StorageSharedKeyCredential,
  AnonymousCredential,

  // SAS
  BlobSASPermissions,
  ContainerSASPermissions,
  AccountSASPermissions,
  AccountSASServices,
  AccountSASResourceTypes,
  generateBlobSASQueryParameters,
  generateAccountSASQueryParameters,

  // Options & Responses
  BlobDownloadResponseParsed,
  BlobUploadCommonResponse,
  ContainerCreateResponse,
  BlobItem,
  ContainerItem,

  // Errors
  RestError,
} from "@azure/storage-blob";
typescript
import {
  // 客户端
  BlobServiceClient,
  ContainerClient,
  BlobClient,
  BlockBlobClient,
  AppendBlobClient,
  PageBlobClient,

  身份验证
  StorageSharedKeyCredential,
  AnonymousCredential,

  // SAS
  BlobSASPermissions,
  ContainerSASPermissions,
  AccountSASPermissions,
  AccountSASServices,
  AccountSASResourceTypes,
  generateBlobSASQueryParameters,
  generateAccountSASQueryParameters,

  // 选项与响应
  BlobDownloadResponseParsed,
  BlobUploadCommonResponse,
  ContainerCreateResponse,
  BlobItem,
  ContainerItem,

  // 错误
  RestError,
} from "@azure/storage-blob";

Best Practices

最佳实践

  1. Use DefaultAzureCredential — Prefer AAD over connection strings/keys
  2. Use streaming for large files
    uploadStream
    /
    downloadToFile
    for files > 256MB
  3. Set appropriate content types — Use
    setHTTPHeaders
    for correct MIME types
  4. Use SAS tokens for client access — Generate short-lived tokens for browser uploads
  5. Handle errors gracefully — Check
    RestError.statusCode
    for specific handling
  6. Use
    *IfNotExists
    methods
    — For idempotent container/blob creation
  7. Close clients — Not required but good practice in long-running apps
  1. 使用DefaultAzureCredential —— 优先选择AAD而非连接字符串/密钥
  2. 大文件使用流式传输 —— 对于大于256MB的文件,使用
    uploadStream
    /
    downloadToFile
  3. 设置合适的内容类型 —— 使用
    setHTTPHeaders
    设置正确的MIME类型
  4. 客户端访问使用SAS令牌 —— 为浏览器上传生成短期令牌
  5. 优雅处理错误 —— 检查
    RestError.statusCode
    进行针对性处理
  6. 使用
    *IfNotExists
    方法
    —— 实现幂等的容器/blob创建
  7. 关闭客户端 —— 非强制要求,但在长期运行的应用中是良好实践

Platform Differences

平台差异

FeatureNode.jsBrowser
StorageSharedKeyCredential
uploadFile()
uploadStream()
downloadToFile()
downloadToBuffer()
uploadData()
SAS generation
DefaultAzureCredential
Anonymous/SAS access
功能Node.js浏览器
StorageSharedKeyCredential
uploadFile()
uploadStream()
downloadToFile()
downloadToBuffer()
uploadData()
SAS生成
DefaultAzureCredential
匿名/SAS访问