react学习9:mock后台数据

52 阅读3分钟

mockjs

安装

npm i mockjs --save
npm i @types/mockjs --save-dev

创建index.ts

import Mock from 'mockjs'

Mock.mock('/api/test', 'get', () => {
  return {
    code: 0,
    msg: 'success',
    data: {
      name: 'pcj',
    },
  }
})

app.tsx文件中引入:

import '../_mock'

const Home: FC = () => {
  useEffect(() => {
    fetch('/api/test', { method: 'GET' })
      .then(res => res.json())
      .then(data => console.log(data))
  }, [])

  return (
    <div ></div>
  )
}

可以看到控制台报错了,这是因为Mockjs 只能劫持 XMLHttpRequest,不能劫持 fetch 等其他请求

所以,我们使用axios替换下:

useEffect(() => {
    axios.get('/api/test').then(data => console.log(data))
  }, [])

使用axios之后,请求就会被劫持,因此,并不会发送真正的请求,也就是在控制台的network面板中找不到发送的请求。

但是,前端使用mockjs有两个问题:

  • mockjs只能劫持XMLHttpRequest请求,如果在多人开发中,有的人使用了fetch就没有办法劫持了;
  • import '../_mock'可能被打包到生产环境中,同时mockjs库非常大(130kb);

因此,只能求助于服务端。

nodejs 服务 + mockjs

那已经用服务端来mock数据了,为什么还需要用到mockjs呢?

因为mockjs除了劫持请求外,还有强大的mock.random数据的能力。

image.png

所以,把mockjs用于服务端就是使用了其random的能力。

我们这里采用koa来启动一个nodejs服务,目录结构如下:

image.png

package.json代码如下:

{
  "name": "wenjuan-mock",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "dev": "nodemon index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@koa/cors": "^5.0.0",
    "koa": "^3.0.2",
    "koa-router": "^14.0.0",
    "mockjs": "^1.1.0"
  },
  "devDependencies": {
    "nodemon": "^3.1.10"
  }
}

index.js代码如下:

import Koa from 'koa'
import Router from 'koa-router'
import cors from '@koa/cors'
import mockList from './mock/index.js'

const app = new Koa()
const router = new Router()

app.use(cors())

async function getRes(fn, ctx) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const res = fn(ctx)
      resolve(res)
    }, 1000)
  })
}

// 注册 mock 路由
mockList.forEach((item) => {
  const { url, method, response } = item
  router[method](url, async (ctx) => {
    // const res = response()
    const res = await getRes(response, ctx) // 模拟网络请求的加载状态,1s
    ctx.body = res // 输入结果
  })
})

app.use(router.routes())
app.listen(3001) // port 端口

接口列表question.js代码如下:

import Mock from 'mockjs'

const random = Mock.Random

export default [
  {
    url: '/api/question/:id',
    method: 'get',
    response: (ctx) => {
      console.log('ctx', ctx.url)
      return {
        code: 0,
        msg: 'success',
        data: {
          id: random.id(),
          title: random.csentence(10, 20),
          options: random.shuffle(['A', 'B', 'C', 'D']),
          image: random.image('125x125', '#4A7BF7', '#fff', 'png', 'question'),
        },
      }
    },
  },
  {
    url: '/api/question/test',
    method: 'post',
    response: (ctx) => {
      return {
        code: 0,
        msg: 'success',
        data: {
          id: random.id(),
        },
      }
    },
  },
]

如果有多个接口文件可以收敛到一个index.js文件中:

import question from './question.js'

const mockList = [...question]

export default mockList

启动后台服务npm run dev,前端代码到3001这个服务:

 server: {
    // port: 3000, // 开发服务器端口号,默认 5173
    open: true, // 启动后自动打开浏览器
    host: '0.0.0.0', // 允许外部设备访问(如手机连同一WiFi访问电脑IP)
    strictPort: true, // 端口被占用时,是否强制退出(避免自动切换端口)
    
    // 2. 跨域代理(解决开发环境跨域问题)
    proxy: {
      // 示例1:匹配以 /api 开头的请求,转发到目标服务器
      '/api': {
        target: 'http://localhost:3001', // 后端接口地址(真实服务器地址)
        changeOrigin: true, // 开启跨域(修改请求头中的 Origin 为 target 地址)
        // rewrite: (path) => path.replace(/^\/api/, ''), // 重写路径(去掉 /api 前缀)
        // 示例:请求 /api/user → 转发到 http://localhost:8080/user
      },
      
      // 示例2:匹配以 /mock 开头的请求,转发到 Mock 服务
      // '/mock': {
      //   target: 'http://localhost:3001',
      //   changeOrigin: true,
      // },
    }
  },