中间件基本使用

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 中间件洋葱模型源码分析相关推荐

  1. WPF(六) Command 命令模型源码分析

    1.ICommand源码分析 ​ 在之前 WPF(三) WPF命令 中我们已经分析过了 WPF 的命令系统,包括WPF默认的 RoutedCommand 以及我们自定义的 ICommand 命令实现. ...

  2. memcached(二)事件模型源码分析

    在memcachedd中,作者为了专注于缓存的设计,使用了libevent来开发事件模型.memcachedd的时间模型同nginx的类似,拥有一个主进行(master)以及多个工作者线程(woker ...

  3. zebra源码分析-导读

    zebra源码分析-导读 客户端架构 JDBC 核心部分介绍 代码流程 数据源 Statement 参考 zebra源码分析-导读 zebra是一个基于JDBC API协议上开发出的高可用.高性能的数 ...

  4. koa2 一网打尽(基本使用,洋葱圈,中间件机制和模拟,源码分析,核心点,生态)

    原文https://juejin.im/entry/5bfbe5a76fb9a049cb186cfa/detail koa homepage 优秀的下一代 web 开发框架. Koa 应用程序不是 H ...

  5. Koa洋葱圈模型源码浅析(`await next()`为什么能够形成洋葱圈模型?)

    Koa洋葱圈模型源码浅析 写在前面 什么是中间件? 为什么要使用中间件? auth中间件源码 Koa源码浅析 我们先来康一张gif图片 我们的探索流程图 listen函数 callback函数 cre ...

  6. 数据库中间件 MyCAT源码分析 —— XA分布式事务

    title: MyCAT 源码分析 -- XA分布式事务 date: 2017-07-15 tags: categories: MyCAT permalink: MyCAT/xa-distribute ...

  7. koa源码分析-co模块以及thunk

    Thunk以及CO模块 co4.0之前都是返回的thunk函数 之后的都是返回promise thunk thunk:在 JavaScript 语言中,Thunk 函数替换的是将多参数函数,替换成单参 ...

  8. Django源码分析5:session会话中间件分析

    django源码分析 本文环境python3.5.2,django1.10.x系列 1.这次分析django框架中的会话中间件. 2.会话保持是目前框架都支持的一个功能,因为http是无状态协议,无法 ...

  9. Django源码分析4:staticfiles静态文件处理中间件分析

    django源码分析 本文环境python3.5.2,django1.10.x系列1.在上一篇文章中已经分析过handler的处理过程,其中load_middleware就是将配置的中间件进行初始化, ...

最新文章

  1. js阻止a标签默认事件的几种方法
  2. 【电子信息复试】考研复试常考问题——组成原理
  3. linux 实时 网口 速率_Linux 命令行网络端口速度测试
  4. 最短编辑距离问题理解
  5. HDU4006(The kth great number)
  6. 百度大数据可视化产品矩阵
  7. 软件测试管理工具禅道开源版下载安装
  8. 基于SSM的Java Web应用开发原理初探
  9. openStack 手动部署文档
  10. 服务器注意事项(切记!)
  11. 冯诺依曼计算机主机,冯诺依曼计算机的基本思想是什么?
  12. 施耐德控制器维修伺服驱动器维修C400A8
  13. java oracle spool,Oracle 数据导出工具 Spool | 学步园
  14. 阿里云服务器安装nodejs
  15. 音诺恒RK3568高性能智能商显安卓广告机主板解决方案
  16. 《脱颖而出——成功网店经营之道》一2.6 连横:返利模式的应用及分销
  17. python画图显示中文加标题控制字体
  18. web打印页眉页脚_Web设计中页眉和页脚的20种创意组合
  19. SQL48 将所有获取奖金的员工当前的薪水增加10%
  20. NOIP2016·洛谷·天天爱跑步

热门文章

  1. 什么样的人适合当软件工程师?
  2. ARP是什么?+ARP欺骗 MAC为ff:ff:ff:ff:ff:ff是什么意思
  3. mqtt 变为乱码 接受16进制字节流_转战物联网#183;基础篇07-深入理解MQTT协议之控制报文(数据包)格式...
  4. pygame外星人来了小游戏
  5. 数据中心服务器大战:思科vs惠普vs…
  6. 二、详解 DVWA_Reflected反射型XSS
  7. 陪审团的人选(Python)
  8. 阿里云中间件是什么-阿里云中间件介绍
  9. html设置背景图片自适应
  10. 服务器参数知多少 带你一一认识这些参数