I recently read a blog in Nodejitsu and I am wondering how this piece of code works.
var fs = require('fs'),
http = require('http'),
httpProxy = require('../lib/node-http-proxy');
module.exports = function (logging) {
// Code here is run when the middleware is initially loaded.
var logFile = fs.createWriteStream('./requests.log');
return function (request, response, next) {
// Code here is run on each request.
if (logging) {
logFile.write(JSON.stringify(request.headers, true, 2));
}
next();
}
}
And the explanation given for this piece of code is:
This middleware is for very simple logging - it will write the headers of each request to a log file.
the above module exported can be used as,
httpProxy.createServer(
require('./example-middleware')(true),
8000, 'localhost'
).listen(9000)
How is the code in the above method with next() invoked in every request? The usage is pretty simple: require the above module and it gets invoked every time.
I'll simplify the actual process but the gist of it:
When a request comes in, node passes the request and response object to the first middleware in the middleware stack. If that middleware sends a response or closes the connection in any way, then subsequent middleware are not called. Otherwise, that middleware has to tell node it's finished doing it's job to keep on moving through the middleware stack, so you call next() within your middleware to tell it to continue processing middleware.
Okay, so this is a pretty common thing. What this module contains is a single function, specified by this line, where we set module.exports to a function, module.exports = function (logging) {. The function returned by the module (and therefore returned by require()) returns another function, which is the middleware for the HTTP proxy (this middleware allows you to transforms the request). This middleware function gets called for every HTTP request made to the server. Quickredfox's answer provides a fairly good explanation of middlewares.
So the require('./example-middleware')(true) actually calls the function assigned to module.exports, but does not call the function inside that, which is returned immediately and passed as a middleware into the httpProxy.createServer function. This is a good way to set up some options for your middleware using closures. If you have any more questions, feel free to comment. :D
Related
My question begs a recommendation on best practice.
I wrote a simple Express server that creates a JWT and sends it to the client whenever it (the client) hits an API route.
I have kept the route handler in a separate module and exported it from there because I want to keep the code as modular as possible. I placed the app.use() call that utilizes the middleware for that route within the callback of signJWT() and though this works, I need to know if this is good practice. I did this because the response to be sent back needs the JWT to be signed and ready and this itself is an asynchronous operation. If this isn't good way to go about it, that is placing an app.use() call within an async callback, I would like to know a better way to do so without having to declare my route handler in the same file as my server entry file (app.js) code.
There are 2 main files to examine here; app.js and routes.js. I have included code from a third file - my client-side JavaScript file (script.js) just for context.
1. app.js (Server + Application-wide middleware usage):
const express = require("express");
const app = express();
const path = require("path");
// JWT Library
const jose = require("jose");
// library for generating symmetric key for jwt
const { createSecretKey } = require("crypto");
// Route handler
const routes = require("./routes");
// Create key
const secretKey = createSecretKey("MySecret", "utf-8");
// Sign the token
async function signJWT() {
const jwt = await new jose.SignJWT({
"urn:example:claim": true,
})
.setProtectedHeader({ alg: "HS256" })
.setExpirationTime("1h")
.sign(secretKey);
return jwt;
}
// Expose static content
app.use(express.static(path.join(__dirname, "public")));
// This works but is this okay?
signJWT().then((jwt) => app.use("/login", routes({ jwt: jwt })));
app.listen(81);
console.log("Listening on port 81");
The callback in question:
Should app.use() even be in callbacks?
// This works but is this okay?
signJWT().then((jwt) => app.use("/login", routes({ jwt: jwt })));
I initially tried to do this, but values from the Async operation in signJWT() weren't ready and understandably so:
app.use("/login", routes({ jwt: signJWT() }));
Of course, this works - I used it initially, but I don't want to clutter app.js with route handler declarations:
app.get("/login", async function (req, res) {
const jwt = await signJWT();
res.json({ jwt: jwt });
});
2. routes.js (Route Handler file):
const express = require("express");
const router = express.Router();
const wrapper = function (route_params) {
router.get("/", function (req, res) {
res.json(route_params);
});
return router;
};
module.exports = wrapper;
3. script.js (Client JavaScript):
document.getElementById("btn").onclick = function () {
makeRequest("/login");
};
function makeRequest(url) {
fetch(url, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
})
.then((res) => res.json())
.then((json) => console.log(json));
}
Sample output (in Client's browser console):
{jwt: 'eyJhbGciOiJIUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6d…Dk3fQ.0C_n25RPQNAP-wxy9PHmpo4SRtXBiiHn0fxGPspqxQM'}
Even though this works, placing an app.use() call within an async callback feels hacky to me and it looks like something that could cause problems later on, to me at least, because Express' execution of top-level code is contingent on an async callback.
Is there a better way to declare this call and pass the async value from signJWT() to it so that it will be available in the route handler?
Thank you.
This statement:
signJWT().then((jwt) => app.use("/login", routes({ jwt: jwt })));
is fine. But, what it means is that the /login route handler will not be defined immediately and your server will actually startup initially without that route defined. Though that is unlikely to cause much of a problem in the real world, it would be technically safer to not start your server until after this asynchronous operation finishes like this:
signJWT().then((jwt) => {
app.use("/login", routes({ jwt: jwt }));
app.listen(81);
console.log("Listening on port 81");
});
Is it advisable to use the Express app.use() method call within an async callback?
That is not a common way to write Express code, but there's nothing technically wrong with it. If setting up your route definitions depend upon some asynchronous operation and you don't have access to top level await, then this is one of your options. The other options would be to gather all your asynchronous info first and then define all the routes together inside of one main callback. Then, it feels more natural as you define all the routes sequentially in one block of code.
This:
app.get("/login", async function (req, res) {
const jwt = await signJWT();
res.json({ jwt: jwt });
});
works quite differently. This calls signJWT() on each /login request whereas the previous calls it only once upon startup. So, you need to decide which architecture you want and go with that version of the code. The first code block above calls signJWT() only once upon server startup. This version calls it for every /login request.
Is it advisable to use the Express app.use() method call within an async callback?
That is perfectly fine. Express pays no attention at all to the return value from the app.use() callback so it doesn't matter to it whether you're returning a promise or returning nothing or returning some random value. Likewise, Express doesn't do anything when the callback returns either so it doesn't matter that it doesn't wait for that returned promise to resolve. Express only continues with route matching when you manually call next(), so again it's just ignoring the promise the async function returns (and that's fine). So, if your code works more easily by using an async callback, that's perfectly fine. You do need to know that your handler is entirely responsible for catching it's own rejections because Express will not catch them for you. Some people use a wrapper with Express to catch rejections (and turn them into 5xx error statuses).
I am writing an express application using
NodeJS v8
express (latest version)
After looking at the onHeaders module and finding out how the module rewrites the HTTP head, I wanted to make use of that function of JavaScript.
I wanted to write a small session system using my SQL server. I am aware of the session module from express, but this module is not able to handle the specific tables and customization, I need.
For convenience reasons I wanted the session to be inserted into the request before the controllers and saved after all controllers finished. (e.g. the writeHead method has been called)
My code in the session looks like:
core = async function(req, res, next) {
res.writeHead = hijackHead(res.writeHead); // Hijack the writeHead method to apply our header at the last
}
//[...](Omitted code)
hijackHead = function(writeFunction) {
let fired = false;
return function hackedHead(statusCode) {
if ( fired ) {
return;
}
//[...](Omitted code)
debug("Session data has changed. Writing");
sessionManager.storeSessionData(session.identifier, session).then(() => { // Promise taking ~60ms to resolve
debug("Finished writing...");
callMe(); // Current idea of calling the writeHead of the original res
});
let that = this, // Arguments to apply to the original writeHead
args = arguments
function callMe() {
debug("Finished! Give control to http, statuscode: %i", statusCode);
writeFunction.apply(that, args); // Call the original writeHead from the response
debug("Sent!")
}
} // End of hackedHead
} // End of hijackHead
The core function is being passed to express as a middleware.
Additionally sessionManager.storeSessionData is a Promise storing data and fulfilling after that, taking ~60ms. The Promise has been testes and works perfectly.
When I now make a request using this Controller, the Node net Module returns the error:
TypeError: Invalid data, chunk must be a string or buffer, not object
at Socket.write (net.js:704:11)
at ServerResponse._flushOutput (_http_outgoing.js:842:18)
at ServerResponse._writeRaw (_http_outgoing.js:258:12)
at ServerResponse._send (_http_outgoing.js:237:15)
at write_ (_http_outgoing.js:667:15)
at ServerResponse.end (_http_outgoing.js:751:5)
at Array.write (/usr/lib/node_modules/express/node_modules/finalhandler/index.js:297:9)
at listener (/usr/lib/node_modules/express/node_modules/on-finished/index.js:169:15)
at onFinish (/usr/lib/node_modules/express/node_modules/on-finished/index.js:100:5)
at callback (/usr/lib/node_modules/express/node_modules/ee-first/index.js:55:10)
Since the new function needs about 30ms to react and return the Promise, the function finishes earlier causing Node to crash.
I already tried blocking the Node loop with a while, timeout or even a recursive function. Neither of them worked.
I tries to simplfy the code as much as possible and I hope that I didn't simplify it too much.
Now I am asking if anybody can help me, how to call the writeHead function properly after the Promise has resolved?
The issue with this is, that net.js directly responds to those methods when writeHead has finished. Even though the head has not been written, it tries to write the body.
Instead it is possible to catch the end()method which will await everything and then close the connection.
Do we use it only in middlewares or the functions with no routes? I have used it in my authentication file...
function ensureAuthenticated(req, res, next){
if(req.isAuthenticated()){
return next();
} else {
req.flash('error_msg' , 'Please login First...')
res.redirect('/users/login');
}
}
You execute it in order to execute the next middleware in the pipe. If you don't execute it manually, you're probably passing it on to a different module that executes it for you. Otherwise, if you don't execute next, you cut the "pipe" short i.e. yours is the last middleware that runs.
In your case it makes perfect sense to call next() when the user is authenticated. That passes the control to the next piece of middleware. It also makes sense not to call next() in the case that you've already established that the user is not authenticated, since in most cases you don't want the rest of the middleware in the "pipe" to execute.
So yes, next() is used by middleware, or modules intended to be called by middleware.
I hope that answers your question.
If you talking about Express framework here - next function is just a callback telling that this particular middleware handler should execute next operation in Express middleware chain.
If you define any handler with signature someHandler(req, res, next) and register it with app.use, it will become a part of that chain. Essentially it just a special callback function - disregarding the purpose of the function itself - route controller, authentication, body parser, etc.
This is something that has been bothering me and I cant seem to find a straight answer.
Here is a form of Node function that I use a lot, it handles a web request and does a bit of IO:
function handleRequest(req, res) {
doSomeIo()
.then(function(result) {
res.send(result)
})
}
This function gets called and the res parameter is set to the current response object and it goes of into the land of IO, while its playing out there a second request comes through and sets the res to a new object? Now the first request comes back from IO, and uses the res object, is this now the first instance or the second i.e. does node essentially make a separate copy of everything each time the handleRequest function is called, with its own parameter values or is there only one instance of it and its parameters? Are the parameters in the the above function safe in an async environment or would it be better to do something like this:
function handleRequest(req, res) {
doSomeIo()
.then(function(res) {
return function(result) {
res.send(result)
}
}(res))
}
Or am I just completely ignorant of how Node and Java Script works, which seems pretty likely.
You don't have to worry at all about this case. The req object contains information about the HTTP request that the server received. Everything is sandboxed in per request basis. This will be helpful for you: What are "res" and "req" parameters in Express functions?
You can expect the current req and res object to remain the same among multiple events (I/O responses are essentially events) unless you do something to them, or you have other middleware that does something. There's no need to do anything like your second code snippet.
If you're new to JavaScript and/or the concept of closures, that's probably why you're uneasy with the syntax.
Each call to the function handleRequest() will not use the same variable values of previous calls to handleRequests(). An easy way to see this behavior would be to log the number of times the method was called, and the value of an incrementer in handleRequest().
Example:
In app.js (or whatever js file you initialize your server in), add the following:
var app = express(),
calls = 0; app.set('calls', calls);
Then in your handler add the following:
function handleRequest(req, res) {
doSomeIo()
.then(function(res) {
req.calls++;
return function(result) {
res.send(req.calls)
}
}(res))
}
You should notice that each call to the endpoint, no matter how quickly you make each call, count increases by 1 each time (get ready for race conditions).
I am working through an excellent tutorial on using the Node.js package Passport (link) for user authentication, and I ran into a piece of code that I really don't understand:
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user : req.user // get the user out of session and pass to template
});
});
My question is with the isLoggedIn parameter. I looked at the official site, and did some google searches, but nowhere does it say that you can pass three parameters into app.get. I've only ever seen two. What is this third (optional, I assume) parameter?
I'm not asking about the isLoggedIn itself, but rather, about the fact that it's a third parameter I've never seen passed into app.get() before.
It's called middleware, and it's called before the third parameter (the callback).
Middleware functions examples: access checks, check to see if user is logged in before passing resources, and such.
It's in the express documentation: http://expressjs.com/en/5x/api.html#app.get
The syntax is:
app.get(path, callback [, callback ...])
i.e.
app.get(path, ...callback)
The syntax includes taking in a path as the first parameter, followed by as many middleware (having access to the request and response) callback functions as you desire. It's not limited to one. They are asynchronous and chained together by calling the next() parameter.
function callbackOne(req, res, next) {
//some code
next();
}
function callbackTwo(req, res, next) {
//some code
res.render();
}
app.get(path, callbackOne, callbackTwo)
So, in your case, the isLoggedIn parameter is simply just another middleware function that eventually calls next() if the user is logged in to bring execution to the third parameter.