Javascript 为Firebase启用云中CORS功能
我目前正在学习如何为Firebase使用新的云函数,我遇到的问题是无法访问通过AJAX请求编写的函数。我得到了“No‘Access Control Allow Origin’”错误。下面是我编写的函数示例:Javascript 为Firebase启用云中CORS功能,javascript,firebase,google-cloud-platform,cors,google-cloud-functions,Javascript,Firebase,Google Cloud Platform,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'}); }) 该函数位于以下url中: F
exports.test = functions.https.onRequest((request, response) => {
response.status(500).send({test: 'Testing functions'});
})
该函数位于以下url中:
Firebase docs建议在函数中添加CORS中间件,我已经尝试过了,但它对我不起作用:
我就是这样做的:
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使用的示例:
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
})
});
// Init the firebase SDK first
const functions = firebase.functions();
const addMessage = functions.httpsCallable(`newRequest`);
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()}`);
});
});
我刚刚发表了一篇关于这方面的小文章: 一般来说,您应该使用Express,这需要稍加修改以满足GCF/Firebase函数中的要求
希望有帮助 另外一条信息,只是为了那些在一段时间后在谷歌上搜索的人: 如果您使用的是firebase托管,您还可以设置重写,以便(firebase_hosting_host)/api/myfunction等url重定向到(firebase_cloudfunctions_host)/doStuff函数。这样,因为重定向是透明的,并且是服务器端的,所以您不必处理COR 您可以通过firebase.json中的“重写”部分进行设置:
"rewrites": [
{ "source": "/api/myFunction", "function": "doStuff" }
]
对于@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错误,因为它没有相应的异步/等待。不要使用返回静态数据的快速原型化端点之外的端点。对于试图在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
});
没有CORS解决方案适合我。。。直到现在强>
不确定是否有其他人遇到了我遇到的相同问题,但我设置了CORS,就像我发现的示例中的5种不同方式一样,但似乎没有任何效果。我用Plunker设置了一个最小的例子,看看它是否真的是一个bug,但是这个例子运行得很好。我决定检查firebase函数日志(在firebase控制台中找到),看看这是否能告诉我什么我的节点服务器代码中有几个错误,与CORS无关,当我调试时,发布了我的CORS错误消息。我不知道为什么与CORS无关的代码错误会返回CORS错误响应,但它让我在错误的兔子洞里呆了好几个小时
tl;灾难恢复-如果没有CORS解决方案工作,请检查firebase功能日志,并调试任何错误。您可以在云功能中设置CORS,如下所示
response.set('Access-Control-Allow-Origin','*')代码>
无需导入cors
包,因为我在将app
传递到onRequest
时遇到了同样的问题。我意识到问题是firebase函数的请求url上有一个尾随斜杠。Express正在查找'/'
,但我在函数[project id].cloudfunctions.net/[function name]
上没有尾随斜杠。CORS错误为假阴性。当我添加尾随斜杠时,我得到了预期的响应 如果您不使用Express或只是想使用CORS。下面的代码将有助于解决此问题
const cors = require('cors')({ origin: true, });
exports.yourfunction = functions.https.onRequest((request, response) => {
return cors(request, response, () => {
// *Your code*
});
});
只有这种方式对我有效,因为我在请求中有授权:
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)
} )};
这可能会有帮助。
我使用express(自定义URL)创建了firebase HTTP云函数
请确保已添加“重写”部分
"rewrites": [
{
"source": "/api/v1/**",
"function": "functionName"
}
]
如果有像我这样的人:如果你想从云函数本身所在的同一个项目调用云函数,你可以初始化firebase sdk并使用onCall方法。它将为您处理一切:
exports.newRequest = functions.https.onCall((data, context) => {
console.log(`This is the received data: ${data}.`);
return data;
})
按如下方式调用此函数:
exports.fn = functions.https.onRequest((req, res) => {
cors(req, res, () => {
// your function body here - use the provided req and res from cors
})
});
// Init the firebase SDK first
const functions = firebase.functions();
const addMessage = functions.httpsCallable(`newRequest`);
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()}`);
});
});
Firebase文档:
如果无法初始化SDK,以下是其他建议的要点:
- 如果在默认位置使用firebase主机和主机,请选择“重写”:
- 或者像krishnazden建议的那样使用COR:
如果您在本地测试firebase应用程序,则需要将函数指向localhost
而不是云。默认情况下,firebase-serve
或firebase-emulators:start
在web应用程序上使用时,将函数指向服务器而不是本地主机
在firebase初始化脚本之后的html标头中添加以下脚本:
<script>
firebase.functions().useFunctionsEmulator('http://localhost:5001')
</script>
firebase.functions().useFunctionsEmulator('http://localhost:5001')
确保在将代码部署到服务器时删除此代码段
如果您不/不能使用cors插件,那么在handler函数中首先调用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));
}
在我的例子中,错误是由云函数调用程序限制访问引起的。请将诱惑者添加到云函数调用器。请接电话。请参阅以了解更多信息,通过更改true
“*”
为我完成了这项任务,因此它看起来是这样的:
const cors = require('cors')({ origin: "*" })
我尝试这种方法是因为
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!"
});
});
});
import * as express from "express";
import * as cors from "cors";
const api = express();
api.use(cors({ origin: true }));
api.get("/url", function);
//Express
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors({
origin: 'https://pericope.app'
}));
const applyMiddleware = handler => (req, res) => {
return cors(req, res, () => {
return handler(req, res)
})
}
exports.handler = functions.https.onRequest(applyMiddleware(handler))
https://xxxx-default-rtdb.firebaseio.com/myendpoint
https://xxxx-default-rtdb.firebaseio.com/myendpoint.json
app.get('/create-customer', (req, res) => {
return cors()(req, res, () => {
... your code ...
firebase.functions().httpsCallable('makeSureThisStringIsCorrect');
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()}`);
});
});