在Firebase的云功能中启用CORS

时间:2017-03-13 01:01:10

标签: javascript firebase cors google-cloud-functions

我目前正在学习如何为Firebase使用新的云功能,而我遇到的问题是我无法访问我通过AJAX请求编写的功能。我得到了" No' 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),我最初完全错过了。

28 个答案:

答案 0 :(得分:90)

Firebase小组提供了两个sample functions来演示CORS的使用:

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

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

import java.util.Arrays;

public class FindCommon {

/*
 * @param a 3xN integer array, assume a is not null or empty
 * @return the largest common number among a[0], a[1], a[2],  null if no  common number exists
 */
public static Integer getLargestCommonNumber(int[][] a) {

    //Check if array is empty
    if (a == null || a.length == 0){
        return 0;
    }
    //Initialize
    int [] Row1 = a[0];
    int [] Row2 = a[1];
    int [] Row3 = a[2];

    Arrays.sort(a);

    int i = 0, j = 0, k = 0;

    // Iterate through three arrays while all arrays have elements
    while (i < Row1.length && j < Row2.length && k < Row3.length)
    {
         if (Row1[i] > Row2[j] && Row2[j] > Row3[k]){
             System.out.print(Row1[i]+" ");   
             int max = Row1[i];
         }
         else if (Row2[i] > Row1[j] && Row2[j] > Row3[k]){
             System.out.print(Row2[i]+" ");
             int max = Row2[i];
         }
         else if (Row3[i] > Row1[j] && Row3[j] > Row2[k]){
             int max = Row3[i];
         }


    }
}
}

答案 1 :(得分:24)

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

答案 2 :(得分:21)

对于任何尝试在Typescript中执行此操作的人,代码如下:

LocalDate.of(2018, 1, 31).until(LocalDate.of(2018, 2, 28), ChronoUnit.MONTHS); //  0     
LocalDate.of(2018, 1, 31).plusMonths(1); // but 2018-02-28

答案 3 :(得分:15)

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

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

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

不要忘记在开幕式中提到的初始角色:

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

答案 4 :(得分:14)

另外一条信息,仅仅是为了那些在一段时间后用Google搜索的信息: 如果您正在使用firebase托管,您还可以设置重写,以便例如像(firebase_hosting_host)/ api / myfunction这样的URL重定向到(firebase_cloudfunctions_host)/ doStuff函数。这样,由于重定向是透明的,服务器端,你不必处理cors。

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

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

答案 5 :(得分:7)

找到了一种无需导入任何“ 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();
});

答案 6 :(得分:6)

我刚刚发表了一篇文章:

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

通常,您应该使用Express CORS package,这需要一点点黑客来满足GCF / Firebase功能中的要求。

希望有所帮助!

答案 7 :(得分:6)

没有CORS解决方案对我有用……到目前为止!

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

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

答案 8 :(得分:2)

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

答案 9 :(得分:2)

只有当我在请求中获得授权时,这种方式才对我有用:

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

答案 10 :(得分:2)

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

答案 11 :(得分:2)

true更改为"*"对我来说是成功的秘诀,这就是它的样子:

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

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

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

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

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

答案 12 :(得分: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

答案 13 :(得分:1)

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

答案 14 :(得分:1)

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

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

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

  1. 转到菜单

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

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

  2. 单击“添加成员”,键入“ allUsers”,然后选择角色“ Cloud Function Invoker”

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

现在,通过正确配置GCP或Firebase项目,每个人都可以从Internet访问。 (请注意

答案 15 :(得分:1)

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

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

代替

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

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

答案 16 :(得分:1)

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

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

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

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

答案 17 :(得分:0)

我已经尝试了很长时间了。

当我做出这个改变时,它终于奏效了。

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

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

它现在可以完美运行。

答案 18 :(得分:0)

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

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

答案 19 :(得分: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'
}));

答案 20 :(得分:0)

我收到错误,因为我调用了一个在客户端不存在的函数。例如:

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

答案 21 :(得分: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()}`);
  });
});

来自Source

答案 22 :(得分:0)

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

我已经重命名了我的云功能(这是我进行大升级后第一次尝试使用的功能)。

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

在我的Firebase应用程序中修复了云函数名称,从而解决了该问题。

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

答案 23 :(得分: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'
});

答案 24 :(得分:0)

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

答案 25 :(得分:0)

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

答案 26 :(得分:0)

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

答案 27 :(得分:0)

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

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