在Firebase的云功能中启用CORS


140

我目前正在学习如何为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)的回答很有帮助。添加({产地:真})固定的问题,我也不得不改变response.status(500)response.status(200)我完全错过了在第一。



我有一些功能可与提供的解决方案一起使用,但现在正在尝试一个新功能,该功能实际上将打开的图形添加到index.html的顶部,并返回更新的index.html,但我无法使其正常工作:(不断获取访问控制---错误
TheeBen'Apr

2
像上面那样将传入的请求包装在cors()中是唯一对我有用的方法
Charles Harring

您可以编辑“更新”以强调需要cors中间件吗?这将节省一些时间
Antoine Weber

Answers:


151

Firebase团队提供了两个示例函数来演示CORS的使用:

第二个示例使用的cors使用的方式与当前使用的方式不同。

另外,请考虑像这样导入,如示例所示:

const cors = require('cors')({origin: true});

2
谢谢!添加({origin:true})有所帮助。
Andrey Pokrovskiy

2
尼斯,你肯定需要origin: true为留出来将导致此不工作
斯科特

4
看起来这是定义允许访问的域白名单的地方?并设置origin: true允许任何域访问?(npmjs.com/package/cors)@Doug Stevenson您认为firebase可以编写有关客户端/服务器https功能所需的基础知识的文档吗?样本仓库很好,但是我们错过了额外的需求。
艾伦(Alan)

9
对于愿意在后端添加CORS支持的任何人:请确保您了解后果以及如何正确配置它。“ origin:true”对于测试很酷,但是却无法达到目的:)
dSebastien

1
谷歌云功能不允许通配符产地:cloud.google.com/functions/docs/writing/...
科里·科尔

73

您可以像这样在云功能中设置CORS

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

无需导入cors


2
对于我的情况而言,这是完美的工作,一个云功能可以对Mailchimp API进行XHR调用。
elverde

1
那就是需要的答案。
吉米·凯恩

1
谷歌云功能不允许通配符产地:cloud.google.com/functions/docs/writing/...
科里·科尔

4
@CoreyCole我认为只有在您需要添加Authorization标题时才这样。以上似乎工作正常。
Stuart Memo

这行代码放在哪里?云功能的哪一部分?
Antonio Ooi

41

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

3
解决方案将使您失去对云功能的日志记录(非常糟糕)和正确的异步/等待功能,您可能会担心函数内容在长调用中在回调内提前结束。
奥利弗·迪克森

2
谷歌云功能不允许通配符产地:cloud.google.com/functions/docs/writing/...
科里·科尔

29

一条额外的信息,只是为了在一段时间后使用Google进行搜索:如果您使用的是Firebase托管,还可以设置重写,例如,例如(firebase_hosting_host)/ api / myfunction的url重定向到( firebase_cloudfunctions_host)/ doStuff函数。这样,由于重定向是透明的并且是服务器端的,因此您不必处理cors。

您可以在firebase.json中通过重写部分进行设置:

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

1
imo,这是最好的答案,因为它可以解决实际问题而不添加任何其他安全问题。这样,云功能便与其余功能在同一域中提供服务,您甚至不需要任何附加费用。
koljaTM

3
确实,这是一个很棒的功能,但是当前仅在功能位于默认区域(us-central1)中时才有效。由于延迟原因,我想将功能部署到europe-west1并遇到了这个问题:github.com/firebase/firebase-tools/issues/842
Alex Suzuki,

重定向工作正常,并使URL更加整洁,但是我还没有弄清楚如何传递GET参数。该函数(重写后)似乎在没有参数的情况下被调用。
royappa '19

20

到目前为止,没有CORS解决方案对我有用。

不知道是否有人遇到过与我相同的问题,但是我以与发现的示例不同的5种方式设置了CORS,但似乎没有任何效果。我与Plunker一起建立了一个最小的示例,以查看它是否确实是一个错误,但是示例运行得很好。我决定检查firebase函数日志(在firebase控制台中找到),看看是否可以告诉我任何事情。我在节点服务器的代码有一对夫妇的错误不CORS相关的,当我调试释放了我CORS错误消息。我不知道为什么与CORS无关的代码错误会返回CORS错误响应,但是它导致我在错误的兔子洞中呆了好几个小时...

tl; dr-检查您的Firebase功能日志是否没有CORS解决方案,并调试您拥有的任何错误


1
这让我发疯。就我而言,这甚至不是代码错误!有人 Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com 因此基本上是免费的配额超出和函数返回CORS错误
斯坦尼斯洛斯Buzunko

