application源码解析

依赖模块

  1. const debug = require('debug')('koa:application')
  2. // 设置名为 koa:application 的 debug 装饰器
  3. const onFinished = require('on-finished')
  4. // 当 HTTP 请求终止时执行回调
  5. const compose = require('koa-compose')
  6. // 合并中间件
  7. const statuses = require('statuses')
  8. // 提供状态码与消息的一一对应关系
  9. const Emitter = require('events')
  10. // 提供事件触发器
  11. const util = require('util')
  12. // 工具模块,支持 Node.js 内部 API 的需求
  13. const Stream = require('stream')
  14. // 工具模块,支持 Node.js 内部 API 的需求
  15. const http = require('http')
  16. // 提供对 HTTP 服务器和客户端的流处理和消息解析
  17. const only = require('only')
  18. // 设置对象白名单属性
  19. const { HttpError } = require('http-errors')
  20. // 创建 HTTP 错误
  21. const context = require('./context')
  22. const request = require('./request')
  23. const response = require('./response')

Application 导出对象

  1. module.exports = class Application extends Emitter {
  2. // 内容如下
  3. }

constructor

  1. constructor (options) {
  2. super()
  3. options = options || {}
  4. this.proxy = options.proxy || false
  5. this.subdomainOffset = options.subdomainOffset || 2
  6. this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For'
  7. this.maxIpsCount = options.maxIpsCount || 0
  8. this.env = options.env || process.env.NODE_ENV || 'development'
  9. if (options.keys) this.keys = options.keys
  10. this.middleware = []
  11. this.context = Object.create(context)
  12. this.request = Object.create(request)
  13. this.response = Object.create(response)
  14. if (util.inspect.custom) {
  15. this[util.inspect.custom] = this.inspect
  16. }
  17. }

listen 创建/启动/返回

  1. listen (...args) {
  2. debug('listen')
  3. const server = http.createServer(this.callback())
  4. return server.listen(...args)
  5. }

 toJSON 格式化函数

  1. toJSON () {
  2. return only(this, [
  3. 'subdomainOffset',
  4. 'proxy',
  5. 'env'
  6. ])
  7. }

inspect 检查函数

  1. inspect () {
  2. return this.toJSON()
  3. }

use 添加中间件

  1. use (fn) {
  2. if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
  3. debug('use %s', fn._name || fn.name || '-')
  4. this.middleware.push(fn)
  5. return this
  6. }

callback 返回一个原生请求处理回调

  1. callback () {
  2. const fn = compose(this.middleware)
  3. if (!this.listenerCount('error')) this.on('error', this.onerror)
  4. const handleRequest = (req, res) => {
  5. const ctx = this.createContext(req, res)
  6. return this.handleRequest(ctx, fn)
  7. }
  8. return handleRequest
  9. }

handleRequest 处理请求

  1. handleRequest (ctx, fnMiddleware) {
  2. const res = ctx.res
  3. res.statusCode = 404
  4. const onerror = err => ctx.onerror(err)
  5. const handleResponse = () => respond(ctx)
  6. onFinished(res, onerror)
  7. return fnMiddleware(ctx).then(handleResponse).catch(onerror)
  8. }

createContext 创建上下文ctx

  1. createContext (req, res) {
  2. const context = Object.create(this.context)
  3. const request = context.request = Object.create(this.request)
  4. const response = context.response = Object.create(this.response)
  5. context.app = request.app = response.app = this
  6. context.req = request.req = response.req = req
  7. context.res = request.res = response.res = res
  8. request.ctx = response.ctx = context
  9. request.response = response
  10. response.request = request
  11. context.originalUrl = request.originalUrl = req.url
  12. context.state = {}
  13. return context
  14. }

onerror 错误处理

  1. onerror (err) {
  2. const isNativeError =
  3. Object.prototype.toString.call(err) === '[object Error]' ||
  4. err instanceof Error
  5. if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err))
  6. if (err.status === 404 || err.expose) return
  7. if (this.silent) return
  8. const msg = err.stack || err.toString()
  9. console.error(`\n${msg.replace(/^/gm, ' ')}\n`)
  10. }

default 弥补TS

  1. static get default () {
  2. return Application
  3. }

respond 响应数据处理

  1. function respond (ctx) {
  2. if (ctx.respond === false) return
  3. if (!ctx.writable) return
  4. const res = ctx.res
  5. let body = ctx.body
  6. const code = ctx.status
  7. if (statuses.empty[code]) {
  8. ctx.body = null
  9. return res.end()
  10. }
  11. if (ctx.method === 'HEAD') {
  12. if (!res.headersSent && !ctx.response.has('Content-Length')) {
  13. const { length } = ctx.response
  14. if (Number.isInteger(length)) ctx.length = length
  15. }
  16. return res.end()
  17. }
  18. if (body == null) {
  19. if (ctx.response._explicitNullBody) {
  20. ctx.response.remove('Content-Type')
  21. ctx.response.remove('Transfer-Encoding')
  22. ctx.length = 0
  23. return res.end()
  24. }
  25. if (ctx.req.httpVersionMajor >= 2) {
  26. body = String(code)
  27. } else {
  28. body = ctx.message || String(code)
  29. }
  30. if (!res.headersSent) {
  31. ctx.type = 'text'
  32. ctx.length = Buffer.byteLength(body)
  33. }
  34. return res.end(body)
  35. }
  36. if (Buffer.isBuffer(body)) return res.end(body)
  37. if (typeof body === 'string') return res.end(body)
  38. if (body instanceof Stream) return body.pipe(res)
  39. body = JSON.stringify(body)
  40. if (!res.headersSent) {
  41. ctx.length = Buffer.byteLength(body)
  42. }
  43. res.end(body)
  44. }

HttpError 提供创建 HTTP 错误途径

  1. module.exports.HttpError = HttpError