Firebase 可调用函数 + CORS

Posted

技术标签:

【中文标题】Firebase 可调用函数 + CORS【英文标题】:Firebase Callable Function + CORS 【发布时间】:2018-10-21 01:22:27 【问题描述】:

我正在尝试从我的应用中调用可调用的云函数,但我遇到了 CORS 问题。

我无法启用 Cors,因为我无权访问 onCall 函数的请求和响应。这是我的功能:

exports.UserInvitation = functions.https.onCall((data, context) => 
  const email = data.email


  return new Promise((resolve, reject) => 
    admin.auth().createUser(
      email: email,
      emailVerified: false,
      password: password
    ).then(resolve).catch((err) => 
      console.error(err.code)
      reject(new functions.https.HttpsError(err.code, err.message))
    )
  )
)

这就是我所说的:

functions.httpsCallable('UserInvitation')( email: this.input.value ).then((data) => 
      console.log('Sent invitation:', data)
)

Firebase-functions 包.json:


  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": 
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  ,
  "dependencies": 
    "bluebird": "^3.5.1",
    "firebase-admin": "~5.12.0",
    "firebase-functions": "^1.0.1"
  ,
  "private": true

WEB SDK Firebase 版本:4.13.1

【问题讨论】:

CORS 应该由 onCall 处理程序自动处理。我怀疑有关 CORS 的错误消息不准确,是函数返回 500 internal 的结果。您在 Firebase 控制台的函数日志中看到了什么? 你说得对,问题出在我的错误处理程序上。文档说我可以拒绝带有functions.https.HttpsError实例的承诺,但即使我这样做了,我也会在客户端收到500错误。我该如何解决? 即使我删除了我的 return 语句并添加了 throw new functions.https.HttpsError('test/code', 'error message'),它也只会返回一个带有消息且状态等于“INTERNAL”的对象 啊,是的,传递给 HttpsError 的状态码不能是test/code。它必须是此处列出的标准代码之一:firebase.google.com/docs/reference/functions/… @bklimt 请用这个评论创建一个答案,我会接受它:) 我相信这个细节应该添加到 firebase onCall 文档中 【参考方案1】:

对于到这里来搜索 firebase 可调用函数 cors 错误的其他人,这是我的清单:

    确保功能已部署。 确保函数名称正确。我打电话给recalculatY,而应该是recalculateY。由于某种原因出现了 cors 错误。 确保函数代码本身不会引发错误。 Use the emulator to help. 这并没有引发 cors 错误,仍然有助于了解。 确保您的区域匹配 - 我使用的是europe-west2。我必须在该区域部署该功能,并使用该区域调用它。有一段时间,我假设如果函数名称正确,客户端会推断出正确的区域。事实并非如此。

将可调用函数部署到特定区域:

// This is the file in which you define your callable function.
const functions = require('firebase-functions');
...
exports.yourFunc = functions.region('europe-west2').https.onCall(async (data, context) => 
    ...
)

从客户端(在本例中为 vuejs Web 应用)调用特定区域中的函数:

// In my case, this is a vuex store file, but it is safe to assume this is plain old javascript
import firebase from 'firebase/app'
import 'firebase/functions'
...
firebase.app().functions('europe-west2').httpsCallable('yourFunc')

注意:firebase.app().function...firebase.app.function...

【讨论】:

这是为我准备的!通话中没有地区。 基本清单...你用“确保函数名称正确”救了我 谢谢。这对我来说是#1。我以为我已经部署了它。 拯救了我的一天。我要编辑一大堆代码。 Angular 参考:github.com/angular/angularfire/blob/master/docs/functions/…【参考方案2】:

对于 2020 年 1 月查看此帖子的任何人..

