1. 程式人生 > >Koa2學習系列02-中介軟體用法——講解 Koa2 中介軟體的用法及如何開發中間件

Koa2學習系列02-中介軟體用法——講解 Koa2 中介軟體的用法及如何開發中間件

middleware 中介軟體

正是因為中介軟體的擴充套件性才使得 Koa 的程式碼簡單靈活。

 

在 app.js 中,有這樣一段程式碼:

app.use(async (ctx, next)=>{
  await next()
  ctx.response.type = 'text/html'
  ctx.response.body = '<h1>Hello World</h1>'  
})

它的作用是:每收到一個 http 請求,Koa 都會呼叫通過 app.use()

 註冊的 async 函式,同時為該函式傳入 ctx 和 next兩個引數。而這個 async 函式就是我們所說的中介軟體。

下面我們簡單介紹一下傳入中介軟體的兩個引數。

 

ctx

 

ctx 作為上下文使用,包含了基本的 ctx.request 和 ctx.response。另外,還對 Koa 內部對一些常用的屬性或者方法做了代理操作,使得我們可以直接通過 ctx 獲取。比如,ctx.request.url

 可以寫成 ctx.url

 

除此之外,Koa 還約定了一箇中間件的儲存空間 ctx.state。通過 state 可以儲存一些資料,比如使用者資料,版本資訊等。如果你使用 webpack 打包的話,可以使用中介軟體,將載入資源的方法作為 ctx.state 的屬性傳入到 view 層,方便獲取資源路徑。

 

next

 

next 引數的作用是將處理的控制權轉交給下一個中介軟體,而 next() 後面的程式碼,將會在下一個中介軟體及後面的中介軟體(如果有的話)執行結束後再執行。

注意: 中介軟體的順序很重要!

 

我們重寫 app.js 來解釋下中介軟體的流轉過程:

// 按照官方示例
const Koa = require('koa')
const app = new Koa()

// 記錄執行的時間
app.use(async (ctx, next) => {
  let stime = new Date().getTime()
  await next()
  let etime = new Date().getTime()
  ctx.response.type = 'text/html'
  ctx.response.body = '<h1>Hello World</h1>'
  console.log(`請求地址: ${ctx.path},響應時間:${etime - stime}ms`)
});

app.use(async (ctx, next) => {
  console.log('中介軟體1 doSomething')
  await next();
  console.log('中介軟體1 end')
})

app.use(async (ctx, next) => {
  console.log('中介軟體2 doSomething')
  await next();
  console.log('中介軟體2 end')
})

app.use(async (ctx, next) => {
  console.log('中介軟體3 doSomething')
  await next();
  console.log('中介軟體3 end')
})

app.listen(3000, () => {
  console.log('server is running at http://localhost:3000')
})

 

執行起來後,控制檯顯示:

server is running at http://localhost:3000

 

然後開啟瀏覽器,訪問 http://localhost:3000,控制檯顯示內容更新為:

server is running at http://localhost:3000
中介軟體1 doSomething
中介軟體2 doSomething
中介軟體3 doSomething
中介軟體3 end
中介軟體2 end
中介軟體1 end
請求地址: /,響應時間:2ms

從結果上可以看到,流程是一層層的開啟,然後一層層的閉合,像是剝洋蔥一樣 —— 洋蔥模型。

 

此外,如果一箇中間件沒有呼叫 await next(),會怎樣呢?答案是『後面的中介軟體將不會執行』。

 

修改 app.js 如下,我們去掉了第三個中介軟體裡面的 await

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

// 記錄執行的時間
app.use(async (ctx, next)=>{
  let stime = new Date().getTime()
  await next()
  let etime = new Date().getTime()
  ctx.response.type = 'text/html'
  ctx.response.body = '<h1>Hello World</h1>'
  console.log(`請求地址: ${ctx.path},響應時間:${etime - stime}ms`)
});

app.use(async (ctx, next) => {
  console.log('中介軟體1 doSomething')
  await next();
  console.log('中介軟體1 end')
})

app.use(async (ctx, next) => {
  console.log('中介軟體2 doSomething')
  // 注意,這裡我們刪掉了 next
  // await next()
  console.log('中介軟體2 end')
})

app.use(async (ctx, next) => {
  console.log('中介軟體3 doSomething')
  await next();
  console.log('中介軟體3 end')
})

app.listen(3000, () => {
  console.log('server is running at http://localhost:3000')
})

 

重新執行程式碼後,控制檯顯示如下:

server is running at http://localhost:3000
中介軟體1 doSomething
中介軟體2 doSomething
中介軟體2 end
中介軟體1 end
請求地址: /,響應時間:1ms

 

與我們的預期結果『後面的中介軟體將不會執行』是一致的。

 

下一節中,我們將學習下如何響應瀏覽器的各種請求。

原文https://github.com/ikcamp/koa2-tutorial/tree/1-middleware