ChatGPT解决这个技术问题 Extra ChatGPT

在 Cloud Functions for Firebase 中启用 CORS

我目前正在学习如何为 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),我一开始完全错过了。

也是文档中的示例here
我有一些功能可以与提供的解决方案一起使用,但现在我正在尝试一个新功能,它基本上将打开的图形添加到我的 index.html 顶部并返回更新后的 index.html,但我无法让它工作:( 继续访问控制---错误
像上面那样将传入的请求包装在 cors() 中是唯一对我有用的东西
您可以编辑您的“更新”以强调需要 cors 中间件吗?这将为一些人节省一些时间

D
Doug Stevenson

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

看起来这是定义允许访问的域白名单的地方?并且设置 origin: true 允许任何域访问? (npmjs.com/package/cors)@Doug Stevenson 您认为 firebase 可以就客户端/服务器 https 功能所需的基础知识编写文档吗?示例 repo 很好,但我们错过了这个额外的要求。
对于愿意在其后端添加 CORS 支持的任何人:请确保您了解后果以及如何正确配置它。 “origin: true”对于测试来说很酷,但它违背了整个目的:)
谷歌云函数不允许使用通配符来源:cloud.google.com/functions/docs/writing/…
只是提醒大家像 Doug 出色地提到的那样导入 cors,不要忘记像 Andrey 那样包装响应,否则它将不起作用!
正如其他人所提到的,您能否更新您的答案以指出确实需要 cors 中间件?如果我们浏览您的答案,我们认为唯一需要的步骤是写 const cors = require('cors')({origin: true});,但事实并非如此
d
deanwilliammills

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

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

无需导入 cors


这非常适合我的情况,一个对 Mailchimp API 进行 XHR 调用的云函数。
谷歌云函数不允许使用通配符来源:cloud.google.com/functions/docs/writing/…
@CoreyCole 我认为仅当您需要添加 Authorization 标头时。以上似乎工作正常。
我将该行添加到我的云功能中,但我的 localhost 获取仍然被 CORS 策略阻止。
@elersong 检查您的本地主机是否有 http 而不是 https
Y
Yayo Arellano

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

解决方案将使您失去对云函数的日志记录(非常糟糕)和正确的异步/等待功能,您可能会在长时间调用的回调中过早结束函数内容。
谷歌云函数不允许使用通配符来源:cloud.google.com/functions/docs/writing/…
@YayoArellano,谢谢。您的回答对我有所帮助,但我做了一点改动:corsHandler(request, response, () => { YOUR CODE HERE });
@OliverDixon您是否有更好的解决方案,它没有可能冒着函数内容在长时间通话中过早结束的风险?可能将它包装在一个仅在回调“完成”后才解决的 Promise 中?
@OliverDixon你能解释一下“你有可能在长时间调用的回调中过早结束函数内容。”请?
P
Pablo Urquiza

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

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

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

imo,这是最好的答案,因为它解决了实际问题而不增加任何额外的安全问题。通过这种方式,云功能与其他功能从同一个域提供服务,您甚至不需要任何 cors。
这确实是一个很棒的功能,但它目前仅在函数位于默认区域 (us-central1) 时才有效。由于延迟原因,我想将我的功能部署到 europe-west1,但遇到了这个问题:github.com/firebase/firebase-tools/issues/842
重定向工作正常并使 URL 更清晰,但我还没有弄清楚如何传递 GET 参数。该函数(重写后)似乎是在没有参数的情况下调用的。
使用 Firebase 托管?如果是,那么您的云功能必须位于“us-central1”区域,这在 2021 年 6 月仍然适用。
有什么方法可以将此重写与 httpCallable 一起使用?或者那时我们需要求助于正常的网络功能吗?
t
tbone849

没有 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 错误
在这里发生了几次,从服务器以及cors返回相同的错误:错误:内部基本上是错误。如果您运行错误的函数,例如错误输入函数名称,也会发生此错误
当您尝试在云功能中请求 Google reCAPTCHA 验证时,浏览器也会向您抛出 CORS 错误。当我检查 Firebase 控制台功能日志时,它显示 access to external network resources not allowed if the billing account is not enabled。启用计费帐户后,它可以完美运行。这也是与 cors 无关的示例之一,但会引发 cors 错误。
就我而言,问题是在运行模拟器之前我没有在正确的 Firebase 项目(命令行上的 firebase use <project-name>)下登录。
K
Kevin Danikowski

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


当其他 SO 手动设置标题的答案没有时,这有效
这可行,但如果您启用它并且无法部署到 Firebase,它可能会导致 TSlint 错误。将响应放入 cors 闭包中以克服它cors(request, response, () => { return response.send("Hello from Firebase!"); });
伙计们,这里有 2 个错误。第一。 cors 函数之后的任何内容都将运行两次(因为第一个请求是预检)。不好。其次,@SpiralOut 您的解决方案将使您失去对云函数的日志记录(非常糟糕)和正确的异步/等待功能,您可能会在回调中过早结束函数内容。
去年学到了很多关于 gcf 的知识,我不会再推荐这个答案了。它对于快速原型可能很方便,但在实际生产案例中避免这种情况
@JaapWeijland 请用任何信息更新您的答案,为什么这种方法对生产代码不利。最终,来自stackoverflow的所有(看似有效的)示例迟早都会投入生产......
G
GorvGoyl

