1.5 Node.js 的 HTTP

发布于:2025-06-08 ⋅ 阅读:(12) ⋅ 点赞:(0)

Node.js 的 http 模块是构建 Web 服务器和客户端的基础核心模块,它提供了创建 HTTP 服务器和发起 HTTP 请求的能力。


1. 核心功能

  • 创建 HTTP 服务器:监听端口,处理客户端请求(如浏览器访问)。
  • 发起 HTTP 请求:作为客户端向其他服务器发送请求(类似 fetch 或 axios 的底层实现)。
  • 处理 HTTP 协议:支持 HTTP/1.1 和部分 HTTP/2 功能(需结合 http2 模块)。

2. 创建 HTTP 服务器

使用 http.createServer() 方法创建服务器,传入一个回调函数处理请求和响应。

const http = require('http');

// 创建服务器
const server = http.createServer((req, res) => {
  // req: 请求对象(包含客户端信息)
  // res: 响应对象(用于向客户端返回数据)

  // 设置响应头
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  
  // 发送响应内容
  res.end('Hello, World!\n');
});

// 监听端口
server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});
  • req 对象:包含请求方法(GET/POST)、URL、头部、Body 等信息。
  • res 对象:用于设置状态码、头部、发送响应内容(end() 结束响应)。

3. 请求对象 (req) 的常用属性和方法

属性/方法 说明
req.method 请求方法(如 'GET''POST')。
req.url 请求的 URL 路径(不包含域名和查询参数)。
req.headers 请求头对象(如 { 'user-agent': 'Chrome' })。
req.on('data') 监听数据块(用于处理 POST 请求的 Body)。
req.on('end') 数据接收完毕时触发。
req.url 解析 URL 可使用 url 模块(如 require('url').parse(req.url))。

处理 POST 请求示例

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.method === 'POST') {
    let body = '';
    req.on('data', chunk => {
      body += chunk.toString(); // 拼接数据块
    });
    req.on('end', () => {
      console.log('Received:', body);
      res.end('Data received');
    });
  } else {
    res.end('Send a POST request');
  }
});

server.listen(3000);

4. 响应对象 (res) 的常用方法

方法 说明
res.writeHead() 设置状态码和响应头(如 200 和 Content-Type)。
res.write() 发送部分响应内容(可多次调用)。
res.end() 结束响应(可附带最后的数据)。
res.statusCode 直接设置状态码(如 res.statusCode = 404)。

 (1) URL 解析

使用 url 模块解析请求 URL:

const url = require('url');
const parsedUrl = url.parse(req.url);
console.log('Path:', parsedUrl.pathname);
console.log('Query:', parsedUrl.query); // 如 ?name=foo&age=20

(2) 路由处理

手动实现简单路由:

const server = http.createServer((req, res) => {
  const { pathname } = url.parse(req.url);
  
  if (pathname === '/') {
    res.end('Home Page');
  } else if (pathname === '/about') {
    res.end('About Page');
  } else {
    res.statusCode = 404;
    res.end('Not Found');
  }
});

(3) HTTP 状态码

常用状态码:

  • 200:成功
  • 404:未找到
  • 500:服务器错误

设置状态码:

res.statusCode = 404;
res.end('Not Found');
const http = require('http');
const url = require('url');
const querystring = require('querystring');

// 模拟数据库数据
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];

