Context
When you have a resource that can be fetched from another domain you must set Access-Control-* headers on the response. Normally send() passes through the original response object and it's all good. But when the resource cannot be found, say it's a 404 error, then all headers are cleared in the error handler, and only some basic headers are set.
Problem
This means that the javascript fetch() call from another domain will return a CORS error, and will never find a 404 status code.
Workaround
I wrote some workaround to fix this issue in my webapp, I was surprised to find there was no event or option to allow passing through certain headers or updating headers before the error response is sent.
For reference, this is how I fixed it, not sure if there are any other headers that may be worth passing through, or if it's only the CORS and any custom headers (like X-Powered-By or whatever).
import statuses from 'statuses';
import escapeHtml from 'escape-html';
const response_stream = send(...);
const createHtmlDocument = function(title, body)
{
return '<!DOCTYPE html>\n' +
'<html lang="en">\n' +
'<head>\n' +
'<meta charset="utf-8">\n' +
'<title>' + title + '</title>\n' +
'</head>\n' +
'<body>\n' +
'<pre>' + body + '</pre>\n' +
'</body>\n' +
'</html>\n';
};
response_stream.on('error', (err) =>
{
const msg = statuses.message[err.status] || String(err.status);
const doc = createHtmlDocument('Error', escapeHtml(msg));
const res = response_stream.res;
// set status code
res.statusCode = err.status;
// clear all headers unless it's preserved (for CORS purposes etc)
const headers = res.getHeaders();
for(const k in headers)
{
const name = k.toLowerCase();
const value = headers[k];
if(name === 'vary') continue;
if(name.startsWith('x-')) continue;
if(name.startsWith('access-control-')) continue;
res.removeHeader(k);
}
// add error headers
if(err && err.headers)
{
for(const k in err.headers)
{
res.setHeader(k, err.headers[k]);
}
}
// set error headers
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
res.setHeader('Content-Length', Buffer.byteLength(doc));
res.setHeader('Content-Security-Policy', "default-src 'none'");
res.setHeader('X-Content-Type-Options', 'nosniff');
res.end(doc);
});
response_stream.pipe(response);
Context
When you have a resource that can be fetched from another domain you must set Access-Control-* headers on the response. Normally send() passes through the original response object and it's all good. But when the resource cannot be found, say it's a 404 error, then all headers are cleared in the error handler, and only some basic headers are set.
Problem
This means that the javascript fetch() call from another domain will return a CORS error, and will never find a 404 status code.
Workaround
I wrote some workaround to fix this issue in my webapp, I was surprised to find there was no event or option to allow passing through certain headers or updating headers before the error response is sent.
For reference, this is how I fixed it, not sure if there are any other headers that may be worth passing through, or if it's only the CORS and any custom headers (like X-Powered-By or whatever).