Appearance
Node.js HTTP服务器
Node.js内置的HTTP模块提供了创建HTTP服务器的能力,无需额外依赖即可构建功能完整的Web服务器。
基础HTTP服务器
简单HTTP服务器
javascript
const http = require('http');
const url = require('url');
// 创建基础HTTP服务器
const server = http.createServer((req, res) => {
// 设置响应头
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.setHeader('Access-Control-Allow-Origin', '*');
// 解析请求URL
const parsedUrl = url.parse(req.url, true);
console.log(`${req.method} ${req.url}`);
// 根据路径和方法处理请求
if (parsedUrl.pathname === '/' && req.method === 'GET') {
res.writeHead(200);
res.end('欢迎使用Node.js HTTP服务器!');
} else if (parsedUrl.pathname === '/api/hello' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello, World!' }));
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('页面未找到');
}
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});
处理POST请求
javascript
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
// 设置CORS头
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
// 处理预检请求
res.writeHead(200);
res.end();
return;
}
if (parsedUrl.pathname === '/api/users' && req.method === 'POST') {
let body = '';
// 收集请求体数据
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
try {
const userData = JSON.parse(body);
// 模拟用户创建
const newUser = {
id: Date.now(),
...userData
};
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(newUser));
} catch (err) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: '无效的JSON数据' }));
}
});
} else if (parsedUrl.pathname === '/api/users' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 1, name: '张三' }, { id: 2, name: '李四' }]));
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('页面未找到');
}
});
server.listen(3000, () => {
console.log('服务器运行在端口3000');
});
静态文件服务器
javascript
const http = require('http');
const fs = require('fs');
const path = require('path');
const url = require('url');
// MIME类型映射
const mimeTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.wasm': 'application/wasm'
};
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url);
let pathname = parsedUrl.pathname;
// 默认文件
if (pathname === '/') {
pathname = '/index.html';
}
const filePath = path.join(process.cwd(), 'public', pathname);
// 防止路径遍历攻击
if (!filePath.startsWith(path.join(process.cwd(), 'public'))) {
res.writeHead(403, { 'Content-Type': 'text/plain' });
res.end('Forbidden');
return;
}
const ext = path.parse(filePath).ext;
const contentType = mimeTypes[ext] || 'application/octet-stream';
fs.readFile(filePath, (err, data) => {
if (err) {
if (err.code === 'ENOENT') {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('File Not Found');
} else {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Internal Server Error');
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(data);
}
});
});
server.listen(3000, () => {
console.log('静态文件服务器运行在端口3000');
});
路由系统
javascript
const http = require('http');
const url = require('url');
class Router {
constructor() {
this.routes = {};
}
addRoute(method, path, handler) {
const key = `${method.toUpperCase()}:${path}`;
this.routes[key] = handler;
}
handle(req, res) {
const parsedUrl = url.parse(req.url, true);
const method = req.method.toUpperCase();
const path = parsedUrl.pathname;
// 尝试精确匹配
const exactKey = `${method}:${path}`;
if (this.routes[exactKey]) {
return this.routes[exactKey](req, res, parsedUrl);
}
// 尝试通配符匹配(简单实现)
for (const [routeKey, handler] of Object.entries(this.routes)) {
const [routeMethod, routePath] = routeKey.split(':');
if (routeMethod === method && this.matchPath(routePath, path)) {
return handler(req, res, parsedUrl);
}
}
// 未找到路由
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not Found' }));
}
matchPath(routePath, actualPath) {
// 简单路径匹配实现
if (routePath === actualPath) return true;
// 支持参数路径匹配 (如 /users/:id)
const routeParts = routePath.split('/');
const actualParts = actualPath.split('/');
if (routeParts.length !== actualParts.length) return false;
for (let i = 0; i < routeParts.length; i++) {
if (routeParts[i] !== actualParts[i] && !routeParts[i].startsWith(':')) {
return false;
}
}
return true;
}
}
// 使用路由器
const router = new Router();
router.addRoute('GET', '/', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>首页</h1>');
});
router.addRoute('GET', '/api/users', (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 1, name: '用户1' }, { id: 2, name: '用户2' }]));
});
router.addRoute('GET', '/api/users/:id', (req, res, parsedUrl) => {
const userId = parsedUrl.pathname.split('/')[3]; // 简单提取ID
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: userId, name: `用户${userId}` }));
});
router.addRoute('POST', '/api/users', (req, res) => {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
try {
const userData = JSON.parse(body);
const newUser = { id: Date.now(), ...userData };
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(newUser));
} catch (err) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Invalid JSON' }));
}
});
});
const server = http.createServer((req, res) => {
router.handle(req, res);
});
server.listen(3000, () => {
console.log('带路由的服务器运行在端口3000');
});
中间件系统
javascript
const http = require('http');
const url = require('url');
class MiddlewareServer {
constructor() {
this.middlewares = [];
this.routes = [];
}
use(middleware) {
this.middlewares.push(middleware);
}
get(path, handler) {
this.routes.push({ method: 'GET', path, handler });
}
post(path, handler) {
this.routes.push({ method: 'POST', path, handler });
}
put(path, handler) {
this.routes.push({ method: 'PUT', path, handler });
}
delete(path, handler) {
this.routes.push({ method: 'DELETE', path, handler });
}
handleRequest(req, res) {
const parsedUrl = url.parse(req.url, true);
const method = req.method.toUpperCase();
// 创建上下文对象
const ctx = {
req,
res,
url: parsedUrl,
method,
headers: req.headers,
query: parsedUrl.query,
params: {},
body: null
};
// 构建中间件执行链
const composed = this.compose(this.middlewares);
// 执行中间件链
composed(ctx, () => {
// 中间件链执行完毕后,处理路由
this.handleRoute(ctx);
});
}
compose(middlewares) {
return (ctx, next) => {
let index = -1;
function dispatch(i) {
if (i <= index) {
return Promise.reject(new Error('next() called multiple times'));
}
index = i;
const fn = middlewares[i] || next;
if (!fn) return Promise.resolve();
try {
return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err);
}
}
return dispatch(0);
};
}
handleRoute(ctx) {
const route = this.routes.find(r =>
r.method === ctx.method && this.matchPath(r.path, ctx.url.pathname)
);
if (route) {
ctx.params = this.extractParams(route.path, ctx.url.pathname);
route.handler(ctx);
} else {
ctx.res.writeHead(404, { 'Content-Type': 'application/json' });
ctx.res.end(JSON.stringify({ error: 'Not Found' }));
}
}
matchPath(routePath, actualPath) {
const routeParts = routePath.split('/');
const actualParts = actualPath.split('/');
if (routeParts.length !== actualParts.length) return false;
for (let i = 0; i < routeParts.length; i++) {
if (routeParts[i] !== actualParts[i] && !routeParts[i].startsWith(':')) {
return false;
}
}
return true;
}
extractParams(routePath, actualPath) {
const routeParts = routePath.split('/');
const actualParts = actualPath.split('/');
const params = {};
for (let i = 0; i < routeParts.length; i++) {
if (routeParts[i].startsWith(':')) {
const paramName = routeParts[i].substring(1);
params[paramName] = actualParts[i];
}
}
return params;
}
listen(port, callback) {
const server = http.createServer((req, res) => {
this.handleRequest(req, res);
});
return server.listen(port, callback);
}
}
// 使用中间件服务器
const app = new MiddlewareServer();
// 日志中间件
app.use(async (ctx, next) => {
console.log(`${ctx.method} ${ctx.req.url}`);
await next();
});
// 解析JSON中间件
app.use(async (ctx, next) => {
if (ctx.method === 'POST' || ctx.method === 'PUT') {
let body = '';
ctx.req.on('data', (chunk) => {
body += chunk.toString();
});
await new Promise((resolve) => {
ctx.req.on('end', () => {
if (body) {
try {
ctx.body = JSON.parse(body);
} catch (e) {
ctx.body = body;
}
}
resolve();
});
});
}
await next();
});
// 路由定义
app.get('/', (ctx) => {
ctx.res.writeHead(200, { 'Content-Type': 'text/html' });
ctx.res.end('<h1>中间件服务器示例</h1>');
});
app.get('/api/users/:id', (ctx) => {
ctx.res.writeHead(200, { 'Content-Type': 'application/json' });
ctx.res.end(JSON.stringify({
id: ctx.params.id,
name: `用户${ctx.params.id}`,
query: ctx.query
}));
});
app.listen(3000, () => {
console.log('中间件服务器运行在端口3000');
});
错误处理和日志
javascript
const http = require('http');
const fs = require('fs');
const path = require('path');
class ServerWithLogging {
constructor() {
this.logStream = fs.createWriteStream(
path.join(__dirname, 'server.log'),
{ flags: 'a' }
);
}
log(message) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] ${message}\n`;
this.logStream.write(logEntry);
console.log(message);
}
createServer() {
return http.createServer((req, res) => {
// 记录请求
this.log(`${req.method} ${req.url} - ${req.socket.remoteAddress}`);
// 模拟可能的错误
if (req.url === '/error') {
this.handleError(req, res);
return;
}
// 正常处理
try {
this.handleRequest(req, res);
} catch (err) {
this.handleError(req, res, err);
}
});
}
handleRequest(req, res) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
message: '请求成功处理',
timestamp: new Date().toISOString()
}));
}
handleError(req, res, error) {
this.log(`错误: ${error ? error.stack : '手动触发的错误'}`);
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
error: '服务器内部错误',
timestamp: new Date().toISOString()
}));
}
}
const server = new ServerWithLogging();
const httpServer = server.createServer();
httpServer.listen(3000, () => {
console.log('带日志的服务器运行在端口3000');
});
服务器性能优化
连接池和超时设置
javascript
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello World' }));
});
// 设置服务器选项
server.setTimeout(30000); // 30秒请求超时
server.headersTimeout = 20000; // 20秒头部超时
server.requestTimeout = 10000; // 10秒请求超时
// 监听连接事件
server.on('connection', (socket) => {
console.log('新连接建立');
// 设置套接字超时
socket.setTimeout(60000); // 60秒无活动超时
socket.on('timeout', () => {
console.log('连接超时');
socket.destroy();
});
});
// 监听错误
server.on('error', (err) => {
console.error('服务器错误:', err);
});
server.listen(3000, () => {
console.log('性能优化的服务器运行在端口3000');
});
压缩中间件
javascript
const http = require('http');
const zlib = require('zlib');
function compressionMiddleware(req, res, next) {
const acceptEncoding = req.headers['accept-encoding'];
if (!acceptEncoding) {
next();
return;
}
// 检查客户端支持的压缩格式
if (acceptEncoding.includes('gzip')) {
res.setHeader('Content-Encoding', 'gzip');
const gzip = zlib.createGzip();
const originalEnd = res.end;
const originalWrite = res.write;
res.write = function(chunk, encoding) {
if (chunk !== undefined) {
gzip.write(chunk, encoding);
}
};
res.end = function(chunk, encoding) {
if (chunk !== undefined) {
gzip.write(chunk, encoding);
}
gzip.end();
gzip.pipe(originalEnd.call(res));
};
} else {
next();
}
}
const server = http.createServer((req, res) => {
// 简单的压缩中间件应用
compressionMiddleware(req, res, () => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('这是一段需要压缩的长文本内容。'.repeat(100));
});
});
server.listen(3000, () => {
console.log('带压缩功能的服务器运行在端口3000');
});
Node.js的HTTP服务器功能强大且灵活,通过合理的设计和优化,可以构建出高性能、可扩展的Web应用服务器。