"Cannot set headers..." error happening only on one specific kind of request
See original GitHub issueI’m using Node 10.1.0, and node-static v0.7.2. The error stack in my logs:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:471:11)
at ServerResponse.writeHead (_http_server.js:231:21)
at Server.finish (/tmp/site/node_modules/node-static/lib/node-static.js:125:17)
at finish (/tmp/site/node_modules/node-static/lib/node-static.js:170:14)
at /tmp/site/node_modules/node-static/lib/node-static.js:337:13
at streamFile (/tmp/site/node_modules/node-static/lib/node-static.js:382:13)
at ReadStream.<anonymous> (/tmp/site/node_modules/node-static/lib/node-static.js:375:17)
at ReadStream.emit (events.js:182:13)
at fs.close (fs.js:2161:14)
at FSReqWrap.oncomplete (fs.js:152:20)
I’m experiencing this persistent error every single time a specific kind of request comes in – but only for that, all other requests are fine – which appears to be a request from a Slackbot. Here are the request headers from the specific request:
{"x-forwarded-host":"my.domain.tld","x-forwarded-proto":"https","x-forwarded-port":"443","x-forwarded-for":"::ffff:52.71.192.87","if-modified-since":"Mon, 17 Oct 2016 23:58:19 GMT","accept-encoding":"gzip,deflate","accept":"*/*","user-agent":"Slackbot 1.0 (+https://api.slack.com/robots)","host":"my.domain.tld","connection":"close"}
Here’s my code:
"use strict";
var path = require("path");
var http = require("http");
var httpServer = http.createServer(handleRequest);
var nodeStatic = require("node-static");
var staticServer = new nodeStatic.Server(path.join(__dirname,"static"),{
serverInfo: "my-server",
cache: 86400,
gzip: true,
});
const HSTS = `max-age=${1E9}; includeSubdomains`;
httpServer.listen(8003);
// *********************
function handleRequest(req,res) {
// unconditional, permanent HTTPS redirect
if (req.headers["x-forwarded-proto"] !== "https") {
res.writeHead(301,{
"Strict-Transport-Security": HSTS,
"Cache-Control": "public, max-age=31536000",
Expires: new Date(Date.now() + 31536000000).toUTCString(),
Location: `https://${req.headers["host"]}${req.url}`
});
res.end();
}
else if (["GET","HEAD"].includes(req.method)) {
req.addListener("end",function requestEnd(){
req.removeListener("end",requestEnd);
res.setHeader("Strict-Transport-Security",HSTS);
staticServer.serve(req,res);
}).resume();
}
else {
res.writeHead(404,{ "Strict-Transport-Security": HSTS });
res.end();
}
}
As you can see, my server is running on localhost:8003
– I have a public server on 80/443 that proxies the requests after doing SSL certificate handling, etc.
In my debugging, I have narrowed down that the error happens inside of the staticServer.serve(..)
call itself, not in this code shown.
And the res.setHeader(..)
call that I make before serve(..)
seems to cause the error, though I don’t understand why. If I comment that line of code out, the error stops.
But my understanding is that me calling setHeader(..)
only queues up a header to be sent. It’s not supposed to flush headers or anything, only prepare a header for later sending. I don’t have any other calls in that code path to res.writeHead(..)
or anything, so I can’t figure out how the error is getting triggered.
I am aware that I could set this response header in the new nodeStatic.Server(..)
constructor call. But I don’t want to do it there, because I actually need to be able to set specific headers on a per-request basis under certain conditions, and that approach sets headers for all static-file responses.
Can you help me figure out why, in only this one specific Slackbot request case, my call to setHeader(..)
is triggering logic in node-static that causes this error? I’m really perplexed.
Issue Analytics
- State:
- Created 5 years ago
- Comments:12
BTW, another reason I can’t just only set headers in the
headers
config of the constructor: certain headers have timestamps in them, and those would be calculated at the time the node server starts up, and never be re-calculated. But they actually should be relative to (recalculated at) each request. Otherwise, the longer the server stays alive without a restart, the more inaccurate that header’s timestamp would be. 😦My only viable option here is to be able to call
setHeader(..)
upon each request. That’s why I need this problem fixed.So far, HEAD shouldn’t send headers which GET wouldn’t; which I guess you aren’t.
Other than that, yes, you can call
writeHead
as many times as you want, if you don’t callsetHeaders()
.