[英]Preflight error on Firebase cloud functions
I'm facing a preflight error when I try to call a cloud function of mine from my website.当我尝试从我的网站调用我的云 function 时,我遇到了预检错误。 I implemented the cors module in my cloud function, and my request got the cors header authorizations
我在我的云 function 中实现了 cors 模块,我的请求得到了 cors Z099FB995346F31C75E3F6 授权
The cloud function:云function:
const cors = require('cors')({ origin: true });
exports.CLOUDFUNCTION = functions.https.onRequest(
(request: any, response: any) => {
cors(request, response, async () => {
response.status(200).send('hello');
})
}
);
The website request:网站要求:
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"}
}
);
The error错误
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.
If you are getting a 403 Forbidden Error when trying to access your function via it's URL, you have a problem with your function's deployment, it's configuration or you have made a mistake in the URL.如果您在尝试通过 URL 访问您的 function 时遇到 403 禁止错误,则您的函数部署有问题,它的配置有问题,或者您在 ZE485903D2A8D2C5DZ 中出错了
Note: While I use "traditional" require
statements here to match your example, I encourage you to use newer ES6+ JavaScript features ( const
, let
, async
/ await
, import
, etc.) for any newly written functions.注意:虽然我在此处使用“传统”
require
语句来匹配您的示例,但我鼓励您对任何新编写的函数使用更新的 ES6+ JavaScript 功能( const
、 let
、 async
/ await
、 import
等)。
firebase-tools
versionfirebase-tools
版本进行部署Make sure you are deploying using the latest version of the firebase-tools
CLI.确保您使用最新版本的
firebase-tools
CLI 进行部署。
When v7.7.0
of firebase-tools
released (Jan 15, 2020), the way Cloud Functions are invoked on the server changed so that functions could be invoked by only authenticated users.当
v7.7.0
firebase-tools
v7.7.0 发布(2020 年 1 月 15 日)时,在服务器上调用 Cloud Functions 的方式发生了变化,因此只能由经过身份验证的用户调用函数。 To be accessible to Firebase Users, these functions must be made public by explicitly granting the allUsers
group the Cloud Function Invoker permission.为了让 Firebase 用户可以访问,必须通过显式授予
allUsers
组Cloud Function Invoker权限来公开这些功能。
In v7.7.0
and later, this is done for you as part of deployment.在
v7.7.0
及更高版本中,这是作为部署的一部分为您完成的。 However, if you deploy functions using an older version, you will need to configure this permission yourself or redeploy using a newer firebase-tools
version.但是,如果您使用旧版本部署功能,则需要自己配置此权限或使用更新的
firebase-tools
版本重新部署。
Make sure the function you export is named what you expect once deployed.确保您导出的 function 在部署后命名为您期望的名称。
In particular, pay close attention to when your function is exported as part of a function group either deliberately or accidentally.特别是,当您的 function 被有意或无意地作为function 组的一部分导出时,请密切注意。 This often turns up when you've split your functions into multiple files.
当您将函数拆分为多个文件时,通常会出现这种情况。 In the below code blocks,
CLOUDFUNCTION
gets exported as myFunctions-CLOUDFUNCTION
and not just CLOUDFUNCTION
as you may expect.在下面的代码块中,
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;
Check the Cloud Functions URL you are using for typos.检查您使用的 Cloud Functions URL 是否存在拼写错误。 Function names in Cloud Functions URLs are case-sensitive.
Cloud Functions URL 中的 Function 名称区分大小写。
The correct URL should follow the format:正确的 URL 应遵循以下格式:
https://<REGION>-<PROJECT_ID>.cloudfunctions.net/<EXPORTED_FUNCTION_NAME>
Example:例子:
https://us-central1-fir-sandbox.cloudfunctions.net/echo
In your code example, you pass in the NextFunction
without an error handler.在您的代码示例中,您传入
NextFunction
而没有错误处理程序。 While using { origin: true }
, this is "fine", but you'll start running into trouble when you start restricting the origins you call your function from.使用
{ origin: true }
时,这“很好”,但是当您开始限制您调用 function 的来源时,您将开始遇到麻烦。 This is particularly handy for preventing your functions being invoked directly by their URL (where origin
would be undefined
).这对于防止您的函数被它们的 URL (其中
origin
将是undefined
)直接调用特别方便。 Take a look at the documentation or the next section for more info.查看文档或下一部分以获取更多信息。
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
configurationcors
配置While you can reflect the Access-Control-*
headers using the cors
package, consider explicitly setting these server-side.虽然您可以使用
cors
package 反映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');
})
}
);
This simplifies your client-side code:这简化了您的客户端代码:
fetch('FIREBASE_URL/CLOUDFUNCTION',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
}
);
If your functions will require you to do actions on behalf of a user, you could make use of Callable Cloud Functions instead of the more bare-bones HTTPS Request functions.如果您的函数需要您代表用户执行操作,您可以使用Callable Cloud Functions而不是更简单的 HTTPS 请求函数。 This version of a HTTPS Function handles CORS, authentication, and supports Promise-based returning of data.
这个版本的 HTTPS Function 处理 CORS,身份验证,并支持基于 Promise 的数据返回。
Note: This will still require the function to be public as described above.注意:这仍然需要 function 如上所述公开。
On the server side:在服务器端:
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";
});
On the client side:在客户端:
const callFunction = firebase.functions().httpsCallable('CLOUDFUNCTION');
callFunction(body)
.then(
(responseData) => {
// TODO: handle response
},
(functionError) => {
// TODO: handle error
}
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.