更新答案:使用支持 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");解决了我的问题
这对我不起作用,因为它在 GET/POST 请求之前不支持 OPTIONS 方法“预检检查”。我不得不切换到 cors 包(或重新创建 OPTIONS 特殊响应,这最终带来的麻烦多于其价值)
S
Sandy

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

对于阅读本文的任何人考虑将 express 放入他们的云功能中 - 只是不要。启动 express 会占用额外的资源等,并且您已经实现了所有这些功能。 Firebase 函数!== 节点。
它可能会为每个请求启动一个新的快速服务器。我真的不确定他们为什么在官方文档中有这些东西。
K
KasparTr

如果您不/不能使用 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));
}

d
dimib

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

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

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

前往菜单

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

选择您的云功能,例如“MyFunction”,右侧应出现一个侧面菜单,显示其访问控制设置单击“添加成员”,输入“allUsers”并选择角色“Cloud Function Invoker”保存 - > 现在,您应该在云功能列表中看到“允许未经身份验证”的备注

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


z
zeekrey

如果有像我这样的人:如果你想从同一个项目中调用云函数作为它自己的云函数,你可以初始化 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


实际上,当我在浏览器上使用 onCall 函数时,我得到了 cors 错误。我可以在这个请求中设置成本头吗?
对于那些也收到 onCall cors 错误的人,试试这个帖子:stackoverflow.com/q/50278537/1411473
G
Gleb Dolzikov

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

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/…
我在哪里放置我的函数体?我在这里发布了我的代码stackoverflow.com/questions/68646425/…
w
wisetap.com

如果您没有在函数中捕获错误,则可能会发生 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 TrinhYayo ArellanoDoug Stevenson


很好的答案,但只有一点:至于错误的状态代码,而不是 500,我认为用 403 响应可能会更好。这(大致)是规范在 fetch.spec.whatwg.org/#http-responses 推荐的内容。一般来说,恕我直言,从应用程序代码中发送 500 似乎不是最佳选择——因为这会让您更难区分应用程序代码抛出预期错误的情况与服务器/运行时代码遇到其他类型的情况内部故障(甚至可能在它执行您的应用程序代码之前)。
感谢您的评论 :) 500 响应代码是因为不是与 cors 相关的错误,因此我认为使用状态代码 >= 500 而不是 403 更合适。你觉得呢?
我已经尝试了此页面上的几乎所有答案,这是唯一有效的答案。谢谢!
我很高兴这奏效了! :)
m
mhaligowski

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

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

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

希望有帮助!


不知道你说的黑客是什么意思?想详细说明一下吗?阅读你的帖子,但我没有看到你提到它
这里是 cors 模块的作者; “hacking” mhaligowski 仅仅意味着他必须包装对 cors 模块的调用以使其与 Express 调用中间件的方式相匹配(即在 req & res 之后提供一个函数作为第三个参数)
该链接已损坏mhaligowski.github.io/blog/2017/03/10/…这就是为什么最好放置外部资源的内容(摘要)而不是外部链接
R
Rob

true 更改为 "*" 对我有用,所以它看起来像这样:

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

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

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

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

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


s
shadyhill

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


还要确保添加您的 [project-id],因为这是我遇到的问题
S
Sercan

进入你的谷歌云函数。您以前可能没有见过这个平台,但它是您解决这个 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!");
});

如果您不在函数内部自己处理身份验证,这不会使您的函数公开并可供任何人使用。
对我来说,这就是让事情正常工作并挽救我的理智所需要的。我向后工作并从那里实施安全措施。如何处理超出了我要回答的范围,但值得一提。
S
Suraj Rao

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

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

G
GorvGoyl

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

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

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

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


u
user1689987

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

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

T
Thomas

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

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

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

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

我在这里填写了一份错误报告https://firebase.google.com/support/troubleshooter/report/bugs


N
Noks1

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


K
Kevin Danikowski

如果您更喜欢制作单个处理函数 (reference answer)

const applyMiddleware = handler => (req, res) => {
  return cors(req, res, () => {
    return handler(req, res)
  })
}
exports.handler = functions.https.onRequest(applyMiddleware(handler))

如果您可能需要添加更多处理程序或具有许多功能,这是一个理想的解决方案
G
Guillaume Renoult

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

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

代替

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

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


A
Abraham

我已经尝试了很长时间。

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

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

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

它现在完美运行。


T
Tris

在 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


K
Kacpero

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


请在您的答案中提供一些链接材料的解释,为什么它是相关的等等
A
Agilan I

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

这已经不可能了。
J
Joel Walkley

请参阅下文,了解我如何使用 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'
}));

B
BorisD

在您的 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