Koa(1)之——koa入门
??koa是基于Node.js的一個(gè)新的web框架,它的特點(diǎn)是輕量、健壯、富有表現(xiàn)力。它是Express的下一代基于Node.js的web 框架,koa2完全使用Promise配合async來(lái)實(shí)現(xiàn)異步。
特點(diǎn)
context對(duì)象
??Koa將Node.js的Request請(qǐng)求和Response響應(yīng)對(duì)象封裝到Context對(duì)象中,所以也可以把Context對(duì)象成為一次對(duì)話(huà)的上下文,通過(guò)加工Context對(duì)象,就可以控制返回給用戶(hù)的內(nèi)容。像Express中的Req和Res都封裝到了Context中。Context中還內(nèi)置了一些常用的屬性:
Koa的中間件機(jī)制
??Koa的應(yīng)用程序其實(shí)就是一個(gè)包含一組中間件函數(shù)的對(duì)象,通過(guò)app.use函數(shù)來(lái)加載中間件,這個(gè)函數(shù)有兩個(gè)參數(shù),context指的是上下文環(huán)境對(duì)象,封裝了一些屬性;next用于把中間件的執(zhí)行權(quán)交給下游的中間件,在當(dāng)前中間件中位于next()之后的代碼會(huì)暫停執(zhí)行,直到最后一個(gè)中間件執(zhí)行完畢,再自下而上依次執(zhí)行每個(gè)中間件中next值周的代碼,類(lèi)似于棧的先進(jìn)后出。這種模型被稱(chēng)作“洋蔥圈模型”。
??洋蔥圈的最外層是最上層的中間件,由上自下執(zhí)行每個(gè)中間件中next()函數(shù)之前的代碼,之后由下自上執(zhí)行每個(gè)中間件中next()函數(shù)之后的代碼。Koa的大部分功能都是通過(guò)中間件實(shí)現(xiàn)的。
代碼示例
const koa = require('koa') const app = new koa() app.use(async function (ctx, next) { //中間件1,位于最上層console.log('one start') //(1)ctx.body = 'Hello Koa' //(2)await next()ctx.body = ctx.body + '!!!'//(9)console.log('one end') //(10) }) app.use(async function (ctx, next) { //中間件2,位于中間console.log('two start') //(3)ctx.type = 'text/html;charset=utf-8' //(4)await next()console.log('two end') //(8) }) app.use(async function (ctx, next) { //中間件3,位于最下層console.log('three start') //(5)ctx.body = ctx.body + ', I am zhunny' //(6)await next()console.log('three end') //(7) }) app.listen(3000, () => {console.log('server is running at http://localhost:3000') })復(fù)制代碼瀏覽器中顯示如下:
node控制臺(tái)打印結(jié)果如下:
錯(cuò)誤處理
??某個(gè)中間件出錯(cuò),可以在它上一級(jí)的錯(cuò)誤處理中間件中捕獲,再一層層向上捕獲,從全局app應(yīng)用層最后到Node層。Koa的錯(cuò)誤處理是向上拋的。
const koa = require('koa') const app = new koa()//響應(yīng)輸出中間件 app.use(async function (ctx, next) {await next()//獲取響應(yīng)頭,印證執(zhí)行順序const rt = ctx.response.get('X-Response-Time')console.log(`輸出計(jì)時(shí):${ctx.method} ${ctx.url} - ${rt}`) })app.use(async function (ctx, next) {const start = Date.now()console.log('開(kāi)始計(jì)時(shí)')await next()const ms = Date.now() - startctx.set('X-Response-Time', `${ms}ms`)console.log('計(jì)時(shí)結(jié)束') })//中間件錯(cuò)誤捕獲 app.use(async (ctx, next) => {try {await next()} catch (error) {ctx.status = error.statusCode || error.status || 500ctx.body = error.message//觸發(fā)應(yīng)用層級(jí)的錯(cuò)誤事件ctx.app.emit('error', error, ctx)//中間件出錯(cuò),可以上拋到中間件錯(cuò)誤捕獲->全局->Node console.log('中間件捕捉', error.message)} })app.use(async function (ctx, next) {console.log('響應(yīng)用戶(hù)請(qǐng)求')//這里設(shè)置一個(gè)未定義的函數(shù)sleep(300)ctx.status = 200ctx.type = 'html'ctx.body = '<h1>Hello Koa</h1>' })//全局的錯(cuò)誤捕獲 app.on('error', err => {console.error('app全局錯(cuò)誤:', err.message)//繼續(xù)上拋到Node,此時(shí)會(huì)中止服務(wù)throw err })app.listen(3000) 復(fù)制代碼node控制臺(tái)打印結(jié)果如下:
路由
??路由具有引導(dǎo)、匹配之意。路由匹配是根據(jù)URL的變更重新渲染頁(yè)面布局和內(nèi)容的過(guò)程。
前端路由和后端路由
??早期,前后端沒(méi)有分離時(shí),由后端來(lái)實(shí)現(xiàn)路由。用戶(hù)將每個(gè)頁(yè)面的靜態(tài)資源全部都放到后端服務(wù)器上,當(dāng)用戶(hù)進(jìn)行頁(yè)面切換時(shí),由瀏覽器向服務(wù)器發(fā)送不同的URL請(qǐng)求,經(jīng)服務(wù)器解析后向?yàn)g覽器返回對(duì)應(yīng)頁(yè)面的靜態(tài)資源和數(shù)據(jù),再由瀏覽器渲染成新的頁(yè)面。后端路由的弊端是每次切換頁(yè)面都會(huì)刷新頁(yè)面,給用戶(hù)造成一種卡頓的感覺(jué),用戶(hù)體驗(yàn)很差。前后端不分離,路由是后端開(kāi)發(fā)人員來(lái)做的,整個(gè)業(yè)務(wù)偏重后端,后端開(kāi)發(fā)任務(wù)繁重,且前后端不解耦,使得服務(wù)器壓力大,開(kāi)發(fā)效率也低。
??前后端分離時(shí)代的到來(lái),使得前后端可以并行開(kāi)發(fā),開(kāi)發(fā)效率,項(xiàng)目性能大大提升。前端服務(wù)器負(fù)責(zé)控制頁(yè)面引用&跳轉(zhuǎn)&路由,前端頁(yè)面異步調(diào)用后端的接口,后端/應(yīng)用服務(wù)器使用tomcat(把tomcat想象成一個(gè)數(shù)據(jù)提供者),加快整體響應(yīng)速度。前端路由不再是每次都刷新頁(yè)面,而是在需要的時(shí)候才加載相應(yīng)頁(yè)面的內(nèi)容。不同路由切換對(duì)應(yīng)的僅僅是一個(gè)文檔樹(shù)的切換,頁(yè)面所需的數(shù)據(jù)才會(huì)向后端服務(wù)器發(fā)起請(qǐng)求。前端路由的主要場(chǎng)景是SPA單頁(yè)面應(yīng)用,Vue、React等流行的前端框架都提供了路由切換。
koa路由
自定義路由
??如果不采用路由組件應(yīng)該如何根據(jù)不同的url和方法做不同的響應(yīng)?如下自定義一個(gè)404頁(yè)面:
const koa = require('koa') const app = new koa()app.use(async (ctx, next) => {if (ctx.url === '/' && ctx.method === 'GET') {ctx.body = 'Page Not Found'ctx.status = 404} else {ctx.body = 'Defalut Page'ctx.status = 200}await next() }) 復(fù)制代碼??上述這種方式將路由處理和輸出響應(yīng)都放在了一個(gè)中間件函數(shù)中,而實(shí)際的項(xiàng)目中會(huì)存在很多的路由,如果按照這樣的方式處理,會(huì)嚴(yán)重影響到代碼的可讀性和可維護(hù)性。我們通常使用路由組件來(lái)定義路由。
koa-router
??koa-router具有豐富的API,可以實(shí)現(xiàn)命名路由、命名參數(shù)、多路由中間件、嵌套路由等多種功能。上述的代碼可以用koa-router來(lái)改寫(xiě):
const koa = require('koa') const app = new koa() const Router = require('koa-router') const router = new Router()router.get('/', (ctx, next) => {ctx.body = 'Page Not Found!!!'ctx.status = 404 })app.use(router.routes())app.listen(3000) 復(fù)制代碼??在實(shí)際項(xiàng)目中,根據(jù)不同的職能將路由分為不同的模塊,在入口文件中統(tǒng)一調(diào)用這些路由模塊。例如現(xiàn)在有一個(gè)users模塊,負(fù)責(zé)用戶(hù)信息的增刪改查,一個(gè)index模塊,負(fù)責(zé)默認(rèn)頁(yè)面路由。
index.js的內(nèi)容如下 const Router = require('koa-router') const router = new Router()router.get('/', ctx => {ctx.body = 'index' })module.exports = router 復(fù)制代碼
users.js的內(nèi)容如下:
const Router = require('koa-router') const router = new Router({ prefix: '/users' })router.get('/', ctx => {ctx.body = 'user' })module.exports = router 復(fù)制代碼入口文件中使用這些路由中間件:
const index = require('./routes/index') const users = require('./routes/users') app.use(index.routes()) app.use(users.routes()) 復(fù)制代碼瀏覽器中顯示如下:
超強(qiáng)干貨來(lái)襲 云風(fēng)專(zhuān)訪(fǎng):近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的Koa(1)之——koa入门的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 大三下学期十一周总结
- 下一篇: 云转型缓慢并不甲骨文在中国区大裁员的唯一