目录

一、状态码是干什么的?

二、五大类状态码速览

三、高频状态码详解(前端必背)

🟢 2xx:成功类

200 OK —— 一切正常

201 Created —— 创建成功

204 No Content —— 成功但无内容

🔄 3xx:重定向类

301 Moved Permanently —— 永久重定向(⚠️ 要小心)

302 Found —— 临时重定向

304 Not Modified —— 未修改(⭐ 面试必问)

❌ 4xx:客户端错误类(前端背锅)

400 Bad Request —— 请求参数错误

401 Unauthorized —— 未认证

403 Forbidden —— 禁止访问

404 Not Found —— 资源不存在

💥 5xx:服务端错误类(后端背锅)

500 Internal Server Error —— 服务器内部错误

502 Bad Gateway —— 网关错误

504 Gateway Timeout —— 网关超时

四、面试高频“对比题”

301 vs 302

401 vs 403

304 vs 200

五、前端实战:响应拦截器统一处理(代码模板)

六、速记口诀(收藏背诵)

写在最后


一、状态码是干什么的?

当浏览器向服务器发送请求后,服务器会返回一个三位数字,告诉浏览器这次请求的结果如何。

我们可以用取快递来类比:

  • 2xx(成功):快递顺利送到,签收成功。

  • 3xx(重定向):快递员告诉你:“地址换了,去隔壁取。”

  • 4xx(客户端错误):你填错了地址或没带身份证,快递没法给你。

  • 5xx(服务端错误):快递仓库爆仓或机器故障,快递出不来。

二、五大类状态码速览

分类 范围 含义(一句话版)
1xx(信息) 100 - 199 请求已收到,继续处理
2xx(成功) 200 - 299 请求成功,返回了你要的数据
3xx(重定向) 300 - 399 资源位置变了,去别处找
4xx(客户端错误) 400 - 499 请求有问题,是前端/用户的问题
5xx(服务端错误) 500 - 599 服务器出问题了,是后端/运维的问题

💡 记忆口诀1 等、2 好、3 跑、4 错、5 倒

三、高频状态码详解(前端必背)

🟢 2xx:成功类

200 OK —— 一切正常

请求成功,服务器返回了请求的数据(HTML、JSON、图片等)。

场景:页面加载成功、接口正常返回数据。


201 Created —— 创建成功

常见于 POST 请求(注册、新增文章、上传文件),服务器不仅处理了请求,还新建了资源

场景:用户注册成功、发布文章成功。


204 No Content —— 成功但无内容

服务器处理成功了,但响应体是空的

场景:删除操作(DELETE 请求)、更新操作(PUT 请求),只告诉前端“搞定了”,不需要返回数据。


🔄 3xx:重定向类

301 Moved Permanently —— 永久重定向(⚠️ 要小心)

“这个地址永久搬家了,以后都去新地址。”

浏览器会缓存这个新地址,下次自动跳转,不再访问旧地址。

