224

我目前正在学习如何为 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)

4

30 回答 30

219

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
    })
});
于 2017-03-13T04:27:20.163 回答
124

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

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

无需导入cors

于 2018-08-19T23:10:32.933 回答
68

对于尝试在 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
});
于 2018-06-22T16:29:15.573 回答
48

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

您可以使用 firebase.json 中的 rewrites 部分进行设置:

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]
于 2017-11-28T15:09:12.777 回答
30

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

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

tl;dr - 如果没有 CORS 解决方案有效,请检查您的 firebase 功能日志并调试您遇到的任何错误

于 2018-06-29T13:37:42.983 回答
23

我对@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。不要在返回静态数据的快速原型设计端点之外使用。

于 2018-01-17T12:17:09.203 回答
15

这可能会有所帮助。我使用 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"
      }
]
于 2019-04-01T23:43:31.500 回答
13

更新答案:使用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

 });
});

旧答案:(不再工作)
找到了一种无需导入任何“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();
});
于 2020-05-15T19:57:13.160 回答
10

如果您不/不能使用 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));
}
于 2019-12-23T12:29:15.720 回答
8

使用 Google Cloud Console 仪表板的简单解决方案:

  1. 转到您的 GCP 控制台信息中心:

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

  1. 前往菜单

“云功能”(“计算”部分)

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

  2. 点击“添加成员”,输入“allUsers”并选择角色“Cloud Function Invoker”

  3. 保存 -> 现在,您应该会在云功能列表中看到“允许未经身份验证”的备注

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

于 2020-08-13T15:07:14.360 回答
6

如果有像我这样的人:如果您想从与云功能相同的项目中调用云功能,您可以初始化 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,请参阅其他建议的精髓:

于 2019-07-26T21:10:37.913 回答
5

我刚刚发表了一篇关于此的文章:

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

通常,您应该使用 Express CORS 包,这需要稍微修改一下才能满足 GCF/Firebase 函数中的要求。

希望有帮助!

于 2017-03-13T05:13:49.690 回答
5

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

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)
} )};
于 2018-12-30T20:16:08.920 回答
5

如果您没有在函数中捕获错误,则可能会发生 cors 错误。我的建议是try catch在你的 corsHandler中实现

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 TrinhYayo ArellanoDoug Stevenson

于 2020-12-03T14:12:11.493 回答
4

改变trueby"*"对我有用,所以它是这样的:

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

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

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

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

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

于 2020-05-05T23:41:40.267 回答
3

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

于 2018-08-21T16:15:45.800 回答
2

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

const cors = require('cors')({ origin: true, });   
exports.yourfunction = functions.https.onRequest((request, response) => {  
   return cors(request, response, () => {  
        // *Your code*
    });
});
于 2018-12-19T06:51:11.110 回答
2

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

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

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

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

于 2019-11-27T19:30:56.303 回答
2

我收到错误是因为我正在调用客户端不存在的函数。例如:

firebase.functions().httpsCallable('makeSureThisStringIsCorrect');
于 2021-05-30T01:09:54.400 回答
1

补充一下我的经验。我花了几个小时试图找出出现 CORS 错误的原因。

碰巧我重命名了我的云功能(在大升级后我第一次尝试)。

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

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

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

于 2020-07-21T12:36:21.973 回答
1

从这么多搜索中,我可以在同一个 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

于 2021-02-19T23:21:33.290 回答
1

如果您更喜欢制作单个处理函数参考答案

const applyMiddleware = handler => (req, res) => {
  return cors(req, res, () => {
    return handler(req, res)
  })
}
exports.handler = functions.https.onRequest(applyMiddleware(handler))
于 2021-03-12T00:49:28.847 回答
1

我是 Firebase 的初学者(30 分钟前注册)。我的问题是我调用了我的端点

https://xxxx-default-rtdb.firebaseio.com/myendpoint

代替

https://xxxx-default-rtdb.firebaseio.com/myendpoint.json

如果您刚开始使用 Firebase,请确保不要忘记.json扩展。

于 2021-03-21T05:11:05.030 回答
1
  1. 进入您的Google Cloud Functions。您以前可能没有见过这个平台,但它是您解决这个 Firebase 问题的方法。
  2. 找到您要搜索的 Firebase 函数,然后点击名称。如果此页面为空白,您可能需要搜索 Cloud Functions 并从结果中选择页面。
  3. 找到你的函数,点击名字。
  4. 转到权限选项卡。单击添加(添加用户)。
  5. 在新原则下,输入“allUsers”——它应该在你完成输入之前自动完成。
  6. 在选择角色下,搜索 Cloud Functions,然后选择 Invoker。
  7. 节省。
  8. 等几分钟。

这应该解决它。如果没有,请执行此操作并将 CORS 解决方案添加到您的函数代码中,例如:

  exports.sendMail = functions.https.onRequest((request, response) => {
  response.set("Access-Control-Allow-Origin", "*");
  response.send("Hello from Firebase!");
});
于 2022-01-05T11:41:03.533 回答
0

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

于 2020-04-14T16:52:56.580 回答
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'
});
于 2020-06-10T07:46:44.507 回答
0

请参阅下文,了解我如何使用 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'
}));
于 2021-03-11T18:51:06.707 回答
0

我已经尝试了很长时间。

当我进行此更改时,它终于奏效了。

app.get('/create-customer', (req, res) => {
  return cors()(req, res, () => {
    ... your code ...

最大的不同是我使用cors()(req, res...而不是直接使用cors(req, res...

它现在完美运行。

于 2021-04-02T23:20:35.420 回答
0

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

源头

于 2021-05-30T17:02:56.807 回答
0

云功能日志记录会有所帮助,请检查您是否卡住了。

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

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 错误,并且浪费了几个小时。

于 2021-08-21T06:50:54.607 回答