FIREBASE 警告:用户回调引发异常。错误:发送后无法设置标头

2024-03-10

我们正在开发一个应用程序,我们使用 Firebase 作为数据库,并使用 Express 作为中间件/后端来路由我们的 RESTful API,该 API 供我们在 Reactjs 中开发的前端使用。

下面是我们的 server.js 文件的样子:

var express = require('express');
var app = express();

//Used for getting POST variables from forms as well as query parameters
var bodyParser = require('body-parser');
var validator = require('express-validator');

//Contains all the routes
var routes = require('./routes/routes');
var path = require('path');

//Used for serving jade files
app.set('view engine', 'jade');
//For serving static resources like scripts, styleSheets, html
app.use(express.static(__dirname + '/views'));

app.all('/*', function(req, res, next) {
 res.header("Access-Control-Allow-Origin", "*");
 res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept");
 res.header("Access-Control-Allow-Methods", "POST, GET");
 next();
});

// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.use(validator({
    customValidators: {
        onlyAlphabets: function(value) {
            if (value.match('^[a-zA-Z ]*$')) {
                return true;
            } else {
                return false;
            }
        },
        password: function(value) {
            if (value.length >= 6 && value.length <=25 && value.match('^[\x20-\x7F]*$')) {
                return true;
            } else {
                return false;
            }
        }
    }
}));
app.use(routes);

var port = process.env.PORT || 8080; //Set our port

app.listen(port);
console.log('Magic happens on port ' + port);

下面是route.js中的路由代码:

var express = require('express');
var views = __dirname;
// Node.js path library - https://nodejs.org/api/path.html
var path = require('path');
var Firebase = require("firebase");
var myFirebaseRef = new Firebase("https://crackling-inferno-8454.firebaseio.com/vendor_details");
var router = express.Router();
//Password Encryption and decryption helpers
var hashFunction = require('../helpers/encrypt');


// middleware to use for all requests
router.use(function(req, res, next) {
  // do logging
  console.log('Something is happening.');
  next(); // make sure we go to the next routes and don't stop here
});

router.get('/', function(req, res) {
  res.render('vendor_form');
});

router.route('/get_vendors').get(function(request, response) {
    myFirebaseRef.on("value", function(snapshot) {
        var store = snapshot.val();
        // Looping to get the firebaseId generated while push
        for(var key in store){
            store[key].id = key;    //  Store firebaseID generated during push to store in JSON object
        }
        response.send(Object.keys(store).map(function(k) { return store[k]; }));
    }, function (errorObject) {
        response.send("The read failed: " + errorObject.code);
    });
});

router.route('/post_vendor').post(function(request, response) {

    request.checkBody({
        'vendor_name': {
            notEmpty : {
                errorMessage: 'Please enter a vendor\'s name'
            },
            onlyAlphabets : {
                errorMessage: 'Please enter only alphabets'
            }
        },
        'enterprise_name': {
            notEmpty : {
                errorMessage: 'Please enter an enterprise\'s name'
            },
            onlyAlphabets : {
                errorMessage: 'Please enter only alphabets'
            }
        },
        'vendor_email': {
            notEmpty : {
                errorMessage: 'Please enter your email address'
            },
            isEmail : {
                errorMessage: 'please enter an appropriate email format'
            }
        },
        'vendor_password': {
            notEmpty : {
                errorMessage: 'Please enter a password'
            },
            password: {
                errorMessage: 'Password length should be between 6-25 characters'
            }
        },
        'food_preference': {
            notEmpty: {
                errorMessage: 'You must select atleast one food preference'
            }
        }
    });

    var errors = request.validationErrors();

    // var onComplete = function(error) {
    //  if (error) {
    //      response.send('Failed to add stats to the database');
  //     return false;
    //  } else {
    //      // response.render('vendor_form', { success: true });
    //      response.send('Success');
  //     return true;
    //  }
    // };

    if (errors) {
        response.send(errors);
        // response.render('vendor_form', { error: errors });
        return false;
    } else {
        myFirebaseRef.push().set({
            'id': Firebase.ServerValue.TIMESTAMP,
            'vendor_name': request.body.vendor_name,
            'enterprise_name': request.body.enterprise_name,
            'vendor_email': request.body.vendor_email,
            'vendor_password': hashFunction.encrypt(request.body.vendor_password),
            'food_preference': request.body.food_preference
        }, function(err) {
      if (err) {
        response.send('Failed to add stats to the database');
      } else {
        response.send('Success');
      }
    });
    return true;
    }
});

module.exports = router;

下面是我们在前端添加的用于发布数据的代码。我们还使用 Whatwg-fetch 包:

httpservice.js:

var Fetch = require('whatwg-fetch');
var baseUrl = 'http://192.168.1.134:8080';

var Service = {
  get: function(url) {
    console.log('MAKING A GET REQUEST');
    return fetch(baseUrl + url)
    .then(function(response) {
      return response.json();
    });
  },

  post: function(url, postData) {
    console.log('MAKING A POST REQUEST');
    return fetch(baseUrl + url, {
      headers: {

        'Content-Type': 'application/json'
      },
      method: 'POST',
      body: JSON.stringify(postData)
    }).then(function(response) {
      return response;
    });
  }
}

