繁体   English   中英

为Firebase在云函数中启用CORS

[英]Enabling CORS in Cloud Functions for Firebase

我目前正在学习如何为 Firebase 使用新的 Cloud Functions,我遇到的问题是我无法访问我通过 AJAX 请求编写的 function。 我收到“无‘Access-Control-Allow-Origin’”错误。 这是我写的 function 的示例:

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

function 位于这个 url: https://us-central1-fba-shipper-140ae.cloudfunctions.net/test

Firebase 文档建议在 function 中添加 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) ,我一开始完全错过了。

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

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

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

无需导入cors

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

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

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

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

没有 CORS 解决方案对我有用……直到现在!<\/strong>

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

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

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

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

更新答案:<\/strong>使用带有 Typescript 支持的cors<\/code>库:

安装cors<\/code>

npm i -S cors
npm i --save-dev @types/cors

如果你不\/不能使用 cors 插件,首先在处理函数中调用setCorsHeaders()<\/code>函数也可以。

回复时也使用 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));
}

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

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

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

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

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

希望有帮助!

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

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

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

通过"*"更改true对我来说是诀窍,所以它看起来像这样:

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

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

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

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

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

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

"

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

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

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

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

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

Firebase v2 的云函数

Cloud Functions for Firebase v2现在允许您直接在 HTTP 选项中配置cors 它无需任何第三方 package 即可工作:


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

谨防:

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

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

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

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

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

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

从这么多搜索中,我可以在同一个 firebase 文档中找到这个解决方案,只需在路径中实现 cors:

import * as express from "express";
import * as cors from "cors";


const api = express();
api.use(cors({ origin: true }));
api.get("/url", function);

如果您更喜欢制作单个处理函数<\/strong>( 参考答案<\/a>)

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

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

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

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

我的 CORS 问题出在存储(而不是 RTDB 和浏览器......),然后我没有信用卡(按照上述解决方案的要求),我的无信用卡解决方案是:

  1. 安装 gsutil: https://cloud.google.com/storage/docs/gsutil_install#linux-and-macos

  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

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

"

如果其他解决方案都不起作用,您可以尝试在调用开始时添加以下地址以启用 CORS - 重定向:

https:\/\/cors-anywhere.herokuapp.com\/<\/a>

带有 JQuery AJAX 请求的示例代码:

请参阅下文,了解我如何使用 CORS 设置我的 Express。

“https:\/\/pericope.app”是我的 Firebase 项目的自定义域。

看起来所有其他答案都推荐origin:true<\/code>或*<\/code> 。

我很犹豫是否允许所有来源,因为它会允许其他任何人访问 api。 如果您正在创建公共服务,那很好,但如果您对数据做任何事情,那是有风险的,因为它是一个特权环境。 例如,此管理 SDK 会绕过您为 Firestore 或 Storage 设置的任何安全规则。

//Express
const express = require('express');
const app = express();

const cors = require('cors');
app.use(cors({
  origin: 'https://pericope.app'
}));

我已经尝试了很长时间。

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

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

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

它现在完美运行。

在您的 https.onRequest 上使用 cors 和Typescript<\/strong> ,如下所示:

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

这个老问题,但是谢谢格莱布·多尔齐科夫

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM