如何让Backblaze B2返回Access-Control-Allow-Origin响应头?
问题分析与解决方案
Backblaze B2是支持CORS预检请求的,你的问题出在CORS规则配置细节,以及跨域请求类型的理解差异上:
为什么img标签能成功,但Fetch失败?
img标签的请求属于简单请求,不需要发送OPTIONS预检,且你把Authorization放在URL参数里而非自定义请求头,浏览器不会触发严格的跨域检查规则。- 而Fetch请求中你将Authorization放在请求头里,属于非简单请求,浏览器会先发送OPTIONS预检请求,要求服务器返回允许的Origin、Headers等信息,只有通过预检,才会发送实际的GET请求。
CORS规则的问题修正
你的现有规则有几个需要调整的地方:
1. 移除多余的access-control-allow-origin暴露头
access-control-allow-origin是服务器返回给浏览器验证跨域合法性的响应头,不需要配置在exposeHeaders里——这个头是B2根据你的allowedOrigins自动生成的,添加到exposeHeaders不会起作用,反而可能干扰规则匹配。
2. 确保请求头的大小写匹配
你的规则里allowedHeaders写的是小写的authorization,但浏览器发送的请求头是大写开头的Authorization。B2的CORS头匹配严格区分大小写,建议修改为Authorization以确保匹配。
3. 确认Origin完全匹配
检查allowedOrigins中的域名是否和前端实际域名完全一致:
- 如果前端是带端口的(比如
https://example.com:3000),规则里的https://example.com不会匹配,必须写完整的带端口域名; - 不要遗漏协议(http/https),域名和协议必须完全对应。
4. 等待规则生效
B2的CORS规则修改后,通常需要1-5分钟才能全局生效,修改后不要立即测试,等待几分钟再验证。
修正后的下载规则示例:
{ "allowedHeaders": [ "range", "referer", "Authorization", "sec-ch-ua", "sec-ch-ua-mobile", "sec-ch-ua-platform", "user-agent" ], "allowedOperations": [ "b2_download_file_by_id", "b2_download_file_by_name" ], "allowedOrigins": [ "https://example.com" ], "corsRuleName": "downloadRules", "exposeHeaders": [ "x-bz-content-sha1" ], "maxAgeSeconds": 3600 }
替代方案:PHP代理请求
如果调整CORS规则后还是无法解决,可以用你的PHP后端做代理:
- 前端请求你的PHP接口,传递文件名等参数;
- PHP后端使用curl或file_get_contents请求B2的资源,带上Authorization头;
- PHP将获取到的资源内容返回给前端,同时设置正确的Content-Type头。
示例PHP代码:
<?php session_start(); $bucketName = "your-bucket-name"; $filePath = "test/test.avif"; $downloadUrl = $_SESSION["downloadUrl"]; $authToken = $_SESSION["authorizationToken"]; $url = $downloadUrl . "/file/" . $bucketName . "/" . $filePath; $headers = [ "Authorization: " . $authToken ]; $ch = curl_init($url); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $response = curl_exec($ch); $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); curl_close($ch); if ($statusCode == 200) { header("Content-Type: " . $contentType); echo $response; } else { http_response_code($statusCode); echo "Error fetching file"; } ?>
前端直接请求这个PHP文件即可,无需处理跨域问题。
内容的提问来源于stack exchange,提问作者Castles
相关产品推荐
相关产品推荐

