跳到主要内容

HTTP 模块

Node.js 的 http 模块提供了创建 HTTP 服务器和客户端的能力,是构建 Web 应用的基础。

创建 HTTP 服务器

基本服务器

const http = require('node:http');

const server = http.createServer((req, res) => {
// 设置响应状态码和头
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain; charset=utf-8');

// 发送响应
res.end('你好,世界!');
});

server.listen(3000, '127.0.0.1', () => {
console.log('服务器运行在 http://127.0.0.1:3000/');
});

请求对象 (req)

const http = require('node:http');

const server = http.createServer((req, res) => {
// 请求方法
console.log('请求方法:', req.method); // GET, POST, PUT, DELETE...

// 请求 URL
console.log('请求 URL:', req.url); // /path?query=value

// 请求头
console.log('请求头:', req.headers);
console.log('User-Agent:', req.headers['user-agent']);

// HTTP 版本
console.log('HTTP 版本:', req.httpVersion); // 1.1

// 客户端地址
console.log('客户端 IP:', req.socket.remoteAddress);

res.end('OK');
});

server.listen(3000);

响应对象 (res)

const http = require('node:http');

const server = http.createServer((req, res) => {
// 设置状态码
res.statusCode = 200;

// 设置响应头
res.setHeader('Content-Type', 'application/json');
res.setHeader('X-Custom-Header', 'value');

// 设置多个响应头
res.writeHead(200, {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
});

// 发送响应体
res.write('第一块数据\n');
res.write('第二块数据\n');
res.end('最后一块数据');

// 或一次性发送
// res.end(JSON.stringify({ message: '成功' }));
});

server.listen(3000);

路由处理

简单路由

const http = require('node:http');
const url = require('node:url');

const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const method = req.method;

// 路由匹配
if (method === 'GET' && pathname === '/') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('首页');
} else if (method === 'GET' && pathname === '/users') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ users: ['Alice', 'Bob'] }));
} else if (method === 'POST' && pathname === '/users') {
// 处理 POST 请求
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', () => {
console.log('请求体:', body);
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: '用户已创建' }));
});
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('未找到');
}
});

server.listen(3000);

RESTful API 示例

const http = require('node:http');
const url = require('node:url');

// 模拟数据库
let users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
];

const server = http.createServer(async (req, res) => {
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname;
const method = req.method;

// 解析请求体
const getBody = () => new Promise((resolve) => {
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', () => {
try {
resolve(JSON.parse(body));
} catch {
resolve({});
}
});
});

// 辅助函数
const json = (data, status = 200) => {
res.writeHead(status, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
};

// 路由:获取所有用户
if (method === 'GET' && pathname === '/users') {
json(users);
}
// 路由:获取单个用户
else if (method === 'GET' && pathname.match(/^\/users\/\d+$/)) {
const id = parseInt(pathname.split('/')[2]);
const user = users.find(u => u.id === id);
user ? json(user) : json({ error: '用户不存在' }, 404);
}
// 路由:创建用户
else if (method === 'POST' && pathname === '/users') {
const body = await getBody();
const newUser = {
id: users.length + 1,
...body
};
users.push(newUser);
json(newUser, 201);
}
// 路由:更新用户
else if (method === 'PUT' && pathname.match(/^\/users\/\d+$/)) {
const id = parseInt(pathname.split('/')[2]);
const index = users.findIndex(u => u.id === id);
if (index !== -1) {
const body = await getBody();
users[index] = { ...users[index], ...body };
json(users[index]);
} else {
json({ error: '用户不存在' }, 404);
}
}
// 路由:删除用户
else if (method === 'DELETE' && pathname.match(/^\/users\/\d+$/)) {
const id = parseInt(pathname.split('/')[2]);
users = users.filter(u => u.id !== id);
json({ message: '删除成功' });
}
// 404
else {
json({ error: '路由不存在' }, 404);
}
});

server.listen(3000, () => {
console.log('API 服务器运行在 http://localhost:3000');
});

处理请求体

解析 JSON

const http = require('node:http');

const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';

// 接收数据块
req.on('data', (chunk) => {
body += chunk.toString();
});

// 数据接收完成
req.on('end', () => {
try {
const data = JSON.parse(body);
console.log('解析的数据:', data);

res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ received: data }));
} catch (error) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: '无效的 JSON' }));
}
});
}
});

server.listen(3000);

解析表单数据

const http = require('node:http');
const querystring = require('node:querystring');

const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.headers['content-type'] === 'application/x-www-form-urlencoded') {
let body = '';

req.on('data', chunk => body += chunk);
req.on('end', () => {
const data = querystring.parse(body);
console.log('表单数据:', data);

res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`收到: ${JSON.stringify(data)}`);
});
}
});

server.listen(3000);

处理文件上传

const http = require('node:http');
const fs = require('node:fs');
const path = require('node:path');

const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/upload') {
const boundary = req.headers['content-type'].split('boundary=')[1];
let body = [];

req.on('data', chunk => body.push(chunk));
req.on('end', () => {
const buffer = Buffer.concat(body);
const content = buffer.toString();

// 简单提取文件内容(实际应用中应使用 multer 等库)
const matches = content.match(/filename="(.+?)"/);
if (matches) {
const filename = matches[1];
const start = content.indexOf('\r\n\r\n') + 4;
const end = content.lastIndexOf(`--${boundary}--`) - 2;
const fileContent = buffer.slice(start, end);

fs.writeFileSync(path.join('uploads', filename), fileContent);

res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: '上传成功', filename }));
}
});
}
});

