这篇文章上次修改于 710 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

http 模块是 node.js 处理 networking 网络的关键模块。在之前的章节我介绍了使用 http 模块建立 server 以及发起 GET/POST 请求的方法,可以参考:https://blog.niekun.net/archives/2137.html

http 模块集成于 node.js 核心无需单独安装,使用下面命令引入模块:

const http = require('http')

模块提供了很多 propertiesmethodsclasses

Properties 属性

http.METHODS

http.METHODS property 返回 http 所有的可用 method 列表:

> console.log(require('http').METHODS)
[
  'ACL',        'BIND',        'CHECKOUT',
  'CONNECT',    'COPY',        'DELETE',
  'GET',        'HEAD',        'LINK',
  'LOCK',       'M-SEARCH',    'MERGE',
  'MKACTIVITY', 'MKCALENDAR',  'MKCOL',
  'MOVE',       'NOTIFY',      'OPTIONS',
  'PATCH',      'POST',        'PRI',
  'PROPFIND',   'PROPPATCH',   'PURGE',
  'PUT',        'REBIND',      'REPORT',
  'SEARCH',     'SOURCE',      'SUBSCRIBE',
  'TRACE',      'UNBIND',      'UNLINK',
  'UNLOCK',     'UNSUBSCRIBE'
]

http.STATUS_CODES

http.STATUS_CODES 返回所有的 http 状态码及描述的 list 列表:

> console.log(require('http').STATUS_CODES)
{
  '100': 'Continue',
  '101': 'Switching Protocols',
  '102': 'Processing',
  '103': 'Early Hints',
  '200': 'OK',
  '201': 'Created',
  '202': 'Accepted',
  '203': 'Non-Authoritative Information',
  '204': 'No Content',
  '205': 'Reset Content',
  '206': 'Partial Content',
  '207': 'Multi-Status',
  '208': 'Already Reported',
  '226': 'IM Used',
  '300': 'Multiple Choices',
  '301': 'Moved Permanently',
  '302': 'Found',
  '303': 'See Other',
  '304': 'Not Modified',
  '305': 'Use Proxy',
  '307': 'Temporary Redirect',
  '308': 'Permanent Redirect',
  '400': 'Bad Request',
  '401': 'Unauthorized',
  '402': 'Payment Required',
  '403': 'Forbidden',
  '404': 'Not Found',
  '405': 'Method Not Allowed',
  '406': 'Not Acceptable',
  '407': 'Proxy Authentication Required',
  '408': 'Request Timeout',
  '409': 'Conflict',
  '410': 'Gone',
  '411': 'Length Required',
  '412': 'Precondition Failed',
  '413': 'Payload Too Large',
  '414': 'URI Too Long',
  '415': 'Unsupported Media Type',
  '416': 'Range Not Satisfiable',
  '417': 'Expectation Failed',
  '418': "I'm a Teapot",
  '421': 'Misdirected Request',
  '422': 'Unprocessable Entity',
  '423': 'Locked',
  '424': 'Failed Dependency',
  '425': 'Too Early',
  '426': 'Upgrade Required',
  '428': 'Precondition Required',
  '429': 'Too Many Requests',
  '431': 'Request Header Fields Too Large',
  '451': 'Unavailable For Legal Reasons',
  '500': 'Internal Server Error',
  '501': 'Not Implemented',
  '502': 'Bad Gateway',
  '503': 'Service Unavailable',
  '504': 'Gateway Timeout',
  '505': 'HTTP Version Not Supported',
  '506': 'Variant Also Negotiates',
  '507': 'Insufficient Storage',
  '508': 'Loop Detected',
  '509': 'Bandwidth Limit Exceeded',
  '510': 'Not Extended',
  '511': 'Network Authentication Required'
}

http.globalAgent

http.globalAgent 指向 http.Agent class 的一个 instance 实例,也就是一个 Agent object。

这个 Agent object 用来管理 server 同 http 客户端链接的持续连接和链接复用,这也是 node.js 网络服务的关键点。

> console.log(require('http').globalAgent)
Agent {
  _events: [Object: null prototype] {
    free: [Function (anonymous)],
    newListener: [Function: maybeEnableKeylog]
  },
  _eventsCount: 2,
  _maxListeners: undefined,
  defaultPort: 80,
  protocol: 'http:',
  options: { path: null },
  requests: {},
  sockets: {},
  freeSockets: {},
  keepAliveMsecs: 1000,
  keepAlive: false,
  maxSockets: Infinity,
  maxFreeSockets: 256,
  scheduling: 'lifo',
  maxTotalSockets: Infinity,
  totalSocketCount: 0,
  [Symbol(kCapture)]: false
}

