request文件源码解析

依赖模块

  1. const URL = require('url').URL
  2. // 处理 url
  3. const net = require('net')
  4. // 模块 net 提供了异步的网络 API
  5. const accepts = require('accepts')
  6. // HTTP 内容协商,可获取网络请求支持的编码、语言、类型等信息
  7. const contentType = require('content-type')
  8. // 创建和解析 Http Content-Type
  9. const stringify = require('url').format
  10. // 序列化 url
  11. const parse = require('parseurl')
  12. // 类似于 url.parse,但是具有缓存功能
  13. const qs = require('querystring')
  14. // 模块 querystring 提供了用于解析和格式化网址查询字符串的实用工具
  15. const typeis = require('type-is')
  16. // 提供对请求的类型检查
  17. const fresh = require('fresh')
  18. // 判断缓存是否过期
  19. const only = require('only')
  20. // 设置对象白名单属性
  21. const util = require('util')
  22. // 工具模块,支持 Node.js 内部 API 的需求

全局变量

  1. const IP = Symbol('context#ip')
  2. // 创建全局唯一变量 IP

导出对象

  1. module.exports = {
  2. // 内容如下
  3. }

header

  1. // 保持 header & headers 一致
  2. get header () {
  3. return this.req.headers
  4. }
  5. set header (val) {
  6. this.req.headers = val
  7. }
  8. get headers () {
  9. return this.req.headers
  10. }
  11. set headers (val) {
  12. this.req.headers = val
  13. }

url

  1. get url () {
  2. return this.req.url
  3. }
  4. set url (val) {
  5. this.req.url = val
  6. }

origin

  1. get origin () {
  2. return `${this.protocol}://${this.host}`
  3. }

