4、请求与响应对象:深入理解 Request 与 Response
这一章我们来聊聊 Express 里最核心的两个对象——Request 和 Response。说实话,我刚学 Express 那会儿,总觉得这两个东西就是拿来取参数、返回数据的。后来做项目多了才发现,这里面的门道还真不少。
你想想看,一个 API 请求从客户端发过来,到服务器处理完返回结果,中间所有的信息都在这两个对象里。搞懂了它们,你基本就掌握了 Express 的命脉。
Request 对象:你收到的每一份请求
Request 对象(通常简写为 req)封装了客户端发来的所有信息。我个人习惯把它分成三块来看:参数从哪里来、请求头里有什么、请求体里装了什么。
1. req.params:路由参数
路由参数是 URL 路径里动态变化的部分。比如你要查询某个用户的资料,URL 可能是 /users/123,这里的 123 就是用户 ID。
// 定义路由
app.get('/users/:id', (req, res) => {
console.log(req.params); // { id: '123' }
res.send(`用户ID是:${req.params.id}`);
});
req.params.id 去查数据库,结果前端传了个字符串 "abc",数据库直接报错。后来我养成了习惯:所有路由参数进来先转数字,或者用中间件统一校验。
2. req.query:查询字符串
查询字符串就是 URL 问号后面的部分。比如 /users?page=1&limit=10,Express 会自动解析成对象。
// 请求:/search?keyword=node&page=2
app.get('/search', (req, res) => {
const { keyword, page } = req.query;
console.log(keyword); // 'node'
console.log(page); // '2'(注意:是字符串)
res.send(`搜索关键词:${keyword},第${page}页`);
});
req.query 里的值全是字符串。如果你需要数字,记得手动转换。我见过太多人直接拿 page 去做加法运算,结果变成了字符串拼接。
3. req.body:请求体
请求体通常用在 POST、PUT 等需要提交数据的请求中。但要注意,Express 默认不解析请求体,你需要用中间件。
// 必须引入 body-parser 或使用 Express 内置的 json 解析
app.use(express.json()); // 解析 JSON 格式的请求体
app.use(express.urlencoded({ extended: true })); // 解析表单数据
app.post('/users', (req, res) => {
const { name, age } = req.body;
console.log(name, age);
res.send(`创建用户:${name}`);
});
req.body 始终是 undefined。排查了半天才发现,是忘了加 express.json() 中间件。嗯,这种低级错误犯过一次就再也不会忘了。
Response 对象:你返回的每一份响应
Response 对象(通常简写为 res)是你给客户端的回复。说白了,客户端发请求给你,你总得回点东西吧?
1. res.send():最通用的响应方法
res.send() 可以返回各种类型的数据:字符串、Buffer、对象、数组。Express 会自动设置 Content-Type。
app.get('/hello', (req, res) => {
res.send('Hello World'); // 返回纯文本
});
app.get('/data', (req, res) => {
res.send({ message: '成功', code: 200 }); // 自动转为 JSON
});
res.send() 快速调试。但生产环境里,我建议明确指定返回类型,避免 Express 自动推断出错。
2. res.json():专门返回 JSON
这个方法和 res.send() 传对象的效果一样,但语义更明确。我推荐在 API 开发中统一使用 res.json()。
app.get('/api/users', (req, res) => {
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
];
res.json({
success: true,
data: users,
total: 2
});
});
3. res.render():渲染模板
如果你在用 Express 做服务端渲染(SSR),res.render() 就是你的好帮手。它会用模板引擎渲染 HTML 页面。
// 先设置模板引擎
app.set('view engine', 'ejs');
app.get('/profile', (req, res) => {
const user = { name: '王五', age: 28 };
res.render('profile', { user }); // 渲染 profile.ejs 模板
});
res.render()。但如果你在做全栈项目,或者需要服务端渲染 SEO 友好的页面,这个方法还是很实用的。
4. res.redirect():重定向
重定向就是告诉客户端:「你要找的东西不在这里,去那边看看。」
app.get('/old-path', (req, res) => {
res.redirect('/new-path'); // 默认 302 重定向
});
app.get('/old-path-permanent', (req, res) => {
res.redirect(301, '/new-path'); // 301 永久重定向
});
链式调用:优雅的代码风格
Express 的 Response 对象支持链式调用。什么意思呢?就是你可以连续调用多个方法,不用每次都写 res。
app.get('/chain', (req, res) => {
res
.status(201) // 设置状态码
.set('X-Custom-Header', 'hello') // 设置自定义头
.json({ message: '创建成功' }); // 返回 JSON
});
我个人非常喜欢这种写法。它让代码看起来更紧凑,逻辑也更清晰。你想想看,如果不链式调用,你得写成这样:
// 不推荐:代码冗余
app.get('/chain', (req, res) => {
res.status(201);
res.set('X-Custom-Header', 'hello');
res.json({ message: '创建成功' });
});
总结一下
这一章我们聊了 Request 和 Response 的核心用法。说白了,Request 就是「你收到了什么」,Response 就是「你要回什么」。搞清楚了参数的三种来源(params、query、body),以及响应的四种方式(send、json、render、redirect),你就能应付大部分 API 开发场景了。
下一章我们会深入聊聊中间件——Express 的灵魂所在。到时候你会发现,理解了 Request 和 Response,中间件学起来会轻松很多。