Firebase 函数 CORS 错误访问控制允许来源

Firebase functions CORS error Access Control Alow Origin

我有一个简单的 firebase 函数,return是一个 hello world

exports.myFunc = functions
    .runWith({
        maxInstances: 1,
        memory: "128MB"
    })
    .https.onRequest(async (request, response) => {
        response.set("Content-Type", "text/plain");
        response.status(200).send('Hello world!');
    }

我用 POST 请求调用它,这些 headers:

>  {
>    host: 'localhost:5001',
>    connection: 'keep-alive',
>    pragma: 'no-cache',
>    'cache-control': 'no-cache',
>    accept: '*/*',
>    'access-control-request-method': 'POST',
>    'access-control-request-headers': 'authorization,content-type',
>    origin: 'http://localhost:8080',
>    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
>    'sec-fetch-mode': 'cors',
>    'sec-fetch-site': 'same-site',
>    'sec-fetch-dest': 'empty',
>    referer: 'http://localhost:8080/',
>    'accept-encoding': 'gzip, deflate, br',
>    'accept-language': 'en-US,en;q=0.9'
>  }

问题是当我尝试调用它时 运行 遇到 CORS 错误,因为我是从托管在 firebase 上的 vue 应用程序调用它的。好的,有道理,所以我阅读了一些关于 CORS 的文档,它抛出的第一个错误是:

from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

好的,我添加所需的 header:

exports.myFunc = functions
    .runWith({
        maxInstances: 1,
        memory: "128MB"
    })
    .https.onRequest(async (request, response) => {
        if (request.method === 'OPTIONS') {
            response.set('Access-Control-Allow-Origin', '*');
            response.status(204).send('');
        } else {
            // return hello world 
        }
    }

我知道允许所有 (*) 是一种糟糕的安全做法并且违背了 CORS 的某些目的,但这是为了测试。通过上述设置,我得到另一个 CORS 错误:

from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

好的,我再补充一些headers:

exports.myFunc = functions
    .runWith({
        maxInstances: 1,
        memory: "128MB"
    })
    .https.onRequest(async (request, response) => {
        if (request.method === 'OPTIONS') {
            response.set('Access-Control-Allow-Headers', "authorization,content-type");
            response.set('Access-Control-Allow-Origin', '*');
            response.status(204).send('');
        } else {
            // return hello world 
        }
    }

但是添加 HEADER 会给我与第一个错误相同的错误! :

from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我已经尝试了所有随机 headers 组合、auth header、凭据 header、启用所有 header 方法等。似乎没有任何组合可以工作我做错了吗?我在网上找到的所有答案都告诉我添加

'Access-Control-Allow-Origin', '*' 

是解决方案,但它不起作用?一种解决方案会导致另一种错误,依此类推。

这是 return header 我正在 returning:

>  [Object: null prototype] {
>    'x-powered-by': 'Express',
>    'access-control-allow-headers': 'authorization,content-type',
>    'access-control-allow-origin': '*'
>  }

所以我找出了原因,这是一些错误的地方,希望这能帮助以后和我有同样错误的人。

  1. 处理 CORS 时,您需要确保在初始 CORS 预检请求和 THE ACTUAL REQUEST 的响应中发送所需的 headers在 之后。在我的案例中发生的事情是我 return 为选项预检请求设置了正确的 header,但不是之后的实际请求。

  2. 如果您使用chrome进行调试,您可以将开发者控制台设置为同时显示预检和实际请求。 我的 chrome 版本结合了两个请求 这让我一直相信它是预检仍然导致问题。您可以按照以下答案更改 chrome 设置:Chrome not showing OPTIONS requests in Network tab.

  3. 最后,最后修复很简单,只需要在实际请求中再次添加所需的cors header 就修复了一切。这是代码:

     .https.onRequest(async (request, response) => {
    
         if (request.method === 'OPTIONS') {
             response.set('Access-Control-Allow-Headers', "authorization,content-type");
             response.set('Access-Control-Allow-Origin', '*');
             response.status(204).send('');
         } 
         else {
             // return hello world 
             response.set('Access-Control-Allow-Origin', '*');
         }
    

注意响应现在也会 return 访问控制允许来源 header 无论它是预检选项请求还是实际请求。