在实际开发中,res.status() 通常用于设置响应的 HTTP 状态码,以 表示请求的处理结果

HTTP 状态码

在 HTTP 协议中,状态码是响应的一部分,用来告诉客户端请求的处理状态。例如,200 表示请求成功,404 表示请求的资源未找到,500 表示服务器内部错误等。

常用的 HTTP 状态码

  • 200: OK - 请求成功。
  • 201: Created - 创建成功,通常用于 POST 请求创建新的资源。
  • 204: No Content - 请求成功,但没有需要返回的实体内容。
  • 400: Bad Request - 请求有语法错误,服务器无法理解。
  • 401: Unauthorized - 需要用户验证。
  • 403: Forbidden - 服务器理解请求,但拒绝执行。
  • 404: Not Found - 服务器无法找到请求的资源。
  • 500: Internal Server Error - 服务器内部错误。

状态码的作用

🤔 状态码有什么用?我们为什么需要设置状态码?如果不设置状态码会存在什么问题?

状态码可以帮助客户端理解请求的处理结果,并据此做出正确的处理。

客户端通常是不确定的,可以是:

  • 前端 JavaScript 代码
  • 其他服务器
  • API 客户端
  • ……

如果我们不设置正确的状态码,那么可能会出现以下问题:

  1. 客户端可能会误解请求的处理结果。例如,如果客户端请求了一个不存在的资源,但服务器返回了 200 状态码,那么客户端可能会误以为请求是成功的。
  2. 如果我们的 API 遵循某种规范(例如,REST),那么不设置正确的状态码可能会违反这种规范。
  3. 不设置正确的状态码可能会使调试变得困难,因为状态码是调试 HTTP 问题的重要线索。

因此,正确设置 HTTP 状态码是一个很好的实践,它可以使我们的应用或 API 更易于理解和使用。

设置 HTTP 状态码的合适时机

HTTP 状态码通常在发送响应消息之前设置

在处理请求的过程中,我们可能会基于各种条件判断和操作结果来决定应该返回什么样的状态码。例如,如果客户端请求了一个不存在的资源,我们可能会在查询数据库并确认资源不存在之后,设置状态码为 404

如果我们在接收到请求后立刻设置状态码,可能会遇到一些问题。

  1. 首先,我们可能还没有足够的信息来确定正确的状态码。例如:如果客户端请求了一个资源,我们可能需要先查询数据库才能确定资源是否存在,从而决定是返回 200 还是 404
  2. 其次,如果我们在处理请求的过程中遇到了错误,我们可能需要改变状态码,但如果我们已经设置过状态码,那么就需要额外的逻辑来处理这种情况。

小结:
设置状态码应该在我们有足够信息来确定正确的状态码,且确定不会再有任何改变状态码的条件出现之后。一旦设置了状态码并开始发送响应,我们就不能再更改状态码了,因为 HTTP 响应的头部(包含状态码)一旦发送,就不能再修改。

Express 中的 HTTP 状态码

默认值

在 Express 中,默认的 HTTP 状态码是 200,除非响应被重定向,那么状态码就是 302。也就是说,如果我们不调用 res.status() 来设置状态码,那么 Express 会使用默认的状态码。这在很多情况下是没有问题的。例如,如果我们的路由处理器只是返回一个资源或者视图,并且没有出现任何错误,那么默认的 200 状态码是正确的。

小结:
大多数情况下,我们无需去手动调用 res.status(code) 去设置响应的 HTTP 状态码。Express 会根据我们的操作自动设置合适的响应状态码,不需要我们手动设置响应状态码。例如:

  • 当我们使用 res.send()res.json() 发送响应时,Express 会自动设置状态码为 200(OK)
  • 当使用 res.redirect() 时,默认状态码为 302(Found)

需要手动设置状态码的常见场景

然而,在其他一些情况下,我们可能需要设置一个不同的状态码。例如:

  • 201 如果我们的路由处理器创建了一个新的资源,那么应该返回 201 状态码,表示资源已被成功创建。
  • 400 如果客户端发送了一个错误的请求(例如,请求体格式不正确),那么应该返回 400 状态码,表示客户端请求错误。
  • 404 如果客户端请求了一个不存在的资源,那么应该返回 404 状态码,表示资源未找到。

设置状态码的合适时机

在 Express 中,res.status() 方法并不会立即发送响应,而只是设置状态码,因此我们可以在调用 res.status() 之后,继续添加或修改响应头,或设置响应体。只有当我们调用如 res.send()res.json() 等方法时,Express 才会发送响应。因此,我们可以根据需要,灵活地在处理请求的过程中设置和修改状态码