module.exports = Service;

VendorForm.js(React 组件文件)

HTTP.post('/post_vendor', httpRequestBody)
.then(function(response) {
      console.log(response);
 }.bind(this));

我们启动我们的服务器,它提供在 FIREBASE + EXPRESS 中开发的 RESTful API,通过nodemon。这是我们发布时收到的错误:

FIREBASE WARNING: Exception was thrown by user callback. Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
    at ServerResponse.header (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:718:10)
    at ServerResponse.send (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:163:12)
    at ServerResponse.json (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:249:15)
    at ServerResponse.send (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:151:21)
    at /var/www/tutorials/express_firebase/routes/routes.js:30:12
    at /var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:200:710
    at ec (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:52:165)
    at ac (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:31:216)
    at bc (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:30:1259)
    at Ji.h.Mb (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:220:440)
    at X.set (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:256:335)
    at /var/www/tutorials/express_firebase/routes/routes.js:96:24
    at Layer.handle [as handle_request] (/var/www/tutorials/express_firebase/node_modules/express/lib/router/layer.js:95:5)
    at next (/var/www/tutorials/express_firebase/node_modules/express/lib/router/route.js:131:13)
    at Route.dispatch (/var/www/tutorials/express_firebase/node_modules/express/lib/router/route.js:112:3) 
/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:52
(d="0"+d),c+=d;return c.toLowerCase()}var zd=/^-?\d{1,10}$/;function td(a){return zd.test(a)&&(a=Number(a),-2147483648<=a&&2147483647>=a)?a:null}function ec(a){try{a()}catch(b){setTimeout(function(){R("Exception was thrown by user callback.",b.stack||"");throw b;},Math.floor(0))}}function S(a,b){if(t(a)){var c=Array.prototype.slice.call(arguments,1).slice();ec(function(){a.apply(null,c)})}};function Ad(a){var b={},c={},d={},e="";try{var f=a.split("."),b=Pb(id(f[0])||""),c=Pb(id(f[1])||""),e=f[2],d=c.d||{};delete c.d}catch(g){}return{oh:b,Dc:c,data:d,ah:e}}function Bd(a){a=Ad(a).Dc;return"object"===typeof a&&a.hasOwnProperty("iat")?z(a,"iat"):null}function Cd(a){a=Ad(a);var b=a.Dc;return!!a.ah&&!!b&&"object"===typeof b&&b.hasOwnProperty("iat")};function Dd(a){this.Y=a;this.g=a.n.g}function Ed(a,b,c,d){var e=[],f=[];Na(b,function(b){"child_changed"===b.type&&a.g.Ad(b.Le,b.Ma)&&f.push(new H("child_moved",b.Ma,b.Ya))});Fd(a,e,"chi

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
    at ServerResponse.header (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:718:10)
    at ServerResponse.send (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:163:12)
    at ServerResponse.json (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:249:15)
    at ServerResponse.send (/var/www/tutorials/express_firebase/node_modules/express/lib/response.js:151:21)
    at /var/www/tutorials/express_firebase/routes/routes.js:30:12
    at /var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:200:710
    at ec (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:52:165)
    at ac (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:31:216)
    at bc (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:30:1259)
    at Ji.h.Mb (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:220:440)
    at X.set (/var/www/tutorials/express_firebase/node_modules/firebase/lib/firebase-node.js:256:335)
    at /var/www/tutorials/express_firebase/routes/routes.js:96:24
    at Layer.handle [as handle_request] (/var/www/tutorials/express_firebase/node_modules/express/lib/router/layer.js:95:5)
    at next (/var/www/tutorials/express_firebase/node_modules/express/lib/router/route.js:131:13)
    at Route.dispatch (/var/www/tutorials/express_firebase/node_modules/express/lib/router/route.js:112:3)
[nodemon] app crashed - waiting for file changes before starting...

根据错误,我们知道一些回调将标头设置两次,但不确定它是如何发生的。经历了一些堆栈溢出问题,但仍然没有找到解决方案。任何帮助,将不胜感激。谢谢期待。


如果您看到堆栈跟踪

at /var/www/tutorials/express_firebase/routes/routes.js:30:12

这是文件route.js中的第30行

response.send(Object.keys(store).map(function(k) { return store[k]; }));

你需要改变方法on for once,否则每次数据更新时都会触发您的回调函数,

router.route('/get_vendors').get(function(request, response) {
  myFirebaseRef.on("value", function(snapshot) {

当您调用 post 方法时会破坏您的响应,因为标头已在第 30 行中发送。

参见参考资料https://firebase.google.com/docs/database/server/retrieve-data#section-reading-once https://firebase.google.com/docs/database/server/retrieve-data#section-reading-once

基本上你正在做什么once方法是在读取值后立即删除回调。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FIREBASE 警告:用户回调引发异常。错误:发送后无法设置标头 的相关文章

随机推荐