Azure Blob 存储时间戳
@azure/storage-blob (TypeScript/JavaScript)
用于 Azure Blob Storage 操作的 SDK —— 支持上传、下载、列出以及管理 Blob 和容器。
安装
npm install @azure/storage-blob @azure/identity当前版本: 12.x
Node.js: >= 18.0.0
环境变量
AZURE_STORAGE_ACCOUNT_NAME=<account-name>
AZURE_STORAGE_ACCOUNT_KEY=<account-key>
或连接字符串
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...身份验证
DefaultAzureCredential (推荐)
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()
);
连接字符串
import { BlobServiceClient } from "@azure/storage-blob";
const client = BlobServiceClient.fromConnectionString(
process.env.AZURE_STORAGE_CONNECTION_STRING!
);
StorageSharedKeyCredential (仅限 Node.js)
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 令牌
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}
);
客户端层级结构
BlobServiceClient (账户级)
└── ContainerClient (容器级)
└── BlobClient (Blob 级)
├── BlockBlobClient (块 Blob - 最常用)
├── AppendBlobClient (追加 Blob)
└── PageBlobClient (页 Blob - VHDs)容器操作
创建容器
const containerClient = client.getContainerClient("my-container");
await containerClient.create();
// 或在不存在时创建
await containerClient.createIfNotExists();
列出容器
for await (const container of client.listContainers()) {
console.log(container.name);
}
// 使用前缀过滤
for await (const container of client.listContainers({ prefix: "logs-" })) {
console.log(container.name);
}
删除容器
await containerClient.delete();
// 或在存在时删除
await containerClient.deleteIfExists();Blob 操作
上传 Blob (简单上传)
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);
从文件上传 (仅限 Node.js)
const blockBlobClient = containerClient.getBlockBlobClient("uploaded-file.txt");
await blockBlobClient.uploadFile("/path/to/local/file.txt");从流上传 (仅限 Node.js)
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} 字节),
});
从浏览器上传
const blockBlobClient = containerClient.getBlockBlobClient("browser-upload.txt");
// 从 File 输入框上传
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);
下载 Blob
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");
}
下载到文件 (仅限 Node.js)
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
await blockBlobClient.downloadToFile("/path/to/local/destination.txt");下载到 Buffer (仅限 Node.js)
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
const buffer = await blockBlobClient.downloadToBuffer();
console.log(buffer.toString());列出 Blobs
// 列出所有 blobs
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});
}
}
删除 Blob
const blobClient = containerClient.getBlobClient("my-file.txt");
await blobClient.delete();
// 如果存在则删除
await blobClient.deleteIfExists();
// 删除及其快照
await blobClient.delete({ deleteSnapshots: "include" });
复制 Blob
const sourceBlobClient = containerClient.getBlobClient("source.txt");
const destBlobClient = containerClient.getBlobClient("destination.txt");
// 开始复制操作
const copyPoller = await destBlobClient.beginCopyFromURL(sourceBlobClient.url);
await copyPoller.pollUntilDone();
Blob 属性与元数据
获取属性
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);
设置元数据
### 设置 HTTP 标头## SAS 令牌生成 (仅限 Node.js)
生成 Blob SAS
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};
### 生成容器 SASimport { 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();
### 生成账户 SASimport {
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 类型
块 Blob (Block Blob - 默认)
最常用的文本和二进制文件类型。
const blockBlobClient = containerClient.getBlockBlobClient("document.pdf");
await blockBlobClient.uploadFile("/path/to/document.pdf");
### 追加 Blob (Append Blob)
针对追加操作进行了优化(如日志、审计跟踪)。
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);
### 页 Blob (Page Blob)
用于随机读写的固定大小 Blob(如 VHD)。
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);
## 错误处理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 类型参考
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";
最佳实践
1. 使用 DefaultAzureCredential — 优先使用 AAD 而非连接字符串/密钥
2. 大文件使用流式传输 — 文件 > 256MB 时使用 uploadStream/downloadToFilesetHTTPHeaders
3. 设置正确的内容类型 — 使用 设置正确的 MIME 类型RestError.statusCode
4. 客户端访问使用 SAS 令牌 — 为浏览器上传生成短效令牌
5. 优雅地处理错误 — 检查 进行针对性处理*IfNotExists
6. **使用 方法 — 实现容器/Blob 创建的幂等性
7. 关闭客户端** — 虽然非强制,但在长期运行的应用中是良好的习惯
平台差异
| 功能 | Node.js | 浏览器 |
|---------|---------|---------|
| StorageSharedKeyCredential | ✅ | ❌ |uploadFile()
| | ✅ | ❌ |uploadStream()
| | ✅ | ❌ |downloadToFile()
| | ✅ | ❌ |downloadToBuffer()
| | ✅ | ❌ |uploadData()` | ✅ | ✅ |
|
| SAS 生成 | ✅ | ❌ |
| DefaultAzureCredential | ✅ | ❌ |
| 匿名/SAS 访问 | ✅ | ✅ |
适用场景
本技能适用于执行概览中所描述的工作流或操作。局限性
- 仅在任务明确符合上述范围时使用此技能。
- 不要将输出视为环境特定验证、测试或专家评审的替代方案。
- 如果缺失必要输入、权限、安全边界或成功标准,请停止并请求澄清。