首页 > 语言 > JavaScript > 正文

玩转Koa之核心原理分析

2024-05-06 15:43:43
字体:
来源:转载
供稿:网友

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;}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选