您好,登錄后才能下訂單哦!
本篇內容主要講解“如何使用nodejs中的koa”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何使用nodejs中的koa”吧!
koa指的是一個類似于Express的基于Node實現的web框架,致力于成為web應用和API開發領域中的一個更小、更富有表現力、更健壯的基石。Koa并沒有捆綁任何中間件,而是提供了一套優雅的方法,幫助用戶快速而愉快地編寫服務端應用程序。
本教程操作環境:windows7系統、nodejs 12.19.0&&koa2.0版、Dell G3電腦。
Koa
是一個類似于Express的Web
開發框架,創始人也是同一個人。它的主要特點是,使用了ES6的Generator函數
,進行了架構的重新設計。也就是說,Koa的原理和內部結構很像Express,但是語法和內部結構進行了升級。
Koa 是一個新的 web 框架,由 Express 幕后的原班人馬打造, 致力于成為 web 應用和 API 開發領域中的一個更小、更富有表現力、更健壯的基石。 通過利用 async 函數,Koa 幫你丟棄回調函數,并有力地增強錯誤處理。 Koa 并沒有捆綁任何中間件, 而是提供了一套優雅的方法,幫助您快速而愉快地編寫服務端應用程序。
官方faq
有這樣一個問題:”為什么koa不是Express 4.0?“,回答是這樣的:”Koa與Express有很大差異,整個設計都是不同的,所以如果將Express 3.0按照這種寫法升級到4.0,就意味著重寫整個程序。所以,我們覺得創造一個新的庫,是更合適的做法。“
一個Koa應用
就是一個對象
,包含了一個middleware
數組,這個數組由一組Generator函數
組成。這些函數負責對HTTP請求進行各種加工,比如生成緩存、指定代理、請求重定向等等。
var koa = require('koa'); var app = koa(); app.use(function *(){ this.body = 'Hello World'; }); app.listen(3000);
上面代碼中,變量app就是一個Koa應用。它監聽3000端口,返回一個內容為Hello World
的網頁。
app.use
方法用于向middleware
數組添加Generator函數
。
listen
方法指定監聽端口,并啟動當前應用。
它實際上等同于下面的代碼。
var http = require('http'); var koa = require('koa'); var app = koa(); http.createServer(app.callback()).listen(3000);
Koa
的中間件很像Express的中間件
,也是對HTTP請求進行處理的函數
,但是必須是一個Generator函數
。
而且,Koa的中間件是一個級聯式(Cascading)
的結構,也就是說,屬于是層層調用,第一個中間件調用第二個中間件
,第二個調用第三個
,以此類推。上游的中間件必須等到下游的中間件返回結果
,才會繼續執行,這點很像遞歸。
中間件通過當前應用的use
方法注冊。
app.use(function* (next){ var start = new Date; // (1) yield next; // (2) var ms = new Date - start; // (3) console.log('%s %s - %s', this.method, this.url, ms); // (4) });
上面代碼中,app.use
方法的參數就是中間件,它是一個Generator函數
, 最大的特征就是function命令
與參數之間,必須有一個星號
。Generator函數的參數next
,表示下一個中間件。Generator
函數內部使用yield
命令,將程序的執行權轉交給下一個中間件,即yield next
,要等到下一個中間件返回結果,才會繼續往下執行。
上面代碼中,Generator函數體內部
,第一行賦值語句首先執行,開始計時,
第二行yield
語句將執行權交給下一個中間件,當前中間件就暫停執行
等到后面的中間件全部執行完成,執行權就回到原來暫停的地方,繼續往下執行,這時才會執行第三行,
計算這個過程一共花了多少時間,第四行將這個時間打印出來。
下面是一個兩個中間件級聯的例子。
app.use(function *() { this.body = "header\n"; yield saveResults.call(this); this.body += "footer\n"; }); function *saveResults() { this.body += "Results Saved!\n"; }
上面代碼中,第一個中間件調用第二個中間件saveResults,它們都向this.body寫入內容。最后,this.body的輸出如下。
header Results Saved! footer
只要有一個中間件缺少yield next
語句,后面的中間件都不會執行,這一點要引起注意。
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'); }); app.use(function *(next){ console.log('>> three'); yield next; console.log('<< three'); });
上面代碼中,因為第二個中間件少了yield next
語句,第三個中間件并不會執行。
如果想跳過一個中間件,可以直接在該中間件的第一行語句寫上return yield next。
app.use(function* (next) { if (skip) return yield next; })
由于Koa要求中間件唯一的參數就是next
,導致如果要傳入其他參數,必須另外寫一個返回Generator函數
的函數。
function logger(format) { return function *(next){ var str = format .replace(':method', this.method) .replace(':url', this.url); console.log(str); yield next; } } app.use(logger(':method :url'));
上面代碼中,真正的中間件是logger函數的返回值,而logger函數是可以接受參數的。
由于中間件的參數統一為next
(意為下一個中間件),因此可以使用.call(this, next)
,將多個中間件進行合并。
function *random(next) { if ('/random' == this.path) { this.body = Math.floor(Math.random()*10); } else { yield next; } }; function *backwards(next) { if ('/backwards' == this.path) { this.body = 'sdrawkcab'; } else { yield next; } } function *pi(next) { if ('/pi' == this.path) { this.body = String(Math.PI); } else { yield next; } } function *all(next) { yield random.call(this, backwards.call(this, pi.call(this, next))); } app.use(all);
上面代碼中,中間件all內部,就是依次調用random、backwards、pi,后一個中間件就是前一個中間件的參數。
Koa內部使用koa-compose
模塊,進行同樣的操作,下面是它的源碼。
function compose(middleware){ return function *(next){ if (!next) next = noop(); var i = middleware.length; while (i--) { next = middleware[i].call(this, next); } yield *next; } } function *noop(){}
上面代碼中,middleware是中間件數組。前一個中間件的參數是后一個中間件,依次類推。如果最后一個中間件沒有next參數,則傳入一個空函數。
可以通過this.path屬性,判斷用戶請求的路徑,從而起到路由作用。
app.use(function* (next) { if (this.path === '/') { this.body = 'we are at home!'; } }) // 等同于 app.use(function* (next) { if (this.path !== '/') return yield next; this.body = 'we are at home!'; })
下面是多路徑的例子。
let koa = require('koa') let app = koa() // normal route app.use(function* (next) { if (this.path !== '/') { return yield next } this.body = 'hello world' }); // /404 route app.use(function* (next) { if (this.path !== '/404') { return yield next; } this.body = 'page not found' }); // /500 route app.use(function* (next) { if (this.path !== '/500') { return yield next; } this.body = 'internal server error' }); app.listen(8080)
上面代碼中,每一個中間件負責一個路徑,如果路徑不符合,就傳遞給下一個中間件。
復雜的路由需要安裝koa-router插件。
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);
上面代碼對根路徑設置路由。
Koa-router實例提供一系列動詞方法,即一種HTTP動詞對應一種方法。典型的動詞方法有以下五種。
router.get()
router.post()
router.put()
router.del()
router.patch()
這些動詞方法可以接受兩個參數,第一個是路徑模式
,第二個是對應的控制器方法
(中間件),定義用戶請求該路徑時服務器行為。
router.get('/', function *(next) { this.body = 'Hello World!'; });
上面代碼中,router.get
方法的第一個參數是根路徑,第二個參數是對應的函數方法。注意
,路徑匹配的時候,不會把查詢字符串考慮在內。比如,/index?param=xyz匹配路徑/index。
有些路徑模式比較復雜,Koa-router允許為路徑模式起別名。
起名時,別名要添加為動詞方法的第一個參數,這時動詞方法變成接受三個參數。
router.get('user', '/users/:id', function *(next) { // ... });
上面代碼中,路徑模式\users\:id
的名字就是user
。路徑的名稱,可以用來引用對應的具體路徑,比如url方法可以根據路徑名稱,結合給定的參數,生成具體的路徑。
router.url('user', 3); // => "/users/3" router.url('user', { id: 3 }); // => "/users/3"
上面代碼中,user就是路徑模式的名稱,對應具體路徑/users/:id。url方法的第二個參數3,表示給定id的值是3,因此最后生成的路徑是/users/3。
Koa-router允許為路徑統一添加前綴。
var router = new Router({ prefix: '/users' }); router.get('/', ...); // 等同于"/users" router.get('/:id', ...); // 等同于"/users/:id"
路徑的參數通過this.params
屬性獲取,該屬性返回一個對象,所有路徑參數都是該對象的成員。
// 訪問 /programming/how-to-node router.get('/:category/:title', function *(next) { console.log(this.params); // => { category: 'programming', title: 'how-to-node' } }); param方法可以針對命名參數,設置驗證條件。 router .get('/users/:user', function *(next) { this.body = this.user; }) .param('user', function *(id, next) { var users = [ '0號用戶', '1號用戶', '2號用戶']; this.user = users[id]; if (!this.user) return this.status = 404; yield next; })
上面代碼中,如果/users/:user
的參數user對應的不是有效用戶(比如訪問/users/3),param方法注冊的中間件會查到,就會返回404錯誤。
redirect方法會將某個路徑的請求,重定向到另一個路徑,并返回301狀態碼。
router.redirect('/login', 'sign-in'); // 等同于 router.all('/login', function *() { this.redirect('/sign-in'); this.status = 301; });
redirect方法的第一個參數是請求來源,第二個參數是目的地,兩者都可以用路徑模式的別名代替。
中間件當中的this
表示上下文對象context
,代表一次HTTP請求和回應
,即一次訪問/回應的所有信息,都可以從上下文對象獲得。
context對象封裝了request和response對象,并且提供了一些輔助方法。每次HTTP請求,就會創建一個新的context對象。
app.use(function *(){ this; // is the Context this.request; // is a koa Request this.response; // is a koa Response });
context
對象的很多方法,其實是定義在ctx.request對象或ctx.response對象上面
比如,ctx.type
和ctx.length
對應于ctx.response.type
和ctx.response.length
,ctx.path和ctx.method對應于ctx.request.path和ctx.request.method。
context對象的全局屬性。
request:指向Request對象
response:指向Response對象
req:指向Node的request對象
req:指向Node的response對象
app:指向App對象
state:用于在中間件傳遞信息。
this.state.user = yield User.find(id);
上面代碼中,user
屬性存放在this.state
對象上面,可以被另一個中間件讀取。
context對象的全局方法。
throw():拋出錯誤,直接決定了HTTP回應的狀態碼。
assert():如果一個表達式為false,則拋出一個錯誤。
this.throw(403); this.throw('name required', 400); this.throw('something exploded'); this.throw(400, 'name required'); // 等同于 var err = new Error('name required'); err.status = 400; throw err;
Koa提供內置的錯誤處理機制,任何中間件拋出的錯誤都會被捕捉到,引發向客戶端返回一個500
錯誤,而不會導致進程停止,因此也就不需要forever這樣的模塊重啟進程。
app.use(function *() { throw new Error(); });
上面代碼中,中間件內部拋出一個錯誤,并不會導致Koa應用掛掉。Koa內置的錯誤處理機制,會捕捉到這個錯誤。
當然,也可以額外部署自己的錯誤處理機制。
app.use(function *() { try { yield saveResults(); } catch (err) { this.throw(400, '數據無效'); } });
上面代碼自行部署了try...catch
代碼塊,一旦產生錯誤,就用this.throw
方法拋出。該方法可以將指定的狀態碼和錯誤信息,返回給客戶端。
對于未捕獲錯誤,可以設置error事件的監聽函數。
app.on('error', function(err){ log.error('server error', err); });
error
事件的監聽函數還可以接受上下文對象,作為第二個參數。
app.on('error', function(err, ctx){ log.error('server error', err, ctx); });
如果一個錯誤沒有被捕獲,koa會向客戶端返回一個500錯誤“Internal Server Error”。this.throw
方法用于向客戶端拋出一個錯誤。
this.throw(403); this.throw('name required', 400); this.throw(400, 'name required'); this.throw('something exploded'); this.throw('name required', 400) // 等同于 var err = new Error('name required'); err.status = 400; throw err; this.throw方法的兩個參數,一個是錯誤碼,另一個是報錯信息。如果省略狀態碼,默認是500錯誤。 this.assert方法用于在中間件之中斷言,用法類似于Node的assert模塊。 this.assert(this.user, 401, 'User not found. Please login!');
上面代碼中,如果this.user屬性不存在,會拋出一個401錯誤。
由于中間件是層級式調用,所以可以把try { yield next }
當成第一個中間件。
app.use(function *(next) { try { yield next; } catch (err) { this.status = err.status || 500; this.body = err.message; this.app.emit('error', err, this); } }); app.use(function *(next) { throw new Error('some error'); })
cookie的讀取和設置。
this.cookies.get('view'); this.cookies.set('view', n);
get和set
方法都可以接受第三個參數,表示配置參數。其中的signed
參數,用于指定cookie
是否加密。
如果指定加密的話,必須用app.keys指定加密短語。
app.keys = ['secret1', 'secret2']; this.cookies.set('name', '張三', { signed: true });
this.cookie的配置對象的屬性如下。
signed
:cookie是否加密。
expires
:cookie何時過期
path
:cookie的路徑,默認是“/”。
domain
:cookie的域名。
secure
:cookie是否只有https請求下才發送。
httpOnly
:是否只有服務器可以取到cookie,默認為true。
var session = require('koa-session'); var koa = require('koa'); var app = koa(); app.keys = ['some secret hurr']; app.use(session(app)); app.use(function *(){ var n = this.session.views || 0; this.session.views = ++n; this.body = n + ' views'; }) app.listen(3000); console.log('listening on port 3000');
到此,相信大家對“如何使用nodejs中的koa”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。