如何通过带SAS Token的PUT请求向Azure Blob Storage上传10GB+大文件?
解决Azure Blob Storage大文件(10GB+)SAS URL上传问题
问题根源
你遇到的413错误是因为Azure Blob Storage的单个PUT请求上传Blob的大小限制:对于存储服务版本2016-05-31,单个Blob的直接PUT上传上限是4GB,超过这个大小必须使用**分块上传(Block Blob Upload)**方案,该方案支持最大5TB的Blob上传(每个块最大100MB,最多50000个块)。
解决方案步骤
1. 调整后端SAS Token生成逻辑
确保SAS Token具备分块上传所需权限,并升级存储服务版本以获得更好兼容性:
代码优化(修正原变量错误+适配分块上传)
function generate_signed_url(BLOB_NAME) { const ACCOUNT_NAME = process.env.AZURE_BLOB_STORAGE_ACCOUNT_NAME; const CONTAINER_NAME = process.env.AZURE_BLOB_STORAGE_CONTAINER_NAME; const ACCESS_KEY = process.env.AZURE_BLOB_STORAGE_ACCESS_KEY; const sharedKeyCredential = new StorageSharedKeyCredential(ACCOUNT_NAME, ACCESS_KEY); // 延长SAS有效期,避免大文件上传超时(设置为4小时) const expDate = new Date(new Date().valueOf() + 14400 * 1000); // 升级存储服务版本到2021-06-08,支持更多分块上传特性 const blobSAS = generateBlobSASQueryParameters({ containerName: CONTAINER_NAME, blobName: BLOB_NAME, // 明确包含分块所需权限:read、add、create、write、delete permissions: BlobSASPermissions.parse("racwd"), startsOn: new Date(), expiresOn: expDate, ipRange: { start: "0.0.0.0", end: "255.255.255.255" }, protocol: SASProtocol.Https, // 建议仅用HTTPS提升安全性 version: "2021-06-08" }, sharedKeyCredential).toString(); // 修正原代码变量错误:AZURE_CONTAINER -> CONTAINER_NAME,AZURE_BLOB -> BLOB_NAME,containerSAS -> blobSAS const SaSURL = `https://${ACCOUNT_NAME}.blob.core.windows.net/${CONTAINER_NAME}/${BLOB_NAME}?${blobSAS}`; console.log(`SAS URL for blob is: ${SaSURL}`); return SaSURL; }
2. 前端实现分块上传逻辑
使用Axios实现分块上传,核心步骤为分割文件、上传每个块、提交块列表组装完整Blob:
// 分块上传核心函数,默认100MB每块 async function uploadLargeFileWithSAS(sasUrl, file, chunkSize = 100 * 1024 * 1024) { const chunkCount = Math.ceil(file.size / chunkSize); const blockIds = []; // 逐个上传分块 for (let i = 0; i < chunkCount; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, file.size); const chunk = file.slice(start, end); // 生成Base64编码的唯一块ID,需保证长度一致 const blockId = btoa(`block-${String(i).padStart(6, '0')}`); blockIds.push(blockId); // 构造块上传URL:在原SAS URL基础上添加块操作参数 const [blobBaseUrl, sasQuery] = sasUrl.split('?'); const chunkUploadUrl = `${blobBaseUrl}?comp=block&blockid=${blockId}&${sasQuery}`; await axios({ method: 'PUT', url: chunkUploadUrl, data: chunk, headers: { 'Content-Length': chunk.size } }); } // 提交块列表,组装成完整Blob const blockListBody = `<?xml version="1.0" encoding="utf-8"?> <BlockList> ${blockIds.map(id => `<Latest>${id}</Latest>`).join('')} </BlockList>`; const [blobBaseUrl, sasQuery] = sasUrl.split('?'); const commitUrl = `${blobBaseUrl}?comp=blocklist&${sasQuery}`; await axios({ method: 'PUT', url: commitUrl, data: blockListBody, headers: { 'Content-Type': 'application/xml' } }); console.log('大文件上传完成'); } // 调用示例 // uploadLargeFileWithSAS(SaSUrl, file);
3. 额外优化建议
- 断点续传:记录已上传的块ID,下次上传时跳过已完成的块
- 进度监控:监听每个块的上传进度,汇总成整体上传进度
- 错误重试:对块上传失败的请求添加重试逻辑,提升稳定性
- SAS有效期:根据文件大小调整SAS有效期,避免上传过程中Token过期
内容的提问来源于stack exchange,提问作者Kid_Learning_C
相关产品推荐
相关产品推荐

