Koa作為下一代Web開發框架,不僅讓我們體驗到了async/await語法帶來同步方式書寫異步代碼的酸爽,而且本身簡潔的特點,更加利于開發者結合業務本身進行擴展。
本文從以下幾個方面解讀Koa源碼:
封裝創建應用程序函數 擴展res和req 中間件實現原理 異常處理一、封裝創建應用程序函數
利用NodeJS可以很容易編寫一個簡單的應用程序:
const http = require('http')const server = http.createServer((req, res) => { // 每一次請求處理的方法 console.log(req.url) res.writeHead(200, { 'Content-Type': 'text/plain' }) res.end('Hello NodeJS')})server.listen(8080)注意:當瀏覽器發送請求時,會附帶請求/favicon.ico。
而Koa在封裝創建應用程序的方法中主要執行了以下流程:
組織中間件(監聽請求之前) 生成context上下文對象 執行中間件 執行默認響應方法或者異常處理方法// application.jslisten(...args) { const server = http.createServer(this.callback()); return server.listen(...args);}callback() { // 組織中間件 const fn = compose(this.middleware); // 未監聽異常處理,則采用默認的異常處理方法 if (!this.listenerCount('error')) this.on('error', this.onerror); const handleRequest = (req, res) => { // 生成context上下文對象 const ctx = this.createContext(req, res); return this.handleRequest(ctx, fn); }; return handleRequest;}handleRequest(ctx, fnMiddleware) { const res = ctx.res; // 默認狀態碼為404 res.statusCode = 404; // 中間件執行完畢之后 采用默認的 錯誤 與 成功 的處理方式 const onerror = err => ctx.onerror(err); const handleResponse = () => respond(ctx); onFinished(res, onerror); return fnMiddleware(ctx).then(handleResponse).catch(onerror);}二、擴展res和req
首先我們要知道NodeJS中的res和req是http.IncomingMessage和http.ServerResponse的實例,那么就可以在NodeJS中這樣擴展req和res:
Object.defineProperties(http.IncomingMessage.prototype, { query: { get () { return querystring.parse(url.parse(this.url).query) } }})Object.defineProperties(http.ServerResponse.prototype, { json: { value: function (obj) { if (typeof obj === 'object') { obj = JSON.stringify(obj) } this.end(obj) } }})而Koa中則是自定義request和response對象,然后保持對res和req的引用,最后通過getter和setter方法實現擴展。
// application.jscreateContext(req, res) { const context = Object.create(this.context); const request = context.request = Object.create(this.request); const response = context.response = Object.create(this.response); context.app = request.app = response.app = this; context.req = request.req = response.req = req; // 保存原生req對象 context.res = request.res = response.res = res; // 保存原生res對象 request.ctx = response.ctx = context; request.response = response; response.request = request; context.originalUrl = request.originalUrl = req.url; context.state = {}; // 最終返回完整的context上下文對象 return context;}
新聞熱點
疑難解答
圖片精選