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

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

我有一个简单的基于节点的API,它需要解析一些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" });
                        }
                    }
                });
        }
    })
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块仅在出现错误时返回,并返回数组中无法处理的特定对象的错误堆栈。我认为应该有一个退出,只是为了保持数据库的干净。如果第一次迭代成功,第二次迭代失败怎么办?标题将已经设置,响应将在该点终止,从而再次导致现有问题。