mockjs 使用以及反向校驗


一、背景

  1. 前端開發需要依賴后端接口
  2. 后端接口輸出慢、接口規范隨時可能會變,而前端毫無感知
  3. 前端需要自己 mock 假數據 json 文件
  4. 假數據 json 數據內容是靜態的,測試不同返回情況需要修改 json 文件
    ...

因此我們需要一種可以幫我們構造數據的工具,並解決以上的若干痛點
mock.js 是一個不錯的工具

本文 github mock 使用完整例子

二、安裝與使用

安裝

yarn add mockjs -D

使用

// 使用 Mock
import Mock from 'mockjs'
Mock.mock('http://test.com/getjson.json', 'get', {
    // 屬性 list 的值是一個數組,其中含有 1 到 10 個元素
    'list|1-10': [{
        // 屬性 id 是一個自增數,起始值為 1,每次增 1
        'id|+1': 1
    }]
})

三、常用構造指令

以下示例可以在
http://mockjs.com/examples.html
網頁上打開控制台

使用Mock.mock({示例代碼})查看生成的結果

1、時間戳:

'name|1564577990837-2564577990837': 0

2、id

'name|1-123456789': 0 // 6174430

3、指定長度范圍,隨機中文字符

name: '@cword(2, 6)' // 價親三身千然

'name|2-6': '@cword(1)'

4、指定長度范圍,隨機英文字符

name: '@word(1, 10)' // yyuj

'name|1-10': '@word(1)'

5、http url

name: '@url(http)' // "http://djldfusj.in/ccnknb"

6、生成布爾值,false/true各一半幾率

'name|1': true

7、包含小數數字

'name|1-100.3': 1 // 63.895

8、隨機選擇數組中的元素

'name|1': ['AMD', ''CMD, 'UMD'] // 隨機出現數組中的元素

9、萬能的正則

(1)時間戳

name: /170\d{10}/ // 1705237332101

(2)小數數字

name: /\d{2}\.\d{3}/ // 78.635

(3)id

name: /\d{1,9}/ // 651866094

(4)英文字符串

name: /\W{1,3}/ // DvX

(5)中文字符串

name: /[\u4e00-\u9fa5]{1,9}/ // 風我齤劉杌菦炧荷岆


四、從零開始完成一個使用例子

#1、創建環境

  1. yarn global add @vue/cli
    1. 安裝 vuecli3.x 環境
  2. vue create mock-demo --- 創建項目 mock-demo
    1. 選擇 default (babel, eslint)
    2. 選擇 Use Yarn
  3. 安裝依賴
    1. 安裝 axios
      1. yarn add axios
    2. 安裝 mockjs
      1. yarn add mockjs -D
  4. 運行項目 yarn serve
    1. 按照命令中顯示的項目地址,用瀏覽器打開

#2、封裝 axios

  1. 在 src 下創建 utils 目錄,在 utils 下創建 fetch.js 文件
// fetch.js
import axios from 'axios'
export default class baseRequest {
    constructor(baseURL) {
        baseURL = baseURL || window.location.origin
        this.$http = axios.create({
            timeout: 30000,
            baseURL
        })
        this.$http.interceptors.request.use(async config => {
            return config
        })
        this.$http.interceptors.response.use(
            ({ data, config }) => {
                if (data.code === 0) {
                    return data
                } else {
                    return Promise.reject(data)
                }
            },
            e => {
                console.log(e, '報錯了')
                return Promise.reject({
                    msg: '網絡開小差了,請稍后重試'
                })
            }
        )
    }
    post(url, params = {}, config = {}) {
        return this.$http.post(url, params, config)
    }
    get(url, params = {}, config = {}) {
        return this.$http.get(url, {
            params,
            ...config
        })
    }
}

#3、封裝 api 接口

  1. 在 src 下創建 service 目錄,在 service 下創建 bilibili-server.js 文件
// bilibili-server.js
// 在本例子中,我們將獲取 bilibili 的最近更新番劇接口作為例子
import fetch from '@/utils/fetch.js'
let axios = new fetch()
export const getLastestAnima = () => {
    return axios.get('/api/timeline_v2_global')
}

#4、調用獲取番劇接口

  1. 在 src 下的 App.vue 文件中,created 生命周期中調用
