我目前正在学习如何为 Firebase 使用新的 Cloud Functions,我遇到的问题是我无法访问通过 AJAX 请求编写的函数。我收到“无 'Access-Control-Allow-Origin'”错误。这是我编写的函数的示例:
exports.test = functions.https.onRequest((request, response) => {
response.status(500).send({test: 'Testing functions'});
})
该函数位于此网址中:https://us-central1-fba-shipper-140ae.cloudfunctions.net/test
Firebase 文档建议在函数中添加 CORS 中间件,我已经尝试过,但它对我不起作用:https://firebase.google.com/docs/functions/http-events
我是这样做的:
var cors = require('cors');
exports.test = functions.https.onRequest((request, response) => {
cors(request, response, () => {
response.status(500).send({test: 'Testing functions'});
})
})
我究竟做错了什么?我将不胜感激。
更新:
Doug Stevenson 的回答有所帮助。添加 ({origin: true}) 解决了这个问题,我还不得不将 response.status(500)
更改为 response.status(200)
,我一开始完全错过了。
Firebase 团队提供了两个 sample functions 来演示 CORS 的使用:
具有日期格式的时间服务器
需要身份验证的 HTTPS 端点
第二个示例使用与您当前使用的不同的方式处理 cors。
考虑像这样导入,如示例所示:
const cors = require('cors')({origin: true});
你的函数的一般形式是这样的:
exports.fn = functions.https.onRequest((req, res) => {
cors(req, res, () => {
// your function body here - use the provided req and res from cors
})
});
您可以像这样在云功能中设置 CORS
response.set('Access-Control-Allow-Origin', '*');
无需导入 cors
包
Authorization
标头时。以上似乎工作正常。
http
而不是 https
。
对于尝试在 Typescript 中执行此操作的任何人,这是代码:
import * as cors from 'cors';
const corsHandler = cors({origin: true});
export const exampleFunction= functions.https.onRequest(async (request, response) => {
corsHandler(request, response, () => {});
//Your code here
});
corsHandler(request, response, () => { YOUR CODE HERE });
还有一条信息,只是为了那些在一段时间后使用谷歌搜索的人:如果您使用的是 firebase 托管,您还可以设置重写,以便例如 (firebase_hosting_host)/api/myfunction 之类的 url 重定向到 ( firebase_cloudfunctions_host)/doStuff 函数。这样,由于重定向是透明的并且是服务器端的,因此您不必处理 cors。
您可以使用 firebase.json 中的 rewrites 部分进行设置:
"rewrites": [
{ "source": "/api/myFunction", "function": "doStuff" }
]
没有 CORS 解决方案对我有用……直到现在!
不知道其他人是否遇到了与我相同的问题,但我设置了 5 种与我发现的示例不同的方式来设置 CORS,但似乎没有任何效果。我用 Plunker 建立了一个最小的例子,看看它是否真的是一个错误,但这个例子运行得很好。我决定检查 firebase 函数日志(在 firebase 控制台中找到),看看是否能告诉我任何信息。我的节点服务器代码中有几个错误,与 CORS 无关,当我调试时释放了我的 CORS 错误消息。我不知道为什么与 CORS 无关的代码错误会返回 CORS 错误响应,但它让我在错误的兔子洞里呆了好几个小时……
tl;dr - 如果没有 CORS 解决方案有效,请检查您的 firebase 功能日志并调试您遇到的任何错误
Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com
,所以基本上超出了免费配额并且函数返回了 cors 错误
access to external network resources not allowed if the billing account is not enabled
。启用计费帐户后,它可以完美运行。这也是与 cors 无关的示例之一,但会引发 cors 错误。
firebase use <project-name>
)下登录。
我对@Andreys 对他自己的问题的回答有一点补充。
似乎您不必在 cors(req, res, cb)
函数中调用回调,因此您只需调用函数顶部的 cors 模块,而无需将所有代码嵌入回调中。如果您想在之后实施 cors,这要快得多。
exports.exampleFunction = functions.https.onRequest((request, response) => {
cors(request, response, () => {});
return response.send("Hello from Firebase!");
});
不要忘记在开篇文章中提到的初始化 cors:
const cors = require('cors')({origin: true});
更新:任何需要时间的响应函数都会冒这个实现出现 CORS 错误的风险,因为它没有适当的 async/await。不要在返回静态数据的快速原型设计端点之外使用。
cors(request, response, () => { return response.send("Hello from Firebase!"); });
更新答案:使用支持 Typescript 的 cors
库:
安装cors
npm i -S cors
npm i --save-dev @types/cors
index.ts
:
import * as cors from "cors";
const corsHandler = cors({ origin: true });
// allow cors in http function
export const myFunction = functions.https.onRequest((req, res) => {
corsHandler(req, res, async () => {
// your method body
});
});
旧答案:(不再工作)
找到了一种无需导入任何“cors”库即可启用 cors 的方法。它也适用于 Typescript
并在 chrome 版本 81.0 中进行了测试。
exports.createOrder = functions.https.onRequest((req, res) => {
// browsers like chrome need these headers to be present in response if the api is called from other than its base domain
res.set("Access-Control-Allow-Origin", "*"); // you can also whitelist a specific domain like "http://127.0.0.1:4000"
res.set("Access-Control-Allow-Headers", "Content-Type");
// your code starts here
//send response
res.status(200).send();
});
res.set("Access-Control-Allow-Origin", "*")
;只是没有工作res.set("Access-Control-Allow-Headers", "Content-Type");
解决了我的问题
cors
包(或重新创建 OPTIONS
特殊响应,这最终带来的麻烦多于其价值)
这可能会有所帮助。我使用 express(自定义 URL)创建了 firebase HTTP 云功能
const express = require('express');
const bodyParser = require('body-parser');
const cors = require("cors");
const app = express();
const main = express();
app.post('/endpoint', (req, res) => {
// code here
})
app.use(cors({ origin: true }));
main.use(cors({ origin: true }));
main.use('/api/v1', app);
main.use(bodyParser.json());
main.use(bodyParser.urlencoded({ extended: false }));
module.exports.functionName = functions.https.onRequest(main);
请确保您添加了重写部分
"rewrites": [
{
"source": "/api/v1/**",
"function": "functionName"
}
]
如果您不/不能使用 cors 插件,首先在处理函数中调用 setCorsHeaders()
函数也可以。
回复时也使用 respondSuccess/Error 函数。
const ALLOWED_ORIGINS = ["http://localhost:9090", "https://sub.example.com", "https://example.com"]
// Set CORS headers for preflight requests
function setCorsHeaders (req, res) {
var originUrl = "http://localhost:9090"
if(ALLOWED_ORIGINS.includes(req.headers.origin)){
originUrl = req.headers.origin
}
res.set('Access-Control-Allow-Origin', originUrl);
res.set('Access-Control-Allow-Credentials', 'true');
if (req.method === 'OPTIONS') {
// Send response to OPTIONS requests
res.set('Access-Control-Allow-Methods', 'GET,POST','PUT','DELETE');
res.set('Access-Control-Allow-Headers', 'Bearer, Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
}
}
function respondError (message, error, code, res) {
var response = {
message: message,
error: error
}
res.status(code).end(JSON.stringify(response));
}
function respondSuccess (result, res) {
var response = {
message: "OK",
result: result
}
res.status(200).end(JSON.stringify(response));
}
使用 Google Cloud Console 仪表板的简单解决方案:
转到您的 GCP 控制台信息中心:
https://console.cloud.google.com/home/dashboard
前往菜单
“云功能”(“计算”部分)
选择您的云功能,例如“MyFunction”,右侧应出现一个侧面菜单,显示其访问控制设置单击“添加成员”,输入“allUsers”并选择角色“Cloud Function Invoker”保存 - > 现在,您应该在云功能列表中看到“允许未经身份验证”的备注
现在,互联网上的每个人都可以通过正确的配置访问您的 GCP 或 Firebase 项目。 (当心)
如果有像我这样的人:如果你想从同一个项目中调用云函数作为它自己的云函数,你可以初始化 firebase sdk 并使用 onCall 方法。它将为您处理一切:
exports.newRequest = functions.https.onCall((data, context) => {
console.log(`This is the received data: ${data}.`);
return data;
})
像这样调用这个函数:
// Init the firebase SDK first
const functions = firebase.functions();
const addMessage = functions.httpsCallable(`newRequest`);
Firebase 文档:https://firebase.google.com/docs/functions/callable
如果您无法在此处初始化 SDK,请参阅其他建议的精髓:
如果您在默认位置使用 firebase 托管和托管,请选择重写:https://firebase.google.com/docs/hosting/full-config#rewrites
或者像 krishnazden 建议的那样使用 CORS:https://stackoverflow.com/a/53845986/1293220
只有这种方式对我有用,因为我在我的请求中有授权:
exports.hello = functions.https.onRequest((request, response) => {
response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Credentials', 'true'); // vital
if (request.method === 'OPTIONS') {
// Send response to OPTIONS requests
response.set('Access-Control-Allow-Methods', 'GET');
response.set('Access-Control-Allow-Headers', 'Content-Type');
response.set('Access-Control-Max-Age', '3600');
response.status(204).send('');
} else {
const params = request.body;
const html = 'some html';
response.send(html)
} )};
如果您没有在函数中捕获错误,则可能会发生 cors 错误。我的建议是在您的 corsHandler 中实现 try catch
const corsHandler = (request, response, handler) => {
cors({ origin: true })(request, response, async () => {
try {
await handler();
}
catch (e) {
functions.logger.error('Error: ' + e);
response.statusCode = 500;
response.send({
'status': 'ERROR' //Optional: customize your error message here
});
}
});
};
用法:
exports.helloWorld = functions.https.onRequest((request, response) => {
corsHandler(request, response, () => {
functions.logger.info("Hello logs!");
response.send({
"data": "Hello from Firebase!"
});
});
});
感谢 stackoverflow 用户:Hoang Trinh、Yayo Arellano 和 Doug Stevenson
我刚刚发表了一篇关于此的文章:
https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-functions.html
通常,您应该使用 Express CORS package,这需要稍微修改一下才能满足 GCF/Firebase 函数中的要求。
希望有帮助!
将 true
更改为 "*"
对我有用,所以它看起来像这样:
const cors = require('cors')({ origin: "*" })
我尝试了这种方法,因为通常这是设置此响应标头的方式:
'Access-Control-Allow-Origin', '*'
请注意,这将允许任何域调用您的端点,因此它不安全。
此外,您可以阅读以下文档的更多信息:https://github.com/expressjs/cors
将 app
传递给 onRequest
时,我遇到了同样的问题。我意识到这个问题是 firebase 函数的请求 url 上的斜杠。 Express 正在寻找 '/'
,但函数 [project-id].cloudfunctions.net/[function-name]
上没有斜杠。 CORS 错误是假阴性。当我添加斜杠时,我得到了我期望的响应。
[project-id]
,因为这是我遇到的问题
进入你的谷歌云函数。您以前可能没有见过这个平台,但它是您解决这个 Firebase 问题的方法。找到您要搜索的 Firebase 函数,然后点击名称。如果此页面为空白,您可能需要搜索 Cloud Functions 并从结果中选择页面。找到你的函数,点击名字。转到权限选项卡。单击添加(添加用户)。在新原则下,输入“allUsers”——它应该在你完成输入之前自动完成。在选择角色下,搜索 Cloud Functions,然后选择 Invoker。节省。等几分钟。
这应该解决它。如果没有,请执行此操作并将 CORS 解决方案添加到您的函数代码中,例如:
exports.sendMail = functions.https.onRequest((request, response) => {
response.set("Access-Control-Allow-Origin", "*");
response.send("Hello from Firebase!");
});
如果您不使用 Express 或只是想使用 CORS。以下代码将帮助解决
const cors = require('cors')({ origin: true, });
exports.yourfunction = functions.https.onRequest((request, response) => {
return cors(request, response, () => {
// *Your code*
});
});
如果您在本地测试 firebase 应用程序,则需要将函数指向 localhost
而不是云。默认情况下,当您在 Web 应用程序上使用 firebase serve
或 firebase emulators:start
时,会将函数指向服务器而不是 localhost。
在 firebase 初始化脚本之后的 html 头中添加以下脚本:
<script>
firebase.functions().useFunctionsEmulator('http://localhost:5001')
</script>
确保在将代码部署到服务器时删除此代码段。
我收到错误是因为我正在调用客户端不存在的函数。例如:
firebase.functions().httpsCallable('makeSureThisStringIsCorrect');
补充一下我的经验。我花了几个小时试图找出出现 CORS 错误的原因。
碰巧我重命名了我的云功能(在大升级后我第一次尝试)。
因此,当我的 firebase 应用程序使用不正确的名称调用云函数时,它应该抛出 404 错误,而不是 CORS 错误。
修复我的 firebase 应用程序中的云函数名称解决了这个问题。
我在这里填写了一份错误报告https://firebase.google.com/support/troubleshooter/report/bugs
从这么多搜索中,我可以在同一个 firebase 文档中找到这个解决方案,只需在路径中实现 cors:
import * as express from "express";
import * as cors from "cors";
const api = express();
api.use(cors({ origin: true }));
api.get("/url", function);
链接 firebase 文档:https://firebase.google.com/docs/functions/http-events
如果您更喜欢制作单个处理函数 (reference answer)
const applyMiddleware = handler => (req, res) => {
return cors(req, res, () => {
return handler(req, res)
})
}
exports.handler = functions.https.onRequest(applyMiddleware(handler))
我是 Firebase 的初学者(30 分钟前注册)。我的问题是我调用了我的端点
https://xxxx-default-rtdb.firebaseio.com/myendpoint
代替
https://xxxx-default-rtdb.firebaseio.com/myendpoint.json
如果您刚开始使用 Firebase,请确保不要忘记 .json
扩展程序。
我已经尝试了很长时间。
当我进行此更改时,它终于奏效了。
app.get('/create-customer', (req, res) => {
return cors()(req, res, () => {
... your code ...
最大的不同是我使用 cors()(req, res...
而不是直接使用 cors(req, res...
它现在完美运行。
在 devtool 控制台中使用相同的访问允许控制源错误,我发现了其他具有更现代语法的解决方案:
我的 CORS 问题在于存储(而不是 RTDB,也不是浏览器......),然后我没有信用卡(按照上述解决方案的要求),我的无信用卡解决方案是:
安装 gsutil : https://cloud.google.com/storage/docs/gsutil_install#linux-and-macos 创建一个 cors.json 文件,通过终端使用 gsutil 加载
gsutil cors set cors.json gs://[ your-bucket ]/-1.appspot.com
https://firebase.google.com/docs/storage/web/download-files#cors_configuration
如果其他解决方案都不起作用,您可以尝试在调用开始时添加以下地址以启用 CORS - 重定向:
https://cors-anywhere.herokuapp.com/
带有 JQuery AJAX 请求的示例代码:
$.ajax({
url: 'https://cors-anywhere.herokuapp.com/https://fir-agilan.web.app/gmail?mail=asd@gmail.com,
type: 'GET'
});
请参阅下文,了解我如何使用 CORS 设置我的 Express。
“https://pericope.app”是我的 Firebase 项目的自定义域。
看起来所有其他答案都推荐 origin:true
或 *
。
我很犹豫是否允许所有来源,因为它会允许其他任何人访问 api。如果您正在创建公共服务,那很好,但如果您对数据做任何事情,那是有风险的,因为它是一个特权环境。例如,此管理 SDK 会绕过您为 Firestore 或 Storage 设置的任何安全规则。
//Express
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors({
origin: 'https://pericope.app'
}));
在您的 https.onRequest 上使用 cors 和 Typescript,如下所示:
import * as cors from 'cors';
const corsHandler = cors({origin: true});
export const pingFunctionWithCorsAllowed = functions.https.onRequest((request, response) => {
corsHandler(request, response, () => {
response.send(`Ping from Firebase (with CORS handling)! ${new Date().toISOString()}`);
});
});
来自Source
不定期副业成功案例分享
origin: true
允许任何域访问? (npmjs.com/package/cors)@Doug Stevenson 您认为 firebase 可以就客户端/服务器 https 功能所需的基础知识编写文档吗?示例 repo 很好,但我们错过了这个额外的要求。const cors = require('cors')({origin: true});
,但事实并非如此