如果您在尝试通过其 URL 访问您的函数时遇到 403 Forbidden Error,则您的函数的部署、配置有问题,或者您在 URL 中犯了错误。
注意:虽然我在这里使用“传统”require 语句来匹配您的示例,但我鼓励您使用更新的 ES6+ JavaScript 功能(const、let、async/ await、import 等)用于任何新编写的函数。
使用最新的firebase-tools 版本部署
确保您使用最新版本的 firebase-tools CLI 进行部署。
v7.7.0 或 firebase-tools 发布时(2020 年 1 月 15 日),在服务器上调用 Cloud Functions 的方式发生了变化,因此只能由经过身份验证的用户调用函数。为了可供 Firebase 用户访问,这些函数必须通过显式授予 allUsers 组 Cloud 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
}
);