「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。
手撕koa,从零掌握koa的实现原理(5)
往期更文
前言
- 回顾昨天的内容,在每次的请求来临的时候,我们创建了每次请求的上下文对象
ctx,createContext函数中是我们的处理逻辑。 koa/koa/lib/application.jsconst http = require('http') const EventEmitter = require('events') const context = require('./context'); const request = require('./request'); const response = require('./response'); class Application extends EventEmitter { constructor(){ super() this.context = Object.create(context) this.request = Object.create(request) this.response = Object.create(response) } createContext(req, res){ // req, res 是原生的 request 和 response 是我们自己扩展 const ctx = Object.create(this.context) const request = Object.create(this.request) const response = Object.create(this.response) ctx.request = request ctx.request.req = ctx.req = req ctx.response = response; ctx.response.res = ctx.res = res; return ctx } handleRequest = (req, res) => { const ctx = this.createContext(req, res) } listen(){ const server = http.createServer(this.handleRequest) server.listen(...arguments) } } module.exports = Application
扩展request对象
- 在每次请的时候,我们虽然创建了上下文对象,但是
ctx上还没有任何的属性,下面我们来扩展一下context、request、response,这三个对象。 - 我们在
createContext时候,给request身上添加了req属性,目的就是为了在request对象扩展的时候可以快速地拿到原生的req。我们下面只扩展了三个属性作为示范,在官方的koa中request对象也是这样扩展的。koa/koa/lib/request.jsconst url = require('url') const request = { get url(){ return this.req.url }, get path(){ let {pathname} = url.parse(this.req.url) return pathname }, get query(){ let {pathname, query} = url.parse(this.req.url, true) return query } } module.exports = request
扩展response对象
response响应对象中我们扩展一下,我们使用的ctx.body,为什么我们给ctx.body赋值,浏览器就会拿到我们的返回结果呢,答案就在这里。koa/koa/lib/response.jsconst response = { _body:undefined, get body(){ return this._body }, set body(content){ this.res.statusCode = 200 this._body = content } }
扩展context对象
context上下文对象的扩展,koa中使用的是__defineGetter__与__defineSetter__方法来代理属性的,就是相当于Object.defineProperty方法的get与set,从下面的代码我们可以看出来,当我们访问或设置ctx对象上的属性时,会被代理到request与response对象上,这样做的作用就是为了,我们在使用的时候能够更简便。例如,我要访问
ctx.request.path时,可以直接访问ctx.path。koa/koa/lib/context.jsconst context = {}; function defineGetter(target, key) { context.__defineGetter__(key,function () { return this[target][key] }) } function defineSetter(target, key) { context.__defineSetter__(key,function (value) { this[target][key] = value }) } defineGetter('request', 'path') defineGetter('request', 'url') defineGetter('request', 'query') defineGetter('response', 'body') defineSetter('response', 'body') module.exports = context;
下期预告
koa的中间件实现原理
更文第五天,加油,还剩35天。