const server = http.createServer((req, res) => {
  // 解析 URL 和查询参数
  const parsedUrl = url.parse(req.url, true);
  const path = parsedUrl.pathname.replace(/^\/+|\/+$/g, ''); // 去除首尾斜杠
  const query = parsedUrl.query;
  
  // 设置 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');
  
  // 处理 OPTIONS 请求(预检请求)
  if (req.method === 'OPTIONS') {
    res.writeHead(200);
    res.end();
    return;
  }

  // 路由处理
  if (path === 'users') {
    switch (req.method) {
      case 'GET':
        // 获取用户列表或单个用户
        if (query.id) {
          const user = users.find(u => u.id === parseInt(query.id));
          if (user) {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(user));
          } else {
            res.writeHead(404, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'User not found' }));
          }
        } else {
          res.writeHead(200, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify(users));
        }
        break;

      case 'POST':
        // 创建新用户
        let body = '';
        req.on('data', (chunk) => {
          body += chunk;
        });
        req.on('end', () => {
          try {
            const newUser = JSON.parse(body);
            newUser.id = users.length + 1;
            users.push(newUser);
            res.writeHead(201, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(newUser));
          } catch (error) {
            res.writeHead(400, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'Invalid request body' }));
          }
        });
        break;

      case 'PUT':
        // 更新用户
        if (!query.id) {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({ error: 'Missing user ID' }));
          return;
        }
        
        let updateBody = '';
        req.on('data', (chunk) => {
          updateBody += chunk;
        });
        req.on('end', () => {
          try {
            const updatedData = JSON.parse(updateBody);
            const index = users.findIndex(u => u.id === parseInt(query.id));
            
            if (index !== -1) {
              users[index] = { ...users[index], ...updatedData };
              res.writeHead(200, { 'Content-Type': 'application/json' });
              res.end(JSON.stringify(users[index]));
            } else {
              res.writeHead(404, { 'Content-Type': 'application/json' });
              res.end(JSON.stringify({ error: 'User not found' }));
            }
          } catch (error) {
            res.writeHead(400, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: 'Invalid request body' }));
          }
        });
        break;

      case 'DELETE':
        // 删除用户
        if (!query.id) {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({ error: 'Missing user ID' }));
          return;
        }
        
        const index = users.findIndex(u => u.id === parseInt(query.id));
        if (index !== -1) {
          const deletedUser = users.splice(index, 1)[0];
          res.writeHead(200, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify(deletedUser));
        } else {
          res.writeHead(404, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({ error: 'User not found' }));
        }
        break;

      default:
        res.writeHead(405, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Method not allowed' }));
    }
  } else {
    // 未知路由
    res.writeHead(404, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Route not found' }));
  }
});

// 启动服务器
server.listen(3000, () => {
  console.log('API 服务器已启动,监听端口 3000');
});

5. 发起 HTTP 请求(客户端)

使用 http.request() 方法向其他服务器发送请求。

基本示例

const http = require('http');

const options = {
  hostname: 'example.com',
  port: 80,
  path: '/',
  method: 'GET'
};

const req = http.request(options, (res) => {
  console.log(`Status Code: ${res.statusCode}`);
  
  let data = '';
  res.on('data', (chunk) => {
    data += chunk;
  });
  
  res.on('end', () => {
    console.log('Response:', data);
  });
});

req.on('error', (e) => {
  console.error('Request failed:', e);
});

req.end(); // 必须调用 end() 发送请求

简化版(使用 http.get

const http = require('http');

http.get('http://example.com', (res) => {
  let data = '';
  res.on('data', (chunk) => {
    data += chunk;
  });
  res.on('end', () => {
    console.log('Response:', data);
  });
});


6. 与 https 模块的区别

  • http:明文传输(不加密)。
  • https:基于 TLS/SSL 加密(需配置证书)。

创建 HTTPS 服务器:

const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
};

https.createServer(options, (req, res) => {
  res.end('Secure Server');
}).listen(443);

.注意事项

  • 性能问题http 模块是底层 API,高并发场景建议使用 Express 或 Fastify
  • 错误处理:必须监听 error 事件(如网络错误)。
  • Body 解析:POST 请求的 Body 需要手动拼接(生产环境可用 body-parser 或类似中间件)。

总结

  • 服务器端http.createServer() + req/res 处理请求。
  • 客户端http.request() 或 http.get() 发起请求。
  • 扩展性:结合 urlquerystring 等模块实现更复杂功能。