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

Azure存储分块上传提交阶段出现CORS错误排查求助

问题描述

我需要实现用户直接将大文件上传至Azure Storage,现有Flask Python Web应用,因服务器容量限制,不想让文件先上传到Web服务器。流程如下:

  1. 调用API生成SAS URL和Blob名称(代码见下方);
  2. 通过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(你已配置,可再次核对)
    • 保存配置后等待几分钟生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:32:02