在前后端的協作過程中,通常都是並行開發的狀態,那么在后端接口還沒有開發完畢時,前端的業務邏輯工作就很難展開。因此也就有很多模擬接口數據的方式,這些方式各有個的優缺點:
- 直接在代碼中模擬接口數據:侵入業務邏輯,在后期需要刪除這些模擬數據;
- fiddler 替換文件:頁面接口比較多時,需要替換的文件比較多;
- fs 模塊讀取 json 文件:若是長列表的話,需要造的數據很多;
- mockjs:避免上述方式的缺點,但無法校驗參數是否缺失;
- service worker:基於 service worker 可以攔截前端的請求,並構建假數據返回,但無法攔截 node 端發起的請求;
方式 | 校驗參數合法性 | 切換環境方便 | 前后端請求均可 | 不修改業務代碼 | 模擬數據方便 |
---|---|---|---|---|---|
直接在業務代碼 中寫接口數據 |
|||||
fiddler 替換文件 | yes | ||||
fs 讀取 json 文件 | yes | yes | |||
mockjs | yes | yes | yes | ||
sw | yes |
我們理想的狀態是:
- 提前校驗請求接口中參數的合法性,是否缺失某些參數等;
- 切換環境方便,既可以使用模擬數據,也可以使用測試環境中的數據,同時也可以用正式環境中的數據進行檢驗;
- 可以攔截前后端均發起的請求,並盡量少的修改業務代碼;
- 生成的模擬數據方便,假如接口中要返回前 1000 名用戶的數據,總不能在 json 文件中寫 1000 條數據;
上面的這幾種方式,在我們搶金達人項目中,均不適用,或者對原有邏輯改動太大,或者使用起來不方便。這里我根據我們項目的需要,基於 mockjs 並與 express 的結合,實現了一套模擬數據的方法。
1. 模擬數據並校驗參數的合法性
把接口的數據全部寫在 json 文件,然后通過 fs 模塊進行讀取的這種方式,在構造大量數據時非常不方便。因此我們基於 mockjs 來實現模擬的數據,幾行代碼就能實現排行榜等大量的模擬數據,同時,也可以模擬一些稍微極端的情況,例如用戶的昵稱長度過長等,這些數據在測試環境一般很少能遇到,或者在后端接口模擬的成本也會比較高。
// rank-person.js
Mock.mock({
"rank|1000": [
{
"no|+1": 1,
uin: () => Mock.Random.string(32),
nick: () => Mock.Random.string(1, 20),
face: () => faces[Mock.Random.integer(0, 3)],
region: "INVALID",
title: "初露鋒芒",
level: () => Mock.Random.integer(1, 20),
score: () => Mock.Random.integer(1, 2000),
winPercent: 86
}
]
});
但是,純基於 mockjs 數據的方式,我們無法提現獲知接口參數的異常。當我們在匹配到接口請求后就返回數據,會降低對參數的敏感度。這里,我對配置文件進行改造,當前接口中需要的參數提前設定好,類似於 jQuery.validate 中的設定。
這里我們的排行榜接口里有個last
參數,0 表示是本周的數據,1 表示是上周的數據:
module.exports = {
params: {
last: {
required: true, // 是否必須
type: "number", // 參數的類型
defaults: 0, // 默認值
min: 0, // 最小值
max: 1 // 最大值等
}
}
};
當 mock server 接收到請求后,會先校驗參數的合法性,若參數不合法直接返回。其實我們排行榜的 last 參數不是必傳項,不傳時即默認是 0,但我們在這里測試時改為必傳,只要不傳 last 參數即為參數不合法:
當參數校驗通過后,才會返回后面模擬的數據:
2. 數據環境的切換
我們在上面的圖中可以看到,當 mock 字段為"mock"時,讀取模擬的數據,是不是一定要加一個 mock="mock"的參數才能去讀模擬的數據呢?
這個要看咱們項目到什么狀態了,當項目還在前提開發階段時,大部分接口都還沒有完成,這里我們可以將接口默認指向到模擬數據,mock="testing"時就指向到測試環境的接口;當項目已穩定上線了,在迭代更新的階段時,大部分接口已經存在和完善了,只有部分的接口需要進行模擬調試,這時我們用mock="mock"
參數來指向到模擬數據。
這里我使用 mock 參數控制,還有一個原因是,前端項目會根據當前是哪個環境,自動請求對應環境的接口,所有的接口均是統一控制的:
如上圖所示,如果我們要通過環境變量控制 api 字段,最終強行修改某個接口變相請求其他環境的數據,會造成其他接口數據的混亂,最終可能的結果是頁面整體會掛掉。我們在使用mock
字段作為參數時,侵入的業務邏輯會維持到最小的程度,同時,也能把前后端的協作,縮小到單個接口的粒度。而且,mock 參數也只會在 local 環境生效,即使忘了去掉這個參數,也不會對線上環境造成影響。
再有,當我們前端邏輯發生變化后,除了使用模擬數據來檢驗,如果線上有接口,我們也想用線上的數據檢驗一下。可以,當傳入mock="production"
的參數時,mockServer 會讀取線上接口的數據並返回。
3. mock 與 json
有的同學會創建一個 json 文件,把接口需要的數據都放到這個 json 文件里,然后使用fs.readFile
來讀取。這樣倒是也可以,但是當接口數據多的時候怎么辦,例如有一個排行榜是要輸出前 100 名、前 1000 名用戶的數據,總不能復制出 1000 份用戶的數據吧。
在當前最好的方式,就是使用 mockjs 的工具來生成數據了,可以任意的隨機,也可以生成任意個數的數組數據。我們這里把對參數的校驗和 mock 生成的模擬數據放到一起:
module.exports = {
params: {
last: {
required: true, // 是否必須
type: "number", // 參數的類型
defaults: 0, // 默認值
min: 0, // 最小值
max: 1 // 最大值等
}
},
result: {
code: 0,
msg: "success",
"x-from": "mock",
data: Mock.mock({
"rank|100": [
{
"no|+1": 1,
uin: () => Mock.Random.string(32),
nick: () => Mock.Random.string(1, 20),
face: () => faces[Mock.Random.integer(0, 3)],
region: "INVALID",
title: "初露鋒芒",
level: () => Mock.Random.integer(1, 20),
score: () => Mock.Random.integer(1, 2000),
winPercent: 86
}
]
})
}
};
params 字段表示必須的參數,result 表示要返回的數據,data 中即為我們偽造的數據。
4. 實時修改模擬數據
我們可以在頁面中直接實時修改數據,然后進行保存,自動刷新頁面后,就會得到剛才想要的結果。
我們在頁面中 mock 的接口都會在調試面板中展出來,默認調試面板時關閉的,開發者在點擊頁面右下角的灰色按鈕后,可以呼起調試面板。修改里面的數據保存后,就實時看到剛才的效果。
5. 總結
在開發和后期維護的過程中,前端會經常遇到模擬接口數據的情況,要么是接口還沒有開發完成,要么是接口不太好返回我們想要的狀態。我也是在對比多種方案后,選擇了適合當前項目的一種前后端協作方案。
歡迎關注我的公眾號,多多交流: