FIREBASE警告:用户回调引发了异常.错误:发送后无法设置标题 [英] FIREBASE WARNING: Exception was thrown by user callback. Error: Can't set headers after they are sent

查看:44
本文介绍了FIREBASE警告:用户回调引发了异常.错误:发送后无法设置标题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在开发一个应用程序,其中我们将Firebase用作数据库,并表示为路由RESTful API的中间件/后端,该RESTful API由Reactjs中开发的前端使用.

We are developing an app where we are using Firebase as a database and express as the middleware/backend for routing our RESTful API's which is used by our Front-end developed in Reactjs.

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

Below is what our server.js file looks like:

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中存在的路由代码:

Below is the code for routing which is present in 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包:

Below is the code for we added in the front-end for posting data. We are also using whatwg-fetch package:

httpservice.js:

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(反应组件文件)

VendorForm.js (React component file)

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

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

We start our server which provides RESTful API developed in FIREBASE + EXPRESS through nodemon. This is the error that we are receiving when we post our:

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...

根据错误,我们知道某些回调将标头设置两次,但不确定其发生方式.经历了几个堆栈溢出问题,但仍未找到解决方案.任何帮助,将不胜感激.谢谢您的期待.

As per the error, we know that some callback is setting the header twice but not sure how is it happening. Been through few stack overflow questions but still didn't find the solution. Any help would be appreciated. Thanks in anticipation.

推荐答案

如果看到堆栈跟踪

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

文件route.js中的第30行

Which is line 30 in file route.js

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

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

You need to change method on for once, otherwise your callback function gets triggered every time there is an update to your data,

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

调用标头方法时中断响应,因为标头已经在第30行中发送了.

breaking your response when you call post method since headers are already sent in line 30.

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

基本上,您使用 once 方法执行的操作是在读取值后立即删除回调.

Basically what you are doing with the once method is removing the callback immediately after value is read.

这篇关于FIREBASE警告:用户回调引发了异常.错误:发送后无法设置标题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