在这里发生两次,从服务器以及cors返回相同的错误:错误:内部基本上是错误。如果运行错误的函数(例如,错误输入函数名称),也会发生此错误
HenrikBøgelundLavstsen,

当您尝试在云功能中请求Google reCAPTCHA验证时,浏览器也会抛出CORS错误。当我检查Firebase控制台功能日志时,显示access to external network resources not allowed if the billing account is not enabled。启用结算帐户后,它可以正常运行。这也是与非cors相关的示例之一,但是会引发cors错误。
安东尼奥伊

19

除了@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});


1
当其他SO手动设置标题的答案不起作用时,此方法有效
Jim Factor

此方法有效,但是如果启用它会导致TSlint错误,并且无法部署到Firebase。将响应放入cors封闭中以克服该问题cors(request, response, () => { return response.send("Hello from Firebase!"); });
螺旋

1
伙计们,这里有2个错误。第一。cors函数之后的所有内容都会运行两次(因为第一个请求是预检)。不好。其次,@ SpiralOut解决方案将使您失去对云功能的日志记录(非常糟糕)以及正确的异步/等待功能,您可能会担心函数内容在回调中提前结束。
奥利弗·迪克森

@SpiralOut你可以简单地禁用tslint
弗拉德

1
去年,我已经学到了很多有关gcf的知识,所以我不再推荐这个答案。快速原型可能会很方便,但在实际生产中应避免使用
Jaap Weijland

11

这可能会有所帮助。我用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"
      }
]

1
你的答案太低了,我的朋友,到目前为止最好的答案。
阿夫兰·维吉尔

谢谢。@AvramVirgil
桑迪

这是最快,最简单的方法,谢谢!
Gaurav Kakkar

8

我刚刚发表了一点关于:

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

通常,您应该使用Express CORS软件包,该软件包需要一些修改才能满足GCF / Firebase Functions中的要求。

希望有帮助!


4
不知道黑客是什么意思?介意详细一点吗?阅读您的文章,但我看不到您提及它
TheeBen

1
这里是cors模块的作者;mhaligowski所说的“黑客攻击”只是意味着他必须将对cors模块的调用包装起来,以使其与Express调用中间件的方式相匹配(即,在请求和响应之后提供函数作为第三参数)
Troy

4

如果外面有像我这样的人:如果您想从与自己的云函数相同的项目中调用云函数,则可以初始化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,则这里是其他建议的本质:


3
实际上,当我在浏览器上使用onCall函数时,出现了cors错误。我可以在此请求中设置costom标头吗?
维克多·哈杜贝

4

找到了一种无需导入任何“ cors”库即可启用cors的方法。它还可以与Typescriptchrome版本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();
});

3

值得的是,app进入时我遇到了同样的问题onRequest。我意识到问题是firebase函数的请求网址末尾有一个斜杠。Express在寻找,'/'但是我没有在函数上加上斜线[project-id].cloudfunctions.net/[function-name]。CORS错误是假阴性。当我添加结尾斜杠时,我得到了期望的响应。


还请确保添加您的内容,[project-id]因为这是我面临的问题
拔下电源

3

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

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

谷歌云功能不允许通配符产地:cloud.google.com/functions/docs/writing/...
科里·科尔

3

如果您不/不能使用cors插件,则setCorsHeaders()在处理程序函数中首先调用该函数也将起作用。

回复时,请同时使用responseSuccess / 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));
}

2

如果您要在本地测试Firebase应用,则需要将功能指向localhost而不是云。默认情况下,firebase servefirebase emulators:start在Web应用程序上将功能指向服务器而不是localhost时使用。

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

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

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


2

改变对我来说true"*"成功的窍门,所以它看起来像这样:

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

我尝试了这种方法,因为通常,这是设置此响应标头的方式:

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

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

此外,您可以在文档上阅读更多信息:https : //github.com/expressjs/cors


1

如果您不使用Express或只是想使用CORS。以下代码将有助于解决

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

0

在我的情况下,该错误是由云函数调用程序限制访问引起的。请将allUsers添加到云函数调用程序。请点击链接。请参阅文章以获取更多信息


请在您的答案中提供链接材料的说明,为什么如此相关
Firefly

0

如果其他解决方案均无效,则可以尝试在呼叫开始时添加以下地址以启用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'
});

0

增加我的经验。我花了几个小时试图找出为什么我有CORS错误。

碰巧,我已经重命名了我的云功能(在进行大升级之后,我第一次尝试使用该功能)。

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

在我的Firebase应用程序中修复云函数名称可解决此问题。

我在这里https://firebase.google.com/support/troubleshooter/report/bugs填写了有关此问题的错误报告

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.