简体   繁体   中英

ExpressJs res.json : Can't set headers after they are sent

I'm using expressjs, I have a route like this:

router.route('/monitor')
.all(function (req, res, next) {
    next();
}).get(monitor.monitorServers);

And a controller (called monitor, that has monitorServers function called by the above router), here's the complete code for the controller:

    var argv = require('minimist')(process.argv.slice(2));
var path = require("path");
var config = require(path.resolve(argv.conf));
var bunyan = require('bunyan');
var log = require(path.resolve('./lib/logger')).createLogger;
// create the S3 object
var AWS = require('aws-sdk');

var commonFunctions = require(path.resolve('./lib/functions-common'));
var async = require('async');

/**
 * Monitor the different severs needed by the book server (check if they still running and connected to them)
 * @param req
 * @param res
 */
exports.monitorServers = function (req, res) {
    // Redis Clients
    var redisBs = commonFunctions.createRedisBS();
    var redisMapi = commonFunctions.createRedisMapi();
    var s3 = new AWS.S3();
    // default values for the response
    var status = 200;
    var message = "Ok";
    var errorMessage = "There's was an error in the book service, check the log to see which part";
    async.waterfall([
        /**
         * Check Redis server of the book service
         * @param callback
         */
        function (callback) {
            redisBs.on('ready', function (error) {
                if (error) {
                    log.fatal({part: 'Redis'}, error);
                }
                if (!redisBs.connected) {
                    status = 500;
                    message = errorMessage;
                    log.fatal({part: 'Redis'}, 'Book service failed to connect to its Redis Server');
                }
                callback(null);
            });
        },
        /**
         * Check the redis server of Mapi
         * @param callback
         */
        function (callback) {
            //REDIS MAPI
            redisMapi.on('ready', function (error) {
                if (error) {
                    log.fatal({part: 'Redis'}, error);
                }
                if (!redisBs.connected) {
                    status = 500;
                    message = errorMessage;
                    log.fatal({part: 'Redis Mapi'}, 'Book service failed to connect to Redis Mapi');
                }
                callback(null);
            });

        },
        /**
         * Check the S3 bucket connexion
         */
        function () {
            s3.headBucket({Bucket: config.bucketEnc}, function (error) {
                if (error) {
                    status = 500;
                    message = errorMessage;
                    log.fatal({part: 'AWS S3'}, 'Book service failed to connect to AWS S3 bucket ' + error);
                }
                res.status(status);
                res.json({book_service: message});
            });

        }

    ], function (err) {  // in case of unexpected error
        if (err) {
            log.error("There was an error on monitoring " + err);
            res.end();
        }
    });

};

The response is returned correctly from the controller, but from time to time, even when I don't call the route, I get error saying Can't set headers after they are sent The error is fired on line where I put res.json({book_service: message}); Do you have any idea where's the root of the error?

You should handle both success and failure case in the final callback of async.waterfall() rather than in the middle of waterwall process.

/**
 * Check the S3 bucket connexion
 */
function (callback) {
    s3.headBucket({Bucket: config.bucketEnc}, function (error) {
        if (error) {
            status = 500;
            message = errorMessage;
            log.fatal({part: 'AWS S3'}, 'Book service failed to connect to AWS S3 bucket ' + error);
            callback(error);
        }

        // VERY IMPORTANT TO ENSURE WATERFALL PROCESS CAN FINISH!
        callback(null, {book_service: message});
    });
}

// Final callback of async.waterfall()
function (err, data) {  // in case of unexpected error
    if (err) {
        log.error("There was an error on monitoring " + err);
        res.end();
    } else {
        res.json(data);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM