如何在Node.js的@azure/storage-blob中自动刷新Azure Blob SAS令牌
问题根因
你遇到的认证报错本质是@azure/storage-blob对TokenCredential接口的使用逻辑和EventHub SDK存在差异:
- EventHub SDK的
TokenCredential实现返回的SAS令牌会被组装为SharedAccessSignature <token>格式放入Authorization请求头,完全符合EventHub的SAS认证规范 - 存储Blob SDK的
TokenCredential默认仅支持Azure AD颁发的OAuth2令牌,会把返回的令牌组装为Bearer <token>格式放入请求头,和Blob服务的SAS认证逻辑不兼容,所以直接传入SAS生成的TokenCredential会报认证失败。
推荐解决方案(支持所有操作中途自动刷新)
方案1:升级SDK版本(最易用,推荐)
你当前使用的12.6.0版本没有原生支持SAS动态刷新能力,先升级到@azure/storage-blob@12.10.0及以上版本,该版本新增了AzureSasCredential类,支持运行时动态更新SAS令牌,SDK内部所有操作(包括大文件分块上传的每一个分块请求)都会自动读取最新的SAS。
示例实现代码如下:
const { BlobServiceClient, AzureSasCredential } = require("@azure/storage-blob"); // 你的SAS生成函数,返回格式为{ sasToken: string, expiresOn: number },expiresOn为毫秒级过期时间戳 async function fetchNewSas() { // 调用你自己的SAS生成服务接口 const res = await yourSasGeneratorService.getSas(); return { sasToken: res.sas.replace(/^\?/, ''), // 统一去掉SAS前缀的?号,避免拼接错误 expiresOn: res.expireTimestamp }; } // 初始化凭证 let currentSas = await fetchNewSas(); const sasCredential = new AzureSasCredential(currentSas.sasToken); // 启动定时刷新任务,提前30秒刷新避免网络波动导致过期 const REFRESH_BUFFER = 30 * 1000; setInterval(async () => { if (Date.now() >= currentSas.expiresOn - REFRESH_BUFFER) { currentSas = await fetchNewSas(); sasCredential.update(currentSas.sasToken); } }, 10 * 1000); // 每10秒检查一次,可按需调整间隔 // 初始化BlobServiceClient const blobServiceClient = new BlobServiceClient( "https://<你的存储账户名>.blob.core.windows.net", sasCredential );
方案2:兼容12.6.0版本的自定义实现
如果无法升级SDK版本,可以通过自定义请求管道策略,在每个请求发出前自动替换最新的SAS令牌:
const { BlobServiceClient, AnonymousCredential, newPipeline } = require("@azure/storage-blob"); // 同上实现SAS获取和定时刷新逻辑,维护latestSasToken变量存储最新SAS let latestSasToken = await fetchNewSas().then(r => r.sasToken.replace(/^\?/, '')); // 定时刷新逻辑同上 // 自定义SAS注入策略 const sasInjectionPolicy = { create: (nextPolicy, options) => { return { sendRequest: async (request) => { // 将最新SAS拼接到请求URL的查询参数中 const url = new URL(request.url); const sasParams = new URLSearchParams(latestSasToken); sasParams.forEach((value, key) => { url.searchParams.set(key, value); }); request.url = url.toString(); return nextPolicy.sendRequest(request); } }; } }; // 构建自定义管道 const pipeline = newPipeline(new AnonymousCredential(), { retryOptions: { maxTries: 4 } }); // 将自定义策略添加到管道最前位 pipeline.factories.unshift(sasInjectionPolicy); // 用自定义管道初始化BlobServiceClient const blobServiceClient = new BlobServiceClient( "https://<你的存储账户名>.blob.core.windows.net", pipeline );
注意事项
- SAS刷新缓冲时间建议留够至少30秒,避免网络延迟导致刷新不及时
- 大文件上传时SDK默认会自动分块,每一个分块都是独立请求,两种方案都会自动给每个分块请求附加最新的SAS,不会出现中途上传失败的问题
内容的提问来源于stack exchange,提问作者Ruslan Beselovskyi
相关产品推荐
相关产品推荐

