Nodejs Express unwanted behavior: getting two different http requests replied in a unique answer

1.2k Views Asked by At

Here is the code:

FILE: server.js 
var express = require('express'),
    app = express(),
    useragent = require('express-useragent'),
    compression = require('compression'),
    vhost = require('vhost');

app.use(vhost("blabla.com", 'app.js'));
app.disable('x-powered-by');
app.use(compression());
app.use(useragent.express());
app.listen(80);

FILE app.js
var useragent = require('express-useragent'),
        express = require('express'),
        sessao = require('express-session'),
        armazenamento_ficheiros = require('session-file-store')(sessao),
        compression = require('compression'),
        app = express(),
        favicon = require('serve-favicon');

global.uuid = require('uuid');

app.all('/u/my.json', function (req, res) {
    var body = '';
    p.on('data', function (d) {
        body += d;
    });
    p.on('end', function () {
        var g = require('./gateway');
        g.e(body,res);
    }, 'utf-8');
});

module.exports = app;

FILE:gateway.js
module.exports = {
    e: function (body,res) {
    //connects to database using data in body and send results to client....
    res.header("Cache-Control", "no-cache, no-store, must-revalidate");
    res.header("Pragma", "no-cache");
    res.header("Expires", 0);
    res.header('Last-Modified', (new Date()).toUTCString());
    res.header("Content-type", "application/json; charset=utf-8");
    res.send(JSON.stringify({"a":1}));
    }
};

The problem is that sometimes, the client makes two http requests and randomly, both are replied in a unique answer instead of each http request getting a corresponding reply. The problem seems to be when one of the http request makes a request to a database (creating a delay in getting the answer) and gets replied in another request. Since i send the headers, it gives error.
I check that the gateway.js file is loaded and executed with each http request but i do not understand why they get mixed. What is wrong with my code? Any help will be appreciate. Thank you.

1

There are 1 best solutions below

5
On BEST ANSWER

Yep, when using async code, you can't assign a unique function to a global variable and then expect the right async operation to get the right unique function out of the global. Your code doesn't run synchronously so you can't put something into a shared variable and then know that the right thing will be there at the right time and not have been overwritten. That's just a bad design that will never be reliable.

In Express architected servers, there is a unique request and response object created for each request and at least the response object is usually passed around until the response is done (since it is needed to make the response). If you need a place to store data that is specific to this particular request, then you can add your own custom property to the response or request object and you will avoid the issue where two requests running in overlapping timeframes because of async operations might trounce each other's state.

I don't completely follow your code, but since it appears you are passing the response object around, you can put a unique function on the response object and then call it from there. But even better would be to pass your unique data along with the response object rather than create a new function each time.

Other issues I see:

  1. You're creating multiple app objects by doing var app = express(); more than once. That is rarely the right implementation. You will usually want to create only one app object and that should be the one that you call app.listen(80) on.

  2. Your single letter variable names make your code a lot harder for someone who does not already know your code to immediately understand it. Please use descriptive and meaningful variable names. This is not a place to try to save a few bytes.

  3. What is the first argument to global.make_reply() supposed to be? When you define that function, you make it look like a response object that has a .header() and .send() method. But, when you call it in gateway.js, you pass a string as that first argument. I don't see how this could possibly work as you've written the code.