如何正确设置 CORS 以将带有 presignedUrl 的文件上传到 Firebase 存储?

Posted

技术标签:

【中文标题】如何正确设置 CORS 以将带有 presignedUrl 的文件上传到 Firebase 存储?【英文标题】:How can I setup CORS properly to upload file with a presignedUrl to firebase storage? 【发布时间】:2020-09-07 11:55:51 【问题描述】:

我一直在尝试将图像直接从我的 react spa 上传到我的 firebase 存储桶,但我无法正确配置 cors。

我使用 GCP 控制台在 muy bucket 中设置 cors 配置,如下:

[
  
    "origin": ["http://localhost:3000"],
    "method": ["PUT"],
    "responseHeader": [
        "Content-Type",
        "Access-Control-Allow-Origin",
        "x-goog-resumable"],
    "maxAgeSeconds": 3600
  
]

但它在浏览器中不起作用,而是在邮递员中按预期工作。

我的应用实现如下:

首先我在我的节点 api 中生成预签名的 url:

const admin = require('firebase-admin');
const uuid = require('uuid');

admin.initializeApp(
    credential: admin.credential.applicationDefault(),
    storageBucket: "<BUCKET-NAME>"
);

var bucket = admin.storage().bucket();

const generateSignedUrl = async (userId) => 
    const key = `$userId/$uuid.v1().jpeg`;
    const options = 
        version: 'v4',
        action: 'write',
        expires: Date.now() + 5*60 * 1000,
        contentType: 'image/jpeg'
    ;

    const [ url ] = await bucket
        .file(key)
        .getSignedUrl(options);

    return [url, key];
;

然后在 spa 中,我使用 axios 执行 put 请求,以便使用我的节点 api 提供的 presignedUrl 上传文件。

 const config = 
   headers:  'Content-Type': 'application/octet-stream' 
 ;
 await axios.put(presignedUrl, file, config);

但是出现了CORS错误:

Access to XMLHttpRequest at 'https://storage.googleapis.com/...' from origin 'http://localhost:3000' has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

【问题讨论】:

简单看一下the docs,你好像配置错了responseHeader。此外,您需要 REST API 版本,而不是 gsutil 你能通过this troubleshotting steps吗?特别是第 4 点和第 5 点。您的请求中似乎缺少一些听众。 我也看过了,但我没有意识到我的错误是什么,你能具体说明它是什么@llompalles 吗?请 您的错误与Access-Control-Allow-OriginOrigin 听者有关,这导致CORS 请求失败,如here 所述。远程故障排除很困难,但您能否将 CORS 配置中的 "origin": ["http://localhost:3000"] 更改为通配符 "origin": ["*"] 谢谢@llompalles 我解决了这个问题:) 【参考方案1】:

最后我解决了我的问题,我在这里发布了答案,也许它可以帮助其他人。 我有两个问题。

首先,我一直在为所有请求发送一个授权标头,但由于我的 CORS 配置,firebase 没有正确分析它。我决定将预签名上传请求的 auth 标头省略为:
    delete axios.defaults.headers.common["x-auth-token"];
其次,contentType头设置错误,但由于chrome默认不显示network选项卡中的options请求(out-of-blink-cors),所以总是出现No 'Access-Control-Allow-Origin' header is present..错误。由于 firefox,我发现了正确的错误后,我将 signedUrl 生成的选项更改为:
    const options = 
        version: 'v4',
        action: 'write',
        expires: Date.now() + 5*60 * 1000,
        contentType: `image/$type`
    ;

其中 type 是要上传的图片类型,由 spa 提供。

cors 配置按预期工作。

[
    "origin": ["http://localhost:3000"],
    "method": ["PUT"],
    "responseHeader": [
        "Content-Type"
    ],
    "maxAgeSeconds": 3600
]

【讨论】:

很好地找到了解决方案!你能accept your own answer吗?它将使其更加明显,并在您找到解决方案时帮助遇到相同问题的人。谢谢!

以上是关于如何正确设置 CORS 以将带有 presignedUrl 的文件上传到 Firebase 存储?的主要内容,如果未能解决你的问题,请参考以下文章

如何获得正确的范围以将值设置为单元格?

如何获得正确的范围以将值设置为单元格?

带有清单版本 3 的 CORS Chrome 扩展程序

如何正确设置 GET/POST 获取的标头以避免 CORS

带有自定义标头的 Ajax 请求发送到启用 CORS 的 Web API 服务器

如何设置 UWP C# StorageFile 以将 SoftwareBitmap 存储到特定路径