在Firebase的云功能中启用CORS

And*_*kiy 98 javascript cors firebase google-cloud-functions

我目前正在学习如何为Firebase使用新的Cloud Functions,而我遇到的问题是我无法访问我通过AJAX请求编写的函数.我收到"No'Access-Control-Allow-Origin'"错误.这是我写的函数的一个例子:

exports.test = functions.https.onRequest((request, response) => {
  response.status(500).send({test: 'Testing functions'});
})
Run Code Online (Sandbox Code Playgroud)

该函数位于以下URL: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'});
   })
})
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?我很感激任何帮助.

更新:

道格史蒂文森的回答有所帮助.添加({产地:真})固定的问题,我也不得不改变response.status(500),以response.status(200)我在第一次完全错过.

Dou*_*son 118

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

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

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

const cors = require('cors')({origin: true});
Run Code Online (Sandbox Code Playgroud)

  • 看起来这是定义允许访问的域的白名单的位置?设置`origin:true`允许任何域访问?(https://www.npmjs.com/package/cors)@Doug Stevenson你认为firebase可以编写关于客户端/服务器https功能所需基础知识的文档吗?样品回购是好的,但我们错过了额外的需求. (4认同)
  • 对于愿意为其后端添加CORS支持的任何人:请确保您了解其后果以及如何正确配置它."origin:true"对测试很酷,但却打败了整个目的:) (4认同)
  • 谷歌云功能不允许通配符来源:https://cloud.google.com/functions/docs/writing/http#authentication_and_cors (2认同)
  • 正如其他人提到的,您能否更新您的答案以指出确实需要 cors 中间件?如果我们浏览您的答案,我们认为唯一需要的步骤是编写 `const cors = require('cors')({origin: true});`,但事实并非如此 (2认同)

dea*_*lls 40

您可以像这样设置云功能中的CORS response.set('Access-Control-Allow-Origin', '*');无需导入cors

  • 我将该行添加到我的云函数中,但我的 localhost 获取仍然被 CORS 策略阻止。 (7认同)
  • @CoreyCole我_认为_只有当您需要添加“授权”标头时才如此。上面的似乎工作正常。 (4认同)
  • 谷歌云功能不允许通配符来源:https://cloud.google.com/functions/docs/writing/http#authentication_and_cors (3认同)
  • 对于我的情况而言,这是完美的工作,一个云功能可以对Mailchimp API进行XHR调用。 (2认同)

Yay*_*ano 25

对于试图在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
});
Run Code Online (Sandbox Code Playgroud)

  • @YayoArellano,谢谢。你的回答对我有帮助,但是我做了一些小小的改变:`corsHandler(request, response, () => { YOUR CODE HERE });` (3认同)
  • 解决方案将使您失去对云功能的日志记录(非常糟糕)和正确的异步/等待功能,您可能会担心在长时间调用时函数内容在回调中提前结束。 (2认同)
  • 谷歌云功能不允许通配符来源:https://cloud.google.com/functions/docs/writing/http#authentication_and_cors (2认同)
  • @OliverDixon您是否有更好的解决方案,并且不会带来函数内容在长时间调用期间过早结束的风险?可能将其包装在一个仅在回调“完成”后才解析的 Promise 中? (2认同)

小智 24

另外一条信息,只是为了一段时间之后用Google搜索这个:如果你正在使用firebase托管,你也可以设置重写,以便例如像(firebase_hosting_host)/ api/myfunction这样的网址重定向到( firebase_cloudfunctions_host)/ doStuff函数.这样,由于重定向是透明的并且是服务器端的,因此您不必处理cors.

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

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]
Run Code Online (Sandbox Code Playgroud)

  • 有什么方法可以将此重写与 httpCallable 一起使用吗?或者我们此时需要诉诸正常的网络功能吗? (3认同)
  • imo,这是最好的答案,因为它解决了实际问题,而不会增加任何额外的安全问题。这样,云功能与其他功能从同一域提供服务,您甚至不需要任何 cors。 (2认同)
  • 确实,这是一个很棒的功能,但是当前仅在功能位于默认区域(us-central1)中时才起作用。由于延迟原因,我想将功能部署到europe-west1并遇到了这个问题:https://github.com/firebase/firebase-tools/issues/842 (2认同)

Jaa*_*and 15

我对@Andreys回答他自己的问题有一点补充.

看起来您不必在cors(req, res, cb)函数中调用回调函数,因此您只需调用函数顶部的cors模块,而无需在回调中嵌入所有代码.如果你想在之后实施cors,这会快得多.

exports.exampleFunction = functions.https.onRequest((request, response) => {
    cors(request, response, () => {});
    return response.send("Hello from Firebase!");
});
Run Code Online (Sandbox Code Playgroud)

不要忘记在开幕式帖子中提到的init cors:

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

  • 当手动设置标题的其他 SO 答案没有时,这有效 (2认同)
  • 伙计们,这里有 2 个错误。第一。cors 函数之后的任何内容都将运行两次(因为第一个请求是预检)。不好。其次,@SpiralOut 你的解决方案会让你失去对云函数的登录(非常糟糕)和适当的异步/等待功能,你可能会冒着函数内容在回调中过早结束的风险。 (2认同)
  • 去年学到了很多关于 gcf 的知识,我不会再推荐这个答案了。这对于快速原型可能很方便,但在实际生产案例中避免这种情况 (2认同)
  • @JaapWeijland 请用任何信息更新您的答案,为什么这种方法对生产代码不利。最终,来自 stackoverflow 的所有(看似有效的)示例迟早都会投入生产...... (2认同)

