Azure Blob Storage上传大Blob时如何延长SAS token有效期且不丢失上传进度
可行方案(最低复杂度,无需修改后端逻辑,不丢失上传进度)
核心思路
利用@azure/storage-blob V12 SDK 内置的动态凭证能力,传入可自动刷新有效SAS的自定义凭证,SDK会自动处理上传过程中的凭证刷新,已上传成功的分块不会因为SAS过期失效。
Azure Blob存储的分块上传逻辑中,未提交的分块会和目标Blob绑定、保留7天,仅和存储账户的资源关联,和之前用来上传分块的SAS有效期无关,只要新的SAS对目标Blob有写入权限,就可以直接续传剩余分块,不会丢失已上传进度。
具体实现步骤
- 前端实现SAS缓存与刷新逻辑,避免频繁请求后端接口
// 全局缓存当前使用的SAS和对应的过期时间 let cachedSas = null; let sasExpireTimestamp = 0; async function getValidSas(blobName) { const now = Date.now(); // 提前30秒刷新SAS,避免临界时间节点请求失败 if (cachedSas && now < sasExpireTimestamp - 30 * 1000) { return cachedSas; } // 调用现有后端接口获取指定Blob的SAS,不需要修改原有后端逻辑 const resp = await fetch(`/api/get-blob-sas?blobName=${encodeURIComponent(blobName)}`); const { sasToken, expiresOn } = await resp.json(); cachedSas = sasToken; sasExpireTimestamp = new Date(expiresOn).getTime(); return cachedSas; }
- 实现符合SDK规范的动态SAS凭证类
class DynamicSasCredential { constructor(blobName) { this.blobName = blobName; } // 实现SDK要求的getToken方法,每次请求前SDK会自动调用该方法获取有效凭证 async getToken() { const validSas = await getValidSas(this.blobName); // 处理SAS前缀,返回符合SDK要求的格式 const formatSas = validSas.startsWith('?') ? validSas.slice(1) : validSas; return { token: formatSas, expiresOnTimestamp: sasExpireTimestamp }; } }
- 构造BlockBlobClient执行上传,原有上传逻辑无需修改
import { BlockBlobClient, newPipeline } from '@azure/storage-blob'; async function uploadLargeFile(blobName, file) { // 用自定义动态凭证构造请求管道 const uploadPipeline = newPipeline(new DynamicSasCredential(blobName), { // 可保留你原有配置,比如重试策略、超时时间等 retryOptions: { maxTries: 4 } }); // 注意这里用不带SAS的原始Blob地址 const blobBaseUrl = `https://${你的存储账户名}.blob.core.chinacloudapi.cn/${你的容器名}/${encodeURIComponent(blobName)}`; const blockBlobClient = new BlockBlobClient(blobBaseUrl, uploadPipeline); // 完全复用你原有uploadData逻辑即可,不需要调整分块、并发配置 return await blockBlobClient.uploadData(file, { blockSize: 4 * 1024 * 1024, // 你原有分块大小配置 concurrency: 5, // 你原有并发数配置 onProgress: (progress) => console.log(`已上传字节数:${progress.loadedBytes}`) }); }
方案优势
- 改造成本极低:仅需要调整前端BlockBlobClient的初始化逻辑,原有上传逻辑、后端SAS生成接口完全不需要修改
- 自动保留进度:SDK内部会自动跟踪已上传成功的分块,不会重复上传,无需额外开发进度记录逻辑
- 安全性不变:仍然保持原有短有效期SAS的安全策略,不会因为大文件上传刻意延长SAS有效期
可选增强:支持页面刷新后续传
如果需要支持用户刷新页面后仍然能从断点续传,可以在上传前先查询服务端已存在的未提交分块,跳过已上传的部分:
// 上传前先获取当前Blob已上传的未提交分块列表 const blockList = await blockBlobClient.getBlockList('uncommitted'); const uploadedBlockIds = new Set(blockList.uncommittedBlocks.map(block => block.name)); // 拆分文件生成块ID时,跳过已存在于uploadedBlockIds中的块即可
内容的提问来源于stack exchange,提问作者Farid Hajnal
相关产品推荐
相关产品推荐