href

  1. get href () {
  2. if (/^https?:\/\//i.test(this.originalUrl)) return this.originalUrl
  3. return this.origin + this.originalUrl
  4. }

method

  1. get method () {
  2. return this.req.method
  3. }
  4. set method (val) {
  5. this.req.method = val
  6. }

path

  1. get path () {
  2. return parse(this.req).pathname
  3. }
  4. set path (path) {
  5. const url = parse(this.req)
  6. if (url.pathname === path) return
  7. url.pathname = path
  8. url.path = null
  9. this.url = stringify(url)
  10. }

query

  1. get query () {
  2. const str = this.querystring
  3. const c = this._querycache = this._querycache || {}
  4. return c[str] || (c[str] = qs.parse(str))
  5. }
  6. set query (obj) {
  7. this.querystring = qs.stringify(obj)
  8. }

querystring

  1. get querystring () {
  2. if (!this.req) return ''
  3. return parse(this.req).query || ''
  4. }
  5. set querystring (str) {
  6. const url = parse(this.req)
  7. if (url.search === `?${str}`) return
  8. url.search = str
  9. url.path = null
  10. this.url = stringify(url)
  11. }

search

  1. get search () {
  2. if (!this.querystring) return ''
  3. return `?${this.querystring}`
  4. }
  5. set search (str) {
  6. this.querystring = str
  7. }

host

  1. get host () {
  2. const proxy = this.app.proxy
  3. let host = proxy && this.get('X-Forwarded-Host')
  4. if (!host) {
  5. if (this.req.httpVersionMajor >= 2) host = this.get(':authority')
  6. if (!host) host = this.get('Host')
  7. }
  8. if (!host) return ''
  9. return host.split(/\s*,\s*/, 1)[0]
  10. }

hostname

  1. get hostname () {
  2. const host = this.host
  3. if (!host) return ''
  4. if (host[0] === '[') return this.URL.hostname || ''
  5. return host.split(':', 1)[0]
  6. }

URL

  1. get URL () {
  2. if (!this.memoizedURL) {
  3. const originalUrl = this.originalUrl || ''
  4. try {
  5. this.memoizedURL = new URL(`${this.origin}${originalUrl}`)
  6. } catch (err) {
  7. this.memoizedURL = Object.create(null)
  8. }
  9. }
  10. return this.memoizedURL
  11. }

fresh

  1. get fresh () {
  2. const method = this.method
  3. const s = this.ctx.status
  4. if (method !== 'GET' && method !== 'HEAD') return false
  5. if ((s >= 200 && s < 300) || s === 304) {
  6. return fresh(this.header, this.response.header)
  7. }
  8. return false
  9. }

stale

  1. get stale () {
  2. return !this.fresh
  3. }

idempotent

  1. // 判断请求方法是否幂等
  2. get idempotent () {
  3. const methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']
  4. return !!~methods.indexOf(this.method)
  5. }

socket

  1. // 获取对底层套接字的引用
  2. get socket () {
  3. return this.req.socket
  4. }

charset

  1. get charset () {
  2. try {
  3. const { parameters } = contentType.parse(this.req)
  4. return parameters.charset || ''
  5. } catch (e) {
  6. return ''
  7. }
  8. }

length

  1. get length () {
  2. const len = this.get('Content-Length')
  3. if (len === '') return
  4. return ~~len
  5. }

protocol

  1. get protocol () {
  2. if (this.socket.encrypted) return 'https'
  3. if (!this.app.proxy) return 'http'
  4. const proto = this.get('X-Forwarded-Proto')
  5. return proto ? proto.split(/\s*,\s*/, 1)[0] : 'http'
  6. }

secure

  1. get secure () {
  2. return this.protocol === 'https'
  3. }

ips

  1. get ips () {
  2. const proxy = this.app.proxy
  3. const val = this.get(this.app.proxyIpHeader)
  4. let ips = proxy && val
  5. ? val.split(/\s*,\s*/)
  6. : []
  7. if (this.app.maxIpsCount > 0) {
  8. ips = ips.slice(-this.app.maxIpsCount)
  9. }
  10. return ips
  11. }

ip

  1. get ip () {
  2. if (!this[IP]) {
  3. this[IP] = this.ips[0] || this.socket.remoteAddress || ''
  4. }
  5. return this[IP]
  6. }
  7. set ip (_ip) {
  8. this[IP] = _ip
  9. }

subdomains

  1. get subdomains () {
  2. const offset = this.app.subdomainOffset
  3. const hostname = this.hostname
  4. if (net.isIP(hostname)) return []
  5. return hostname
  6. .split('.')
  7. .reverse()
  8. .slice(offset)
  9. }

accept

  1. get accept () {
  2. return this._accept || (this._accept = accepts(this.req))
  3. }
  4. set accept (obj) {
  5. this._accept = obj
  6. }

type

  1. get type () {
  2. const type = this.get('Content-Type')
  3. if (!type) return ''
  4. return type.split(';')[0]
  5. }

^accepts 判断请求支持类型|编码|语言

  1. accepts (...args) {
  2. return this.accept.types(...args)
  3. }
  4. acceptsEncodings (...args) {
  5. return this.accept.encodings(...args)
  6. }
  7. acceptsCharsets (...args) {
  8. return this.accept.charsets(...args)
  9. }
  10. acceptsLanguages (...args) {
  11. return this.accept.languages(...args)
  12. }

is 检查请求类型

  1. is (type, ...types) {
  2. return typeis(this.req, type, ...types)
  3. }

get 获取请求头属性值

  1. get (field) {
  2. const req = this.req
  3. switch (field = field.toLowerCase()) {
  4. case 'referer':
  5. case 'referrer':
  6. return req.headers.referrer || req.headers.referer || ''
  7. default:
  8. return req.headers[field] || ''
  9. }
  10. }

inspect 检查函数

  1. inspect () {
  2. if (!this.req) return
  3. return this.toJSON()
  4. }

toJSON 格式化函数

  1. toJSON () {
  2. return only(this, [
  3. 'method',
  4. 'url',
  5. 'header'
  6. ])
  7. }

自定义检查函数

  1. if (util.inspect.custom) {
  2. module.exports[util.inspect.custom] = module.exports.inspect
  3. }