FIREBASE警告:用户回调引发了异常.错误:发送后无法设置标题 [英] FIREBASE WARNING: Exception was thrown by user callback. Error: Can't set headers after they are sent
问题描述
我们正在开发一个应用程序,其中我们将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屋!