Prepend content
Node makes it easy and quick to start Http services:
const http = require("http");
// Create an HTTP service
const server = http.createServer((req, res) = > {
res.end("hello Node");
});
// Listen on the port
server.listen(3000.() = > {
console.log("Services started");
});
Copy the code
The Node service will start, and the browser will return Hello Node if it visits http://127.0.0.1:3000, but there is no route yet, so you’ll find that either http://127.0.0.1:3000/hi or any other path will return the same result. Therefore, Node server framework Express provides routing, middleware, request processing and other functions to help us provide services efficiently.
Starting the Express Service
Let’s use an example to understand how Express starts a service
const express = require("express");
const app = express();
// Start the Express service
app.listen("3000".() = > {
console.log("Service already running on port 3000");
});
Copy the code
-
Express is a function. Executing Express returns an app function, which is used as a handler for http.createServer
-
Call app.listen to enable the Node service, which is essentially enabled through http.createserver (app)
-
Next can control the next call to handle or middleware and hand over the specific logic to App. handle. In fact, this is a very common proxy mode in Express. The app provides a unique entry point for all requests in the Express service
Registered routing
const express = require("express");
const app = express();
app.get("/".(req, res, next) = > {
res.end("hello");
});
// Start the Express service
app.listen("3000".() = > {
console.log("Service already running on port 3000");
});
Copy the code
Express only needs to call app.get to complete the route registration of GET request method. The internal execution process of route registration in Express involves the four most important modules: APP, Router, Route and layer.
- The APP layer is the top-level design in Express and holds a Router routing object
- The Router layer stores all routing information, and the internal layer stores it in its own stack
- There are three main types of layer in Express (which are abstracted into the Layer class uniformly) :
- route layer: Holds the route and saves it in
router
, - middleware layer: does not hold route, only corresponding
handle
Function, saved inrouter
, - handle layer: Holds the final route
handle
And stored in theroute
In the
- route layer: Holds the route and saves it in
App. get route registration process after we understand the responsibilities of each module in Express, app.get route registration process looks like this:
- App. get calls the router’s route method, which generates one
route
And aroute layer
And letroute layer
holdroute
.route
provideroute layer
adispatch
Method as ahandle
And finally press inrouter
The stack - All of the
handle
Function is passed to the newly generatedroute
, route.get is generatedhandle layerSave the corresponding Handle and store it on its own stack
Again through the source code to see express concrete implementation:
// application.js
// methods are a collection of HTTP methods defined in app.get, app.post, etc
methods.forEach(function(method){
app[method] = function(path){
if (method === 'get' && arguments.length === 1) {
// app.get(setting)
return this.set(path);
}
// Lazily initializes the Router object
this.lazyrouter();
// Perform the first step, executing the route method of the router
var route = this._router.route(path);
// Perform the second step, calling the newly created route.get method and passing the Handle
route[method].apply(route, slice.call(arguments.1));
return this;
};
});
// router.js
proto.route = function route(path) {
// Generate a new route
var route = new Route(path);
// Generate a Route Layer
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: this.strict,
end: true
}, route.dispatch.bind(route));
// Let layer hold route
layer.route = route;
// Push layer onto the stack
this.stack.push(layer);
// Return the route object
return route;
};
// route.js
methods.forEach(function(method){
Route.prototype[method] = function(){
// Flattens the array data structure
var handles = flatten(slice.call(arguments));
// Iterate over all handlers
for (var i = 0; i < handles.length; i++) {
var handle = handles[i];
if (typeofhandle ! = ='function') {
var type = toString.call(handle);
var msg = 'Route.' + method + '() requires a callback function but got a ' + type
throw new Error(msg);
}
// Create a Handle Layer. Each Handle layer holds a handle function
var layer = Layer('/', {}, handle);
layer.method = method;
this.methods[method] = true;
// The Handle Layer is pushed onto the route stack
this.stack.push(layer);
}
return this;
};
});
Copy the code
Hit the routing
Since we registered a route through app.get, the browser will respond to http://127.0.0.1:3000/, but not to any other address, indicating that the route is already working.
The routing flow now looks like this:
- As we know from the previous section, all requests to express will go through the serviceappIn the logic of,appexecute
app.handle
Method,app.handle
And to deal with the specific logicrouter.handle
Is equivalent to forwarding the request to the Router layer for processing - The request reaches the Router layer,
router.handle
You go over yourselfstack
All of thelayer(Route layer and Middleware layer, in this case route Layer), and based onThe url addresses currently requested match the route path saved during registrationIs executed when a condition hitslayerthehandle_request
Method, which is bound to theroute layer
Of the corresponding routedispatch
methods route.dispatch
The logical androuter.handle
Similarly, traversal executes itselfstack
In thehandle layer, the implementation of thehandle_request
Method, which is bound when the registered route is performedhandle
Function. Here Express will call the next onelayer.handle_requestGive it to the developer, if there are more than onehandle layer
, developers can display the functions provided by Express (typically next) to implement eachhandle
Logic of invocation
The middleware
Middleware Registration
Middleware is an important module of the Web server framework. The server often gives the same logic in the system to the middleware to complete, so as to realize authentication, logging, error handling, data conversion and other functions. Middleware in Express is a function, and we can use app.use to add a middleware.
const express = require("express");
const app = express();
app.use(function(req, res, next) {
console.log('Current requested address :', req.url);
// Note that next must be explicitly called otherwise the request/will not be matched
next()
})
app.get("/".(req, res, next) = > {
res.end("hello");
});
// Start the Express service
app.listen("3000".() = > {
console.log("Service already running on port 3000");
});
Copy the code
We created a middleware that prints the request path. The internal flow of the Express registry middleware is as follows:
app.use
Will allhandles
The handler is passed torouter.use
methodsrouter.use
It’s going to go through all of themhandles
Each Handle creates onemiddleware layer, save it inmiddleware layerOn, androute layerThe difference is that this layer does not holdroute
And finally press it inrouter
The stack
Middleware hit
Use (path,… FNS), without path, it is a global middleware that can respond to all requests, because the registration of middleware is similar to that of route, and the matching process is the same as that of route. They both search for the corresponding layer according to path and execute its bound Handle function.
app.handle
Give the processing logic torouter.handle
router.handle
throughpath
Find the correspondingmiddleware layerSince we are registering global middleware in the example, this will be hitmiddleware layerAnd pull it out to perform binding on thelayer
On thehandle_request
methods
Path matching
Express supports re as a path to register routes. You can use the following methods:
app.get('some? path', handle)
// String is regularapp.get('somepath/:id', handle)
// The path takes parametersapp.get(/somepath/, handle)
// Regular expression paths are supported
These features benefit from path-to-Regexp support, where routing hits in Express are based on the re saved at registration time.
conclusion
Express designs app as a top-level structure, exposing app as an interface layer for developers to use, and internally handing the specific processing logic of app’s use, GET, and Handle methods to router, which is equivalent to app as an outward-exposed agent. Meanwhile, Express uses the while-interruptible route matching method to allow developers to use next to control the call of handle function, and developers need to pay attention to the order of each other when defining routes or middleware.