Javascript 如何从Node.js API正确发送响应代码
我有一个简单的基于节点的API,它需要解析一些JSON,将一些数据保存到Postgres中,然后发送相应的响应代码,如http 201。 我的代码如下所示:Javascript 如何从Node.js API正确发送响应代码,javascript,sql,node.js,postgresql,Javascript,Sql,Node.js,Postgresql,我有一个简单的基于节点的API,它需要解析一些JSON,将一些数据保存到Postgres中,然后发送相应的响应代码,如http 201。 我的代码如下所示: router.route('/customer') .post(function(req, res) { Customers = req.body; var numberOfCustomers = Customers.length; for(var i = 0; i < Cus
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" });
}
}
});
}
})
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' });
});
});
我需要说明一个事实,我在一个循环中多次执行Postgres插入,因此在第一次插入完成后,我无法发送响应头
在我的“POST”处理程序中,放置res.status201.send{message:created}最合适的位置是什么;
正确的方法是,我还建议您研究异步或lodash库
正确的方法是,我还建议您研究Async或lodash库
撇开架构决策不谈,例如,您可能需要一个单独的模块作为HTTP适配器来处理发送响应代码的逻辑,而不是在路由控制器内部执行,您可以使用承诺等待所有插入完成,然后发送单个响应代码。例如,类似这样的内容:
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" });
}
}
});
}
})
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,但其概念应该类似:您需要等待数据库的所有请求首先得到解决。例如,除了架构决策,您可能需要一个单独的模块,作为HTTP适配器来处理发送响应代码的逻辑,而不是在路由控制器内部执行,您可以使用承诺等待所有插入完成,然后发送单个响应代码。例如,类似这样的内容:
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" });
}
}
});
}
})
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,但其概念应该是类似的:您需要等待数据库的所有请求首先得到解决。如上所述:是的,异步助手(如Promises和async)对这些问题是有益的。然而,我相信解决这个问题的“最佳”方法是只使用一个查询。不是每个查询只执行一次插入,而是将它们全部批处理到一个查询中,如下所示:
INSERT into customer (name, address, date_modified)
VALUES
($1, $2, $3),
($4, $5, $6),
($7, $8, $9),
...
RETURNING id'
暗示
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,则可以通过使用字符串模板简化字符串生成操作
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
`;
如上所述:是的,异步助手(如Promissions和async)对这些事情是有益的。然而,我相信解决这个问题的“最佳”方法是只使用一个查询。不是每个查询只执行一次插入,而是将它们全部批处理到一个查询中,如下所示:
INSERT into customer (name, address, date_modified)
VALUES
($1, $2, $3),
($4, $5, $6),
($7, $8, $9),
...
RETURNING id'
暗示
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,则可以通过使用字符串模板简化字符串生成操作
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
`;
最合适的位置是您希望向请求发送单个响应的位置。这完全取决于您的需求,最合适的位置是您希望发送对请求的单个响应的位置。这完全取决于您的要求。为什么不使用承诺的本机实现?@cbass如果您使用的是最新的node.js,那么您可以使用承诺的本机实现。或者,如果您使用的是旧版本,并且希望将es6传输到es5,这也是一个选项。为什么不使用承诺的本机实现?@cbass如果您使用的是最新的node.js,那么您可以使用承诺的本机实现。或者,如果您使用的是旧版本,并且希望将您的es6传输到es5,这也是一个选项。不幸的是,这将导致OP看到的相同问题。您正在循环中改变标题。因此,在第一次迭代之后,您将得到一个errorTrue@Seth,但是if块仅在出现错误时返回,并返回数组中无法处理的特定对象的错误堆栈。我认为应该有一个退出,只是为了保持数据库的干净。如果第一次迭代成功,第二次迭代失败怎么办?标题已设置,响应在此点终止,导致再次出现现有问题。不幸的是,这将导致OP看到的问题相同。您正在循环中改变标题。因此,在第一次迭代之后,您将得到一个errorTrue@Seth,但是if块仅在出现错误时返回,并返回数组中无法处理的特定对象的错误堆栈。我认为应该有一个退出,只是为了保持数据库的干净。如果第一次迭代成功,第二次迭代失败怎么办?标题将已经设置,响应将在该点终止,从而再次导致现有问题。