request文件源码解析
依赖模块
const URL = require('url').URL// 处理 urlconst net = require('net')// 模块 net 提供了异步的网络 APIconst accepts = require('accepts')// HTTP 内容协商,可获取网络请求支持的编码、语言、类型等信息 const contentType = require('content-type')// 创建和解析 Http Content-Typeconst stringify = require('url').format// 序列化 urlconst parse = require('parseurl')// 类似于 url.parse,但是具有缓存功能const qs = require('querystring')// 模块 querystring 提供了用于解析和格式化网址查询字符串的实用工具const typeis = require('type-is')// 提供对请求的类型检查const fresh = require('fresh')// 判断缓存是否过期const only = require('only')// 设置对象白名单属性const util = require('util')// 工具模块,支持 Node.js 内部 API 的需求
全局变量
const IP = Symbol('context#ip')// 创建全局唯一变量 IP
导出对象
module.exports = { // 内容如下}
header
// 保持 header & headers 一致get header () { return this.req.headers}set header (val) { this.req.headers = val}get headers () { return this.req.headers}set headers (val) { this.req.headers = val}
url
get url () { return this.req.url}set url (val) { this.req.url = val}
origin
get origin () { return `${this.protocol}://${this.host}`}
href
get href () { if (/^https?:\/\//i.test(this.originalUrl)) return this.originalUrl return this.origin + this.originalUrl}
method
get method () { return this.req.method}set method (val) { this.req.method = val}
path
get path () { return parse(this.req).pathname}set path (path) { const url = parse(this.req) if (url.pathname === path) return url.pathname = path url.path = null this.url = stringify(url)}
query
get query () { const str = this.querystring const c = this._querycache = this._querycache || {} return c[str] || (c[str] = qs.parse(str))}set query (obj) { this.querystring = qs.stringify(obj)}
querystring
get querystring () { if (!this.req) return '' return parse(this.req).query || ''}set querystring (str) { const url = parse(this.req) if (url.search === `?${str}`) return url.search = str url.path = null this.url = stringify(url)}
search
get search () { if (!this.querystring) return '' return `?${this.querystring}`}set search (str) { this.querystring = str}
host
get host () { const proxy = this.app.proxy let host = proxy && this.get('X-Forwarded-Host') if (!host) { if (this.req.httpVersionMajor >= 2) host = this.get(':authority') if (!host) host = this.get('Host') } if (!host) return '' return host.split(/\s*,\s*/, 1)[0]}
hostname
get hostname () { const host = this.host if (!host) return '' if (host[0] === '[') return this.URL.hostname || '' return host.split(':', 1)[0]}
URL
get URL () { if (!this.memoizedURL) { const originalUrl = this.originalUrl || '' try { this.memoizedURL = new URL(`${this.origin}${originalUrl}`) } catch (err) { this.memoizedURL = Object.create(null) } } return this.memoizedURL}
fresh
get fresh () { const method = this.method const s = this.ctx.status if (method !== 'GET' && method !== 'HEAD') return false if ((s >= 200 && s < 300) || s === 304) { return fresh(this.header, this.response.header) } return false}
stale
get stale () { return !this.fresh}
idempotent
// 判断请求方法是否幂等get idempotent () { const methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'] return !!~methods.indexOf(this.method)}
socket
// 获取对底层套接字的引用get socket () { return this.req.socket}
charset
get charset () { try { const { parameters } = contentType.parse(this.req) return parameters.charset || '' } catch (e) { return '' }}
length
get length () { const len = this.get('Content-Length') if (len === '') return return ~~len}
protocol
get protocol () { if (this.socket.encrypted) return 'https' if (!this.app.proxy) return 'http' const proto = this.get('X-Forwarded-Proto') return proto ? proto.split(/\s*,\s*/, 1)[0] : 'http'}
secure
get secure () { return this.protocol === 'https'}
ips
get ips () { const proxy = this.app.proxy const val = this.get(this.app.proxyIpHeader) let ips = proxy && val ? val.split(/\s*,\s*/) : [] if (this.app.maxIpsCount > 0) { ips = ips.slice(-this.app.maxIpsCount) } return ips}
ip
get ip () { if (!this[IP]) { this[IP] = this.ips[0] || this.socket.remoteAddress || '' } return this[IP]}set ip (_ip) { this[IP] = _ip}
subdomains
get subdomains () { const offset = this.app.subdomainOffset const hostname = this.hostname if (net.isIP(hostname)) return [] return hostname .split('.') .reverse() .slice(offset)}
accept
get accept () { return this._accept || (this._accept = accepts(this.req))}set accept (obj) { this._accept = obj}
type
get type () { const type = this.get('Content-Type') if (!type) return '' return type.split(';')[0]}
^accepts 判断请求支持类型|编码|语言
accepts (...args) { return this.accept.types(...args)}acceptsEncodings (...args) { return this.accept.encodings(...args)}acceptsCharsets (...args) { return this.accept.charsets(...args)}acceptsLanguages (...args) { return this.accept.languages(...args)}
is 检查请求类型
is (type, ...types) { return typeis(this.req, type, ...types)}
get 获取请求头属性值
get (field) { const req = this.req switch (field = field.toLowerCase()) { case 'referer': case 'referrer': return req.headers.referrer || req.headers.referer || '' default: return req.headers[field] || '' }}
inspect 检查函数
inspect () { if (!this.req) return return this.toJSON()}
toJSON 格式化函数
toJSON () { return only(this, [ 'method', 'url', 'header' ])}
自定义检查函数
if (util.inspect.custom) { module.exports[util.inspect.custom] = module.exports.inspect}