Caio Fontes
Caio Fontes

Reputation: 2143

Can only make one GET request without error: "Can't set headers after they are sent."

I want my http server to return some json returned from a async function. I've managed to make it work, but it only works once, then it throws: "Can't set headers after they are sent." error.

here is the following code:

var server = restify.createServer();

server.get('/', function(req, res, next) {
    feed("dilma",[]);
    eventEmitter.on('retorno', function(retorno){   
        res.send(retorno);
    });
});

server.on("listening", function() {
   console.log("server running!");
});

server.listen(7171);

feed function:

var feed = function headLinesBySite(word, l) {
    if (!Array.isArray(l)) {
        console.log("por favor passe um array");
        return false;
    }
    if (l !== []) {
        links = l;
    }
    links = ["http://www.estadao.com.br/", "http://atarde.uol.com.br/"];
    var teste = 0;
    var final = [];
    for (i = links.length - 1; i >= 0; i--) {
        findHeadlines(links[i], word.toLowerCase(), function(r, url) {
            final.push({
                url: url,
                manchetes: r
            });
            //console.log(url+" - "+r);
            teste++;
            console.log((teste / links.length) * 100 + "%");
            if (teste === links.length) {
                console.log("Concluído!");
                console.log(final);
                eventEmitter.emit('retorno', final);
            }
        });
    }
};

findHeadlines function:

var findHeadlines = function findHeadlines(url, word, cb) {
    request(url, {
        timeout: 1000
    }, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            $ = cheerio.load(body);
            texto = [];
            var retorno = [];
            b = $('body').text().toLowerCase();
            c = b.replace(/\s+/g, ' ');
            texto = c.split("¬");
            for (var i = texto.length - 1; i >= 0; i--) {
                if (texto[i].search(word) !== -1 && texto[i].length < 100) {
                    //console.log(texto[i]);
                    retorno.push("+" + texto[i] + "+");
                }
            }
            cb(retorno, url);
        } else {
            console.log(error);
            cb([], url);
        }
    });
};

The first time I call localhost/7171 I get the info, but after that, any GET request throws : "Can't set headers after they are sent.". I've read some similar questions about this same error but none of them helped me fix it... I just want to make the GET request wait for the async return of the feed function... Appreciate any help.

Upvotes: 2

Views: 62

Answers (1)

Golo Roden
Golo Roden

Reputation: 150614

With

eventEmitter.on('retorno', function(retorno){   
    res.send(retorno);
});

you are subscribing to the retorno event, but you never unsubscribe. Hence, if the event is raised a second time, the old route handler runs res.send again - but now on an already closed connection.

Change on to once and the problem might be gone. For more details one would have to have a closer look at your entire code.

Hope this helps.

With subscribing and unsubscribing I mean that subscribing is like saying "From now on, I want to get notified when event X happens". This is valid until you say that you aren't interested any more (i.e., you unsubscribe). on is the equivalent of subscribe, usually you have to use removeListener to unsubscribe.

If you use once, you are effectively saying that you are subscribing, but only until the event has happened a single time - and then you would like to unsubscribe automatically. That's why it works then :-)

Upvotes: 2

Related Questions