/*
{
_connectionListener: [Function: connectionListener],
METHODS: [
'ACL', 'BIND', 'CHECKOUT',
'CONNECT', 'COPY', 'DELETE',
'GET', 'HEAD', 'LINK',
'LOCK', 'M-SEARCH', 'MERGE',
'MKACTIVITY', 'MKCALENDAR', 'MKCOL',
'MOVE', 'NOTIFY', 'OPTIONS',
'PATCH', 'POST', 'PROPFIND',
'PROPPATCH', 'PURGE', 'PUT',
'REBIND', 'REPORT', 'SEARCH',
'SOURCE', 'SUBSCRIBE', 'TRACE',
'UNBIND', 'UNLINK', 'UNLOCK',
'UNSUBSCRIBE'
],
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'
},
Agent: [Function: Agent] { defaultMaxSockets: Infinity },
ClientRequest: [Function: ClientRequest],
IncomingMessage: [Function: IncomingMessage],
OutgoingMessage: [Function: OutgoingMessage],
Server: [Function: Server],
ServerResponse: [Function: ServerResponse],
createServer: [Function: createServer],
validateHeaderName: [Function: __node_internal_],
validateHeaderValue: [Function: __node_internal_],
get: [Function: get],
request: [Function: request],
setMaxIdleHTTPParsers: [Function: setMaxIdleHTTPParsers],
maxHeaderSize: [Getter],
globalAgent: [Getter/Setter]
}
*/
const http = require('node:http')
console.log(http)
createServer
const http = require('node:http')
// req => IncomingMessage
// res => ServerResponse => OutgoingMessage
const server = http.createServer((req, res) => {
console.log(req)
console.log(res)
res.statusCode = 404
res.end(String(404))
})
server.listen(3300)
request
测试可知,OutgoingMessage
是 ClientRequest ServerResponse
的基类。
IncomingMessage
OutgoingMessage
ClientRequest
ServerResponse
const http = require('node:http')
const options = {
hostname: 'www.example.com',
port: 80,
path: '/',
method: 'GET'
}
// req => ClientRequest => OutgoingMessage
// res => IncomingMessage
const req = http.request(options, res => {
// res.on('data', (chunk) => {
// console.log(`响应体: ${chunk}`)
// })
// res.on('end', () => {
// console.log('响应结束')
// })
console.log(res)
})
console.log(req)
req.end()
1.Agent
http.Agent
是 Node.js
中 HTTP
客户端使用的一个类,用于管理和复用网络连接。
它主要用于控制 HTTP
请求的行为,比如连接的复用、最大并发连接数等。
默认情况下,Node.js
的 HTTP
请求会自动使用 http.Agent
。
不过,也可以通过自定义 http.Agent
实现更复杂的需求。
const http = require('http')
// 创建自定义 Agent
const agent = new http.Agent({
keepAlive: true, // 保持连接
maxSockets: 10, // 最大并发连接数
maxFreeSockets: 5, // 最大空闲连接数
timeout: 60000 // 超时时间
})
// 使用自定义 Agent 发起请求
const options = {
hostname: 'www.example.com',
port: 80,
path: '/',
method: 'GET',
agent: agent
}
const req = http.request(options, (res) => {
// 处理响应
console.log(`状态码: ${res.statusCode}`)
// 监听数据事件
res.on('data', (chunk) => {
console.log(`响应体: ${chunk}`)
})
// 监听结束事件
res.on('end', () => {
console.log('响应结束')
})
})
req.on('error', (e) => {
console.error(`请求遇到问题: ${e.message}`)
})
// req.end() 标志着你已经发送完所有的请求数据。在调用 req.end() 后,请求会发送出去
req.end()
2.ClientRequest
http.clientRequest
是 Node.js
的 HTTP
模块中的一个类,代表一个 HTTP
请求对象。
它是由 http.request()
或 http.get()
方法创建的,并且用于向服务器发送 HTTP
请求。
http.clientRequest
对象具有许多方法和事件,用于控制和处理 HTTP
请求的生命周期。
常用的属性和方法:
write(chunk, [encoding], [callback])
: 向请求主体写入数据。chunk
是你要发送的数据块。end([data], [encoding], [callback])
: 完成发送请求。当所有的请求数据都通过write()
方法写入后,需要调用end()
方法通知服务器请求已经完成。abort()
: 中止请求。如果请求已经发送但尚未完成,你可以使用这个方法取消请求。setTimeout(timeout, [callback])
: 设置请求的超时时间。timeout
是以毫秒为单位的时间,超过这个时间请求会自动终止。callback
是一个可选的回调函数,它将在超时时被调用。on(event, listener)
: 用于监听请求过程中的事件。常见的事件包括:
response
: 当服务器响应时触发,返回一个http.IncomingMessage
对象。error
: 当请求发生错误时触发。timeout
: 当请求超时时触发
const http = require('http')
const options = {
hostname: 'example.com',
port: 80,
path: '/',
method: 'GET'
}
const req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`)
console.log(`HEADERS: ${JSON.stringify(res.headers)}`)
res.setEncoding('utf8')
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`)
})
res.on('end', () => {
console.log('No more data in response.')
})
})
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`)
})
req.end()
3.IncomingMessage
http.IncomingMessage
是 Node.js
中 HTTP
模块的一个类,表示服务器接收到的 HTTP
请求或客户端收到的 HTTP
响应。
在服务器端,当使用 http.createServer()
创建一个 HTTP
服务器时,每次收到请求时,回调函数的第一个参数就是一个 http.IncomingMessage
对象。它包含了请求的详细信息,比如 HTTP
头、请求方法、URL
等。
在客户端,当你使用 http.request()
或 http.get()
发送一个 HTTP
请求时,http.IncomingMessage
对象会作为回调函数的参数,表示服务器的响应。
主要属性和方法:
httpVersion
: 一个字符串,表示HTTP
版本号,例如1.1
。headers
: 一个对象,包含了请求或响应的头部信息。键是头部名称,值是头部的值。rawHeaders
: 一个数组,包含了头部的原始信息,以键值对的形式交替存储。method
: 仅适用于服务器端,表示请求的方法,比如GET
、POST
等。url
: 仅适用于服务器端,表示请求的URL
。statusCode
: 仅适用于客户端,表示服务器响应的HTTP
状态码,比如200
、404
。statusMessage
: 仅适用于客户端,表示与statusCode
关联的状态消息,例如OK
对应状态码200
。socket
: 一个net.Socket
对象,表示底层的网络套接字。setEncoding([encoding])
: 设置接收到的数据的编码。如果你不设置编码,数据将作为Buffer
对象传递。on(event, listener)
: 用于监听事件,常见的事件有:
data
: 每当接收到一块数据时触发。数据将作为一个参数传递给回调函数。end
: 在接收到数据流结束时触发,表示所有的数据都已经被接收。error
: 当接收数据时发生错误时触发。close
: 当消息完全结束并且底层连接已被关闭时触发。
const http = require('http')
// 同时支持get和post请求
const server = http.createServer((req, res) => {
console.log(`Request method: ${req.method}`)
console.log(`Request URL: ${req.url}`)
console.log(`Request headers: ${JSON.stringify(req.headers)}`)
// 监听请求体
req.on('data', (chunk) => {
console.log(`Body chunk: ${chunk}`)
})
req.on('end', () => {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Hello, world!\n')
})
})
server.listen(3000, () => {
console.log('Server is listening on port 3000')
})
4.OutgoingMessage
http.OutgoingMessage
是 Node.js
中 HTTP
模块的一个类,它代表可以从 Node.js
应用程序发送到客户端或服务器的 HTTP
响应消息或请求消息。
应用场景:
服务器端:当你创建一个
HTTP
服务器并使用http.createServer()
处理客户端的请求时,响应对象res
是http.ServerResponse
类的实例,而http.ServerResponse
是继承自http.OutgoingMessage
的。客户端:当你使用
http.request()
或http.get()
发送HTTP
请求时,返回的请求对象(即http.ClientRequest
实例)也是继承自http.OutgoingMessage
的。
主要属性和方法:
chunkedEncoding
: 表示是否启用了分块传输编码。当你使用res.write()
或req.write()
发送数据时,如果不知道内容的总长度,可以启用分块编码。finished
: 表示消息是否已发送完成。headersSent
: 表示是否已发送HTTP
头部。通常在发送消息体数据之前发送头部。setHeader(name, value)
: 设置HTTP
头部信息。name
是头部的名称,value
是头部的值。getHeader(name)
: 获取指定名称的HTTP
头部值。removeHeader(name)
: 移除指定名称的HTTP
头部信息。write(chunk, [encoding], [callback])
: 向消息体写入数据块。chunk
是要写入的数据,encoding
是可选的编码方式,callback
是写入完成后的回调函数。end([data], [encoding], [callback])
: 表示消息的结束。可以选择在调用end()
时发送最后一块数据。data
是要发送的数据,encoding
是数据的编码,callback
是可选的回调函数。addTrailers(headers)
: 在消息末尾添加HTTP
头部的尾部信息(通常用于分块传输编码)。
const http = require('http')
const server = http.createServer((req, res) => {
// 设置响应头
res.setHeader('Content-Type', 'text/plain')
res.setHeader('X-Custom-Header', 'CustomHeaderValue')
// 写入响应主体数据
res.write('Hello, ')
res.write('world!\n')
// 结束响应并发送剩余数据
res.end('Goodbye!\n')
})
server.listen(3000, () => {
console.log('Server listening on port 3000')
})
5.Server
http.Server
主要方法和属性:
server.listen(port[, hostname][, backlog][, callback])
: 使服务器开始监听指定的端口和主机名。callback
是一个可选的回调函数,当服务器开始监听时触发。server.close([callback])
: 关闭服务器,停止接收新的连接。callback
是一个可选的回调函数,当服务器完全关闭时触发。server.on(event, listener)
: 为服务器注册事件监听器。常见的事件包括:
request
:每当有请求时触发。connection
:每当有新的TCP
连接时触发。close
:服务器关闭时触发。
const http = require('http')
// 创建一个 HTTP 服务器
const server = http.createServer((req, res) => {
// 设置响应头
res.writeHead(200, { 'Content-Type': 'text/plain' })
// 设置响应内容
res.end('Hello, World!\n')
})
// 监听端口 3000
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/')
})
6.ServerResponse
http.ServerResponse
是 Node.js
中 HTTP
模块的一部分,用于表示服务器向客户端发送的响应。
它提供了各种方法和属性,允许你构建和发送 HTTP
响应,包括设置状态码、响应头、以及发送响应数据。
主要方法:
res.writeHead(statusCode[, statusMessage][, headers])
:
- 设置响应的状态码、状态消息和响应头。
- 例如:
res.writeHead(200, {'Content-Type': 'text/html'})
;
res.write(chunk[, encoding][, callback])
:
- 发送响应体的一部分数据。可以多次调用这个方法来发送响应体的不同部分。
- 例如:
res.write('<h1>Hello, World!</h1>')
;
res.end([data][, encoding][, callback])
:
- 结束响应。
data
是可选的,可以在结束响应时发送最后一块数据。 - 例如:
res.end('Goodbye!')
;
res.setHeader(name, value)
:
- 设置单个响应头。
- 例如:
res.setHeader('Content-Type', 'application/json')
;
res.getHeader(name)
:
- 获取指定的响应头值。
- 例如:
const contentType = res.getHeader('Content-Type')
;
res.removeHeader(name)
:
- 移除指定的响应头。
- 例如:
res.removeHeader('Content-Type')
;
res.writeContinue()
:
- 发送
100 Continue
的HTTP
响应。
res.addTrailers(headers)
:
- 添加
HTTP trailers
,这些是在消息体之后发送的额外头。
属性:
res.statusCode
:
- 获取或设置响应的状态码。
- 例如:
res.statusCode = 404
;
res.statusMessage
:
- 获取或设置响应的状态消息。
- 例如:
res.statusMessage = 'Not Found'
;
res.headersSent
:
- 如果响应头已发送,则返回
true
。
res.finished
:
- 如果响应已结束(
res.end()
被调用),则返回true
。
7.createServer
http.createServer
是 Node.js
中的一个方法,用于创建一个 HTTP
服务器。
这个服务器能够监听客户端的 HTTP
请求,并发送响应。
const http = require('http')
const server = http.createServer((req, res) => {
// req 是 http.IncomingMessage 的实例,表示客户端的请求
// res 是 http.ServerResponse 的实例,用于向客户端发送响应
console.log('createServer', req.url)
res.statusCode = 200 // 设置响应状态码
res.setHeader('Content-Type', 'text/plain') // 设置响应头
res.end('Hello, World!\n') // 结束响应并发送内容
})
server.on('request', (req, res) => {
console.log('request', req.url)
})
server.listen(3000, () => {
console.log('服务器正在监听端口 3000')
})
8.validateHeaderName
http.validateHeaderName
是 Node.js
中的一个内部方法,用于验证 HTTP
头部字段的名称是否符合 HTTP/1.1
规范。
- 如果
name
是合法的HTTP
头部字段名称,这个函数不会返回任何内容。 - 如果
name
不合法,它将抛出一个TypeError
,指出无效的头部名称。
合法的 HTTP 头部字段名称
根据 HTTP/1.1
规范,头部字段名称必须符合以下规则:
- 仅包含
ASCII
字符。 - 只能由字母
(a-z,A-Z)
、数字(0-9)
、连字符(-)
和下划线(_)
组成。 - 不允许空格或其他特殊字符。
const http = require('node:http')
console.log(http.validateHeaderName('Content-Type'))
console.log(http.validateHeaderName('Content.Type'))
console.log(http.validateHeaderName('Content&Type'))
console.log(http.validateHeaderName('Content Type'))
9.validateHeaderValue
http.validateHeaderValue
是 Node.js
中的一个内部方法,用于验证 HTTP
头部字段的值是否符合 HTTP/1.1
规范。
和 http.validateHeaderName
类似,这个方法主要用于确保设置的 HTTP
头部字段值是合法的。
参数:
name
: 一个字符串,表示HTTP
头部字段的名称。value
: 一个字符串,表示HTTP
头部字段的值。
行为:
- 如果
value
是合法的HTTP
头部字段值,这个函数不会返回任何内容。 - 如果
value
不合法,它将抛出一个TypeError
,指出无效的头部值。
const http = require('http');
console.log(http.validateHeaderValue('Content-Type', 'text/html'))
// console.log(http.validateHeaderValue('Content-Type'))
console.log(http.validateHeaderValue('Content-Type', 'text/html\n'))
10.get
http.get
是 Node.js
提供的一个简化方法,用于发起 HTTP GET
请求。
与 http.request
不同,http.get
专门用于 GET
请求,并且不需要手动调用 req.end()
。它会自动完成请求的结束和发送。
const http = require('http')
// 使用 http.get 发起 GET 请求
http.get('http://www.example.com', (res) => {
console.log(`状态码: ${res.statusCode}`)
// 监听数据事件
res.on('data', (chunk) => {
console.log(`响应体: ${chunk}`)
})
// 监听结束事件
res.on('end', () => {
console.log('响应结束')
})
}).on('error', (e) => {
console.error(`请求遇到问题: ${e.message}`)
})
11.request
http.request
是 Node.js
中用于发起 HTTP
请求的一个方法。
适用于需要发送各种 HTTP
方法(如 POST、PUT、DELETE
等)以及需要自定义请求头和其他参数的场景。
之所以使用 res.on('data')
监听:
在 Node.js
中,HTTP
响应是以数据流(stream
)的形式传输的。
数据流的传输方式意味着响应内容并不是一次性到达,而是以小块(chunk
)的形式逐步传输。
当服务器向客户端发送数据时,这些数据会被拆分成一个个的块,data
事件在每个块到达时触发。
const http = require('http')
// 请求数据
const postData = JSON.stringify({
'msg': 'Hello World'
})
// 请求选项
const options = {
hostname: 'www.example.com',
port: 80,
path: '/post',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
}
// 发起请求
const req = http.request(options, (res) => {
console.log(`状态码: ${res.statusCode}`)
// 监听数据事件
res.on('data', (chunk) => {
console.log(`响应体: ${chunk}`)
})
// 监听结束事件
res.on('end', () => {
console.log('响应结束')
})
})
// 监听错误事件
req.on('error', (e) => {
console.error(`请求遇到问题: ${e.message}`)
})
// 写入请求数据
req.write(postData)
// 结束请求
req.end()
12.setMaxIdleHTTPParsers
http.setMaxIdleHTTPParsers
是 Node.js
中的一个内部方法,用于设置最大空闲 HTTP
解析器的数量。
这个方法在 Node.js
的 HTTP
模块中用于管理连接池中的 HTTP
解析器,以提高性能和资源管理。
在处理 HTTP
请求时,Node.js
使用 HTTP
解析器来解析传入的请求数据。
为了优化性能,Node.js
会维护一个解析器池(parser pool
),以便可以重复使用这些解析器,而不是每次都创建新的解析器。
当连接关闭时,解析器可以被释放并返回池中,等待下一个请求。
http.setMaxIdleHTTPParsers
方法允许你设置池中可以保留的空闲解析器的最大数量。
超出这个数量的解析器将被销毁,而不是保留在池中等待下一次使用。
const http = require('http')
// 设置最大空闲 HTTP 解析器数量为 10
http.setMaxIdleHTTPParsers(10)
13.maxHeaderSize
http.maxHeaderSize
是用于获取 HTTP
头部的大小限制。
安全性: 适当的头部大小限制有助于保护服务器免受头部攻击(例如,过大的头部数据)。
性能: 设置合理的头部大小限制可以帮助平衡性能和资源使用,避免服务器因处理过大的头部数据而变得缓慢或不稳定。
应用需求: 根据应用的需求和预期的请求头部大小,调整
maxHeaderSize
的值。对于大多数应用程序,默认值已经足够。
const http = require('node:http')
console.log(http.maxHeaderSize / 1024) // kb
14.globalAgent
http.globalAgent
是 Node.js
中的一个全局代理对象,用于处理所有 HTTP
请求的代理设置。
它是 http.Agent
类的一个实例,主要用于管理连接池和连接复用。
作用:
- 连接池:
http.globalAgent
管理一个全局的连接池,重用和管理与同一主机的连接,以提高性能。 - 代理设置: 通过设置代理配置,可以控制
HTTP
请求的行为,如代理服务器的使用等。
属性:
maxSockets
: 该属性指定了全局代理能够同时保持的最大连接数。默认为10
。你可以调整这个值来限制并发连接的数量。maxFreeSockets
: 该属性指定了在连接池中保持的最大空闲连接数。默认值通常是256
。keepAlive
: 这是一个布尔值,指示是否启用Keep-Alive
功能(持久连接)。默认为true
。keepAliveMsecs
: 指定连接在关闭之前应保持空闲的毫秒数。默认为1000
毫秒(1 秒)。
方法:
addRequest(req, socket)
: 用于将一个新的请求添加到代理中。destroy()
: 销毁所有连接并关闭代理。
const http = require('http')
// 修改全局代理设置
http.globalAgent.maxSockets = 20 // 允许最多 20 个并发连接
http.globalAgent.keepAlive = true // 启用 Keep-Alive 功能