以前有寫過一篇 本地化接口模擬、先後端並行開發,講到過本地接口模擬,但不太細緻。此次細細的說說本地接口模擬。css
本地接口模擬最大的好處就是可以使先後端項目解耦,前端更專一於開發,減小線上調試,以此提高開發效率。html
本地接口模擬通常分爲工具層面和代碼層面。前端
就工具層面而言,通常是由項目的構建工具提供的功能。好比,當咱們用 webpack-dev-server、webpack-dev-middleware + browser-sync 等工具時,就能夠向工具裏添加本地接口模擬功能。node
注:這裏不講解工具如webpack-dev-server
、webpack-dev-middleware
+browser-sync
等的用法,若有須要,能夠本身去了解一下
下面以 webpack-dev-server
爲例進行講解,其餘工具相似。webpack
最簡單的,咱們能夠用靜態 json
文件作本地接口模擬功能。git
|-- / # 項目根目錄 |-- mock/ # 模擬數據目錄(能夠自定義) |-- 1.json |-- 2.json |-- ... |-- ... # 其餘文件
而後用 webpack-dev-server
以項目根目錄爲基地址來開啓本地開發調試,在頁面中就能夠這樣訪問:github
fetch('/mock/1.json'); // 訪問 1.json fetch('/mock/2.json'); // 訪問 2.json # 能夠將 fetch 換成其餘請求方式
這種方式能夠訪問項目中全部的文件,不光是 json
文件,其餘的如 html
、js
、css
之類的文本文件、如圖片之類的二進制文件也能夠訪問。另外,只要文件有更新,刷新瀏覽器頁面就能夠從新獲取新的文件,沒有緩存。web
由於本地接口模擬功能主要是針對的返回值爲 json
格式的異步請求,因此這種方式主要用 json
文件。ajax
這種方式是最簡單、快捷、使用難度最低的方式。json
使用靜態文件作本地接口模擬功能主要存在如下的一些問題:
get
方法訪問因此,多數狀況下,都會採用動態註冊接口的方式作本地接口模擬功能。
這種方式是用 js
文件編寫一系列的 路由 => 響應
映射,而後動態的把定義好的接口註冊到工具實例中。
目錄結構:
|-- / # 項目根目錄 |-- mock/ # 模擬數據目錄(能夠自定義) |-- user.js |-- home.js |-- ... |-- ... # 其餘文件
示例 mock
文件的寫法(能夠自定規範,下面只是演示):
# mock/user.js module.exports = { 'GET /user/profile': { ... }, // 直接返回一個對象 'POST /user/update': (req, res) => { ... }, // 根據 `req, res` 的自定義響應 ... }; # mock/home.js const mockjs = require('mockjs'); module.exports = { 'GET /home/list': mockjs.mock({ // 用 mockjs 輔助生成假數據 'list|1-10': [{ 'id|+1': 1 }], }), };
注:
webpack-dev-server
的相關配置:
# webpack.config.js const beforeDevServer = app => { // 在這裏讀取 mock 目錄下的全部文件,按照必定的規範和格式,載入動態接口 // 好比: app.get('/user/profile', function(req, res) { res.json({ ... }); // 返回文件中定義的 `GET /user/profile` 的值 }); app.post('/user/update', function(req, res) { handle(req, res); // handle:文件中定義的 `POST /user/update` 的自定義處理函數 }); ... }; module.exports = { //... devServer: { before: beforeDevServer, } };
而後用 webpack-dev-server
開啓本地開發調試,在頁面中就能夠這樣訪問:
fetch('/user/profile'); // 訪問 /user/profile fetch('/user/update', {method: 'post', body: { ... }}); // 訪問 /user/update fetch('/home/list'); // 訪問 /home/list # 能夠將 fetch 換成其餘請求方式
通常來講,咱們還會用上 chokidar 來監聽 mock
目錄下的文件變更,來更新路由及其響應,以此可以作到每次訪問到的都是最新的資源(由於 node
針對某個模塊只會加載一次)。
const chokidar = require('chokidar'); const watcher = chokidar.watch('./mock'); watcher.on('change', path => { // 先清除模塊緩存,保證加載最新的資源 if (require.cache[path]) delete require.cache[path]; const mapObj = require(path); // 接下來把映射對象 mapObj 從新映射到 app 中 ... });
這種方式比較複雜,尤爲是對項目搭建者要求比較高,須要對相關工具備深刻的瞭解,好在社區已經有封裝好的工具:roadhog。
但這種方式對使用者是很棒的,由於可以徹底模擬服務器接口,包括接口名、HTTP 方法、參數、返回值等,因此一樣的代碼既能夠在本地運行,也能夠在服務器上運行。
因此,這也是比較推薦的方式。
注:上面的代碼只是演示構建過程,並不保證能夠運行
這種方式是把本地模擬文件寫在另外一個單獨項目裏,而後使用使用代理的方式,訪問模擬接口。
mock
項目(以 koa 爲例):
const Koa = require('koa'); const Router = require('koa-router'); const app = new Koa(); const router = new Router(); router.get('/api/user/profile', (ctx, next) => { ctx.body = { ... }; }); router.post('/api/user/update', (ctx, next) => { // ... }); app .use(router.routes()) .use(router.allowedMethods()); app.listen(3000);
app
應用項目:
webpack-dev-server
的相關配置:
# webpack.config.js module.exports = { //... devServer: { proxy: { '/api': 'http://localhost:3000' // 把全部 `/api` 開頭的接口都代理到 `mock` 項目中 } } };
而後用 webpack-dev-server
開啓本地開發調試,在頁面中就能夠這樣訪問:
fetch('/api/user/profile'); // 訪問 mock 項目的 /api/user/profile fetch('/api/user/update', {method: 'post', body: { ... }}); // 訪問 mock 項目的 /api/user/update # 能夠將 fetch 換成其餘請求方式
通常來講,咱們還會用上 nodemon 來監聽 mock
項目中的文件變更,自動重啓 mock
應用程序,以此可以作到每次訪問到的都是最新的資源(由於 node
針對某個模塊只會加載一次)。
nodemon app.js
這種方式能夠統一管理多個項目的數據模擬文件,多個項目能夠共享一些模擬數據。
有些時候,當咱們在產品環境的時候(在線上)也可能想用模擬數據(好比APP、微信小程序、用於演示的 web 應用等),或者須要一個線上的地方來統一管理模擬數據時,就須要線上接口模擬了。
線上接口模擬擁有完備的 UI 操做界面,能夠添加多個用戶、多個團隊、多個倉庫,能夠生成爲每個請求參數添加類型限定、描述,爲響應數據字段添加描述等。
由於是在線上的模擬數據,因此在任何地方均可用,不論是本地開發,仍是線上調試、演示,都是可用的。
比較有名的線上接口模擬工具備:
環境需求:Node.js (>= v8.9) & MongoDB (>= v3.4) & Redis(>= v4.0)
安裝步驟請參考官方的文檔 easy-mock#quick-start
easy-mock
主要提供瞭如下的一些功能:
支持 Swagger | OpenAPI Specification (1.2 & 2.0 & 3.0)
環境需求:Node.js (>= v8.9) & MySQL (>= v5.7) & Redis(>= v4.0)
RAP 目前有兩個版本,第一個版本的 RAP 已經被官方廢棄了,建議用第二個版本。
RAP2 分紅了兩個包:
RAP2 的安裝步驟要麻煩一些,rap2-delos
能夠參考官方文檔 rap2-delos#部署、非官方rap2-delos部署文檔,rap2-dolores
能夠參考官方文檔 rap2-dolores#deployment-部署。
RAP2 提供了與 easy-mock
相似的功能,但比 easy-mock
要更強大一些,固然也要複雜一些,好比:
headers
、query params
、body params
RAP2 比 easy-mock
要更強大一些,但也要複雜一些,因此追求功能完備的能夠用 RAP2,追求簡單快捷的能夠用 easy-mock
。
從上面能夠看出,除了第二種方式 動態註冊接口
以外,其餘的方式都不能作到徹底模擬服務器環境,至少服務器接口地址與本地模擬地址不同,這就有一個問題:每次上線前都得改爲服務器地址。
另外,前端與後端對接的過程當中也老是不免會遇到一些問題:
page
、從 1 開始,後端定的 pageNum
、從 0 開始一種好的、解決這些問題的方式是對應用進行分層、把異步請求進行隔離封裝。
我通常會用 see-fetch、see-ajax 對異步請求進行隔離封裝。
注:see-fetch 是對 window.fetch
的封裝,see-ajax 是對 XMLHttpRequest
對象的封裝。
能夠在代碼中設置多個內部環境,而後針對不一樣的外部環境設置不一樣的內部環境(如:本地環境、線上環境等),這樣就能夠作到不改代碼,只改一個環境值。
若是搭配 define-plugin,連環境值都不須要改,直接由 define-plugin
在運行的過程當中指定。
import seeFetch from 'see-fetch'; seeFetch.setEnv(0/1/2/3); seeFetch.setEnv(__SEE_ENV__); // __SEE_ENV__ 由 define-plugin 運行中指定
配置一個異步請求:
seeFetch.config(name, { // 定義一個名爲 name 的異步請求(下面的配置能夠是多環境,每一個環境能夠設置不一樣的值) method, // 當前請求使用什麼 http 方法 stringify, settings, url, // 當前請求 url 地址 req, // 請求參數鍵名的映射,好比 `page => pageNum` pre, // 操做請求參數,好比 page 從 1 開始改爲從 0 開始 refactor, // 重構響應數據,如字段重命名、類型轉換等 post, // 操做響應數據,以把數據轉換成本身所須要的數據 implement, // 自定義請求,好比後端返回一個模板字符串,而不是接口 });
發起訪問:
seeFetch(name, params).then(result => { // 這裏的 result 是通過格式化後的最終數據 });
從上面能夠看出:一個請求的不肯定性都被封裝到了配置中,不論是接口地址更新、前端請求參數與後端不一致、後端響應數據與前端所需的差別很大等,均可以在配置中進行操做,而絲絕不須要改其餘地方的代碼。
這樣,若是後端接口有什麼改動的,只須要找到配置文件進行更新,而不用在項目中找哪裏使用了這個接口。
如此,既能很好的使用本地數據模擬,也能夠從容應對後端接口的改動,便能事半功倍。
更多博客,查看 https://github.com/senntyou/blogs
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)