欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前端 mock 数据

程序员文章站 2022-03-18 17:03:34
...

前端 mock 数据

Easy Mock

由于easy mock线上服务基本打不开的情况,所以有能力的还是做一下本地部署(参考)
在easymock创建一个项目,并将项目的 Base URL 配置到axios的 baseURL,easymock不需要解决跨域的问题。前端 mock 数据

Yapi

公司内部的话也可以做一下内网部署
用法和easymock差不多,将yapi内项目的mock地址配置到axios的baseURL,也不需要解决跨域的问题

vue cli3 配置本地 mock 数据

通过webpack的 devServer.before 来实现

module.exports = {
  //...
  devServer: {
    before: function(app, server) {
      app.get('/some/path', function(req, res) {
        res.json({ custom: 'response' });
      });
    }
  }
};

如果mock数据过多,我们可以单独建一个文件夹用来存放:
mock/login.js:

const loginMock = [
    {
        type: 'post',
        url: '/api/loginPost',
        res: function (req, res, next) {
            console.log(req.body)
            res.json({ "data": "post" })
        }
    },
    {
        type: 'get',
        url: '/api/loginGet',
        res: function (req, res, next) {
            console.log(req.query)
            res.json({ "data": "get" })
        }
    }
]

module.exports = loginMock

mock/index.js:

module.exports = app => {
    // 使用Express中间件body-parser来解析请求体
    const bodyParser = require('body-parser')
    // 解析 application/json
    app.use(bodyParser.json())
    // 解析 application/x-www-form-urlencoded
    app.use(bodyParser.urlencoded({
        extended: true
    }))
    // 引入mock数据
    const loginMock = require('./login.js')
    const mocks = [
        ...loginMock,
        ...chartMock
    ]

    for (const mock of mocks) {
        app[mock.type](mock.url, mock.res)
    }
}

vue.config.js:

module.exports = {
    ...
    devServer: {
        ...
        // 在服务器内部的所有其他中间件之前执行定制中间件
        before: require('./mock/index.js'),
    }
}

按这样配置完后,基本就完成了本地的数据mock。但有一点不足的就是不能够热更新。每当我们重新修改mock数据,需要重新启动服务才能看到最新的mock数据。
解决这个问题我们可以通过chokidar插件来监控mock文件夹的变化,在发生变化时会清除之前注册的mock-api接口,重新动态挂载新的接口,从而支持热更新。
修改mock/index.js:

const bodyParser = require('body-parser') // 使用Express中间件body-parser来解析请求体
const chokidar = require('chokidar') // 文件夹监控
const path = require('path')

const mockDir = path.join(process.cwd(), 'mock') // 获取文件夹路径

function registerRoutes(app) {
    let mockLastIndex

    const baseMock = require('./base.js')
    const chartMock = require('./chart.js')
    const mocks = [
        ...baseMock,
        ...chartMock
    ]
    for (const mock of mocks) {
        app[mock.type](mock.url, mock.res) // 在express中注册路由
        mockLastIndex = app._router.stack.length // 获取所有已注册路由的长度
    }

    const mockRoutesLength = Object.keys(mocks).length // 获取所有mock数据的长度
    return {
        mockRoutesLength: mockRoutesLength,
        mockStartIndex: mockLastIndex - mockRoutesLength
    }
}
// nodejs清除require缓存 参考:https://blog.hellozwh.com/?post=433
function unregisterRoutes() {
    Object.keys(require.cache).forEach(i => {
        if (i.includes(mockDir)) {
            delete require.cache[require.resolve(i)] // require.resolve 相当于把相对路径转化成绝对路径,避免了自己手写的绝对路径跟cache里的key不一致的问题
        }
    })
}

module.exports = app => {
    // 解析 application/json
    app.use(bodyParser.json())
    // 解析 application/x-www-form-urlencoded
    app.use(bodyParser.urlencoded({
        extended: true
    }))

    const mockRoutes = registerRoutes(app)
    var mockRoutesLength = mockRoutes.mockRoutesLength
    var mockStartIndex = mockRoutes.mockStartIndex

    chokidar.watch(mockDir, { // 监控当前目录
        ignored: /index/, // 忽略index.js文件的变更
        ignoreInitial: true // 忽略对增加文件或者增加文件夹而触发事件
    }).on('all', (event, path) => { // 监听除了ready, raw, and error之外所有的事件类型
        if (event === 'change' || event === 'add') { // 文件内容改变或新增文件时触发
            try {
                // 删除已经挂载到express的路由
                app._router.stack.splice(mockStartIndex, mockRoutesLength)

                // clear routes cache
                unregisterRoutes()

                const mockRoutes = registerRoutes(app)
                mockRoutesLength = mockRoutes.mockRoutesLength
                mockStartIndex = mockRoutes.mockStartIndex

                console.log('请求更新!')
            } catch (error) {
                console.log('请求更新出错:', error)
            }
        }
    })
}

用node启动一个本地服务,来实现mock

在项目根目录建一个mockServer.js文件:

let express = require('express') // 引入express
let Mock = require('mockjs') // 引入mock

let app = express() // 实例化express

app.use(function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*')
    res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS')
    res.header('Access-Control-Allow-Headers', 'X-Requested-With')
    res.header('Access-Control-Allow-Headers', 'Content-Type')
    next()
})
// mock接口示例
app.post('/api/loginPost', function (req, res) {
    res.json(Mock.mock({
        'status': 200,
        'data|1-9': [{
            'key|+1': 1,
            'mockTitle|1': ['肆无忌惮'],
            'mockContent|1': ['角色精湛主题略荒诞', '理由太短 是让人不安', '疑信参半 却无比期盼', '你的惯犯 圆满', '别让纠缠 显得 孤单'],
            'mockAction|1': ['下载', '试听', '喜欢']
        }]
    }))
})

// 实际项目中肯定有很多mock接口,可以分类目建立,然后引入
const loginMock = require('./mock/login.js')
const chartMock = require('./mock/chart.js')
const mocks = [
    ...loginMock,
    ...chartMock
]
// 挂载这些接口
for (const mock of mocks) {
    app[mock.type](mock.url, mock.res)
}
// 启用一个端口并监听。注意不能和项目一个端口,会把项目停掉
app.listen('3001', () => {
    console.log('监听端口 3001')
})

在vue.config.js里配置跨域代理:

module.exports = {
    ...
    devServer: {
        ...
        // 跨域代理
        proxy: {
            '/web': {
                target: 'http://localhost:3001', // mockServer监听的端口号
                ws: false,
                changeOrigin: true
            }
        }
    }
}

在package.json里配置启动命令:

"scripts": {
    "mock": "node ./mockServer"
},

yarn mock启动mock服务

相关标签: mock