🎯 第 13 课:深入理解 request 与 response

3 阅读2分钟

太棒了!👏 你已经能让服务器“返回内容”,现在我们来学习如何让服务器“接收数据”——

🔍 如何解析查询参数、处理 POST 提交的数据?

📌 核心知识点

  • req.url 中提取查询参数(query string)
  • 使用 url 模块解析 URL
  • 接收并处理客户端通过 POST 发送的请求体(body)

🧩 场景一:获取查询参数(GET 请求)

比如浏览器访问:
👉 http://localhost:3000/search?q=node.js&lang=zh

我们想提取出 qlang

✅ 解决方案:使用内置 url 模块

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

const server = http.createServer((req, res) => {
  // 解析 URL(包括 query)
  const parsedUrl = url.parse(req.url, true); // true 表示自动解析 query

  const { pathname, query } = parsedUrl;

  if (pathname === '/search' && req.method === 'GET') {
    const keyword = query.q;
    const language = query.lang;

    res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
    res.end(
      JSON.stringify({
        message: `你搜索的是: ${keyword}`,
        language: language || '未指定',
      })
    );
  } else {
    res.writeHead(404).end('Not Found');
  }
});

server.listen(3000, () => {
  console.log('✅ 服务器启动:http://localhost:3000');
});

🔍 测试它:

打开浏览器访问:
👉 http://localhost:3000/search?q=node.js&lang=zh

输出:

{
  "message": "你搜索的是: node.js",
  "language": "zh"
}

✅ 成功提取了查询参数!

💡 小贴士:url.parse() 已被标记为“过时”,现代写法推荐用 new URL(),稍后我们会升级。


🧩 场景二:接收表单数据(POST 请求)

用户填写表单提交时,数据在请求体(body)中,不能直接从 URL 看到。

创建一个 HTML 表单测试

新建 form.html 文件:

<!DOCTYPE html>
<html>
<head><title>提交表单</title></head>
<body>
  <h2>登录表单</h2>
  <form action="http://localhost:3000/login" method="POST">
    <label>用户名:<input type="text" name="username" /></label><br><br>
    <label>密码:<input type="password" name="password" /></label><br><br>
    <button type="submit">登录</button>
  </form>
</body>
</html>

打开这个页面(双击运行),填写后点击“登录”。

但我们现在还没处理 /login,所以会报错。接下来我们就加上!


✅ 处理 POST 请求体

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

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

  // 处理 GET /search
  if (pathname === '/search' && req.method === 'GET') {
    const keyword = parsedUrl.query.q;
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ result: keyword }));
  }

  // 处理 POST /login
  else if (pathname === '/login' && req.method === 'POST') {
    let body = '';

    // 数据是一段一段传来的,需要拼接
    req.on('data', chunk => {
      body += chunk; // 接收数据块
    });

    // 所有数据接收完毕
    req.on('end', () => {
      console.log('原始表单数据:', body); // 输出: username=Alice&password=123

      // 手动解析 application/x-www-form-urlencoded 格式
      const params = new URLSearchParams(body);
      const username = params.get('username');
      const password = params.get('password');

      // 模拟验证
      if (username && password) {
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(
          JSON.stringify({
            message: `欢迎回来,${username}!`,
            userId: 1001,
          })
        );
      } else {
        res.writeHead(400).end('缺少必要字段');
      }
    });
  } else {
    res.writeHead(404).end('Not Found');
  }
});

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

🔧 测试步骤:

  1. 启动服务器:node server.js
  2. 打开 form.html 页面
  3. 填写用户名和密码,点击“登录”
  4. 查看终端输出接收到的数据
  5. 浏览器收到 JSON 响应

🎉 成功处理了 POST 请求!


✅ 小结知识点

功能方法
解析 URL 和 queryurl.parse(req.url, true)new URL(req.url, base)
获取 GET 参数parsedUrl.query.xxx
接收 POST 数据监听 req.on('data')req.on('end')
解析表单数据使用 URLSearchParams
设置响应头res.writeHead(statusCode, headers)
返回响应res.end(data)

⚠️ 注意事项

  • req 是一个可读流(Readable Stream),必须监听 'data''end' 事件才能完整接收数据。
  • 对于大文件上传,要考虑流式处理或限制大小。
  • 实际开发中我们会用 Express + 中间件(如 body-parser)简化这些操作,但现在我们要先懂底层原理!

本课小结一句话

通过监听 req'data''end' 事件可以接收 POST 数据,结合 url 模块能解析任何请求参数,这是构建 Web 应用的关键能力。


📬 下一课预告:
第 14 课:返回 HTML 页面和静态资源(如 CSS、图片)—— 让你的网站更美观!

我们将学习如何读取本地 HTML 文件并返回,甚至能支持样式和图片。