如何正确地从Node.js API发送响应代码

我有一个简单的基于节点的API,它需要parsing一些JSON,将一些数据保存到Postgres中,然后发送相应的响应代码(如http 201)。 我的代码如下所示:

router.route('/customer') .post(function(req, res) { Customers = req.body; var numberOfCustomers = Customers.length; for(var i = 0; i < Customers.length; i++){ Customer = Customers[i]; console.log(Customer.Name + " " + Customer.Address); var date = moment(new Date()).unix(); client.query( 'INSERT into customer (name, address, date_modified) VALUES($1, $2, $3) RETURNING id', [Customer.Name, Customer.Address, date], function(err, result) { if (err) { console.log(err); status = 1; } else { console.log('row inserted with id: ' + result.rows[0].id); if(numberOfCustomers === i) { res.status(201).send({ message: "created" }); } } }); } }) 

我得到这个错误:

_

 http_outgoing.js:344 throw new Error('Can\'t set headers after they are sent.'); ^ Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11) 

我需要说明的是,我在一个循环内多次执行我的Postgres插入,所以在第一次插入完成之后,我无法发送我的响应头文件。

什么是我的“POST”处理程序中最适合放置我的res.status(201).send({ message: "created" });

除了架构决定之外(例如,您可能需要一个单独的模块,作为HTTP适配器来处理发送响应代码的逻辑,而不是在您的路由控制器内执行),可以使用promise等待所有插入完成然后发送一个单一的响应码。 例如,像这样的东西:

 var Promise = require('bluebird'); var query = Promise.promisify(client.query); router.route('/customer') .post(function(req, res) { // all your logic, and then return Promise.all(Customers.map(function() { return query(sql, [Customer.Name, Customer.Address, date]); }) .then(function() { res.status(201).send({ message: 'Created' }); }); }); 

查看本示例中使用的API 的蓝鸟文档 。

我不熟悉Postgres的API,但是这个概念应该是类似的:你需要等待所有的数据库请求被首先解决。

如上所述:是的,像承诺和asynchronous这样的asynchronous帮助程序对这些问题是有益的。 不过,我确实相信解决这个问题的“最佳”方法是只使用一个查询。 不是每个查询只执行一次插入,而是将它们全部整理成单个查询,如下所示:

 INSERT into customer (name, address, date_modified) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9), ... RETURNING id' 

build议

 router.route('/customer').post(function(req, res) { //Fetch customers var customers = req.body; //Store parameters and query inserts for db-query. var params = []; var inserts = []; //For each customer // - Add parameters for query // - Build insert string customers.forEach(function(customer){ inserts.push( [ "($", params.push(customer.Name), ", $", params.push(customer.Address), ", ", NOW(), //unnecessary to generate timestamp in js ")", ].join('') ) }); //Build query var query = 'INSERT into customer (name, address, date_modified) VALUES '+ inserts +' RETURNING id'; //Query database in a more simple fashion. client.query(query, params, function(err, result) { if (err) { console.log(err); status = 1; } else { res.status(201).send({ message: "created" }); }); } }) 

如果您使用ES6,则可以使用string模板来简化string构build操作。

 customers.forEach(function(customer){ var query = `($${params.push(customer.Name)}, $${params.push(customer.Address)}, NOW())` inserts.push(query); }); //and var query = ` INSERT into customer (name, address, date_modified) VALUES ${inserts} RETURNING id `; 

正确的方法是,我也build议你看看Async or lodash lib

 router.route('/customer') .post(function(req, res) { var Customers = req.body, numberOfCustomers = Customers.length; for(var i = 0; i < Customers.length; i++){ var Customer = Customers[i]; console.log(Customer.Name + " " + Customer.Address); var date = moment(new Date()).unix(), sql = 'INSERT into customer (name, address, date_modified) VALUES($1, $2, $3) RETURNING id'; client.query(sql, [Customer.Name, Customer.Address, date], function(err, result) { if (err) { console.log(err); res.status(500).json({message: "Server Error", err: err}); } else { console.log('row inserted with id: ' + result.rows[0].id); if (numberOfCustomers === i) { res.status(201).send({ message: "Created" }); } } }); } })