You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 12:54:02