Talking about Http Module, Express and Koa Implementing http Service

Keywords: Javascript JSON Attribute

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);

Posted by cdinca on Fri, 05 Jul 2019 16:10:30 -0700