【问题标题】:Preflight error on Firebase cloud functionsFirebase 云功能上的预检错误
【发布时间】:2021-07-22 15:38:12
【问题描述】:

当我尝试从我的网站调用我的云功能时,我遇到了预检错误。我在我的云函数中实现了 cors 模块,我的请求得到了 cors 标头授权

云功能:

const cors = require('cors')({ origin: true });
exports.CLOUDFUNCTION = functions.https.onRequest(
  (request: any, response: any) => {
    cors(request, response, async () => {
      response.status(200).send('hello');
    })
  }
);

网站请求:

fetch('FIREBASE_URL/CLOUDFUNCTION',
          {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'Access-Control-Allow-Origin': '*',
              'Access-Control-Allow-Headers': 'Content-Type',
              'Access-Control-Allow-Headers': 'Authorization'
               
            },
            body: JSON.stringify(body), // body is a simple {"variable": "value"}
          }
        );

错误

Access to fetch at 'FIREBASE_URL/CLOUDFUNCTION' from origin 'MYWEBSITE' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

【问题讨论】:

  • 在浏览器中打开FIREBASE_URL/CLOUDFUNCTION时,是否也会报错?
  • 你的意思是如果我直接在我的搜索栏中输入它?因为如果我直接尝试访问它会出现 403 错误

标签: javascript typescript firebase google-cloud-functions cors


【解决方案1】:

如果您在尝试通过其 URL 访问您的函数时遇到 403 Forbidden Error,则您的函数的部署、配置有问题,或者您在 URL 中犯了错误。

注意:虽然我在这里使用“传统”require 语句来匹配您的示例,但我鼓励您使用更新的 ES6+ JavaScript 功能(constletasync/ awaitimport 等)用于任何新编写的函数。

使用最新的firebase-tools 版本部署

确保您使用最新版本的 firebase-tools CLI 进行部署。

v7.7.0firebase-tools 发布时(2020 年 1 月 15 日),在服务器上调用 Cloud Functions 的方式发生了变化,因此只能由经过身份验证的用户调用函数。为了可供 Firebase 用户访问,这些函数必须通过显式授予 allUsersCloud Function Invoker 权限来公开。

v7.7.0 及更高版本中,这是作为部署的一部分为您完成的。但是,如果您使用旧版本部署功能,则需要configure this permission yourself 或使用较新的firebase-tools 版本重新部署。

检查导出的函数名

确保您导出的函数按照部署后的预期命名。

特别要密切注意何时将您的函数导出为function group 的一部分,无论是有意还是无意。当您将函数拆分为多个文件时,通常会出现这种情况。在下面的代码块中,CLOUDFUNCTION 被导出为myFunctions-CLOUDFUNCTION,而不仅仅是CLOUDFUNCTION,如您所料。

// myFunctions.js
exports.CLOUDFUNCTION = functions.https.onRequest(...);
// index.js (incorrect)
exports.myFunctions = require("./myFunctions.js");
// index.js (correct)
const myFunctions = require("./myFunctions.js");

exports.CLOUDFUNCTION = myFunctions.CLOUDFUNCTION;

检查函数的 URL

检查您使用的 Cloud Functions URL 是否存在拼写错误。 Cloud Functions URL 中的函数名称区分大小写。

正确的网址应遵循以下格式:

https://<REGION>-<PROJECT_ID>.cloudfunctions.net/<EXPORTED_FUNCTION_NAME>

例子:

https://us-central1-fir-sandbox.cloudfunctions.net/echo

处理 CORS 错误并停止处理

在您的代码示例中,您传入 NextFunction 而不使用错误处理程序。在使用{ origin: true } 时,这“很好”,但是当您开始限制调用函数的来源时,您将开始遇到麻烦。这对于防止您的函数被它们的 URL 直接调用特别方便(其中origin 将是undefined)。查看documentation 或下一部分了解更多信息。

const cors = require('cors')({ origin: true });
exports.CLOUDFUNCTION = functions.https.onRequest(
  (request, response) => { // <-- don't use `: any` here, as you are disabling the built-in types provided by firebase-functions
    cors(request, response, async (err) => {
      if (err) {
        // Denied by CORS/error with CORS configuration
        console.error("CORS blocked request -> ", err);
        response.status(403).send("Forbidden by CORS");
        return;
      }

      response.status(200).send('hello');
    })
  }
);

可选:收紧cors配置

虽然您可以使用 cors 包反映 Access-Control-* 标头,但请考虑在服务器端显式设置这些标头。

const { projectId: PROJECT_ID } = JSON.parse(process.env.FIREBASE_CONFIG);

const cors = require('cors')({
  // during emulation, allow localhost & calling directly (i.e. no origin specified);
  // at all other times, restrict to deployed hosting sites only
  origin: process.env.FUNCTIONS_EMULATOR === "true"
    ? /^(https?:\/\/localhost:\d+|undefined)$/
    : [`https://${PROJECT_ID}.firebaseapp.com`, `https://${PROJECT_ID}.web.app`],
  allowedHeaders: ['Content-Type', 'Authorization']
});

exports.CLOUDFUNCTION = functions.https.onRequest(
  (request, response) => {
    cors(request, response, async (err) => {
      if (err) {
        // Denied by CORS/error with CORS configuration
        console.error("CORS blocked request -> ", err);
        response.status(403).send("Forbidden by CORS");
        return;
      }

      response.status(200).send('hello');
    })
  }
);

这简化了您的客户端代码:

fetch('FIREBASE_URL/CLOUDFUNCTION',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  }
);

可选:使用可调用函数

如果您的功能需要您代表用户执行操作,您可以使用Callable Cloud Functions 代替更简单的 HTTPS 请求功能。此版本的 HTTPS 函数处理 CORS、身份验证,并支持基于 Promise 的数据返回。

注意:这仍然需要如上所述的公开函数。

在服务器端:

exports.CLOUDFUNCTION = functions.https.onCall(async (data, context) => {
  if (!context.auth) {
    // users must be logged in
    throw new functions.https.HttpsError(
      'failed-precondition',
      'The function must be called while authenticated.'
    );
  }

  if (data.variable === undefined)) {
    throw new functions.https.HttpsError(
      'invalid-argument',
      'Parameter "variable" must be a string'
    );
  }

  // you can return a promise here
  // this sends back the JSON string "hello world"
  return "hello world";
});

在客户端:

const callFunction = firebase.functions().httpsCallable('CLOUDFUNCTION');

callFunction(body)
  .then(
    (responseData) => {
      // TODO: handle response
    },
    (functionError) => {
      // TODO: handle error
    }
  );

【讨论】:

  • 非常感谢您的回答非常完整。你在Cloud Function Invoker permission 上所说的让我尝试了所有的云函数(所有的参数都相同,只有这个用 403 回答。我创建了一个新的云函数(我创建了一个新函数并复制粘贴了旧代码切换到新功能并切换我的通话/它在一天结束时工作。我相信当我使用 firebase deploy --only functions:MYCLOUDFUNCTION 创建以前的功能时出了点问题。再次感谢您的时间和支持。非常感谢跨度>
猜你喜欢
  • 2018-11-17
  • 2021-12-01
  • 2018-05-15
  • 1970-01-01
  • 2020-12-28
  • 2021-10-16
  • 2017-10-09
  • 1970-01-01
相关资源
最近更新 更多