I’ve recently come across a problem when working with the built-in req.accepts
, req.acceptsLanguages
, req.acceptsCharsets
, and req.acceptsEncodings
functions in express.
I have an express middleware function like this:
function acceptCheckpoint(acceptOpts) { // Calling the following function results in a TypeError. function checkAccept(req, res, opts) { let acceptFunction = null; switch (opts.whichAccept) { case "type": acceptFunction = req.accepts; break; case "lang": acceptFunction = req.acceptsLanguages; break; case "charset": acceptFunction = req.acceptsCharsets; break; case "encoding": acceptFunction = req.acceptsEncodings; break; default: acceptFunction = req.accepts; break; } return acceptFunction(opts.acceptedTypes); } return (req, res, next) => { const accepted = []; Object.getOwnPropertyNames(acceptOpts).forEach(key => { if (key === "ignoreAcceptMismatch") { return; } const acceptsType = checkAccept(req, res, { whichAccept: key, acceptedTypes: acceptOpts[key] }); accepted.push(acceptsType); }); if (accepted.some(type => !type) && !acceptOpts.ignoreAcceptMismatch) { res.type("html"); res.status(406); res.send("<h1>406 Not Acceptable.</h1>"); return; } next(); }; }
Which, in theory, should work. But the program keeps complaining and logs this error:
TypeError: Cannot read property 'headers' of undefined at new Accepts (/Users/hortoncheng/Desktop/Programs/colonialwars/dev/node_modules/accepts/index.js:37:22) at Accepts (/Users/hortoncheng/Desktop/Programs/colonialwars/dev/node_modules/accepts/index.js:34:12) at req.accepts (/Users/hortoncheng/Desktop/Programs/colonialwars/dev/node_modules/express/lib/request.js:133:16) at checkAccept (/Users/hortoncheng/Desktop/Programs/colonialwars/dev/Lib/middleware.js:208:12) at /Users/hortoncheng/Desktop/Programs/colonialwars/dev/Lib/middleware.js:216:27 at Array.forEach (<anonymous>) at /Users/hortoncheng/Desktop/Programs/colonialwars/dev/Lib/middleware.js:214:44 at Layer.handle [as handle_request] (/Users/hortoncheng/Desktop/Programs/colonialwars/dev/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/Users/hortoncheng/Desktop/Programs/colonialwars/dev/node_modules/express/lib/router/index.js:317:13) at /Users/hortoncheng/Desktop/Programs/colonialwars/dev/node_modules/express/lib/router/index.js:284:7
The thing is, when I use req.accepts
or one of those .accepts
functions in the main function (acceptCheckpoint
), like this:
// Pretend we're in acceptCheckpoint... // This works. accepted.push(req.accepts("html"));
It works. And, when I log the req
object in either of those functions, it returns the expected value. I’ve also tried logging the req
object in the request.js
file of the express module, and there, it returned undefined
. So that led me to believe that it was a problem with express itself. I tried deleting package-lock.json and node_modules, and then running npm install
. Didn’t fix it. And yes, I’m calling the express middleware function correctly. Any idea why this is happening?
I’m using express v4.17.1, Node.JS v12.18.1, and NPM v6.14.5.
Advertisement
Answer
The function is presumably trying to get req
from its this
context. But you’re not passing functions with context.
Change this line:
return acceptFunction(opts.acceptedTypes);
to:
return acceptFunction.call(req, opts.acceptedTypes);
The first argument to the call()
method is the object that should be used as this
in the called function.