常用请求与响应 API
🎯 引言
路由和中间件搭起了骨架,真正干活的是请求对象 req 和响应对象 res。学完这篇文章,你能熟练读取客户端传来的各种数据,并用合适的方式把结果返回给客户端。
🧱 认识 req 与 res
每次请求进来,Express 都会把请求对象 req 和响应对象 res 传给处理函数:
req:客户端发来的所有信息,参数、请求体、请求头都在它身上。res:我们回给客户端的内容,状态码、响应头、响应体都由它控制。
这两个对象在原生 http 模块的基础上做了大量增强,原生能做的事它们都能做,但写法简单得多。
🛠 req:读取客户端数据
路径参数与查询参数
前面路由一篇学过,这里快速回顾:
// 访问 /users/1?keyword=张
app.get('/users/:id', (req, res) => {
console.log(req.params.id); // '1',路径参数,字符串
console.log(req.query.keyword); // '张',查询参数
res.send('ok');
});
请求体 req.body
POST、PUT 提交的数据在请求体里,先加 express.json() 中间件,再从 req.body 读取:
const app = express();
app.use(express.json());
app.post('/users', (req, res) => {
console.log(req.body); // { name: '小明', age: 18 }
res.send('创建成功');
});
请求头 req.headers 与 req.get
请求头记录了客户端的身份和环境信息,比如登录令牌 token、客户端类型。两种读取方式:
app.get('/profile', (req, res) => {
console.log(req.headers.token); // 方式一:属性访问,键名全小写
console.log(req.get('User-Agent')); // 方式二:get() 方法,大小写不敏感
res.send('ok');
});
req.headers 的键名会被统一转成小写,req.get('Token') 则不区分大小写。读单个请求头时,用 req.get() 更省心。🛠 res:控制响应内容
res.send 与 res.json
res.send() 是通用的响应方法,它会根据传入的数据类型自动设置 Content-Type:
app.get('/text', (req, res) => {
res.send('你好'); // 自动设置 text/html; charset=utf-8
});
app.get('/user', (req, res) => {
res.send({ name: '小明' }); // 自动转 JSON 并设置 application/json
});
回想原生 http 模块要手动 setHeader 加 JSON.stringify,现在传什么都能正确处理,中文也不会乱码。
返回 JSON 时,还可以用语义更明确的 res.json(),效果和 res.send(对象) 一样:
app.get('/user', (req, res) => {
res.json({ name: '小明', age: 18 });
});
res.status 设置状态码
res.status() 设置状态码,它返回 res 本身,可以链式调用:
app.post('/users', (req, res) => {
// 创建资源成功,按规范返回 201
res.status(201).json({ message: '创建成功' });
});
app.get('/users/99', (req, res) => {
res.status(404).json({ message: '用户不存在' });
});
res.set 设置响应头
需要自定义响应头时用 res.set(),比如告诉客户端允许缓存多久:
app.get('/config', (req, res) => {
res.set('Cache-Control', 'max-age=3600');
res.json({ theme: 'dark' });
});
res.redirect 重定向
让客户端跳转到另一个地址,常用于旧地址迁移:
app.get('/old-page', (req, res) => {
res.redirect('/new-page');
});
浏览器访问 /old-page 会自动跳到 /new-page。
res.send() 之后再调用 res.json() 会报 Cannot set headers after they are sent,一个处理函数里记得用 return 保证只走一个分支。🧰 调试接口的方式
GET 接口直接用浏览器访问就行,POST、PUT、DELETE 可以在终端用 curl:
# 发送 JSON 的 POST 请求
curl -X POST http://localhost:3000/users -H "Content-Type: application/json" -d "{\"name\":\"小明\"}"
# 带查询参数的 GET 请求
curl "http://localhost:3000/users/1?keyword=张"
习惯图形界面的话,也可以用 Postman、Apifox 这类接口调试工具。
🧾 小节总结
req承载客户端信息:路径参数req.params、查询参数req.query、请求体req.body、请求头req.headers和req.get()。req.body依赖express.json()中间件解析,没加的话是undefined。res.send()按数据类型自动设置 Content-Type,对象会自动转成 JSON。res.status()设状态码、res.set()设响应头、res.redirect()做跳转,res.json()返回 JSON。- 一个请求只能响应一次,多次调用响应方法会报错。
❓ 知识问答
Q1:res.send() 和 res.json() 有什么区别?
传对象时两者效果相同,都返回 JSON。区别在于习惯:res.json() 语义更明确,res.send() 还能返回字符串、Buffer 等其他类型。返回数据接口用 res.json() 更清晰。
Q2:res.status(404) 后忘记 res.json() 会怎样?
res.status() 只设置状态码,不会结束响应。不写后续的响应方法,请求会一直挂着。记住:res.status() 后面必须接 res.json() 或 res.send() 等结束动作。
Q3:req.query 里的数字要转类型吗?
要。和 req.params 一样,查询参数的值也是字符串,?page=2 读出来是 '2'。参与数学计算前用 Number() 转换。
Q4:curl 里中文变成乱码怎么办?
把请求地址里的中文做 URL 编码,或者用 --data-urlencode 让 curl 帮你编码。这是 curl 客户端的编码问题,不影响 Express 本身的解析。
🧪 小练习
写一个 GET /greet 接口:读取查询参数 name,如果有就返回 JSON { "message": "你好,xxx" };如果没有 name,返回状态码 400 和 { "message": "请提供 name 参数" }。
import express from 'express';
const app = express();
// 请在这里编写代码
app.listen(3000);
🎉 恭喜你已经能熟练处理请求和响应了!下一篇我们学习错误处理,让服务器出错时也能优雅地回应客户端。