在 Reddit (https://www.reddit.com/r/reactjs/comments/fsw405/firebase_cloud_functions_cors_policy_error/) 上找到了这个答案

事实证明,Google 于 2020 年 1 月 15 日更改了安全设置,所有新功能不再具有 Cloud Functions Invoker。这意味着所有新创建的函数都将被禁止访问,从而导致 CORS 策略阻塞。

这里是你如何解决它,因为它不是那么明显:

https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_function_invocation

【讨论】:

天哪。找到一个多么混乱的错误。谢谢! 但这将允许所有用户调用此函数我的意思是我已经完成了CORS错误消失但现在我可以从邮递员触发该函数而无需任何标题!这是唯一的方法@Kitson 我使用的是.https.onCall(async (data, context) => ... ),并且上下文可以访问身份验证用户context.auth。然后我使用它来检查权限并为未经身份验证的用户抛出错误。 这太让人生气了——对于这么大的公司来说,关于这个话题的文档到处都是。事情发生时怎么不是到处都是?谢谢。 谢谢,这对我有用。补充一点有趣的花絮是,我同时部署了 3 个函数,只有 1 个有这个问题。【参考方案3】:

我的一些 Firebase 函数遇到了这个问题,但其他函数没有。我最终通过这样做来修复它:

    在 index.js 中注释掉函数 运行 firebase 部署 在提示符处输入 y 删除函数 等待 5 到 10 分钟 移除函数周围的 cmets 并再次运行 firebase deploy

无需对函数本身进行任何更改,它现在运行时不会出现任何 CORS 问题。

【讨论】:

难以置信,在这里花了几个小时尝试所有不同的解决方案后,我删除了每个功能并再次重新部署它们,突然间,它们开始工作而没有任何 CORS 问题。在那段时间里,我仍然不确定我是否还必须为https.onCall(..) 用户经过身份验证的函数执行@Nikita 的解决方案(因为没有任何东西可以使它们工作)。答案是否定的 - 完全删除并重新部署解决了问题。 我尝试了这个线程中的每一件事。但这对我来说是解决方案。只需删除一次所有云功能。然后重新部署,它再次工作! 我做了一些非常相似的事情:用不同的名字部署了完全相同的功能:非常成功。翻了一张桌子,继续前进。 我尝试了各种解决方案,是的,解决方案对我来说是一样的,只是删除所有功能并重新部署它们。实际情况是什么.. 我一直在面对这个错误好几个小时想知道什么以及如何解决这个问题,然后它只是“删除并重试”......感觉很愚蠢。 我尝试了所有其他可能的解决方案......没有冒犯,但我坚持这永远不会奏效,因为我什至从未尝试过,但是伙计......我可以说这是问题所在。谢谢!【参考方案4】:

我的问题不在于 CORS,而在于我的错误处理程序。我没有拒绝承诺,而是直接在 catch 处理程序中使用了throw

catch((err) => 
  throw new functions.https.HttpsError('unknown', err.message, err)
)

【讨论】:

这对我来说似乎非常奇怪。在云函数中拒绝你正在返回的承诺,我觉得这与投掷完全一样......【参考方案5】:

可能很多人会在模拟器和 cors 消息中遇到这个问题。

我在 Google 上看到的任何讨论中都没有讨论过我的案例,我确实看到了很多“无法重现”,也许我的案例会遮住一些光:

就我而言,问题是我没有从 firebase 模拟器运行托管。

当您通过 npm start 运行您的 react 应用程序时 - 当函数通过 firebase emulators:start 运行时,您将看到 Cors 错误。

所以在测试云函数调用时,而不是使用 npm start,你应该这样做 npm run build 然后从模拟器访问应用程序...

搜索类似的内容: "托管:本地服务器:http://localhost:5000"

几个注释 -

你的函数也应该通过

在模拟器上工作

const functions = firebaseApp.functions('europe-west3');// lets assume thats your region functions.useFunctionsEmulator('http://localhost:5000');

【讨论】:

【参考方案6】:

对于在现有 GCloud 项目上启用 firebase 后遇到此错误的用户,如果它只是一个 firebase 应用程序,则会自动处理一些复杂性。

我遇到了这个特定的问题,因为我希望我的 firebase 功能可以公开访问,但如果您使用的是 google 的 Cloud Functions,则必须专门配置它。

以下是修复的步骤:

    转到云功能选项卡 选择您的云功能(复选框) 点击右侧权限选项卡下的“添加成员” 输入“所有用户” 在“新成员”下选择角色为“云函数 ->“云函数调用者” 保存 只需将云功能粘贴到浏览器中即可测试它

干杯

【讨论】:

【参考方案7】:

如果以上都没有帮助: 就我而言,原因是我没有正确设置我的区域。使用 3rd 方库时尤其会发生这种情况。

【讨论】:

你在哪里设置区域?我正在使用一个,但仅在调用中:exports.myf = functions.region("europe-west3").https.onCall(...)。还有什么地方需要摸吗? 您可以将其包装在您自己的模块中,并使用它来代替原来的函数模块,这样您只需调用一次 region。 @Aido 的回答解决了我的问题。还需要让浏览器代码告诉 Firebase 使用哪个区域。【参考方案8】:

我之前将我的函数部署为 HTTP 函数 (https.onRequest),然后切换到可调用函数 (https.onCall)。 Firebase 无法识别此更改。

我通过删除函数并在没有它的情况下进行部署来解决问题,然后将函数放回并再次部署。

【讨论】:

【参考方案9】:

我有同样的问题。我的解决方案是在https://console.cloud.google.com 中打开我的 Firebase 项目 并导航到云功能页面。

在其权限页面查找您的函数名称,并将新角色“Cloud Functions Invoker”添加到“allUsers”成员。

【讨论】:

爱你! ❤️ 拯救了我的一天【参考方案10】:

如果您使用多个环境(Firebase 项目)来分离开发和生产(即 Project-dev、Project-prod),请确保您已切换到所需的环境。就我而言,运行它是有效的:

firebase use default

【讨论】:

感谢我再次启动本地模拟器后的工作。但你也知道为什么吗? firebase 环境与我的本地模拟器有什么关系?【参考方案11】:
    错误应该在https://firebase.google.com/docs/reference/functions/functions.https.HttpsError中给出 我在更改函数名称后部署了可调用函数并且它正在工作。

【讨论】:

【参考方案12】:

当我尝试创建用于登录 firebase 用户的自定义令牌时,我遇到了同样的错误。 我在下面附上了我的代码。但是,我后来发现问题是由于尝试使用相同的参数多次调用该函数来创建多个令牌。

export const getCustomToken = functions.https.onCall((params: any) => 
 return admin.auth().createCustomToken(params).then((token) => 
   return token;
  ).catch((error) => 
    console.log(error);
    return null;
  );
 );

解决方案 我通过在尝试登录之前首先检查用户是否已注销来解决了这个问题。所以我建议您首先检查您尝试创建的用户是否已经存在。 我知道这有点晚了,但我希望这对其他人有所帮助。

this.fireAuth.currentUser.then((signedInAlready) => 
  if (signedInAlready) 
    return this.fireAuth.signOut().then(() => getCustomToken());
   else 
    return getCustomToken();
  
);

在您的 firebase 函数中,您可以按如下方式检查现有用户:

admin.auth().getUserByEmail('your-email').then((userExists) => 
if (userExists) 
  // return user
 else 
  // create a new user
);

【讨论】:

【参考方案13】:

基本上,我做了关于 onCall 云函数的 CORS 错误的页面和答案中提到的所有事情,从更改区域或手动添加调用权限到更明显的权限,对我没有任何帮助。只需将 onCall 转为 OnRequest 即可。

【讨论】:

【参考方案14】:

对我有用的是删除我的云功能中的区域参数,然后重新部署。 来自functions.region("europe-west2").https.onCall(async (data) => ..

functions.https.onCall(async (data) => ..

【讨论】:

以上是关于Firebase 可调用函数 + CORS的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 可调用云函数 CORS 错误

Firebase 可调用函数失败 CORS 重定向

Firebase 可调用函数未接收参数

应用检查对 Firebase 可调用函数的不必要强制执行

使用 Firebase 可调用函数时如何检索用户的身份验证数据?

Firebase Cloud Functions shell:添加身份验证令牌以调用可调用对象