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

how to properly send the response code from Node.js API

本文关键字:响应 代码 API js 正确地 Node      更新时间:2023-09-26

我有一个简单的基于节点的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" });
                        }
                    }
                });
        }
    })

我得到这个错误:

_

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" });的最合适的位置是什么div ?

不考虑架构决策(例如,您可能需要一个单独的模块作为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' });
   });
});

查看bluebird文档,了解本例中使用的API。

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

如上所述:是的,async helper(如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
`;

正确的做法是,我还建议您查看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" });
                    }
                }
            });
    }
})