基本组成
- application.js:框架入口;负责管理中间件,以及处理请求
- context.js:context对象的原型,代理request与response对象上的方法和属性
- request.js:request对象的原型,提供请求相关的方法和属性
- response.js:response对象的原型,提供响应相关的方法和属性
开始
新建test.js
文件
1 | const koa = require('koa'); |
通过node --inspect-brk test
运行,进入调试模式。
浏览器打开http://127.0.0.1:9229/
,点击这个
首先通过new Koa()
创建实例
1 | module.exports = class Application extends Emitter { |
对象实例:
app.use
方法
1 | use(fn) { |
- 判断了传入的
fn
类型是否是function
- 然后判断是否是
generator
函数 - 之后
push
进middleware
数组里
app.listen
方法
1 | listen(...args) { |
- 先执行
this.callback()
,返回一个handleRequest
函数
1 | callback() { |
compose
是由一个名为koa-compose
的库,它可以将多个中间件组合成洋葱式调用的对象。
1 | function compose (middleware) { |
调用
http.createServer
,该函数用来创建一个HTTP服务器,并将handleRequest
作为request
事件的监听函数。server.listen(...args)
启动服务器监听连接,3000
端口号
发送请求到http://localhost:3000/
,执行回调函数
1 | const handleRequest = (req, res) => { |
- 首先调用
createContext
创建上下文对象
1 | createContext(req, res) { |
- 调用
this.handleRequest(ctx, fn)
1 | handleRequest(ctx, fnMiddleware) { |
进入fnMiddleware(ctx).then(handleResponse).catch(onerror);
1 | return function (context, next) { |
小结
1)首先先创建koa
实例
2)app.use
是往middleware
数组里push
进回调函数
3)app.listen
启动服务端器监听,并且添加了回调函数
4)触发接口请求回调函数的时候,会将创建的上下文对象与next
(next其实就是dispatch
方法),作为参数传入到middleware
中每项的函数调用中,如果调用了next
就是调用的dispatch.bind(null, i + 1)
koa-router
1 | const koa = require('koa'); |
看实例化Router
的过程之前,先看一下,遍历数组为Router
构造函数添加prototype
属性
看Router
构造函数
1 | function Router(opts) { |
Router
的实例
router.get
方法
1 | Router.prototype[method] = function (name, path, middleware) { |
在这里调用register
并且传入path
、method
、name
和middleware
(这里有对router.get
传入的值做了一些修改),进入regiseter
方法
1 | Router.prototype.register = function (path, methods, middleware, opts) { |
这里实例化了route
,并且push
到了stack
里
app.use(router.routes())
先看router.routes()
1 | Router.prototype.routes = Router.prototype.middleware = function () { |
声明dispatch
方法并且把Router
实例挂载到了这个方法上
之后调用app.use
把dispatch
方法push
进去了middleware
数组
app.listen
方法
与上面一样,就是传入回调,启动个服务。
访问http://localhost:3000/list/1
触发回调
进入回调函数
1 | return function (context, next) { |
在这里,取得middleware
的第一个回调并且调用
1 | var dispatch = function dispatch(ctx, next) { |
最后调用到compose
方法,传入的layerChina
是个数组,第一个是匿名函数
1 | function(ctx, next) { |
第二个是访问/list
的回调函数
最后又调用进这个方法
1 | return function (context, next) { |
也就是先调用了上面的匿名函数,这个匿名函数为上下文对象
添加了一些属性
之后调用next
方法,走到我们为访问/list
添加的回调那里
小结
1)创建Router
实例
2)router.get
,注册路由规则,并且push
进stack
数组
3)app.use(router.routes())
,将router.routes()
返回的dispatch
方法push
到middleware
数组里
4)app.listen(3000)
,添加回调函数,并且启动服务器监听
5)访问http://localhost:3000/list/1
,调用middleware
数组中第一个函数调用,这个函数调用返回compose(layerChain)(ctx, next);
6)layerChain
是由两个函数组成的数组,里面的第一个函数被调用时候,解析path
,为ctx
上下文对象添加一些属性,之后调用next()
7)也就是走进layerChain
里的第二个函数调用,也就是router.get
的回调函数
koa-cors
test.html
1 |
|
test.js
1 | const koa = require('koa'); |
app.use(cors())
调用
先进入cors()
1 | module.exports = function crossOrigin(options = {}) { |
返回了一个异步函数,之后app.use
把这个函数push
到middleware
数组里
刷新html
页面,触发send
方法,发送请求,触发回调,之后先调用middleware
数组里第一个函数调用,就是上面的这个方法,这个方法(在这个例子中)做的事情:
- 获取
origin
,通过ctx.set('Access-Control-Allow-Origin', origin);
设置头部 - 调用
next()
这里的next
调用就是路由Router.routes()
返回的那个方法,调用步骤与上面路由的地方一样
小结
1)app.use(cors())
把回调传入middleware
数组
2)发送请求,设置响应头
因为这边是简单请求,所以没有OPTIONS
预检请求
- 当替换请求方法为
PUT
的时候,判断是OPTIONS
请求的时候,会设置这个响应头
- 当添加请求头
name
属性的时候,会设置这个响应头
koa-bodyparser
1 | ... |
先进入bodyParser()
最后往middleware数组push进去这个函数
1 | async function bodyParser(ctx, next) { |
收到请求后根据不同的content-type
调用不同的方法解析请求体,这边使用的是application/x-www-form-urlencoded
获取请求的content-encoding
、content-length
和编码方式utf-8
- 先根据
contentn-encoding
的值判断是否需要解压,还是直接返回
- 根据编码方式,Buffer转字符串
- 解析完成后返回str
最后挂载在ctx.request.body上