场景

  • 域名更换(http://oldsite.com → https://newsite.com

  • 不推荐用于临时活动页(因为浏览器会永久记住,换活动就麻烦了)

⚠️ 面试陷阱:301 会被浏览器强缓存,一旦配置错误(比如把临时跳转配成 301),用户可能永远无法访问旧链接,清除缓存都未必有用。


302 Found —— 临时重定向

“这次先借隔壁的,下次还来老地址。”

浏览器不会缓存新地址,每次都会先访问旧地址,再跳转。

场景

  • 未登录用户跳转到登录页

  • 临时活动页跳转

  • 支付成功后跳转到订单页


304 Not Modified —— 未修改(⭐ 面试必问)

“你手里的版本和服务器一样,用你本地缓存的就行。”

它不是错误,而是协商缓存生效的标志。服务器只返回了响应头(很小),没有返回实际的资源文件(省流量)。

场景:刷新页面时,JS/CSS/图片等静态资源未变化。

⚠️ 常见误区:看到 304 不要慌,这说明浏览器的缓存策略配置生效,是性能优化的体现。


❌ 4xx:客户端错误类(前端背锅)

400 Bad Request —— 请求参数错误

“你发的请求格式不对,我听不懂。”

常见原因

  • 前端传的 JSON 格式错了(多了逗号、少了引号)

  • 必填字段没传

  • 参数类型不对(接口要 number,你传了 string)

排查思路:打开浏览器开发者工具的 Network 面板,查看请求的 Payload(负载),和后端确认接口文档。


401 Unauthorized —— 未认证

“你没带身份证,我不认识你。”

含义:用户未登录或 Token 过期/无效

处理方式:前端在 Axios 响应拦截器中捕获 401,清除本地 Token,跳转到登录页。

// axios 响应拦截器示例
if (response.status === 401) {
  localStorage.removeItem('token');
  router.push('/login');
}

⚠️ 401 vs 403 区别

  • 401:没登录 / Token 无效(身份认证失败)

  • 403:登录了但没权限(权限认证失败)


403 Forbidden —— 禁止访问

“你有身份证,但不是这个小区的住户,不让进。”

含义:用户已登录,但没有权限访问这个资源。

场景

  • 普通用户访问管理员后台

  • 免费用户访问付费内容

  • IP 被服务器拉黑

处理方式:跳转到 403 提示页,或提示“暂无权限”。


404 Not Found —— 资源不存在

“你给的地址找不到这间房。”

含义:服务器上没有这个资源

常见原因

  • URL 路径拼写错误(注意大小写!)

  • 资源已被删除

  • 后端没有注册该路由(忘了写接口)

排查思路:检查请求 URL 是否正确,确认后端是否已部署该接口。


💥 5xx:服务端错误类(后端背锅)

500 Internal Server Error —— 服务器内部错误

“后台代码报错了,崩了。”

常见原因

  • 后端代码抛出异常(如空指针、数据库连接失败)

  • 服务器配置错误

处理方式:前端只能提示“系统繁忙,请稍后重试”,需要后端查看日志排查。


502 Bad Gateway —— 网关错误

“快递分拣中心联系不上配送站。”

含义:网关(如 Nginx)无法从后端服务(如 Java/Go 服务)获取有效响应。

常见原因

  • 后端服务挂了(进程崩溃)

  • 后端服务拒绝连接(端口没开)

  • 防火墙拦截


504 Gateway Timeout —— 网关超时

“配送站 30 秒没回话,分拣中心不等了。”

含义:后端服务处理请求太慢,超过了 Nginx 设定的超时时间。

常见原因

  • 数据库慢查询(SQL 没走索引)

  • 后端代码死循环或死锁

  • 第三方接口响应慢

处理方式:优化后端接口性能,或调整 Nginx 超时配置(治标不治本)。

四、面试高频“对比题”

301 vs 302

对比项 301(永久重定向) 302(临时重定向)
缓存行为 被浏览器强缓存 不会被缓存
适用场景 域名永久迁移、HTTP → HTTPS 未登录跳转、临时活动
风险 配错了用户很难恢复 每次都去问,性能略差

401 vs 403

对比项 401 Unauthorized 403 Forbidden
核心问题 你是谁?(身份认证失败) 你配吗?(权限认证失败)
常见原因 未登录、Token 过期 角色权限不够、IP 被封
解决方案 重新登录获取 Token 联系管理员开通权限

304 vs 200

对比项 200 OK 304 Not Modified
返回内容 返回完整的资源文件 只返回响应头,无响应体
触发时机 资源已更新 资源未变化(协商缓存生效)
性能影响 消耗带宽 省流量、速度快

五、前端实战:响应拦截器统一处理(代码模板)

在实际项目中,我们通常会在 Axios 的响应拦截器中统一处理各种状态码:

/**
 * utils/request.js
 * 
 * 基于 axios 封装的统一网络请求模块
 * 
 * 核心功能:
 * 1. 创建统一的 axios 实例,配置基础路径和超时时间
 * 2. 通过响应拦截器统一处理接口返回的状态码
 * 3. 根据不同的 HTTP 状态码,自动执行对应的错误提示和页面跳转
 * 
 * 使用方式:
 * import request from '@/utils/request';
 * const data = await request.get('/user/info');
 */

import axios from 'axios';
import { ElMessage } from 'element-plus';
import router from '@/router';

/**
 * 创建 axios 实例
 * 
 * 为什么要创建独立实例?
 *  - 避免污染 axios 的全局默认配置
 *  - 可以针对当前项目设置专属的 baseURL 和超时时间
 */
const instance = axios.create({
  baseURL: '/api',           // 所有请求自动拼接该前缀(实际开发中可通过环境变量配置)
  timeout: 10000,            // 请求超时时间(单位:毫秒),10秒后无响应则自动终止请求
});

/**
 * 响应拦截器
 * 
 * 作用:在接口响应被 .then / .catch 处理之前,统一拦截并做预处理
 * 
 * 为什么需要它?
 *  - 避免在每个接口调用处重复写状态码判断和错误提示
 *  - 统一处理登录过期、权限不足等全局逻辑
 * 
 * 拦截器分两个回调:
 *   - 第一个:处理正常响应(HTTP 状态码为 2xx)
 *   - 第二个:处理异常响应(HTTP 状态码非 2xx,如 400、401、500 等)
 */
instance.interceptors.response.use(
  /**
   * ===== 正常响应处理 =====
   * 当 HTTP 状态码为 200/201/204 等 2xx 时,进入此函数
   * 
   * 注意:这里只返回 response.data(即后端返回的业务数据),
   * 而不是整个 response 对象,这样调用方直接拿到业务数据,无需再解构
   */
  (response) => {
    // 假设后端统一返回格式为 { code: 0, data: {...}, message: '' }
    // 如果业务 code 不为 0,也可以在这里统一处理业务错误码
    // 但本例中我们专注于 HTTP 状态码的处理,业务码交给具体业务层判断
    return response.data;
  },

  /**
   * ===== 异常响应处理 =====
   * 当 HTTP 状态码为 4xx(客户端错误)或 5xx(服务端错误)时,进入此函数
   * 
   * error 对象包含请求和响应的完整信息,其中最常用的是 error.response
   * 如果网络完全断开,error.response 可能为 undefined,需要做兜底处理
   */
  (error) => {
    // 【安全取值】如果 error.response 不存在(如网络断开),用空对象兜底,避免解构报错
    const { status } = error.response || {};

    // 【根据 HTTP 状态码分别处理】
    switch (status) {
      // ---------- 4xx:客户端错误(通常是前端或用户的问题) ----------

      case 400:
        // 场景:请求参数格式错误、必填字段缺失、参数类型不匹配
        ElMessage.error('请求参数有误,请检查后重试');
        // 不跳转页面,只提示,让用户自行修正
        break;

      case 401:
        // 场景:用户未登录,或登录凭证(Token)已过期 / 无效
        // 
        // 处理流程(三步走):
        // 1. 清除本地存储中失效的 Token(避免带着旧 Token 继续请求)
        // 2. 弹出提示告知用户需要重新登录
        // 3. 跳转到登录页,让用户重新获取有效 Token
        localStorage.removeItem('token');
        ElMessage.warning('登录已过期,请重新登录');
        router.push('/login');
        break;

      case 403:
        // 场景:用户已登录,但当前账号没有访问该资源的权限
        // 例如:普通用户试图访问管理员后台,或免费用户访问付费内容
        ElMessage.error('您没有权限访问该资源');
        router.push('/403'); // 跳转到无权限提示页
        break;

      case 404:
        // 场景:请求的 URL 在服务器上不存在
        // 常见原因:接口路径拼写错误、后端尚未部署该接口、资源已被物理删除
        ElMessage.error('请求的资源不存在');
        // 注意:404 通常不跳转,因为大概率是代码 Bug,跳转反而掩盖了问题
        break;

      // ---------- 5xx:服务端错误(通常是后端或运维的问题) ----------

      case 500:
        // 场景:服务器内部发生了未捕获的异常(如 Java 空指针、数据库连接失败)
        // 这是最通用的服务端错误,具体原因需要后端查看日志定位
        ElMessage.error('服务器开小差了,请稍后重试');
        break;

      case 502:
      case 504:
        // 502 Bad Gateway:网关(如 Nginx)无法从后端服务获取有效响应
        //   常见原因:后端服务进程挂了、端口未开放、防火墙拦截
        // 504 Gateway Timeout:网关等待后端响应超时(超过了 Nginx 配置的超时时间)
        //   常见原因:后端接口执行时间过长(慢 SQL、死循环、第三方接口卡顿)
        ElMessage.error('网络超时,请检查网络连接');
        break;

      // ---------- 兜底处理:未覆盖到的状态码 ----------

      default:
        // 出现未预料的状态码时,给出通用提示,同时将错误继续抛出
        // 这样业务层还可以针对特殊情况进行二次处理
        ElMessage.error('网络异常,请稍后重试');
        break;
    }

    /**
     * 返回一个 rejected 状态的 Promise
     * 
     * 为什么需要这行?
     *  - 让调用方能够通过 .catch() 捕获到这个错误,做额外的业务处理
     *  - 如果这里不 return Promise.reject(error),调用方将无法感知请求失败了
     * 
     * 举例:
     *   try {
     *     await request.get('/api/list');
     *   } catch (err) {
     *     // 这里能捕获到 error,因为拦截器返回了 reject
     *     console.log('请求彻底失败了', err);
     *   }
     */
    return Promise.reject(error);
  }
);

export default instance;

六、速记口诀(收藏背诵)

1 打头继续等,2 打头算成功;
3 打头去别处,4 打头自己崩;
5 打头服务器崩。

高频必背:
200 好,201 造,304 读缓存;
301 永久搬,302 临时转;
400 传错参,401 没登录,403 门禁拦;
404 找不见,500 后端瘫,504 等得烦。

写在最后

状态码是前后端沟通的“通用语言”,记住它们不仅能帮你快速定位问题,还能在面试中对答如流。

建议收藏本文,遇到接口报错时拿出来对照排查,比盲目瞎改高效十倍!

(PS:本文由deepseek辅助生成)

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