1. Node.js HTTP模块核心能力解析
HTTP模块是Node.js标准库中最基础也最常用的模块之一,它提供了完整的HTTP协议实现。不同于Apache/Nginx等传统Web服务器,Node.js的HTTP模块采用事件驱动、非阻塞I/O模型,这使得它在处理高并发连接时具有显著优势。我在实际项目中曾用单个Node.js HTTP服务器处理过每秒5000+的并发请求,而内存占用仅为传统方案的1/3。
这个模块的核心能力可以概括为三个层面:
- 服务端能力:创建HTTP服务器,监听端口,处理请求
- 客户端能力:发起HTTP请求,与外部服务交互
- 协议处理:自动处理连接池、报文解析等底层细节
2. 创建HTTP服务器的完整实践
2.1 基础服务器搭建
创建一个最小化的HTTP服务器只需要几行代码:
const http = require('http'); const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World\n'); }); server.listen(3000, '127.0.0.1', () => { console.log('Server running at http://127.0.0.1:3000/'); });这里有几个关键点需要注意:
createServer方法接收的请求处理函数会在每个请求到达时被调用- 回调函数接收两个参数:
req(请求对象)和res(响应对象) - 必须调用
res.end()来结束响应,否则客户端会一直等待
2.2 生产环境配置要点
在实际生产环境中,我们需要考虑更多因素:
const server = http.createServer(app).listen(port, '0.0.0.0', () => { console.log(`Worker ${process.pid} started`); }); // 处理进程异常退出 process.on('uncaughtException', (err) => { console.error('Uncaught Exception:', err); // 优雅关闭 server.close(() => process.exit(1)); }); // 设置超时防止慢攻击 server.timeout = 5000;关键配置项:
keepAliveTimeout(默认5000ms):保持连接的时长headersTimeout(默认60000ms):等待HTTP头完成的超时maxHeadersCount:限制最大请求头数量防止DDoS
3. 请求与响应处理全解析
3.1 请求对象深度剖析
请求对象(req)包含客户端发来的所有信息,常用属性包括:
// 请求方法 console.log(req.method); // GET/POST等 // URL解析 const url = new URL(req.url, `http://${req.headers.host}`); console.log(url.pathname); // "/api/users" console.log(url.searchParams.get('page')); // 获取查询参数 // 请求头 console.log(req.headers['user-agent']); // 获取POST数据 let body = []; req.on('data', chunk => body.push(chunk)) .on('end', () => { body = Buffer.concat(body).toString(); // 处理请求体 });3.2 响应对象高级技巧
响应对象(res)控制着返回给客户端的内容,一些实用技巧:
// 设置响应头 res.setHeader('Cache-Control', 'public, max-age=3600'); // 流式响应大文件 const fs = require('fs'); const fileStream = fs.createReadStream('./large-file.zip'); fileStream.pipe(res); // 处理JSON响应 res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify({data: result})); // 重定向 res.writeHead(302, {Location: '/new-location'}); res.end();4. 客户端请求实战指南
4.1 发起GET请求
const options = { hostname: 'api.example.com', port: 443, path: '/users?page=2', method: 'GET', headers: { 'Authorization': 'Bearer token123' } }; const req = http.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => console.log(JSON.parse(data))); }); req.on('error', error => console.error(error)); req.end();4.2 POST请求与HTTPS处理
const postData = JSON.stringify({ username: 'example', password: 'secret' }); const options = { hostname: 'api.example.com', port: 443, path: '/login', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': postData.length } }; const req = https.request(options, (res) => { // 处理响应 }); req.write(postData); req.end();5. 性能优化与安全实践
5.1 连接池管理
Node.js HTTP客户端会自动使用连接池,但需要合理配置:
const agent = new http.Agent({ keepAlive: true, maxSockets: 100, // 每个主机最大连接数 maxFreeSockets: 10, // 空闲连接数 timeout: 60000 // socket超时 }); // 在请求中使用 const options = {agent};5.2 安全防护措施
// 防止HTTP头注入 const safeHeaders = { 'Content-Type': 'text/html', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'SAMEORIGIN', 'Content-Security-Policy': "default-src 'self'" }; // 限制请求体大小 const limit = '1mb'; const bodyParser = require('body-parser'); app.use(bodyParser.json({limit})); app.use(bodyParser.urlencoded({extended: true, limit}));6. 常见问题排查手册
6.1 ECONNRESET错误处理
当客户端突然断开连接时会出现这个错误,正确处理方式:
req.on('error', (err) => { if (err.code === 'ECONNRESET') { console.log('Client closed connection prematurely'); return; } // 处理其他错误 });6.2 请求超时控制
// 服务器端超时 server.setTimeout(5000, socket => { socket.destroy(); console.log('Socket timed out'); }); // 客户端超时 const req = http.request(options); req.setTimeout(3000, () => { req.destroy(); console.log('Request timed out'); });6.3 内存泄漏排查
使用以下方法监控HTTP模块的内存使用:
setInterval(() => { const {rss, heapTotal, heapUsed} = process.memoryUsage(); console.log(`Memory: ${rss} ${heapTotal} ${heapUsed}`); }, 5000); // 或者在启动时添加参数 // node --inspect server.js7. 高级应用场景
7.1 实现WebSocket握手
虽然HTTP模块本身不支持WebSocket,但可以处理初始握手:
server.on('upgrade', (req, socket, head) => { if (req.headers['upgrade'] !== 'websocket') { socket.destroy(); return; } // 计算accept key const acceptKey = crypto.createHash('sha1') .update(req.headers['sec-websocket-key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11') .digest('base64'); // 响应握手 socket.write( 'HTTP/1.1 101 Switching Protocols\r\n' + 'Upgrade: websocket\r\n' + 'Connection: Upgrade\r\n' + `Sec-WebSocket-Accept: ${acceptKey}\r\n\r\n` ); // 后续处理... });7.2 实现HTTP/2服务器
Node.js从10.x开始支持HTTP/2:
const http2 = require('http2'); const fs = require('fs'); const server = http2.createSecureServer({ key: fs.readFileSync('server.key'), cert: fs.readFileSync('server.crt') }); server.on('stream', (stream, headers) => { stream.respond({ 'content-type': 'text/html', ':status': 200 }); stream.end('<h1>Hello HTTP/2</h1>'); }); server.listen(8443);8. 性能对比与最佳实践
8.1 与传统服务器对比
| 特性 | Node.js HTTP模块 | Apache/Nginx |
|---|---|---|
| 并发模型 | 事件驱动 | 多线程/进程 |
| 内存占用 | 低 | 较高 |
| 长连接支持 | 优秀 | 良好 |
| 静态文件处理 | 需要额外优化 | 优秀 |
| 开发效率 | 高 | 低 |
8.2 最佳实践总结
对于API服务,建议:
- 使用反向代理(Nginx)处理静态文件
- 启用keep-alive减少连接开销
- 实现健康检查接口
对于高并发场景:
- 使用cluster模块充分利用多核CPU
- 考虑使用连接池管理数据库连接
- 实现请求限流和熔断机制
安全方面:
- 始终验证输入数据
- 设置合理的超时时间
- 使用HTTPS加密通信
- 定期更新Node.js版本
在实际项目中,我发现合理配置HTTP服务器参数可以带来30%以上的性能提升。特别是在处理大量小文件请求时,调整highWaterMark和并发数能显著改善吞吐量。