Skip to content
On this page

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应用服务器。