application源码解析
依赖模块
const debug = require('debug')('koa:application')// 设置名为 koa:application 的 debug 装饰器const onFinished = require('on-finished')// 当 HTTP 请求终止时执行回调const compose = require('koa-compose')// 合并中间件const statuses = require('statuses')// 提供状态码与消息的一一对应关系const Emitter = require('events')// 提供事件触发器const util = require('util')// 工具模块,支持 Node.js 内部 API 的需求const Stream = require('stream')// 工具模块,支持 Node.js 内部 API 的需求const http = require('http')// 提供对 HTTP 服务器和客户端的流处理和消息解析 const only = require('only')// 设置对象白名单属性const { HttpError } = require('http-errors')// 创建 HTTP 错误const context = require('./context')const request = require('./request')const response = require('./response')
Application 导出对象
module.exports = class Application extends Emitter { // 内容如下 }
constructor
constructor (options) { super() options = options || {} this.proxy = options.proxy || false this.subdomainOffset = options.subdomainOffset || 2 this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For' this.maxIpsCount = options.maxIpsCount || 0 this.env = options.env || process.env.NODE_ENV || 'development' if (options.keys) this.keys = options.keys this.middleware = [] 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 }}
listen 创建/启动/返回
listen (...args) { debug('listen') const server = http.createServer(this.callback()) return server.listen(...args)}
toJSON 格式化函数
toJSON () { return only(this, [ 'subdomainOffset', 'proxy', 'env' ])}
inspect 检查函数
inspect () { return this.toJSON()}
use 添加中间件
use (fn) { if (typeof fn !== 'function') throw new TypeError('middleware must be a function!') debug('use %s', fn._name || fn.name || '-') this.middleware.push(fn) return this}
callback 返回一个原生请求处理回调
callback () { const fn = compose(this.middleware) if (!this.listenerCount('error')) this.on('error', this.onerror) const handleRequest = (req, res) => { const ctx = this.createContext(req, res) return this.handleRequest(ctx, fn) } return handleRequest}
handleRequest 处理请求
handleRequest (ctx, fnMiddleware) { const res = ctx.res res.statusCode = 404 const onerror = err => ctx.onerror(err) const handleResponse = () => respond(ctx) onFinished(res, onerror) return fnMiddleware(ctx).then(handleResponse).catch(onerror)}
createContext 创建上下文ctx
createContext (req, res) { const 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 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}
onerror 错误处理
onerror (err) { const isNativeError = Object.prototype.toString.call(err) === '[object Error]' || err instanceof Error if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err)) if (err.status === 404 || err.expose) return if (this.silent) return const msg = err.stack || err.toString() console.error(`\n${msg.replace(/^/gm, ' ')}\n`)}
default 弥补TS
static get default () { return Application}
respond 响应数据处理
function respond (ctx) { if (ctx.respond === false) return if (!ctx.writable) return const res = ctx.res let body = ctx.body const code = ctx.status if (statuses.empty[code]) { ctx.body = null return res.end() } if (ctx.method === 'HEAD') { if (!res.headersSent && !ctx.response.has('Content-Length')) { const { length } = ctx.response if (Number.isInteger(length)) ctx.length = length } return res.end() } if (body == null) { if (ctx.response._explicitNullBody) { ctx.response.remove('Content-Type') ctx.response.remove('Transfer-Encoding') ctx.length = 0 return res.end() } if (ctx.req.httpVersionMajor >= 2) { body = String(code) } else { body = ctx.message || String(code) } if (!res.headersSent) { ctx.type = 'text' ctx.length = Buffer.byteLength(body) } return res.end(body) } if (Buffer.isBuffer(body)) return res.end(body) if (typeof body === 'string') return res.end(body) if (body instanceof Stream) return body.pipe(res) body = JSON.stringify(body) if (!res.headersSent) { ctx.length = Buffer.byteLength(body) } res.end(body)}
HttpError 提供创建 HTTP 错误途径
module.exports.HttpError = HttpError