第四代Express框架koa简介
文章目錄
- 簡介
- koa和express
- koa使用介紹
- 中間件的級聯關系
- koa的構造函數
- 啟動http server
- 自定義中間件
- 異常處理
簡介
熟悉Spring MVC的朋友應該都清楚Spring MVC是基于servlet的代碼框架,這是最傳統的web框架。然后在Spring5中引入了Spring WebFlux,這是基于reactive-netty的異步IO框架。
同樣的,nodejs在最初的Express 3基礎上發展起來了異步的koa框架。koa使用了promises和aysnc來避免JS中的回調地獄,并且簡化了錯誤處理。
今天我們要來介紹一下這個優秀的nodejs框架koa。
koa和express
koa不再使用nodejs的req和res,而是封裝了自己的ctx.request和ctx.response。
express可以看做是nodejs的一個應用框架,而koa則可以看成是nodejs 的http模塊的抽象。
和express提供了Middleware,Routing,Templating,Sending Files和JSONP等特性不同的是,koa的功能很單一,如果你想使用其他的一些功能比如routing,sending files等功能,可以使用koa的第三方中間件。
koa并不是來替換express的,就像spring webFlux并不是用來替換spring MVC的。koa只是用Promises改寫了控制流,并且避免了回調地獄,并提供了更好的異常處理機制。
koa使用介紹
koa需要node v7.6.0+版本來支持ES2015和async function。
我們看一個最最簡單的koa應用:
const Koa = require('koa'); const app = module.exports = new Koa();app.use(async function(ctx) {ctx.body = 'Hello World'; });if (!module.parent) app.listen(3000);koa應用程序就是一個包含了很多個中間件的對象,這些中間件將會按照類似stack的執行順序一個相應request。
中間件的級聯關系
koa.use中傳入的是一個function,我們也可以稱之為中間件。
koa可以use很多個中間件,舉個例子:
const Koa = require('koa'); const app = new Koa();app.use(async (ctx, next) => {await next();console.log('log3'); });app.use(async (ctx, next) => {await next();console.log('log2'); });app.use(async ctx => {console.log('log3'); });app.listen(3000);上面的例子中,我們調用了多次next,只要我們調用next,調用鏈就會傳遞到下一個中間件進行處理,一直到某個中間件不再調用next
為止。
上面的代碼運行輸出:
log1 log2 log3koa的構造函數
我們看下koa的構造函數:
constructor(options) {super();options = options || {};this.proxy = options.proxy || false;this.subdomainOffset = options.subdomainOffset || 2;this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';this.maxIpsCount = options.maxIpsCount || 0;this.env = options.env || process.env.NODE_ENV || 'development';if (options.keys) this.keys = options.keys;this.middleware = [];this.context = Object.create(context);this.request = Object.create(request);this.response = Object.create(response);// util.inspect.custom support for node 6+/* istanbul ignore else */if (util.inspect.custom) {this[util.inspect.custom] = this.inspect;}}可以看到koa接收下面幾個參數:
- app.env 默認值是NODE_ENV或者development
- app.keys 為cookie簽名的keys
看下怎么使用:
app.keys = ['secret1', 'secret2']; app.keys = new KeyGrip(['secret1', 'secret2'], 'sha256');ctx.cookies.set('name', 'jack', { signed: true });- app.proxy 是否支持代理
- app.subdomainOffset 表示子域名是從第幾級開始的,這個參數決定了request.subdomains的返回結果,默認值為2
- app.proxyIpHeader proxy ip header默認值是X-Forwarded-For
- app.maxIpsCount 從proxy ip header讀取的最大ip個數,默認值是0表示無限制。
我們可以這樣用:
const Koa = require('koa'); const app = new Koa({ proxy: true });或者這樣用:
const Koa = require('koa'); const app = new Koa(); app.proxy = true;啟動http server
koa是一種web框架,web框架就需要開啟http服務,要啟動http服務,需要調用nodejs中的Server#listen()方法。
在koa中,我們可以很方便的使用koa#listen方法來啟動這個http server:
const Koa = require('koa'); const app = new Koa(); app.listen(3000);上面的代碼相當于:
const http = require('http'); const Koa = require('koa'); const app = new Koa(); http.createServer(app.callback()).listen(3000);當然你可以同時創建http和https的服務:
const http = require('http'); const https = require('https'); const Koa = require('koa'); const app = new Koa(); http.createServer(app.callback()).listen(3000); https.createServer(app.callback()).listen(3001);自定義中間件
koa中的中間件是參數值為(ctx, next)的function。在這些方法中,需要手動調用next()以傳遞到下一個middleware。
下面看一下自定義的中間件:
async function responseTime(ctx, next) {const start = Date.now();await next();const ms = Date.now() - start;ctx.set('X-Response-Time', `${ms}ms`); }app.use(responseTime);- 給中間件起個名字:
雖然中間件function只接收參數(ctx, next),但是我可以將其用一個wrapper方法包裝起來,在wrapper方法中,我們給中間件起個名字 :
function logger(name) {return async function logger(ctx, next) {console.log(name);await next();}; }- 自定義中間件的擴展:
上面的wrapper創建方式還有另外一個好處,就是可以在自定義中間件中訪問傳入的參數,從而可以根據傳入的參數,對自定義中間件進行擴展。
function logger(format) {format = format || ':method ":url"';return async function (ctx, next) {const str = format.replace(':method', ctx.method).replace(':url', ctx.url);console.log(str);await next();}; }app.use(logger()); app.use(logger(':method :url'));- 組合多個中間件:
當有多個中間件的情況下,我們可以使用compose將其合并:
const compose = require('koa-compose'); const Koa = require('koa'); const app = module.exports = new Koa();// x-response-timeasync function responseTime(ctx, next) {const start = new Date();await next();const ms = new Date() - start;ctx.set('X-Response-Time', ms + 'ms'); }// loggerasync function logger(ctx, next) {const start = new Date();await next();const ms = new Date() - start;if ('test' != process.env.NODE_ENV) {console.log('%s %s - %s', ctx.method, ctx.url, ms);} }// responseasync function respond(ctx, next) {await next();if ('/' != ctx.url) return;ctx.body = 'Hello World'; }// composed middlewareconst all = compose([responseTime,logger,respond ]);app.use(all);if (!module.parent) app.listen(3000);異常處理
在koa中怎么進行異常處理呢?
通用的方法就是try catch:
app.use(async (ctx, next) => {try {await next();} catch (err) {err.status = err.statusCode || err.status || 500;throw err;} });當然你也可以自定義默認的error處理器:
app.on('error', err => {log.error('server error', err) });我們還可以傳入上下文信息:
app.on('error', (err, ctx) => {log.error('server error', err, ctx) });本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/koa-startup/
本文來源:flydean的博客
歡迎關注我的公眾號:「程序那些事」最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
總結
以上是生活随笔為你收集整理的第四代Express框架koa简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在Spring data中使用r2dbc
- 下一篇: javascript开发后端程序的神器n