关于 azure-storage-blob-ts
azure-storage-blob-ts 是使用 @azure/storage-blob SDK 通过 TypeScript 或 JavaScript 管理 Azure Blob Storage 的技能。内容涵盖容器和 Blob 操作、身份验证、元数据与 SAS Token,并说明 Node.js 和浏览器的差异。
主要功能
- 01创建、列出和删除容器
- 02上传、下载、复制和删除 Blob
- 03列出 Blob 并读取其属性
- 04设置 Blob 元数据和 HTTP 标头
- 05介绍身份验证和 SAS Token 选项
适用场景
- 01将应用文件上传到 Blob Storage
- 02列出或获取已存储的 Blob
- 03管理容器内容和元数据
- 04提供限时 SAS 访问
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ sickn33/ agentic-awesome-skills --skill azure-storage-blob-ts安装后在 Claude Code 中输入/azure-storage-blob-ts确认已加载。
详细介绍
@azure/storage-blob (TypeScript/JavaScript)
用于 Azure Blob Storage 操作的 SDK——上传、下载、列出和管理 Blob 与容器。
安装
npm install @azure/storage-blob @azure/identity
示例使用 12.x API 系列。请固定兼容的 SDK 版本,并使用软件包 engines 中当前受支持的 Node 运行时;这并不表示使用最新版本。
环境变量
AZURE_STORAGE_ACCOUNT_NAME=<account-name>
AZURE_STORAGE_ACCOUNT_KEY=<account-key>
# OR connection string
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!; // starts with "?"
const client = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net${sasToken}`
);
客户端层级
BlobServiceClient (account level)
└── ContainerClient (container level)
└── BlobClient (blob level)
├── BlockBlobClient (block blobs - most common)
├── AppendBlobClient (append-only blobs)
└── PageBlobClient (page blobs - VHDs)
选择权限最小的身份或 SAS、较短的过期时间,并仅通过 HTTPS 访问;在支持的情况下,优先使用用户委托 SAS。切勿在浏览器包或日志中暴露账户密钥或签名 URL。删除或覆盖前,请确认账户、容器和 Blob 的具体对象。setMetadata/setHTTPHeaders 会替换字段:请保留必需的现有值,并在需要时使用条件 ETag。这些示例是彼此独立的操作,不应不加判断地按顺序执行。
容器操作
创建容器
const containerClient = client.getContainerClient("my-container");
await containerClient.create();
// Or create if not exists
await containerClient.createIfNotExists();
列出容器
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);
}
删除容器
await containerClient.delete();
// Or delete if exists
await containerClient.deleteIfExists();
Blob 操作
上传 Blob(简单方式)
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);
从文件上传(仅限 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(`Uploaded ${progress.loadedBytes} bytes`),
});
从浏览器上传
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);
下载 Blob
const blobClient = containerClient.getBlobClient("my-file.txt");
const downloadResponse = await blobClient.download();
// Read as string (Node.js only; bounded small blobs)
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");
}
在浏览器中,请使用响应的 blobBody Promise,并在大小限制内读取其文本;readableStreamBody 和 Buffer 仅适用于 Node.js。
下载到文件(仅限 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());
列出 Blob
// 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}`);
}
}
删除 Blob
const blobClient = containerClient.getBlobClient("my-file.txt");
await blobClient.delete();
// Delete if exists
await blobClient.deleteIfExists();
// Delete with snapshots
await blobClient.delete({ deleteSnapshots: "include" });
复制 Blob
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();
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);
设置元数据
await blobClient.setMetadata({
author: "John Doe",
category: "documents",
});
设置 HTTP 标头
await blobClient.setHTTPHeaders({
blobContentType: "text/plain",
blobCacheControl: "max-age=3600",
blobContentDisposition: "attachment; filename=download.txt",
});
生成 SAS 令牌(仅限 Node.js)
生成 Blob SAS
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}`;
生成容器 SAS
import { ContainerSASPermissions, generateBlobSASQueryParameters } from "@azure/storage-blob";
const sasToken = generateBlobSASQueryParameters(
{
containerName: "my-container",
permissions: ContainerSASPermissions.parse("rl"), // read/list example; grant writes only when requested
expiresOn: new Date(Date.now() + 24 * 3600 * 1000), // 24 hours
},
sharedKeyCredential
).toString();
生成账户 SAS
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("rl"), // read/list only; avoid account-wide SAS when blob scope suffices
expiresOn: new Date(Date.now() + 24 * 3600 * 1000),
},
sharedKeyCredential
).toString();
Blob 类型
块 Blob(默认)
最常见的文本和二进制文件类型。
const blockBlobClient = containerClient.getBlockBlobClient("document.pdf");
await blockBlobClient.uploadFile("/path/to/document.pdf");
追加 Blob
针对追加操作(日志、审计记录)进行了优化。
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);
页 Blob
用于随机读写的固定大小 Blob(VHD)。
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);
错误处理
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 {
// 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";
最佳实践
- 使用 DefaultAzureCredential — 优先使用 AAD,而不是连接字符串或密钥
- 大文件使用流式处理 — 对于大于 256MB 的文件,使用
uploadStream/downloadToFile - 设置适当的内容类型 — 使用
setHTTPHeaders设置正确的 MIME 类型 - 使用 SAS 令牌供客户端访问 — 为浏览器上传生成短期令牌
- 妥善处理错误 — 检查
RestError.statusCode,以进行相应处理 - 使用
*IfNotExists方法 — 实现幂等的容器或 Blob 创建 - 生命周期 — 仅使用固定客户端实际公开的生命周期方法;不要虚构 close() 调用
平台差异
| 功能 | Node.js | 浏览器 |
|---|---|---|
StorageSharedKeyCredential | ✅ | ❌ |
uploadFile() | ✅ | ❌ |
uploadStream() | ✅ | ❌ |
downloadToFile() | ✅ | ❌ |
downloadToBuffer() | ✅ | ❌ |
uploadData() | ✅ | ✅ |
| SAS 生成 | ✅ | ❌ |
| DefaultAzureCredential | ✅ | ❌ |
| 匿名/SAS 访问 | ✅ | ✅ |
适用场景
当需要执行概述中所述的工作流或操作时,可以使用此技能。
限制
- 仅当任务明确符合上述范围时才使用此技能。
- 请勿将输出视为环境特定验证、测试或专家审查的替代品。
- 如果缺少必要的输入、权限、安全边界或成功标准,请停止并请求澄清。
评论
支持 Markdown