dim*_*mib 15

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

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

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

  1. 转到菜单

“云函数”(“计算”部分)

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

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

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

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


Mob*_*ent 14

Firebase v2 的云函数

Cloud Functions for Firebase v2cors现在允许您直接在 HTTP 选项中进行配置。它无需任何第三方软件包即可工作:


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
});
Run Code Online (Sandbox Code Playgroud)

谨防:

  • 在撰写本文时,v2正在公开预览中。
  • v2目前仅支持区域的子集。
  • 函数名称仅限于小写字母、数字和破折号。
  • 您可以在单个代码库中并行使用v1和函数。v2为了提高可读性,请分别更新您的导入以访问firebase-functions/v1firebase-functions/v2

  • 这对我不起作用。 (2认同)

tbo*_*849 13

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

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

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

  • 这让我发疯。就我而言,代码中甚至没有错误!这是```错误:超出配额(配额组'NetworkIngressNonbillable'超出配额,并且服务'cloudfunctions.googleapis.com'的限制'CLIENT_PROJECT-1d'``所以基本上超出了免费配额,并且函数返回了cors错误 (3认同)

San*_*ndy 13

这可能会有所帮助。我使用 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);
Run Code Online (Sandbox Code Playgroud)

请确保您添加了重写部分

"rewrites": [
      {
        "source": "/api/v1/**",
        "function": "functionName"
      }
]
Run Code Online (Sandbox Code Playgroud)

  • 对于任何正在阅读本文并考虑将 Express 放入其云功能中的人来说 - 只是不要这样做。启动 Express 会占用额外的资源等,而您已经实现了所有这些功能。Firebase 函数!== 节点。 (3认同)
  • 它实际上可能会*每个请求*启动一个新的快速服务器。我真的不确定他们为什么在官方文档中包含这些内容。 (2认同)

Jer*_*yal 13

更新答案:使用cors支持 Typescript 的库:

安装 cors

npm i -S cors
npm i --save-dev @types/cors
Run Code Online (Sandbox Code Playgroud)

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

 });
});
Run Code Online (Sandbox Code Playgroud)

旧答案:(不再工作)
找到了一种无需导入任何“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();
});
Run Code Online (Sandbox Code Playgroud)

  • 这对我不起作用,因为它不支持 GET/POST 请求之前的 OPTIONS 方法“预检检查”。我不得不切换到“cors”包(或者重新创建“OPTIONS”特殊响应,这最终导致麻烦大于其价值) (2认同)

Kas*_*rTr 8

如果您不/不能使用 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));
}
Run Code Online (Sandbox Code Playgroud)


mha*_*ski 7

我刚刚发表了一篇文章:

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

通常,您应该使用Express CORS软件包,这需要一点点黑客来满足GCF/Firebase功能的要求.

希望有所帮助!

  • 不知道你说的黑客是什么意思?想详细说明一下吗?阅读你的帖子,但我没有看到你提到它 (4认同)
  • 该链接已损坏 https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-functions.html 这就是为什么最好放置外部资源的内容(摘要)而不是外部链接 (3认同)
  • cors 模块的作者在这里;通过“黑客攻击”mhaligowski 只是意味着他必须将调用包装到 cors 模块,以使其与 Express 调用中间件的方式匹配(即在 req 和 res 之后提供一个函数作为第三个参数) (2认同)

Dig*_*iro 6

如果您没有捕获函数中的错误,则可能会发生 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
            });
        }
    });
};
Run Code Online (Sandbox Code Playgroud)

用法:

exports.helloWorld = functions.https.onRequest((request, response) => {
    corsHandler(request, response, () => {
        functions.logger.info("Hello logs!");
        response.send({
            "data": "Hello from Firebase!"
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

感谢 stackoverflow 用户:Hoang TrinhYayo ArellanoDoug Stevenson


Gle*_*kov 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)
} )};
Run Code Online (Sandbox Code Playgroud)


zee*_*rey 5

如果有像我这样的人:如果你想从与云函数本身相同的项目中调用云函数,你可以初始化 firebase sdk 并使用 onCall 方法。它将为您处理一切:

exports.newRequest = functions.https.onCall((data, context) => {
    console.log(`This is the received data: ${data}.`);
    return data;
})
Run Code Online (Sandbox Code Playgroud)

像这样调用这个函数:

// Init the firebase SDK first    
const functions = firebase.functions();
const addMessage = functions.httpsCallable(`newRequest`);
Run Code Online (Sandbox Code Playgroud)

Firebase 文档:https ://firebase.google.com/docs/functions/callable

如果您无法在此处初始化 SDK,则是其他建议的精髓:

  • 实际上,当我在浏览器上使用 onCall func 时,我收到了 cors 错误。我可以在此请求中设置自定义标头吗? (8认同)