Express Static and setHeaders: "Error: Can't set headers after they are sent."

Viewed 1132

I get the error Error: Can't set headers after they are sent. with the following code.

app.use('/assets/u', express.static('./public/img/u', {
  setHeaders: (res, path, stat) => {
    redis.get(`image-mime:1`, (err, reply) => {
      if (err) console.log(err);
      res.set('Content-Type', reply);
    });
  },
}));

I think it has something to do with the callback? Because it I remove the callback in the following way:

app.use('/assets/u', express.static('./public/img/u', {
  setHeaders: (res, path, stat) => {
    res.set('Content-Type', 'image/png');
  },
}));

everything works like it should and I get no errors. Would love some help on this problem.

Edit: When I turn on the Chrome devtools' "Disable Cache", the error disappears. And the moment I turn it off, the error is back.

1 Answers

This is because setHeaders() needs to run synchronously. Solution is to reverse the calls:

app.use('/assets/u', (res, res, next) => {
  redis.get(`image-mime:1`, (err, reply) => {
    if (err) return next(err);
    res.set('Content-Type', reply);
    next();
  });
}, express.static('./public/img/u'));

The first middleware retrieves the mime-type and calls serve-static only when done, unless an error happens.

Have in mind that it would call redis even when the client already has the latest copy of the object, comparing E-Tags, returning 304 in this case. This should explain why turning on Disable Cache, the error doesn't show up. There is a different path when client has got the object already in cache, and when it don't.

Related