[Bug] 在Node.js的服务器框架 Koa 中产生的 Cors 跨域请求问题

195 阅读2分钟

一.问题描述

项目分为基于 vue 的前端部分和基于 Koa 框架的后端部分。 后端已经布置了cors()中间件,
前端使用 axios 查询后端的数据:

image.png

预期应该在控制台打印一条数据,但是出现了 Cors 跨域错误:

image.png

二.解决方案

问题出在这里:

image.png

调整语句,将app.use(cors())放在第一行,问题解决。 image.png

三.深入理解

这个Bug产生的原因,要涉及中间件的洋葱模型。实际上,不仅在基于 Node.js 的koa web框架应用了洋葱模型的中间件,基于Go 的 Gin 框架也是如此。

1.中间件概念

  1. 匹配路由之前和匹配路由之后执行函数。使用app.use()加载中间件。
  2. 每个中间件都是一个函数(不是函数将报错),接收两个参数,ctx上下文对象,next函数(由koa-compose定义)
  3. 中间件分为:应用级中间件、路由级中间件、错误处理中间件、第三方中间件

2.中间件工作原理

  1. 初始化koa实例后,use方法加载中间件(middleware),会有一个middleware中间件数组来存储中间件,use调用顺序会决定中间件的执行顺序。
  2. 在建立好http服务器后,调用koa-compose模块对middleware中间件数组进行处理。
  3. 从middleware数组中取第一个函数开始执行,中间件函数中调用next方法就会去取下一个中间件函数继续执行。每个中间件函数执行完毕后都会返回一个promise对象。(ps:调用next方法并不是表示当前中间件函数执行完毕了,调用next之后仍可以继续执行其他代码)

3.洋葱模型

image.png
洋葱内的每一层都表示一个独立的中间件,用于实现不同的功能,比如Cors 跨域管理、异常处理、缓存处理等。
每次请求都会从左侧开始一层层地经过每层的中间件,当进入到最里层的中间件之后,就会从最里层的中间件开始逐层返回。
因此对于每层的中间件来说,在一个 请求和响应 周期中,都有两个时机点来添加不同的处理逻辑,用next() 区分前后两个时间段。

image.png

4. cors() 中间件必须是第一个被注册的中间件,也就是最外层的中间件

因为前端的各种请求到来时,第一步就是验证跨域安全。如果后端程序的洋葱模型最外层不是cors() 跨域验证中间件,前端程序将判定不可跨域。