补充: 当然,最好还是按照规范来,当我们能够明确本次请求的最终结果时,再去调用 res.status() 即可。

常见示例

创建资源

  1. app.post('/users', (req, res) => {
  2. const user = createUser(req.body); // 假设 createUser 是一个可以创建新用户的函数
  3. if (user) {
  4. res.status(201).json(user); // 如果用户创建成功,返回 201 状态码和新创建的用户对象
  5. } else {
  6. res.status(400).send('Bad Request'); // 如果用户创建失败(例如,请求体格式错误),返回 400 状态码
  7. }
  8. });

获取资源

  1. app.get('/users/:id', (req, res) => {
  2. const user = getUser(req.params.id); // 假设 getUser 是一个可以根据 ID 获取用户的函数
  3. if (user) {
  4. res.json(user); // 如果找到了用户,返回用户对象(默认状态码是 200)
  5. } else {
  6. res.status(404).send('User not found'); // 如果没有找到用户,返回 404 状态码
  7. }
  8. });

处理错误

  1. app.get('/users/:id', (req, res) => {
  2. try {
  3. const user = getUser(req.params.id); // 假设 getUser 是一个可能会抛出错误的函数
  4. res.json(user);
  5. } catch (err) {
  6. console.error(err);
  7. res.status(500).send('Internal Server Error'); // 如果发生错误,返回 500 状态码
  8. }
  9. });

这些只是示例,实际的使用方式会根据你的需求和 API 设计来决定。

demos

demo | 用户管理

源码:230512_res.status().zip.zip%22%2C%22size%22%3A7940%2C%22ext%22%3A%22zip%22%2C%22source%22%3A%22%22%2C%22status%22%3A%22done%22%2C%22download%22%3Atrue%2C%22taskId%22%3A%22u84326ac6-5fea-441a-be08-d53449dd3e4%22%2C%22taskType%22%3A%22transfer%22%2C%22type%22%3A%22application%2Fzip%22%2C%22mode%22%3A%22title%22%2C%22id%22%3A%22JIxmB%22%2C%22card%22%3A%22file%22%7D)

以下是一些简化的示例,我们将使用一个内存中的数据结构来代替真实的数据库,来模拟处理请求中的一些常见行为。

模拟:

  • 写:新建用户
  • 读:获取用户
  • 错误情况的异常处理
  1. const express = require('express');
  2. const app = express();
  3. const port = 3000;
  4. app.use(express.json());
  5. // 假设我们有一个用户数组作为数据源
  6. let users = [
  7. { id: 111, name: 'Tdahuyou' },
  8. { id: 2222, name: 'Txiaohuyou' },
  9. ];
  10. // 创建新用户的函数
  11. function createUser(body) {
  12. const user = { id: Date.now(), name: body.name };
  13. users.push(user);
  14. return user;
  15. }
  16. // 根据 ID 获取用户的函数
  17. function getUser(id) {
  18. return users.find(user => user.id === Number(id));
  19. }
  20. // 创建用户
  21. app.post('/users', (req, res) => {
  22. const user = createUser(req.body);
  23. if (user) {
  24. res.status(201).json(user);
  25. } else {
  26. res.status(400).send('Bad Request');
  27. }
  28. });
  29. // 获取用户
  30. app.get('/users/:id', (req, res) => {
  31. const user = getUser(req.params.id);
  32. if (user) {
  33. res.json(user);
  34. } else {
  35. res.status(404).send('User not found');
  36. }
  37. });
  38. // 获取用户,但可能会发生错误
  39. app.get('/users/error/:id', (req, res) => {
  40. try {
  41. const user = getUser(req.params.id);
  42. if (user) {
  43. throw new Error('An unexpected error occurred'); // 模拟错误
  44. }
  45. res.json(user);
  46. } catch (err) {
  47. console.error(err);
  48. res.status(500).send('Internal Server Error');
  49. }
  50. });
  51. app.listen(port, () => {
  52. console.log(`Server running at http://localhost:${port}`);
  53. });

然后你可以通过 HTTP 工具(如 curl、Postman、Apifox、浏览器等)来模拟请求

  • http://localhost:3000/users 发送 POST 请求以创建新用户
  • http://localhost:3000/users/:id 发送 GET 请求以获取用户
  • http://localhost:3000/users/error/:id 发送 GET 请求以模拟错误处理