Azure存储分块上传提交阶段出现CORS错误排查求助
我需要实现用户直接将大文件上传至Azure Storage,现有Flask Python Web应用,因服务器容量限制,不想让文件先上传到Web服务器。流程如下:
- 调用API生成SAS URL和Blob名称(代码见下方);
- 通过JavaScript分块上传文件,此步骤可正常执行;
但在调用&comp=commitBlockList提交块列表时,始终出现CORS错误,提示缺少Access-Control-Allow-Origin头。已在Blob Service中配置localhost源,允许GET、POST、OPTIONS、PUT方法,尝试重新生成SAS URL仍无效,已定位错误与&comp=commitBlockList参数相关,求问题原因及解决办法。
生成SAS URL代码
blob_name = str(uuid.uuid4()) container_name = os.environ[default_container_name_setting] sas = generate_blob_sas(account_name=service.account_name, account_key=access_key, container_name=container_name, blob_name=blob_name, permission=BlobSasPermissions(write=True, read=True, create=True), expiry=datetime.utcnow() + timedelta(hours=2)) sas_url = 'https://' + service.account_name + '.blob.core.windows.net/' + container_name + '/' + blob_name + '?' + sas return sas_url, blob_name
分块上传代码
const chunkSize = 1024 * 1024 * 20; const totalChunks = Math.ceil(file.size / chunkSize); const blockIds = []; // 存储块ID的数组 for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, file.size); const chunk = file.slice(start, end); const blockId = btoa("block-" + i); // Base64编码块ID blockIds.push(blockId); // 上传每个分块 const uploadResponse = await fetch(sas_url + "&comp=block&blockid=" + blockId, { method: "PUT", headers: { "x-ms-blob-type": "BlockBlob", "Content-Type": file.type }, body: chunk }); if (!uploadResponse.ok) { return false; } }
提交块列表代码
const commitResponse = await fetch(sas_url + "&comp=commitBlockList", { method: "PUT", headers: { "Content-Type": "application/xml", "x-ms-version": "2020-10-02", "Content-Length": "0" }, body: `<BlockList>${blockIds.map(id => `<Latest>${id}</Latest>`).join('')}</BlockList>` }); if (!commitResponse.ok) { throw new Error("提交块列表到Blob失败。"); }
错误信息
从源 'http://localhost:4449' 获取 'https://xxx.blob.core.windows.net/container/e07d13fa-bcd6-45cf-9eea-3295e17dc567?se=2024-11-01T04%2A18%3B30Q&sp=rcw&sv=2024-11-04&sr=b&sig=Cudr...&comp=commitBlockList' 时被CORS策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在 'Access-Control-Allow-Origin' 头。如果不透明响应满足你的需求,请将请求的模式设置为 'no-cors' 以在禁用CORS的情况下获取资源。
1. 错误设置Content-Length导致请求无效
提交块列表的代码里手动设置了"Content-Length": "0",但请求body包含XML格式的块列表内容,这会导致服务器接收到的数据长度与声明的不一致,触发400错误。此时Azure Blob服务不会返回CORS响应头,进而引发浏览器的CORS报错。
解决办法:
移除手动设置的Content-Length头,让浏览器自动计算并设置正确的长度:
const commitResponse = await fetch(sas_url + "&comp=commitBlockList", { method: "PUT", headers: { "Content-Type": "application/xml", "x-ms-version": "2020-10-02" // 移除 Content-Length: "0" }, body: `<BlockList>${blockIds.map(id => `<Latest>${id}</Latest>`).join('')}</BlockList>` });
2. CORS配置缺少必要的请求头部
commitBlockList请求携带了x-ms-version和Content-Type(值为application/xml),如果Blob Service的CORS配置未允许这些请求头,预检请求会失败,导致CORS错误。
解决办法:
在Azure Portal中修改Blob Service的CORS配置:
- 进入存储账户 → 数据存储 → Blob服务 → CORS
- 找到对应的localhost规则:
- Allowed Headers:添加
x-ms-version、Content-Type,或临时使用*(生产环境建议限制具体头部) - 确认Allowed Methods包含
PUT(你已配置,可再次核对) - 保存配置后等待几分钟生效
- Allowed Headers:添加
3. SAS权限与API版本一致性检查
- 确认生成SAS时的
BlobSasPermissions(write=True, read=True, create=True)权限足够:write权限已覆盖commitBlockList操作,这部分无问题。 - 检查请求中的
x-ms-version(2020-10-02)是否与SAS URL中指定的版本(sv=2024-11-04)一致。若版本不匹配可能导致请求异常,可尝试移除请求中的x-ms-version头,使用SAS指定的版本。
4. 验证CORS配置的来源匹配
确认CORS配置中的Allowed Origins是http://localhost:4449(注意端口号和协议,不要带末尾斜杠,除非页面URL确实包含)。分块上传正常说明来源匹配大概率没问题,可再次核对。
内容的提问来源于stack exchange,提问作者rikitikitik

