在Firebase的云功能中启用CORS

我目前正在学习如何使用Firebase的新云函数,我遇到的问题是我无法访问我通过AJAX请求编写的函数。我得到了“No Access-Control-Allow-Origin”;错误。下面是我写的函数示例:

exports.test = functions.https.onRequest((request, response) => {
response.status(500).send({test: 'Testing functions'});
})
函数位于下面的url中: https://us-central1-fba-shipper-140ae.cloudfunctions.net/test < / p >

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'});
})
})

我做错了什么?如果你能帮我,我会很感激。

更新:

道格·史蒂文森的回答有帮助。添加({origin: true})解决了这个问题,我还必须将response.status(500)更改为response.status(200),这是我一开始完全错过的。

208285 次浏览

Firebase团队提供了两个样品的功能来演示CORS的使用:

第二个示例使用与当前使用的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
})
});

我刚刚发表了一篇关于这方面的文章:

https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-functions.html

一般来说,你应该使用Express 歌珥包,这需要一些hack来满足GCF/Firebase Functions中的要求。

希望有帮助!

一个额外的信息,只是为了那些在一段时间后谷歌这个:

如果你正在使用firebase托管,你也可以设置重写,例如,像(firebase_hosting_host)/api/myfunction这样的url重定向到(firebase_cloudfunctions_host)/doStuff函数。这样,由于重定向是透明的并且是服务器端的,所以您不必处理cors。

你可以用firebase.json中的rewrites部分来设置:

"rewrites": [
{ "source": "/api/myFunction", "function": "doStuff" }
]

我对安德烈自己的问题有一些补充。

看起来你不需要在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。不要在返回静态数据的快速原型端点之外使用。

对于任何试图在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
});

没有CORS解决方案对我有效…直到现在!

不确定其他人是否遇到了和我一样的问题,但我从我找到的例子中设置了5种不同的CORS方法,似乎都不起作用。我用Plunker建立了一个最小的例子,看看它是否真的是一个bug,但这个例子运行得很漂亮。我决定检查firebase函数日志(在firebase控制台中找到),看看是否可以告诉我一些东西。我在节点服务器代码中有几个错误与CORS无关,当我调试释放了我的CORS错误信息。我不知道为什么与CORS无关的代码错误会返回CORS错误响应,但它把我带进了错误的兔子洞好几个小时……

dr -如果没有CORS解决方案工作,检查您的firebase函数日志并调试任何错误

在云函数中可以这样设置CORS

response.set('Access-Control-Allow-Origin', '*');

不需要导入cors

无论如何,我在将app传递给onRequest时也遇到了同样的问题。我意识到问题在于firebase函数的请求url上的末尾斜杠。Express正在寻找'/',但我在函数[project-id].cloudfunctions.net/[function-name]上没有后面的斜杠。CORS的错误是假阴性。当我添加后面的斜杠时,我得到了我所期待的响应。

如果您不使用Express或只想使用CORS。下面的代码将帮助解决这个问题

const cors = require('cors')({ origin: true, });
exports.yourfunction = functions.https.onRequest((request, response) => {
return cors(request, response, () => {
// *Your code*
});
});

只有这种方式对我有效,因为我在我的请求中有授权:

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)
} )};
这可能会有帮助。 我创建了firebase HTTP云函数与express(自定义URL)

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"
}
]

如果有像我这样的人:如果你想在同一个项目中调用云函数,你可以init 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 docs: https://firebase.google.com/docs/functions/callable

如果你不能初始化SDK,以下是其他建议的精髓:

如果你在本地测试firebase应用程序,那么你需要将函数指向localhost而不是云。默认情况下,当你在你的web应用程序上使用它时,firebase servefirebase emulators:start将函数指向服务器而不是localhost。

在firebase初始化脚本后的html头中添加以下脚本:

 <script>
firebase.functions().useFunctionsEmulator('http://localhost:5001')
</script>

确保在将代码部署到服务器时删除此代码段。

如果你不/不能使用cors插件,在handler函数中首先调用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));
}

在我的例子中,错误是由云函数调用者限制访问引起的。请将allUsers添加到云函数调用器。请抓住链接。更多信息请参考文章

"*"更改true对我来说很有用,所以它看起来是这样的:

const cors = require('cors')({ origin: "*" })

