context文件源码解析
依赖模块
const util = require('util')// 工具模块,支持 Node.js 内部 API 的需求const createError = require('http-errors')// 创建 HTTP 错误const httpAssert = require('http-assert')// 利用状态码断言const delegate = require('delegates')// 委托const statuses = require('statuses')// 提供状态码与消息的一一对应关系const Cookies = require('cookies')// 创建和设置 HTTP cookies
全局变量
const COOKIES = Symbol('context#cookies')// 创建全局唯一的变量 COOKIES
proto 导出对象
const proto = module.exports = { // 内容如下}
inspect 检查函数
// 检查当前 this 值inspect () { if (this === proto) return this return this.toJSON()}
toJSON 格式化函数
// 返回 koa 格式化上下文对象toJSON () { return { request: this.request.toJSON(), response: this.response.toJSON(), app: this.app.toJSON(), originalUrl: this.originalUrl, req: '<original node req>', res: '<original node res>', socket: '<original node socket>' }}
assert 断言函数
// http-assert 状态码断言方法assert: httpAssert
throw 抛出错误
// http-errors 抛出用户级 HTTP 错误throw (...args) { throw createError(...args)}
onerror 统一错误处理
// 统一错误处理onerror (err) { if (err == null) return // 判断是否是原生错误,若不是,则创建原生错误 const isNativeError = Object.prototype.toString.call(err) === '[object Error]' || err instanceof Error if (!isNativeError) err = new Error(util.format('non-error thrown: %j', err)) let headerSent = false if (this.headerSent || !this.writable) { headerSent = err.headerSent = true } this.app.emit('error', err, this) if (headerSent) { return } const { res } = this if (typeof res.getHeaderNames === 'function') { res.getHeaderNames().forEach(name => res.removeHeader(name)) } else { res._headers = {} } this.set(err.headers) this.type = 'text' let statusCode = err.status || err.statusCode if (err.code === 'ENOENT') statusCode = 404 if (typeof statusCode !== 'number' || !statuses[statusCode]) statusCode = 500 const code = statuses[statusCode] const msg = err.expose ? err.message : code this.status = err.status = statusCode this.length = Buffer.byteLength(msg) res.end(msg)}
cookies getter/setter
get cookies () { if (!this[COOKIES]) { this[COOKIES] = new Cookies(this.req, this.res, { keys: this.app.keys, secure: this.request.secure }) } return this[COOKIES]}set cookies (_cookies) { this[COOKIES] = _cookies}
自定义检查函数
if (util.inspect.custom) { module.exports[util.inspect.custom] = module.exports.inspect}
响应委托
// 将 respose 属性方法委托到 protodelegate(proto, 'response') .method('attachment') .method('redirect') .method('remove') .method('vary') .method('has') .method('set') .method('append') .method('flushHeaders') .access('status') .access('message') .access('body') .access('length') .access('type') .access('lastModified') .access('etag') .getter('headerSent') .getter('writable')
请求委托
// 将 requset 属性方法委托到 protodelegate(proto, 'request') .method('acceptsLanguages') .method('acceptsEncodings') .method('acceptsCharsets') .method('accepts') .method('get') .method('is') .access('querystring') .access('idempotent') .access('socket') .access('search') .access('method') .access('query') .access('path') .access('url') .access('accept') .getter('origin') .getter('href') .getter('subdomains') .getter('protocol') .getter('host') .getter('hostname') .getter('URL') .getter('header') .getter('headers') .getter('secure') .getter('stale') .getter('fresh') .getter('ips') .getter('ip')