server.listen(3000);

HTTP 客户端

GET 请求

const http = require('node:http');

// 方式1:使用 http.request
const req = http.request('http://example.com/api/data', (res) => {
let data = '';

res.on('data', chunk => data += chunk);
res.on('end', () => {
console.log('响应数据:', data);
});
});

req.on('error', (err) => {
console.error('请求错误:', err);
});

req.end();

// 方式2:使用 http.get(简化版)
http.get('http://example.com/api/data', (res) => {
let data = '';

res.on('data', chunk => data += chunk);
res.on('end', () => {
console.log('响应数据:', data);
});
}).on('error', (err) => {
console.error('请求错误:', err);
});

POST 请求

const http = require('node:http');

const postData = JSON.stringify({
name: 'Alice',
email: '[email protected]'
});

const options = {
hostname: 'example.com',
port: 80,
path: '/api/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};

const req = http.request(options, (res) => {
let data = '';

res.on('data', chunk => data += chunk);
res.on('end', () => {
console.log('状态码:', res.statusCode);
console.log('响应:', data);
});
});

req.on('error', (err) => {
console.error('请求错误:', err);
});

req.write(postData);
req.end();

使用 https 模块

const https = require('node:https');

https.get('https://api.github.com/users/nodejs', {
headers: { 'User-Agent': 'Node.js' }
}, (res) => {
let data = '';

res.on('data', chunk => data += chunk);
res.on('end', () => {
console.log(JSON.parse(data));
});
}).on('error', console.error);

服务器配置

监听端口

const server = http.createServer((req, res) => {
res.end('Hello');
});

// 方式1:指定端口
server.listen(3000);

// 方式2:指定端口和主机
server.listen(3000, '127.0.0.1');

// 方式3:指定端口、主机和回调
server.listen(3000, '127.0.0.1', () => {
console.log('服务器启动成功');
});

// 方式4:Unix 套接字
server.listen('/tmp/node.sock');

// 方式5:使用配置对象
server.listen({
port: 3000,
host: '127.0.0.1',
exclusive: false, // 是否独占端口
backlog: 511, // 等待连接队列的最大长度
});

服务器事件

const server = http.createServer();

// 连接事件
server.on('connection', (socket) => {
console.log('新连接:', socket.remoteAddress);
});

// 请求事件
server.on('request', (req, res) => {
console.log('新请求:', req.url);
res.end('OK');
});

// 关闭事件
server.on('close', () => {
console.log('服务器已关闭');
});

// 错误事件
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.error('端口已被占用');
} else {
console.error('服务器错误:', err);
}
});

server.listen(3000);

// 优雅关闭
process.on('SIGTERM', () => {
console.log('正在关闭服务器...');
server.close(() => {
console.log('服务器已关闭');
process.exit(0);
});
});

高级功能

超时设置

const server = http.createServer((req, res) => {
res.end('Hello');
});

// 设置超时时间(毫秒)
server.timeout = 120000; // 2 分钟
server.keepAliveTimeout = 65000; // Keep-Alive 超时
server.headersTimeout = 66000; // 接收 headers 超时

server.listen(3000);

最大连接数

const server = http.createServer();

// 设置最大连接数
server.maxConnections = 1000;

server.listen(3000);

获取连接数

const server = http.createServer();

server.listen(3000, () => {
server.getConnections((err, count) => {
console.log(`当前连接数: ${count}`);
});
});

实用示例

静态文件服务器

const http = require('node:http');
const fs = require('node:fs');
const path = require('node:path');

const MIME_TYPES = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.pdf': 'application/pdf',
};

const server = http.createServer((req, res) => {
// 解析请求路径
let filePath = '.' + req.url;
if (filePath === './') {
filePath = './index.html';
}

// 获取文件扩展名
const ext = path.extname(filePath).toLowerCase();
const contentType = MIME_TYPES[ext] || 'application/octet-stream';

// 读取文件
fs.readFile(filePath, (err, content) => {
if (err) {
if (err.code === 'ENOENT') {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>404 - 文件未找到</h1>');
} else {
res.writeHead(500);
res.end('服务器错误');
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content);
}
});
});

server.listen(3000, () => {
console.log('静态文件服务器运行在 http://localhost:3000');
});

反向代理

const http = require('node:http');
const httpProxy = require('http-proxy');

const proxy = httpProxy.createProxyServer({});

const server = http.createServer((req, res) => {
// 根据路径转发到不同服务
if (req.url.startsWith('/api')) {
proxy.web(req, res, { target: 'http://localhost:3001' });
} else if (req.url.startsWith('/admin')) {
proxy.web(req, res, { target: 'http://localhost:3002' });
} else {
proxy.web(req, res, { target: 'http://localhost:3000' });
}
});

server.listen(80);

小结

本章我们学习了:

  1. 创建服务器:使用 http.createServer 创建基本服务器
  2. 请求处理:处理请求方法、URL、请求头、请求体
  3. 响应处理:设置状态码、响应头、发送响应
  4. 路由实现:实现 RESTful API 路由
  5. HTTP 客户端:发送 GET/POST 请求
  6. 服务器配置:端口、超时、连接数管理
  7. 实用示例:静态文件服务器、反向代理

练习

  1. 实现一个完整的 RESTful API,支持用户 CRUD 操作
  2. 创建一个静态文件服务器,支持缓存和压缩
  3. 实现一个简单的负载均衡器
  4. 使用 HTTP 客户端调用第三方 API 并处理响应