2021 JavaScript Design Pattern Learning chapter 29 - Middleware

(Middleware), also known as the intermediary layer, is the software that provides the connection between system software and application software to facilitate the communication between software components, especially the centralized logic of application software for system software. Middleware represents various software suites in the enterprise architecture, which helps to abstract the underlying mechanisms, such as operating system API, network communication, memory management, etc. developers only need to pay attention to the business modules in the application.

From a broader perspective, middleware can also be defined as a software layer linking underlying services and applications. Later, we mainly use node Take the middleware concept in Koa2, a recently popular framework in JS, as an example, and implement a middleware to deepen understanding.

1. What is middleware

In Express and Koa2, middleware represents a series of functions connected in the form of pipes to process HTTP requests and responses. In other words, middleware is actually a function, a function that executes specific logic. Similar concepts in the front end include interceptor, filter in Vue, route guard in Vue router, etc.

The working principle is to preprocess the specific business before entering it (which is a bit similar to the decorator mode), or post process it after the business.

The schematic diagram is as follows:

When a request is received, the processing of the request can be regarded as a series pipeline. For example, for each request, we want to insert some of the same logic, such as permission verification, data filtering, log statistics, parameter verification, exception handling and other functions. For developers, they naturally do not want to deal with each request in a special way. Therefore, middleware is introduced to simplify and isolate the details between these infrastructure and business logic, so that developers can focus on business development to improve development efficiency.

 

2. Middleware in KOA

2.1. Use of Middleware in koa2

The middleware form in Koa2 is:

app.use(async function middleware(context, next){ 
    // ...  Pretreatment
    await next() // Next Middleware
    // ...  Post processing
})

The first parameter, context, encapsulates the request and response information as a context, through which we can access the request and response; Next is the next middleware. When a middleware is processed, call next() to execute the next middleware. After the next middleware is processed, use next() to realize the pipelining of middleware and the sequential processing of messages.

The general middleware model stipulates that there is a use method to register middleware, and so is Koa2. A thousand words is less than a line of code. Here is a simple middleware:

const koa = require('koa')
const app = new koa()

// Yes, this is middleware
app.use((ctx, next) => {      
    console.log('in Middleware 1')
})

app.listen(10001)
// in middleware 1

There are many types of Middleware in Koa2:

1. Application level middleware;

2. Routing level middleware;

3. Error handling middleware;

4. Third party middleware;

In addition to using third-party middleware such as koa router, KOA bodyparser, KOA static and koa logger to provide some general functions such as routing, serialization, deserialization and logging, we can also write our own application level middleware to complete business-related logic.

1. Parsing and processing of request and response;

2. Generate access log;

3. Manage session s, cookie s, etc;

4. Provide network security protection;

2.2. Onion model

When using multiple middleware, reference a famous onion model diagram:

 

As shown in the onion diagram above, when the request enters the business logic, it will go through a series of middleware to process the data orderly. After the business logic, it will go through the previous Middleware in reverse order like the first in and then out of the stack. The onion model allows the application to perform some post-processing after executing the main logic, and then return the response to the user.

Use the following:

const Koa = require('koa')
const app = new Koa()

// Middleware 1
app.use(async (ctx, next) => {
    console.log('in Middleware 1')
    await next()
    console.log('out Middleware 1')
})

// Middleware 2
app.use(async (ctx, next) => {
    console.log('in Middleware 2')
    await next()
    console.log('out Middleware 2')
})

// response
app.use(async ctx => { ctx.body = 'Hello World' })

app.listen(10001)
console.log('app started at port http://localhost:10001')

// in middleware 1
// in middleware 2
// out middleware 2
// out middleware 1

We can introduce setTimeout to simulate the process of asynchronous requests:

const Koa = require('koa')
const app = new Koa()

// Middleware 1
app.use(async (ctx, next) => {
    console.log('in Middleware 1')
    await next()
    console.log('out Middleware 1')
})

// Middleware 2
app.use(async (ctx, next) => {
    console.log('in Middleware 2')
    await new Promise((resolve, reject) => {
          ctx.zjj_start2 = Date.now()
          setTimeout(() => resolve(), 1000 + Math.random() * 1000)
      }
    )
    await next()
    const duration = Date.now() - ctx.zjj_start2
    console.log('out Middleware 2 time consuming:' + duration + 'ms')
})

// Middleware 3
app.use(async (ctx, next) => {
    console.log('in Middleware 3')
    await new Promise((resolve, reject) => {
          ctx.zjj_start3 = Date.now()
          setTimeout(() => resolve(), 1000 + Math.random() * 1000)
      }
    )
    await next()
    const duration = Date.now() - ctx.zjj_start3
    console.log('out Middleware 3 time consuming:' + duration + 'ms')
})

// response
app.use(async ctx => {
    console.log(' ... Business logic processing process ... ')
})

app.listen(10001)
console.log('app started at port http://localhost:10001')

The effect is as follows:

 

When using multiple middleware, especially in asynchronous scenarios, it is generally necessary to call next through await to ensure that in asynchronous scenarios, the middleware is still executed in the order of onion model, so don't forget that next should also be called through await.

Tags: Javascript html5 Vue.js html css

Posted by roba59 on Sat, 02 Apr 2022 16:33:05 +0300