Preface
Using node to implement server directly is using http module, on which Express and Koa are encapsulated.
This wiki just wants to intuitively see the difference in basic usage before and after encapsulation, without considering in-depth things.
I. http module
1.1 Processing get requests
var http = require("http"); http.createServer(function(req, res) { // homepage if (req.url == "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.write("Welcome to the homepage!"); res.end("Welcome to the homepage!"); } // About page else if (req.url == "/about") { res.writeHead(200, { "Content-Type": "text/html" }); res.end("Welcome to the about page!"); } // 404 error else { res.writeHead(404, { "Content-Type": "text/plain" }); res.end("404 error! File not found."); } }).listen(8080, "localhost");
createServer of http module can directly create an instance of the server, then call the listen method of the instance, and pass in the listening port and host.
The handler operates on http request and response objects as two parameters.
Implementing routing: judging by the url of the request
Write response header: res.writeHead method
Write response body: res.write
End response: res.end
1.2 Processing Post Requests
var http = require('http'); http.createServer(function (req, res) { var content = ""; req.on('data', function (chunk) { content += chunk; }); req.on('end', function () { res.writeHead(200, {"Content-Type": "text/plain"}); res.write("You've sent: " + content); res.end(); }); }).listen(8080);
Listen for data and end events of req. Data events trigger once every data segment is received during the data receiving process.
The received data is passed into the callback function. The end event is triggered when all data is received.
Express Framework
2.1 Middleware
In short, middleware is a function that handles HTTP requests. Its greatest feature is that one middleware is processed and then passed to the next middleware.
An App instance calls a series of middleware during its run. Each middleware can receive three parameters from an App instance.
The order is request object (representing HTTP request), response object (representing HTTP response), next callback function (representing the next middleware).
Each middleware can process HTTP requests (request objects) and decide whether to call the next method to pass the request objects to the next middleware.
A middleware that does nothing but pass request objects is the following.
function uselessMiddleware(req, res, next) { next(); }
Next of the above code is the next middleware. If it has parameters, it means that an error is thrown, with the parameter being the wrong text.
function uselessMiddleware(req, res, next) { next('Wrong!'); }
When an error is thrown, the subsequent middleware will not execute until an error handling function is found.
use is the way to register middleware for express.
app.use(function(request, response, next) { console.log("In comes a " + request.method + " to " + request.url); next(); }); app.use(function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello world!\n"); });
Implementation of 2.2 Routing
2.2.1 request.url
The request.url attribute can be used to determine the request's address, so that different content can be returned and routing can be realized.
app.use(function(request, response, next) { if (request.url == "/") { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Welcome to the homepage!\n"); } else { next(); } }); app.use(function(request, response, next) { if (request.url == "/about") { response.writeHead(200, { "Content-Type": "text/plain" }); } else { next(); } });
2.2.2 use and other methods
In addition to judging the request's address within the callback function, the use method also allows the request's address to be written in the first parameter.
This means that only if the request path matches this parameter will the subsequent middleware take effect. Undoubtedly, it is more clear and convenient to write in this way.
app.use("/home", function(request, response, next) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Welcome to the homepage!\n"); });
For different requests, use can have different aliases, corresponding to http methods, including get post put post delete.
2.2.3 Using Express.Router
var router = express.Router(); router.get('/', function(req, res) { res.send('home page'); }); router.get('/about', function(req, res) { res.send('about'); }); app.use('/', router);
router can mount freely and write routes directly on use, which can bring more flexibility to program writing.
2.3 Processing POST requests
Why mention the post request alone, because the body that gets the request can't be accessed through a body attribute of the request?
As we can see from processing post requests through http, data and end methods that listen for requests need to be spliced, because body may be passed over several times.
The advantage of using frameworks is that someone has written middleware that can be used directly. body-parser for Middleware Processing body in Express
var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));
body-parser provides several conversion formats
JSON body parser
Raw body parser
Text body parser
URL-encoded form body parser
After using middleware, the transformed body can be obtained directly by request.body.
router.post('/testpost', function(req, res, next) { console.log('testpost'); res.send(req.body); });
III. Koa Framework
A Koa application is an object that contains a middleware array composed of a set of Generator functions.
These functions are responsible for various processing of HTTP requests, such as generating caches, specifying proxies, request redirection, and so on.
var koa = require('koa'); var app = koa(); app.use(function *(){ this.body = 'Hello World'; }); app.listen(3000);
As you can see, the Koa framework is very similar to the Express framework. So the focus should be on the differences between Koa frameworks:
1. Middleware uses Generator function, so middleware takes advantage of the interrupt waiting characteristic of Generator function.
2. The request and response objects are encapsulated in the context and accessed through this, so the api of the operation will be different.
3.1 Middleware
The difference between Koa middleware and Express is that it is a Generator function. Generator function uses the yield command to transfer the execution power of the program to the next middleware.
That is yield next, which will not continue to execute until the next middleware returns the result, so it is the order of nested execution.
app.use(function *(next){ console.log('>> one'); yield next; console.log('<< one'); }); app.use(function *(next){ console.log('>> two'); this.body = 'two'; console.log('<< two'); });
Output:
>> one >> two << one << two
So when asynchronous operations are needed, we can use yield to give control to it without writing the processing logic in the callback function.
The Generator function returns a traversal object, the yield statement is the pause identifier, and the Koa framework automatically traverses the Generator function until the end, returning the http request.
So when the http request is returned, koa does not specify as shown in the http module and the Express framework, such as calling res.end, res.send and other methods to end the http response.
koa automatically returns http requests after executing all middleware. Do not wait for incomplete asynchronous operations
3.2 Routing
Two ways
One is to use this.path to make judgments.
let koa = require('koa') let app = koa() // normal route app.use(function* (next) { if (this.path !== '/') { return yield next } this.body = 'hello world' });
One is to use the koa-router plug-in, similar to Express's use and a series of http verb methods.
var app = require('koa')(); var Router = require('koa-router'); var myRouter = new Router(); myRouter.get('/', function *(next) { this.response.body = 'Hello World!'; }); app.use(myRouter.routes()); app.listen(3000);
3.3 context object
this in the middleware represents the context of the context object, representing an HTTP request and response, that is, all the information of an access/response can be obtained from the context object.
The context object encapsulates request and response objects and provides some helpful methods. Each HTTP request creates a new context object.
Global properties of context objects.
Request: Points to the Request object
Response: Point to Response object
req: request object to Node
req: response object to Node
App: Points to App objects
state: Used to transfer information in middleware.
3.4 Processing Post requests
In fact, how to get the body in reauest, using the middleware co-body, can be accessed through this.request.body after processing.
// application/json var body = yield parse.json(this); // application/x-www-form-urlencoded var body = yield parse.form(this); // text/plain var body = yield parse.text(this);