《Express 初学者笔记:再也不怕搞混 req 和 res 了》

前言

hello,同学们好👋。

刚开始用express搭建Web服务器时,大家是不是遇到了跟小凹一样的问题,还不是很了解两个对象:req(请求)和 res(响应)。路由写了一大堆,结果不是 req.body 读不出来,就是响应发了一半报错。
其实它们没那么复杂。花 10 分钟看完这篇文章,你会对这两个对象了如指掌。

本文基于 Express 4.x,Node.js 环境。所有代码均可直接运行验证。

一、Request 对象 ------ 客户端发来了什么?

每收到一个请求,Express 都会把请求的所有信息打包成一个 req 对象,作为第一个参数传给路由处理函数。

js 复制代码
app.get('/some-path', (req, res) => {
  // 所有请求相关的操作都通过 req 来获取
});

下面我们按使用频率,分组来看它的属性和方法。

1. 获取路由参数(req.params

在路由路径中用 : 定义的动态部分,会收集在 req.params 里。

js 复制代码
// 路由:/users/:userId/books/:bookId
app.get('/users/:userId/books/:bookId', (req, res) => {
  console.log(req.params);
  // 输出:{ userId: '123', bookId: '456' }
});

2. 获取查询字符串(req.query

问号 ? 后面的参数,Express 会自动帮你转成对象。

js 复制代码
// 请求:/search?keyword=express&page=2
app.get('/search', (req, res) => {
  console.log(req.query.keyword); // 'express'
  console.log(req.query.page);    // '2'(注意:是字符串,不是数字)
});

3. 获取请求体(req.body)------ 重点

POST、PUT 请求提交的数据(JSON 或表单)都存在这里。但是 Express 默认不会解析 请求体,必须手动挂载中间件

js 复制代码
const express = require('express');
const app = express();

// 这两行中间件至关重要,缺一个都可能读不到数据
app.use(express.json());             // 解析 application/json
app.use(express.urlencoded({ extended: true })); // 解析表单数据

app.post('/login', (req, res) => {
  console.log(req.body.username);
  console.log(req.body.password);
});

⚠️ 新手最常踩的坑req.bodyundefined,99% 是因为忘了加上面两行中间件。

4. 获取请求头(req.headersreq.get()

req.headers 是原始对象,键名统一为小写。推荐用 req.get() 方法,大小写不敏感。

js 复制代码
app.get('/', (req, res) => {
  // 两种方式都可以
  const userAgent1 = req.headers['user-agent'];
  const userAgent2 = req.get('User-Agent');   // 推荐
});

5. 获取 Cookie(需配合中间件)

Express 默认不解析 Cookie,需要安装 cookie-parser

bash 复制代码
npm install cookie-parser
js 复制代码
const cookieParser = require('cookie-parser');
app.use(cookieParser());           // 普通 cookie
// app.use(cookieParser('秘钥'));  // 带签名的 cookie

app.get('/', (req, res) => {
  console.log(req.cookies);        // { theme: 'dark', sessionId: 'abc' }
});

6. 其他常用属性速查

属性 说明 示例值
req.method 请求方法 'GET''POST'
req.url 完整路径(含查询串) '/users?sort=asc'
req.path 不含查询串的路径 '/users'
req.hostname 主机名 'localhost'
req.ip 客户端 IP '::1''192.168.1.1'
req.protocol 协议 'http'
req.secure 是否为 HTTPS true / false
req.xhr 是否为 AJAX 请求 true / false

7. 常用方法

  • req.accepts(types) :检查客户端能接受什么格式。
js 复制代码
if (req.accepts('json')) {
  res.json({ data: '...' });
} else {
  res.send('...');
}
  • req.is(type) :检查请求的 Content-Type
js 复制代码
if (req.is('multipart/form-data')) {
  // 处理文件上传
}

二、Response 对象 ------ 如何回复客户端?

res 对象代表服务器将要发给客户端的响应。任何一个路由处理函数都必须通过 res 来结束请求,否则请求会一直挂起。

1. 发送数据的三驾马车

res.send([body]) ------ 万能方法

根据传入数据的类型,自动设置合适的 Content-Type

js 复制代码
app.get('/test', (req, res) => {
  // 字符串 → Content-Type: text/html
  res.send('<h1>Hello World</h1>');

  // 对象或数组 → Content-Type: application/json
  res.send({ name: 'Express', version: 4 });

  // Buffer → 触发文件下载
  res.send(Buffer.from('hello'));
});
res.json([body]) ------ 明确返回 JSON

res.send(对象) 几乎一样,但语义更清晰。

js 复制代码
app.get('/api/user', (req, res) => {
  res.json({ id: 1, name: 'Alice' });
});
res.end([data]) ------ 底层结束方法

一般不直接使用,除非在处理原始流或 Buffer 时。

2. 文件操作

res.download(path [, filename]) ------ 提示浏览器下载
js 复制代码
app.get('/download', (req, res) => {
  res.download('/path/to/report.pdf', '2024-report.pdf');
});
res.sendFile(path [, options]) ------ 在浏览器中展示

适合图片、PDF 预览等。

js 复制代码
app.get('/logo', (req, res) => {
  res.sendFile('/public/logo.png', { root: __dirname });
});

3. 重定向

js 复制代码
app.get('/old-page', (req, res) => {
  res.redirect(301, '/new-page');  // 永久重定向
  // 或 res.redirect('/new-page') 默认 302
});

4. 状态码与响应头

js 复制代码
app.post('/login', (req, res) => {
  if (!req.body.password) {
    // 链式调用,先设状态码,再发数据
    res.status(400).json({ error: '密码不能为空' });
  }
});
js 复制代码
// 设置单个响应头
res.set('Content-Type', 'text/plain');

// 批量设置
res.set({
  'X-Custom-Header': 'value',
  'Cache-Control': 'no-cache'
});

// 快捷设置 Content-Type
res.type('json');   // → 'application/json'

设置 Cookie 不需要额外中间件,直接用 res.cookie()

js 复制代码
app.get('/set-theme', (req, res) => {
  res.cookie('theme', 'dark', {
    maxAge: 900000,     // 有效期(毫秒)
    httpOnly: true,     // 防止客户端 JS 读取(防 XSS)
    secure: true,       // 仅 HTTPS 下发送
    signed: true        // 需要配合 cookie-parser 的 secret
  });
  res.send('主题已设置为深色');
});

// 删除 Cookie
res.clearCookie('theme');

6. 一个重要属性:res.headersSent

用于检查响应头是否已经发送。可以避免重复发送响应头导致报错。

js 复制代码
app.get('/check', (req, res) => {
  console.log(res.headersSent); // false
  res.send('ok');
  console.log(res.headersSent); // true
});

⚠️ 致命错误 :响应一旦发送(调用了 sendjsonredirect 等方法),就不能再设置状态码或响应头,否则 Node.js 会抛出:

text 复制代码
Error: Cannot set headers after they are sent to the client

三、总结速查表

Request 常用速查

我想获取什么 用这个
路由参数 /user/5 req.params.id
查询参数 ?sort=asc req.query.sort
POST JSON / 表单数据 req.body.field
请求头 req.get('Authorization')
Cookie req.cookies.name(需中间件)
请求方法 req.method
客户端 IP req.ip

Response 常用速查

我想做什么 用这个方法
返回 HTML / 文本 res.send('...')
返回 JSON res.json({...})
设置 HTTP 状态码 res.status(404).send('Not found')
浏览器下载文件 res.download('./file.pdf')
重定向 res.redirect('/new-url')
设置响应头 res.set('X-Header', 'value')
设置 Cookie res.cookie('key', 'value')
删除 Cookie res.clearCookie('key')

写在最后

reqres 是 Express 的灵魂,80% 的日常开发都在和它们打交道。把这篇文章当作速查手册,遇到问题回来翻一翻,慢慢就熟了。

如果觉得有帮助,欢迎点赞收藏~也欢迎在评论区交流你踩过的坑 😊

本文基于 Express 4.x 版本整理,如有更新或出入请以官方文档为准。

相关推荐
炽烈小老头10 小时前
Express Routing(路由系统)
node.js·express
李昊哲小课4 天前
express
express·art-templates
77美式8 天前
Node + Express + MongoDB 后端部署全解析:新手零踩坑
数据库·mongodb·express
走粥8 天前
node.js 中的 express 框架 - 基础到进阶
node.js·express
旺王雪饼 www9 天前
《Express框架深度解析:从基础入门到高级实践与项目架构》
前端·node.js·express
廋到被风吹走13 天前
【AI】Codex + 后端框架实战:Spring/Express/Django 业务逻辑全自动生成
人工智能·spring·express
吴声子夜歌13 天前
Node.js——Express详解(二)
node.js·express
吴声子夜歌14 天前
Node.js——Express详解(一)
node.js·express
吴声子夜歌16 天前
Node.js——Express框架
node.js·express