Express 简介

常用请求与响应 API

掌握 req 和 res 上的常用 API,学会读取请求参数、请求头,控制响应内容、状态码和跳转。

🎯 引言

路由和中间件搭起了骨架,真正干活的是请求对象 req 和响应对象 res。学完这篇文章,你能熟练读取客户端传来的各种数据,并用合适的方式把结果返回给客户端。


🧱 认识 req 与 res

每次请求进来,Express 都会把请求对象 req响应对象 res 传给处理函数:

  • req:客户端发来的所有信息,参数、请求体、请求头都在它身上。
  • res:我们回给客户端的内容,状态码、响应头、响应体都由它控制。

这两个对象在原生 http 模块的基础上做了大量增强,原生能做的事它们都能做,但写法简单得多。


🛠 req:读取客户端数据

路径参数与查询参数

前面路由一篇学过,这里快速回顾:

app.js
// 访问 /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 读取:

app.js
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.js
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.js
app.get('/text', (req, res) => {
    res.send('你好'); // 自动设置 text/html; charset=utf-8
});

app.get('/user', (req, res) => {
    res.send({ name: '小明' }); // 自动转 JSON 并设置 application/json
});

回想原生 http 模块要手动 setHeaderJSON.stringify,现在传什么都能正确处理,中文也不会乱码。

返回 JSON 时,还可以用语义更明确的 res.json(),效果和 res.send(对象) 一样:

app.js
app.get('/user', (req, res) => {
    res.json({ name: '小明', age: 18 });
});

res.status 设置状态码

res.status() 设置状态码,它返回 res 本身,可以链式调用:

app.js
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.js
app.get('/config', (req, res) => {
    res.set('Cache-Control', 'max-age=3600');
    res.json({ theme: 'dark' });
});

res.redirect 重定向

让客户端跳转到另一个地址,常用于旧地址迁移:

app.js
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.headersreq.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 参数" }

app.js
import express from 'express';

const app = express();

// 请在这里编写代码

app.listen(3000);

🎉 恭喜你已经能熟练处理请求和响应了!下一篇我们学习错误处理,让服务器出错时也能优雅地回应客户端。