【问题标题】:Firebase Functions Can't set headers after they are sentFirebase 函数发送后无法设置标头
【发布时间】:2023-04-03 21:54:01
【问题描述】:

我有一个 Firebase 函数,我无法从我的 React.js 网络应用程序中查询,但通过 Postman 没有问题。

当我尝试通过网络应用发出请求时,我的 Firebase 控制台中出现以下错误:

错误:发送后无法设置标头。

at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (/worker/node_modules/express/lib/response.js:767:10)
at ServerResponse.json (/worker/node_modules/express/lib/response.js:264:10)
at ServerResponse.send (/worker/node_modules/express/lib/response.js:158:21)
at exports.uploadImage.functions.https.onRequest (/srv/index.js:21:13)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)

在网络应用程序上,我收到 500 错误响应,但没有返回任何数据。

我的请求是这样提出的:

const data = {
    image: 'image url here',
    options: {
        tags: 'document,doctor',
    }
};
axios.post('*** FUNCTION URL HERE***/uploadImage', data, {
    headers: {
        'Content-Type': 'application/json',
    },
})

但是,如果我通过 Postman 提出请求,我会收到 200 响应,其中包含我期望的数据。

这是我的 functions/index.js 文件的样子:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cloudinary = require('cloudinary');
const cors = require('cors')({origin: true});

admin.initializeApp();

exports.uploadImage = functions.https.onRequest(async (req, res) => {
    cors(req, res, () => {});
    cloudinary.config({
        cloud_name: 'config here',
        api_key: 'config here',
        api_secret: 'config here',
    });

    try { 
        const data = Object.apply({folder: 'myortho'}, req.body.options);
        const response = await cloudinary.uploader.upload(req.body.image, data);
        return res.send(response);
    }catch(error) {
        return res.send(500, {message: 'Error uploading image', error});
    }
});

我看到了许多与我遇到的错误有关的问题,但其中许多问题都与人们的路由问题有关(这不是我关心的问题,因为这是一个云函数,而不是我自己的 Node.js 后端服务器)。

这也是一个我无法理解的错误,因为它是通过 Postman 成功的,但不是通过我的浏览器,所以我真的很困惑。

【问题讨论】:

    标签: javascript node.js reactjs firebase google-cloud-functions


    【解决方案1】:

    回答您的问题,为什么您的请求在 Postman 中按原样工作,但在浏览器中却没有:

    这是因为 Postman 是一种开发工具,因此不依赖于 CORS。另一方面,浏览器有更多的安全问题并依赖 CORS。

    Google Chrome's extension documentation 从技术上解释这是为什么(虽然它是在考虑扩展的情况下编写的,但 Postman 也以这种方式运行):

    常规网页可以使用 XMLHttpRequest 对象从远程服务器发送和接收数据,但它们受到同源策略的限制。内容脚本代表已注入内容脚本的 Web 源发起请求,因此内容脚本也受制于相同的源策略。 (内容脚本自 Chrome 73 以来一直受 CORB 约束,自 Chrome 83 以来一直受 CORS 约束。)扩展程序的来源不受限制——在扩展程序的后台页面或前台选项卡中执行的脚本可以与其来源之外的远程服务器通信,只要扩展程序请求跨域权限。

    还有another thread on Stack Overflow 对此进行了进一步讨论。

    【讨论】:

      【解决方案2】:

      当你使用 cors 时,你应该把你的代码放在你传递给它的回调函数中。您根本没有使用该回调,正在发生的事情是您的代码正在尝试发送两个响应。它应该更像这样:

      exports.uploadImage = functions.https.onRequest(async (req, res) => {
          cors(req, res, () => {
              cloudinary.config({
                  cloud_name: 'config here',
                  api_key: 'config here',
                  api_secret: 'config here',
              });
      
              try { 
                  const data = Object.apply({folder: 'myortho'}, req.body.options);
                  const response = await cloudinary.uploader.upload(req.body.image, data);
                  return res.send(response);
              } catch(error) {
                  return res.send(500, {message: 'Error uploading image', error});
              }
          });
      });
      

      【讨论】:

      • 如果是这个问题,那么你如何解释它是通过 Postman 而不是浏览器成功的?
      • Postman 就像发出一个 curl 请求。这是完全不同的背景。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-06
      • 1970-01-01
      • 2015-12-20
      相关资源
      最近更新 更多