我尝试了这种方法,因为在一般情况下,这是响应头的设置方式:

'Access-Control-Allow-Origin', '*'

请注意,这将允许任何域调用您的端点,因此它是不安全的。

此外,你可以阅读更多关于文档的内容: https://github.com/expressjs/cors < / p >

答:更新使用cors库与Typescript支持:

安装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


});
});

< p >老回答: (not working anymore)
找到了一种不导入任何“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();
});

如果其他解决方案都不起作用,您可以尝试在呼叫开始时添加以下地址以启用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错误

碰巧我重命名了云函数(第一个我尝试后的大升级)。

因此,当我的firebase应用程序使用错误的名称调用云函数时,它应该抛出404错误,而不是CORS错误。

修复我的firebase应用程序中的云函数名称修复了这个问题。

我在这里填了一份关于这个的错误报告 https://firebase.google.com/support/troubleshooter/report/bugs < / p >

使用谷歌云控制台仪表板的简单解决方案:

  1. 转到GCP控制台仪表板:

https://console.cloud.google.com/home/dashboard

  1. 进入菜单

“云Functions"(“Compute"部分)

  1. 选择您的云功能,例如“myfunction”,右侧会出现一个侧菜单,显示它的访问控制设置

  2. 点击“添加成员”,输入“alluser”;选择角色“Cloud Function invoker”;

  3. 保存->现在,您应该看到一个注释&;Allow unauthenticated&;在您的云函数列表中

现在每个人都可以通过正确的配置访问您的GCP或Firebase项目。(小心)

如果没有捕获函数中的错误,就会发生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用户:黄平君陈Yayo Arellano道格·史蒂文森

通过这么多的搜索,我可以在相同的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 doc: https://firebase.google.com/docs/functions/http-events

请参阅下面我如何设置我的快车与CORS。

“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'
}));

如果你想创建单一处理函数 (参考答案)

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...

它现在工作得很完美。

我得到了错误,因为我调用了一个在客户端不存在的函数。例如:

firebase.functions().httpsCallable('makeSureThisStringIsCorrect');

在https上使用cors。使用打印稿的onRequest,如下所示:

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()}`);
});
});

云功能日志有助于检查您是否卡住了。

我的问题原来是我的云函数上的一个类型错误,我有一个数字,其中一个字符串是预期的:

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received type number (1)

出于某种原因,这给了我cors错误的前端,它成为了几个小时的浪费。

  1. 进入你的谷歌云函数。您以前可能没有见过这个平台,但它是解决Firebase问题的方法。
  2. 找到您正在搜索的Firebase函数并单击名称。如果此页为空白,您可能需要搜索“云功能”并从结果中选择该页。
  3. 找到你的函数,点击名称。
  4. 转到权限选项卡。单击“添加”(添加用户)。
  5. 在新的原则下,输入'allUsers' -它应该在你完成输入之前自动完成。
  6. 在“选择角色”下,搜索“云功能”,然后选择“调用器”。
  7. 保存。
  8. 等几分钟。

这应该能解决问题。如果没有,就这样做,并在你的函数代码中添加一个CORS解决方案,比如:

  exports.sendMail = functions.https.onRequest((request, response) => {
response.set("Access-Control-Allow-Origin", "*");
response.send("Hello from Firebase!");
});

在devtool控制台中,同样的访问允许控制源错误,我找到了其他具有更现代语法的解决方案:

我的CORS问题是存储(不是RTDB也不是浏览器…),然后我没有信用卡(正如上述解决方案所要求的那样),我的无信用卡解决方案是:

  1. install gsutil: https://cloud.google.com/storage/docs/gsutil_install#linux-and-macos < / p >

  2. 创建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

Firebase v2的云功能

Firebase v2的云功能现在允许你直接在HTTP选项中配置cors。它的工作不需要任何第三方软件包:


import { https } from 'firebase-functions/v2';


export myfunction = https.onRequest({ cors: true }, async (req, res) => {
// this will be invoked for any request, regardless of its origin
});

请注意:

  • 在撰写本文时,__abc0处于公开预览中。
  • 目前v2中只有一个区域的子集是支持
  • 函数名被限制为小写字母、数字和破折号。
  • 你可以在一个代码库中同时使用v1v2函数。为了提高可读性,请更新导入以分别访问firebase-functions/v1firebase-functions/v2