3
votes

I want to make serial work on backend. I want to select geo_unit and do another work and write response to client. I read http://nodejs.org/docs/v0.4.7/api/events.html#events and Error: Can't set headers after they are sent to the client

Everything works fine when I send the requests slowly e.g. 1 in each 3 seconds.

But it doesnot work when i send the requests fast. and i get the following error. Do i define something globally?


Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (http.js:691:11)
    at ServerResponse.res.setHeader (E:\git\xxxxxx-nodejs\node_modules\express\node_modules\connect\lib\patch.js:63:22)
    at ServerResponse.res.set.res.header (E:\git\xxxxxx-nodejs\node_modules\express\lib\response.js:527:10)
    at ServerResponse.res.json (E:\git\xxxxxx-nodejs\node_modules\express\lib\response.js:194:36)
    at EventEmitter. (E:\git\xxxxxx-nodejs\routes\api_scrapper.js:17:17)
    at EventEmitter.emit (events.js:117:20)
    at ScrapperAPI.externalLocationCallback (E:\git\xxxxxx-nodejs\routes\api_scrapper.js:27:20)
    at Query._callback (E:\git\xxxxxx-nodejs\routes\api_scrapper.js:51:21)
    at Query.Sequence.end (E:\git\xxxxxx-nodejs\node_modules\mysql\lib\protocol\sequences\Sequence.js:78:24)
    at Query._handleFinalResultPacket (E:\git\xxxxxx-nodejs\node_modules\mysql\lib\protocol\sequences\Query.js:143:8)


I am using the following code :


var express = require('express'),
  http = require('http'),
  path = require('path');

var app = module.exports = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var request = require('request');
var cheerio = require('cheerio');


var mysql = require('mysql');
var pool = mysql.createPool({
    host : 'localhost',
    user : 'root',
    database :'evevgez_development',
    password : 'root',
     // socketPath  : '/var/run/mysqld/mysqld.sock'
});

var sahibinden = require('./routes/my_scrapper').newScrapperAPI(pool);

app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(path.join(__dirname, 'public')));
app.use(app.router);
app.use(express.errorHandler());

app.get('/node1', sahibinden.scrap);

server.listen(app.get('port'), function () {
  console.log('Express server listening on port ' + app.get('port'));
});

and myModule is like that


var request = require('request');
var cheerio = require('cheerio');
var iconv = require('iconv-lite');
var EventEmitter = require('events').EventEmitter;
var emitter= new EventEmitter();


function ScrapperAPI(pool) {
    this.scrap = function (req, res,next) {
        var query = req.query;
        console.log('req.params:'+req.query);
        console.log('IL_ID:'+query.il_id);
        emitter.emit('location',query);
        emitter.on('success',function(rows){
            res.json(rows);
        });

    };

    emitter.on('location',function(query){
        console.log('quey1:'+query);
        getExternalLocation(query )
    });

    var getExternalLocation = function (query ) {
        try {
            pool.getConnection(function (err, connection) {

                console.log('query:'+query);
                connection.query("select * from external_geo_units where geo_unit_id = ?  ",query.il_id, function (err, rows) {
                    console.log(err);
                    if (err)    callback(err);
                    emitter.emit('success',rows);
                    connection.release();
                });

            });
        } catch (e) {
            console.log(e);
        }

    };
}

module.exports.newScrapperAPI = function (pool) {
    return new ScrapperAPI(pool);
}
1

1 Answers

7
votes

Using an EventEmitter in this way isn't the best solution for what you're doing, since you're just using it within a request to make a database call and return some rows -- something that could be more easily and simply done with just callbacks.

However if you want to keep the global EventEmitter, you have to switch the on in emitter.on('success' and emitter.on('location' to once instead, to ensure they only get called once per request.