在 Express 应用中,每个路由处理函数都会接收到两个核心对象:请求对象 (req) 和 响应对象 (res)。它们分别封装了来自客户端的请求信息和用于构建响应的各种方法。理解并熟练使用这两个对象是掌握 Express 的关键。
请求对象 req 包含了客户端发送的所有信息,例如 URL 参数、查询字符串、请求头、请求体等。它是对 Node.js 原生 http.IncomingMessage 的扩展,添加了许多便利属性和方法。
| 属性 | 说明 |
|---|---|
req.params |
包含路由参数的对象(例如 /users/:id 中的 id)。 |
req.query |
包含查询字符串参数的对象(例如 ?name=John 中的 { name: 'John' })。 |
req.body |
包含请求体的数据(需要 express.json() 或 express.urlencoded() 等中间件解析)。 |
req.headers |
包含请求头的对象,所有头名称都是小写。 |
req.method |
HTTP 请求方法(GET、POST 等)。 |
req.url |
完整的请求 URL(包含路径和查询字符串)。 |
req.path |
请求的路径部分(不含查询字符串)。 |
req.baseUrl |
路由挂载的基路径(如果使用了路由挂载)。 |
req.originalUrl |
原始的请求 URL(包含基路径和查询字符串)。 |
req.hostname |
客户端请求的主机名(从 Host 头解析)。 |
req.ip |
客户端的 IP 地址。 |
req.protocol |
请求协议(http 或 https)。 |
req.secure |
布尔值,表示是否通过 HTTPS 连接(req.protocol === 'https' 的快捷方式)。 |
req.cookies |
包含 cookie 的对象(需要 cookie-parser 中间件)。 |
req.signedCookies |
包含签名 cookie 的对象(需要 cookie-parser 并传入密钥)。 |
| 方法 | 说明 |
|---|---|
req.get(field) |
获取指定请求头的值(不区分大小写)。 |
req.is(type) |
检查请求的 Content-Type 是否匹配给定的 MIME 类型。 |
req.accepts(types) |
检查客户端可接受的响应类型(基于 Accept 头),返回最佳匹配。 |
req.acceptsCharsets() |
检查可接受的字符集。 |
req.acceptsEncodings() |
检查可接受的编码(如 gzip)。 |
req.acceptsLanguages() |
检查可接受的语言。 |
req.range(size) |
解析 Range 头,用于分片下载。 |
app.get('/users/:id', (req, res) => {
console.log('路由参数:', req.params); // 例如 { id: '123' }
console.log('查询参数:', req.query); // 例如 { name: 'John' }
console.log('请求头:', req.headers);
console.log('方法:', req.method);
console.log('路径:', req.path);
console.log('主机名:', req.hostname);
console.log('IP:', req.ip);
// 获取特定请求头
const userAgent = req.get('User-Agent');
console.log('User-Agent:', userAgent);
res.send('OK');
});
响应对象 res 用于构建并发送 HTTP 响应给客户端。它扩展了 Node.js 原生 http.ServerResponse,提供了更便捷的 API。
| 方法 | 说明 |
|---|---|
res.send(body) |
发送响应,自动设置 Content-Length 和 Content-Type。body 可以是字符串、对象、Buffer 等。 |
res.json(body) |
发送 JSON 响应,自动设置 Content-Type: application/json 并将 body JSON 序列化。 |
res.status(code) |
设置 HTTP 状态码,返回 res 自身以支持链式调用。 |
res.set(field, value) |
设置响应头,也可以接受一个对象同时设置多个头。 |
res.end([data]) |
结束响应过程,可以发送可选数据(通常用于无需 send 的底层操作)。 |
res.redirect([status,] path) |
重定向到指定路径,默认状态码 302。 |
res.render(view, [locals], callback) |
渲染视图模板,并发送渲染后的 HTML。 |
res.sendFile(path, [options], [callback]) |
以流式方式发送文件,自动处理 Content-Type 和 Content-Disposition。 |
res.download(path, [filename], [callback]) |
提示客户端下载文件,相当于 res.attachment() + res.sendFile()。 |
res.cookie(name, value, [options]) |
设置 Cookie(需要 cookie-parser 才能方便地读取)。 |
res.clearCookie(name, [options]) |
清除指定 Cookie。 |
res.type(type) |
设置 Content-Type 头,可接受 MIME 类型或扩展名(如 'html')。 |
res.format(object) |
根据 Accept 请求头协商响应格式,调用对应的处理器。 |
res.append(field, value) |
追加响应头(如果已存在,则用逗号分隔)。 |
许多 res 方法返回 res 自身,因此可以链式调用:
res.status(201)
.set('X-Powered-By', 'Express')
.json({ id: 1, name: 'Alice' });
app.get('/example', (req, res) => {
// 发送纯文本
res.send('Hello World');
// 发送 JSON
res.json({ message: 'Hello World' });
// 设置状态码并发送文本
res.status(404).send('Not Found');
// 重定向
res.redirect('/new-page');
// 发送文件
res.sendFile('/path/to/file.pdf');
// 设置 Cookie
res.cookie('username', 'john', { maxAge: 900000, httpOnly: true });
res.send('Cookie set');
// 协商响应格式
res.format({
'text/plain': () => { res.send('Plain text'); },
'text/html': () => { res.send('HTML
'); },
'application/json': () => { res.json({ format: 'json' }); }
});
});
在 Express 中,默认情况下 req.body 是 undefined。要解析请求体,必须使用中间件:
express.json():解析 application/json 格式的请求体。express.urlencoded({ extended: true }):解析 application/x-www-form-urlencoded 格式的请求体(HTML 表单默认)。express.raw():解析 application/octet-stream,将 body 作为 Buffer。express.text():解析纯文本 body。app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post('/login', (req, res) => {
console.log(req.body); // { username: 'john', password: '123' }
res.send('登录成功');
});
以下是一个路由,它将客户端请求的方法、路径、参数、查询和头信息以 JSON 形式返回:
app.all('/echo', (req, res) => {
res.json({
method: req.method,
url: req.url,
path: req.path,
query: req.query,
params: req.params,
headers: req.headers,
ip: req.ip,
hostname: req.hostname,
body: req.body // 需要确保有解析中间件
});
});
res.send()、res.json() 等最终响应方法,多次调用会导致错误(后续调用被忽略或抛出异常)。res.send() 和 res.json() 会自动设置适当的 Content-Type,但也可以通过 res.type() 或 res.set() 覆盖。res.sendFile() 时,建议提供绝对路径,或使用 path.resolve() 构建安全路径。req 和 res 是 Express 应用的基石。掌握它们的属性和方法,能够灵活地获取客户端信息并构建各种响应。结合中间件和路由,你可以构建功能强大的 Web 应用和 API。