JWT 1:从一个登录请求开始,理解 React 项目里的 API 层与 Mock

很多刚开始做 React 项目的人,会直接在组件里写:

js 复制代码
axios.post('/api/login', {
  username,
  password
})

刚开始当然没问题。

但项目一大,就会出现一个很明显的问题:

页面代码开始和请求代码搅在一起。

登录页面既要负责输入框,又要负责接口地址,又要负责 Axios,还要处理服务器返回的数据。

所以这篇文章先不急着讲 JWT,我们先把一个最基础的问题搞清楚:

React 页面到底应该怎么和后端通信?


一、先想清楚:React 为什么需要 API 层?

假设现在有一个登录页面。

最直接的写法是:

js 复制代码
async function handleLogin() {
  const res = await axios.post('/api/login', {
    username,
    password
  })
}

看起来很简单。

但以后项目里可能还有:

text 复制代码
登录
获取用户信息
获取订单
获取仓库
创建订单
删除数据

如果每个组件都直接使用 Axios,就会变成:

text 复制代码
Login.jsx     → axios
Home.jsx      → axios
Pay.jsx       → axios
Profile.jsx   → axios
Order.jsx     → axios

请求逻辑散落在各种页面里。

所以我们希望把"调用接口"这件事情单独拿出来。

最终变成:

text 复制代码
React 页面
    ↓
调用 API 方法
    ↓
API 文件负责请求
    ↓
Axios 发送 HTTP 请求

这样页面只关心:

"我要登录。"

而不需要关心:

"登录请求到底是 POST 还是 GET、地址是什么、Axios 怎么配置?"


二、创建 api 目录

src 下创建:

text 复制代码
src/
└── api/

这个目录专门放前端调用后端接口的代码。

接下来我们先创建:

text 复制代码
src/api/config.js

为什么先创建它?

因为所有接口都需要使用 Axios。

如果每个文件都自己创建一个 Axios 实例:

js 复制代码
axios.create(...)

那么以后想统一修改:

  • baseURL
  • timeout
  • 请求拦截器
  • 响应拦截器

就要改很多文件。

所以先创建一个统一的 Axios 实例。


三、创建统一的 Axios 实例

src/api/config.js 中:

js 复制代码
import axios from 'axios';

const instance = axios.create({
  baseURL: '/api',
  timeout: 5000
});

export default instance;

这里最重要的是:

js 复制代码
baseURL: '/api'

以后我们写:

js 复制代码
axios.post('/login')

实际请求的就是:

text 复制代码
/api/login

而不是每次都写完整地址。

所以:

text 复制代码
config.js

解决的是:

整个项目怎么统一使用 Axios。

它并不负责某个具体业务。


四、创建用户 API

现在我们需要处理登录。

src/api 下创建:

text 复制代码
src/api/user.js

为什么还要创建 user.js

因为 config.js 只负责 Axios 的公共配置。

而:

text 复制代码
user.js

负责的是:

用户相关的接口。

例如:

  • 登录
  • 获取用户信息
  • 修改用户信息

因此在 user.js 中:

js 复制代码
import axios from './config';

export const login = async (data) => {
  const res = await axios.post('/login', data);
  return res.data;
}

现在我们有两个文件:

text 复制代码
src/api/
├── config.js   // 统一配置 Axios
└── user.js     // 用户相关接口

这两个文件的职责已经不一样了。


五、页面不再直接使用 Axios

登录页面以后不需要写:

js 复制代码
axios.post('/api/login')

而是:

js 复制代码
import { login } from '../api/user';

登录时:

js 复制代码
const res = await login(formData);

这时候,整个过程就非常清楚:

text 复制代码
用户填写账号密码
        ↓
Login 页面调用 login()
        ↓
user.js 负责发送 /login 请求
        ↓
config.js 提供 Axios 实例
        ↓
Axios 发出请求

页面负责"做什么"。

API 层负责"怎么请求"。

这就是最基础的前端分层。


六、可是现在还有一个问题:后端在哪里?

我们现在已经写了:

js 复制代码
axios.post('/login')

但谁来接这个请求?

如果我们真的写一个后端,还需要:

  • Node.js
  • Express
  • 路由
  • 数据库
  • 服务器

对于学习前端来说,这些内容有时候反而会把重点带偏。

所以这个 demo 使用了:

Mock

Mock 的目的很简单:

先假装我们已经有一个后端。


七、使用 Vite Mock 模拟后端

项目根目录创建:

text 复制代码
mock/

然后创建:

text 复制代码
mock/user.js

同时在 Vite 中配置 Mock 插件。

js 复制代码
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteMockServe } from 'vite-plugin-mock'

export default defineConfig({
  plugins: [
    react(),
    viteMockServe({
      mockPath: 'mock',
      localEnable: true
    })
  ],
})

这里:

js 复制代码
mockPath: 'mock'

告诉 Vite:

Mock 接口就在 mock 目录里。


八、创建第一个 Mock 登录接口

在:

text 复制代码
mock/user.js

中:

js 复制代码
export default [
  {
    url: '/api/login',
    method: 'post',
    response: req => {
      const body = req.body || {};

      if (
        body.username !== 'admin' ||
        body.password !== '123456'
      ) {
        return {
          code: -1,
          message: 'username or password error'
        };
      }

      return {
        code: 0,
        user: {
          username: body.username
        }
      };
    }
  }
]

现在,浏览器请求:

text 复制代码
POST /api/login

Mock 就会接住。

于是整个过程变成:

text 复制代码
用户填写账号密码
        ↓
Login 页面调用 login()
        ↓
user.js 发送 /login
        ↓
Axios 处理请求
        ↓
Vite Mock 接收 /api/login
        ↓
mock/user.js 验证账号密码
        ↓
返回 JSON

这时候你应该已经能理解:

Mock 不是前端 API。

它是在开发阶段模拟后端

而 API 层则是:

前端为了调用后端而做的代码组织。

这是两个完全不同的东西。


九、为什么现在还不能说"登录系统完成了"?

因为我们现在只能做到:

text 复制代码
用户名密码正确
        ↓
服务器返回成功

但用户下一次访问:

text 复制代码
/api/repo

服务器怎么知道:

"这个人刚刚已经登录过了?"

这就是下一篇要解决的问题。

相关推荐
东风破_1 小时前
JWT 3:为什么 Token 要放进 Authorization?Axios 拦截器到底解决了什么?
前端·后端
东风破_1 小时前
JWT 5:路由守卫是什么?把整个 JWT 登录鉴权流程串起来
前端·后端
东风破_1 小时前
JWT 2:HTTP 是无状态的,为什么登录成功后还要给 Token?
前端·后端
东风破_1 小时前
JWT 4:Zustand 到底解决了什么?为什么登录状态要放进 Store?
前端·后端
IT_陈寒1 小时前
Vite动态导入差点让我秃头,原来问题出在这
前端·人工智能·后端
白泽_hunter2 小时前
项目里最常见的 5 个 this 指向坑:从规则到实战彻底讲透
前端
宿6742 小时前
vue3-pinia
前端·vue.js
白泽_hunter2 小时前
搞懂 JS 数据类型:从 typeof 到手写完整类型判断,一张图理清
前端
唐青枫2 小时前
别只把大括号当作用域:Zig Block、标签块与控制流实战
后端