// App.vue
import HelloWorld from './components/HelloWorld.vue'
import { getLastestAnima } from '@/service/bilibili-server.js'
export default {
    name: 'app',
    components: {
        HelloWorld
    },
    async created() {
        try {
            let data = await getLastestAnima()
            console.log('getLastestAnima:data:>>>', data)
        } catch (error) {
            console.log('getLastestAnima:error:>>>', error)
        }
    }
}

#5、設置代理

  1. 因為跨域限制,所以需要本地設置代理,才能訪問 bilibili 的接口
  2. 在項目根目錄下創建 vue.config.js 文件
// vue.config.js
module.exports = {
    devServer: {
        disableHostCheck: true,
        open: true, // 是否打開頁面
        host: '0.0.0.0',
        port: 80,
        https: false,
        hotOnly: true,
        proxy: {
            '/api': {
                target: 'https://bangumi.bilibili.com',
                changeOrigin: true
            } 
        }
    }
}
  1. 重啟項目,然后打開項目,在瀏覽器控制台可以看到已經將獲取到的數據打印出來了

#6、加入 mockjs

1). 在 src 下 創建 mock 目錄
2). 在 mock 下創建 index.js 文件,用來注冊各個 mock 接口

// /src/mock/index.js
// 使用 Mock
import Mock from 'mockjs'
import modules from './modules'

// 注冊每個 mock api
for (let key in modules) {
    let module = modules[key]
    // console.log('module:>>>', module)
    Mock.mock(...module)
}

3). 在 mock 下創建 modules,用來分類放置各個微服務相對應的 mock 接口

目錄構成

modules
    bilibili-server // 微服務
        get-lastest-anima.js // mock 接口
    index.js // 用來導出每個微服務下的所有 mock 接口
// /src/mock/modules/bilibili-server/get-lastest-anima.js.js

/* eslint-disable no-console */
import { host } from "../../utils/host"
import { formatMockData } from "../../utils/util"
import Mock from "mockjs"
const formatData = formatMockData("", "", "", {
    code: 0,
    'result|0-100': [
        {
            'area|1': ["日本", '美國', '國產'],
            'arealimit|0-923456789': 0,
            'attention|0-923456789': 0,
            'bangumi_id|0-923456789': 0,
            'bgmcount|1': [/\d{1,6}/, 'SP'],
            cover: '@url(http)',
            'danmaku_count|0-923456789': 0,
            'ep_id|-1-923456789': 0,
            'favorites|0-923456789': 0,
            'is_finish|1': [0, 1],
            'lastupdate|0-1966120600': 0,
            'lastupdate_at': '@datetime',
            'new|1': true,
            'play_count|0-923456789': 0,
            pub_time: '@datetime',
            'season_id|0-9123456789': 5978,
            'season_status|0-9123456789': 13,
            'spid|0-9123456789': 0,
            square_cover: '@url(http)',
            title: "@cword(1,20)",
            'viewRank|0-912345678': 0,
            'weekday|1': [0, 1, 2, 3, 4, 5, 6]
        }
    ],
    message: '@cword(1,10)'
})
let url = host + "/api/timeline_v2_global"
let method = "get"
export default [
    url,
    method,
    function(options) {
        console.log("options:>>>", options)
        return Mock.mock(formatData)
    },
    {
        url,
        method,
        formatData
    }
]

// /src/mock/modules/index.js
import getLastestAnima from './bilibili-server/get-lastest-anima'
export default {
    getLastestAnima
}

4). 在 mock 目錄下創建 utils,用來放置工具類

utils
    host.js
    util.js
// /src/mock/utils/host.js
let h = window.location.origin
export const host = h || ''
// /src/mock/utils/util.js
export const formatMockData = (
    mockData = {},
    codeStatus = 0,
    msg = '@cword(1,10)',
    customData
) => {
    if (customData) return customData
    let initFormatObj = {
        code: codeStatus,
        result: mockData,
        msg: msg
    }
    return initFormatObj
}

// 組合數據
export const comp = function(value) {
    return [null, '', value]
}

5). 最后在項目的 main.js 中引入 mock 入口文件

// /src/main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

// 開發環境使用,生產環境注釋
import '@/mock'