methods 功能

http.createServer()

http.createServer() 返回一个 http.Server class 实例。

const server = http.createServer((req, res) => {
  //handle every single request with this callback
})

http.request()

http.request() 对服务器发起一个 http 请求。返回一个 http.ClientRequest class 实例。

const options = {
    hostname: 'localhost',
    port: 3000,
    path: '/',
    method: 'GET'
}

const req = https.request(options, res => {
    console.log(`statusCode is:${res.statusCode}`);
    res.on('data', d => {
        process.stdout.write(d)
    })
})

req.on('error', err => console.log(err))
req.end()

http.get()

http.get()http.request() 类似,但会自动将 http method 设置为 GET,且自动调用 req.end()

const https = require('http')
const options = {
    hostname: 'localhost',
    port: 3000,
    path: '/'
}

const req = https.get(options, res => {
    console.log(`statusCode is:${res.statusCode}`);
    res.on('data', d => {
        process.stdout.write(d)
    })
})

req.on('error', err => console.log(err))

Classes 类

http 模块提供 5 个 calsses:

  • http.Agent
  • http.ClientRequest
  • http.Server
  • http.ServerResponse
  • http.IncomingMessage

http.Agent

node.js 会创建一个全局的 http.Agent instance 实例来管理 server 同 http 客户端链接的持续连接和链接复用,这个 object 可以确保一个客户端对服务端发起的一系列请求是按队列排序的,且使用单独的 socket 接口。同样 agent object 管理着一个 sockets 池,这是影响性能的关键因素。

http.ClientRequest

http.request()http.get() 被调用时会创建一个 http.ClientRequest object。

当收到来自服务器的 response 时,response event 会被触发,http.request() 内定义的 callback 会作为 response 的响应被调用,同时将 http.IncomingMessage 的实例作为传入参数,其中包含了 response 数据。

response 数据有两种方式读取,第一种是通过 response.read() method,第二种是在 response 的 callback function 中通过监听 data event 来获取 stream 中的数据。

http.Server

当通过 http.createServer() 创建一个 server 时会返回 http.Server 实例。 http.Server 实例需要使用它的以下 method:

  • close() 停止 server 接收新的链接
  • listen() 启动 server 并开始监听请求

http.createServer() 的 callback 监听 request event 并响应。

http.ServerResponse

http.Server object 创建,作为 request event 的第二个参数传入,代码中作为 callback 的 res 参数使用:

const server = http.createServer((req, res) => {
  //res is an http.ServerResponse object
})

end()http.ServerResponse object 必须被使用的 method,用来表示 response 信息已经完整,可以结束这个 response,同时将 response 发送出去。

下面的 method 可以用来处理 http headers:

  • getHeaderNames() 获取当前 http headers 名称的列表
  • getHeaders() 获取当前 http headers 副本
  • setHeader('headername', value) 设置一个 http header
  • getHeader('headername') 获取当前的一个 http header 的设置
  • removeHeader('headername') 删除一个 http header
  • hasHeader('headername') 如果某个 http header 有被设置则返回 true
  • headersSent() 如果 http headers 已经发送给了客户端则返回 true

服务端编辑好 headers 条目后可以通过 response.writeHead() method 发送给客户端,第一个参数是 statusCode。

通过 response.write() 在 response body 中发送数据给客户端,它会将缓冲区的数据发送到 http response stream。如果还没有使用 response.writeHead() 发送 headers 则会先发送 headers,包含 statusCode 和 message,它们可以通过下面语法设置:

response.statusCode = 500
response.statusMessage = 'Internal Server Error'

http.IncomingMessage

http.IncomingMessage 可以在以下两个地方创建:

  • http.Server 当监听 request event
  • http.ClientRequest 当监听 response event

它可以用来访问 response 数据:

  • 通过 statusCodestatusMessage 读取状态信息
  • 通过 headers method 或 rawHeaders method 读取 headers 信息
  • 通过 method method 获取可用 http method
  • 通过 httpVersion method 获取 http 版本信息
  • 通过 url method 获取 URL 信息
  • 通过 socket method 获取底层 socket 信息

http.IncomingMessage 生效一个可读的 stream 接口后,数据可在 stream 中读取。