如何在Google Cloud Storage中配置动态CORS源解决凭证模式下的通配符错误
当Access-Control-Allow-Origin设为通配符*时,若请求的凭证模式为'include',来源网站无法访问Google Cloud Storage(GCS)上的静态脚本文件。
在Nginx中,可通过配置add_header 'Access-Control-Allow-Origin' $http_origin;动态返回请求的Origin解决该问题,但不清楚GCS是否有类似配置。当前GCS配置命令如下:
$ printf '[{"origin": ["*"],"responseHeader": ["*"],"method": ["GET","POST","HEAD"],"maxAgeSeconds": 900}]' > cors.json $ gsutil cors set cors.json gs://mybucket $ gsutil -m rsync -a public-read ./myfolder/ gs://mybucket/myfolder/
收到的错误信息:
Access to script at 'https://storage.googleapis.com/mybucket/myfolder/myfile.js' from origin 'https://www.whatever.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
补充信息:
- 该资源为公开URL,可被任意HTTPS网站调用,包括未知站点。
- 请求的cURL内容:
curl 'https://storage.googleapis.com/whatever/whatever/file.js' \ -H 'authority: storage.googleapis.com' \ -H 'accept: */*' \ -H 'accept-language: en-US,en;q=0.9' \ -H 'cache-control: no-cache' \ -H 'origin: https://www.example.com' \ -H 'pragma: no-cache' \ -H 'referer: https://www.example.com/' \ -H 'sec-ch-ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"' \ -H 'sec-ch-ua-mobile: ?0' \ -H 'sec-ch-ua-platform: "macOS"' \ -H 'sec-fetch-dest: script' \ -H 'sec-fetch-mode: cors' \ -H 'sec-fetch-site: cross-site' \ -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36' \ --compressed
GCS本身不支持像Nginx那样动态返回请求的Origin值,其CORS配置仅支持固定来源列表,无法实现通配符加动态匹配的组合。可通过以下两种方式解决:
方式一:修改前端请求的凭证模式
如果前端代码可控,将请求的凭证模式从'include'改为'same-origin'或'omit'。当凭证模式不包含凭证时,浏览器允许Access-Control-Allow-Origin设为*,即可正常访问资源。
示例fetch请求修改:
fetch('https://storage.googleapis.com/mybucket/myfolder/myfile.js', { credentials: 'omit' // 或根据需求选择'same-origin' });
方式二:通过Cloud Functions/Cloud Run代理请求
若必须保留凭证模式为'include',可搭建代理服务,用Cloud Functions或Cloud Run转发GCS请求,在代理层动态设置Access-Control-Allow-Origin为请求的Origin值,并添加Access-Control-Allow-Credentials: true头。
示例Cloud Functions代码(Node.js):
const { Storage } = require('@google-cloud/storage'); const storage = new Storage(); exports.proxyGCS = async (req, res) => { const origin = req.get('Origin'); // 设置CORS响应头 res.set('Access-Control-Allow-Origin', origin); res.set('Access-Control-Allow-Credentials', 'true'); // 处理OPTIONS预检请求 if (req.method === 'OPTIONS') { res.set('Access-Control-Allow-Methods', 'GET, POST, HEAD'); res.set('Access-Control-Allow-Headers', '*'); res.set('Access-Control-Max-Age', '900'); return res.status(204).send(''); } // 转发请求到GCS const filePath = req.path; const bucket = storage.bucket('mybucket'); const file = bucket.file(filePath); try { const stream = file.createReadStream(); stream.pipe(res); } catch (err) { res.status(404).send('File not found'); } };
部署代理服务后,前端请求代理地址而非直接请求GCS地址即可。
注意事项
- 方式一成本最低,优先考虑修改前端请求配置;
- 方式二需维护代理服务,但可完全保留凭证模式需求;
- GCS的服务特性决定了其无法实现动态Origin匹配。
内容的提问来源于stack exchange,提问作者Michel Gokan Khan