new Vue({
  render: h => h(App),
}).$mount('#app')

#7、反向校驗后端 api 返回數據

1). 在 mock 目錄下的 utils 目錄下 創建 proxy-valid.js 文件

// 反向校驗后端 api 配置文件
/* eslint-disable no-console */
import Mock from 'mockjs'
import modules from '../modules'

export default function(url, method, data) {
    Object.keys(modules).forEach(key => {
        let ele = modules[key][3]
        if (ele && ele.url === url && ele.method === method) {
            let validResult = Mock.valid(ele.formatData, data)
            // 驗證通過,則不用輸出信息
            if (validResult && validResult.length === 0) {
                return
            }
            console.group(url.replace(/http:\/\//, ''))
            console.log('valid response data :>>> url: ', url)
            console.log('valid response data :>>> validMsg: ', validResult)
            console.groupEnd()
        }
    })
}

2). 修改 /src/utils/fetch.js

/* eslint-disable no-console */
import axios from 'axios'
// 開發環境使用,打包前注意要注釋
import proxyValid from '@/mock/utils/proxy-valid.js'
export default class baseRequest {
    constructor(baseURL) {
        baseURL = baseURL || window.location.origin
        this.$http = axios.create({
            timeout: 30000,
            baseURL
        })
        this.$http.interceptors.request.use(async config => {
            return config
        })
        this.$http.interceptors.response.use(
            ({ data, config }) => {
                // 開發環境需要,生產環境需要注釋
                proxyValid(config.url, config.method, data)
                if (data.code === 0) {
                    return data
                } else {
                    return Promise.reject(data)
                }
            },
            e => {
                console.log(e, '報錯了')
                return Promise.reject({
                    msg: '網絡開小差了,請稍后重試'
                })
            }
        )
    }
    post(url, params = {}, config = {}) {
        return this.$http.post(url, params, config)
    }
    get(url, params = {}, config = {}) {
        return this.$http.get(url, {
            params,
            ...config
        })
    }
}

此時,一個完整的 數據 mock 和反向校驗 demo 就完成了


五、根據請求的數據修改 mock 已經生成的數據

根據前端請求的參數,修改 mock 渲染好的數據,然后返回給前端
這樣實現根據不同的參數返回:
1、成功狀態
2、失敗狀態
3、其他異常狀態

/* eslint-disable no-console */
import { host } from "../../utils/host"
import { formatMockData } from "../../utils/util"
import Mock from "mockjs"
const formatData = formatMockData("", "", "", {
    code: 0,
    'result|0-100': [
        {
            'area|1': ["日本", '美國', '國產'],
            'arealimit|0-923456789': 0,
            'attention|0-923456789': 0,
            'bangumi_id|0-923456789': 0,
            'bgmcount|1': [/\d{1,6}/, 'SP'],
            cover: '@url(http)',
            'danmaku_count|0-923456789': 0,
            'ep_id|-1-923456789': 0,
            'favorites|0-923456789': 0,
            'is_finish|1': [0, 1],
            'lastupdate|0-1966120600': 0,
            'lastupdate_at': '@datetime', // bilibili 這邊返回的接口中,有時候這個屬性會少,導致反向校驗出錯
            'new|1': true,
            'play_count|0-923456789': 0,
            pub_time: '@datetime',
            'season_id|0-9123456789': 5978,
            'season_status|0-9123456789': 13,
            'spid|0-9123456789': 0,
            square_cover: '@url(http)',
            title: "@cword(1,20)",
            'viewRank|0-912345678': 0,
            'weekday|1': [0, 1, 2, 3, 4, 5, 6]
        }
    ],
    message: '@cword(1,10)'
})
let url = host + "/api/timeline_v2_global"
let method = "get"
export default [
    url,
    method,
    function(options) {
        console.log("options:>>>", options)
        // options:
            // body: null
            // type: "GET"
            // url: "http://localhost:1385/api/timeline_v2_global"
        // 此處 body 就是前端請求的參數集合
        // 在此處可以根據 body 里面的參數,來修改 Mock.mock(formatData) 渲染后的數據
        // 比如 修改 code = 404 
        // 設置各種成功、異常狀態
        return Mock.mock(formatData)
    },
    {
        url,
        method,
        formatData
    }
]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM