koa 中间件洋葱模型源码分析
中间件基本使用
app.use(async(ctx,next)=>{ctx.state={username:'jeff'};await next();...
})app.use(async(ctx,next)=>{ctx.state={username:'jeff2'};await next();...
})
Koa 初始化应用实例
const app = new Koa()
- 为 app 实例添加 context、request、response、middleware 等属性
constructor(options) {super();this.middleware = [];// 每一个 app 实例,都有下面三个对象的实例this.context = Object.create(context);this.request = Object.create(request);this.response = Object.create(response);if (util.inspect.custom) {this[util.inspect.custom] = this.inspect;}}
app.use() 添加中间件
use(fn) {if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');if (isGeneratorFunction(fn)) {deprecate('Support for generators will be removed in v3. ' +'See the documentation for examples of how to convert old middleware ' +'https://github.com/koajs/koa/blob/master/docs/migration.md');fn = convert(fn);}debug('use %s', fn._name || fn.name || '-');// 直接存入到 middleware 数组中,后续统一处理this.middleware.push(fn);return this;}
app.listen() 监听
listen(...args) {debug('listen');const server = http.createServer(this.callback());return server.listen(...args);}
this.callback()
- 在 Node 的 http 模块,对于每一个请求,都会走到回调函数 callback 中去。所以这个 callback 是用于处理实际请求的
callback() {// 包装所有的中间件,返回一个可执行的函数。koa-compose 实现了洋葱圈模型const fn = compose(this.middleware);if (!this.listenerCount('error')) this.on('error', this.onerror);// 实际触发的函数const handleRequest = (req, res) => {// req res 是 node http模块原生请求参数const ctx = this.createContext(req, res);// 将创建的 ctx 返回,传给所有中间件,作为整个请求的上下文return this.handleRequest(ctx, fn);};return handleRequest;}
this.createContext
- 明确 context 挂载的内容,这个 context 是每一次请求都会生成的
- 每次请求都生成避免了全局污染
this.createContex createContext(req, res) {// 每一个请求对应一个 ctx、request、response、req、resconst 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;// 挂载 node 原生请求参数 req res 到 context、request、response 上context.req = request.req = response.req = req;context.res = request.res = response.res = res;request.ctx = response.ctx = context;request.response = response;response.request = request;context.originalUrl = request.originalUrl = req.url;context.state = {};return context;}
compose 实现洋葱圈模型
- 遍历中间件列表,将下一个中间件的执行函数函数作为参数传递给next,通过递归的方式,在执行当前中间件的next时,进入下一个中间件
function compose (middleware) {// 类型检查if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')for (const fn of middleware) {if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')}//返回的洋葱模型的可执行函数 return function (context, next) {// 上一次被执行的中间件let index = -1//自执行,返回中间件执行的结果return dispatch(0)function dispatch (i /*表示预期想要执行哪个中间件*/) {if (i <= index) return Promise.reject(new Error('next() called multiple times'))index = ilet fn = middleware[i]//递归临界点if (i === middleware.length) fn = next// 没有fn的话,直接返回一个已经reolved的Promise对象if (!fn) return Promise.resolve()try {/*原代码是一行,为了方便理解拆成了三行//获取下一个中间件的执行函数const next = dispatch.bind(null, i + 1);//执行本次中间件函数,执行next就会进行下一个中间件next的分配和执行const fnResult = fn(context, next);//将此每次中间件执行结果Promise化return Promise.resolve(fnResult);*/return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));} catch (err) {return Promise.reject(err)}}}
}
this.handleRequest
- fnMiddleware为执行中间件递归处理的函数,返回Promise
handleRequest(ctx, fnMiddleware) {const res = ctx.res;res.statusCode = 404;const onerror = err => ctx.onerror(err);const handleResponse = () => respond(ctx);onFinished(res, onerror);// 执行 compose 后的中间件函数,最后执行 respondreturn fnMiddleware(ctx).then(handleResponse).catch(onerror);}
koa 中间件洋葱模型源码分析相关推荐
- WPF(六) Command 命令模型源码分析
1.ICommand源码分析 在之前 WPF(三) WPF命令 中我们已经分析过了 WPF 的命令系统,包括WPF默认的 RoutedCommand 以及我们自定义的 ICommand 命令实现. ...
- memcached(二)事件模型源码分析
在memcachedd中,作者为了专注于缓存的设计,使用了libevent来开发事件模型.memcachedd的时间模型同nginx的类似,拥有一个主进行(master)以及多个工作者线程(woker ...
- zebra源码分析-导读
zebra源码分析-导读 客户端架构 JDBC 核心部分介绍 代码流程 数据源 Statement 参考 zebra源码分析-导读 zebra是一个基于JDBC API协议上开发出的高可用.高性能的数 ...
- koa2 一网打尽(基本使用,洋葱圈,中间件机制和模拟,源码分析,核心点,生态)
原文https://juejin.im/entry/5bfbe5a76fb9a049cb186cfa/detail koa homepage 优秀的下一代 web 开发框架. Koa 应用程序不是 H ...
- Koa洋葱圈模型源码浅析(`await next()`为什么能够形成洋葱圈模型?)
Koa洋葱圈模型源码浅析 写在前面 什么是中间件? 为什么要使用中间件? auth中间件源码 Koa源码浅析 我们先来康一张gif图片 我们的探索流程图 listen函数 callback函数 cre ...
- 数据库中间件 MyCAT源码分析 —— XA分布式事务
title: MyCAT 源码分析 -- XA分布式事务 date: 2017-07-15 tags: categories: MyCAT permalink: MyCAT/xa-distribute ...
- koa源码分析-co模块以及thunk
Thunk以及CO模块 co4.0之前都是返回的thunk函数 之后的都是返回promise thunk thunk:在 JavaScript 语言中,Thunk 函数替换的是将多参数函数,替换成单参 ...
- Django源码分析5:session会话中间件分析
django源码分析 本文环境python3.5.2,django1.10.x系列 1.这次分析django框架中的会话中间件. 2.会话保持是目前框架都支持的一个功能,因为http是无状态协议,无法 ...
- Django源码分析4:staticfiles静态文件处理中间件分析
django源码分析 本文环境python3.5.2,django1.10.x系列1.在上一篇文章中已经分析过handler的处理过程,其中load_middleware就是将配置的中间件进行初始化, ...
最新文章
- js阻止a标签默认事件的几种方法
- 【电子信息复试】考研复试常考问题——组成原理
- linux 实时 网口 速率_Linux 命令行网络端口速度测试
- 最短编辑距离问题理解
- HDU4006(The kth great number)
- 百度大数据可视化产品矩阵
- 软件测试管理工具禅道开源版下载安装
- 基于SSM的Java Web应用开发原理初探
- openStack 手动部署文档
- 服务器注意事项(切记!)
- 冯诺依曼计算机主机,冯诺依曼计算机的基本思想是什么?
- 施耐德控制器维修伺服驱动器维修C400A8
- java oracle spool,Oracle 数据导出工具 Spool | 学步园
- 阿里云服务器安装nodejs
- 音诺恒RK3568高性能智能商显安卓广告机主板解决方案
- 《脱颖而出——成功网店经营之道》一2.6 连横:返利模式的应用及分销
- python画图显示中文加标题控制字体
- web打印页眉页脚_Web设计中页眉和页脚的20种创意组合
- SQL48 将所有获取奖金的员工当前的薪水增加10%
- NOIP2016·洛谷·天天爱跑步