mock翻譯過來是模仿的意思,Server是服務器。粗暴點直譯就是模仿服務器。javascript
經過閱讀本文,你將對Mock的使用有必定的瞭解,對先後端分離的概念有了更深一步的認識,對Koa的使用有必定的瞭解。本文先從背景出發去拋出「咱們爲何要用Mock?」的靈魂拷問,緊接着咱們經過Mock在先後端的使用來進行實戰落地,最後咱們再總結回顧,展望高配版的Mock Server。html
本文不會像唸經同樣把官方文檔的API抄一遍告訴讀者這個怎麼用,那個怎麼用,更多地是提供一個思路或者想法以及項目的落地帶着你們學習Mock的使用。由於我堅信「官方文檔始終是最權威的文檔。」,因此「Do Not Repeat"原則,不要作唸經這種事情,由於官方文檔寫的已經很詳細了。還有就是有些項目API茫茫多,若是都全面地寫一遍,累死啦,這個是官方文檔乾的事情。技術只有轉換成生產力,纔是程序員的賺錢的核心競爭力,勸君莫惜金縷衣,勸君惜取少年時。前端
這裏簡單地羅列下Mock的總體知識,讀者後續能夠根據這個大綱有選擇地去看。java
APInode
據不徹底統計,Mock支持18種數據定義,172種數據定義寫法。具體的參見:http://mockjs.com/examples.htmlgit
傳統的非先後端分離的項目,後端老哥除了要作對接服務器數據庫相關的工做,還要搞前端頁面,太多太累太雜了。隨着時代的發展、人類社會的進步,編程技術的更新迭代,慢慢地開始有了專職的前端程序員和後端程序員等等,項目愈來愈複雜,先後端的要求度逐步提升,尤爲是Node.JS技術的迅猛發展,十一年彈指一揮間,在npm、github各種庫和項目如雨後春筍般蹭蹭蹭地雄起,給開發者提供了不少解決方案,這也使得先後端分離成爲可能。事物存在的便是合理的,但咱們也要辯證地去看待這個事物。先後端分離項目的落地比先後端不分離的落地增長了開發人員對接溝通的成本,在某些場景下,前端開發會受限制於後端開發,接地氣地說就是後端接口沒寫好沒提供前端可能就無從下手了,爲了解決這個問題,咱們須要進行相關地Mock,來模擬後端返回的數據也好或者後端的接口也好,總之,咱們須要一個Mock Server。github
# npm安裝 npm i mockjs -D
去Bootcdn引入相關的腳本,地址:https://www.bootcdn.cn/Mock.js/, 形如ajax
<!-- 生產環境 --> <script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/0.1.1/mock-min.js"></script> <!-- 開發環境 --> <script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/0.1.1/mock.js"></script>
import Mock from 'mockjs';
const Mock = require('mockjs');
rurl
的 Ajax 請求時,將根據數據模板 template
生成模擬數據,並做爲響應數據返回rtype
的 Ajax 請求時,將根據數據模板 template
生成模擬數據,並做爲響應數據返回。rurl
的 Ajax 請求時,函數 function(options)
將被執行,並把執行結果做爲響應數據返回。具體的參見:https://github.com/ataola/node-blacksmith/tree/master/code/framework/koa-study/koa-mock/staticshell
在前面咱們瞭解了Mock在前端的使用,咱們還須要思考這麼一個問題,模擬也要模擬的深沉一點,也就是像一點,前面的寫法足以應付大部分場景,可是有的時候咱們須要擬合後端的服務,好比網絡的延遲、跨域、性能等等問題,咱們更加指望是搞一個服務器,模擬後端的一些API行爲。做爲前端選手,Javascript自然會,既然用了Javascript的基礎,咱們天然而然地會想到用Node.JS去搭建一個後端服務。
筆者這裏使用Koa搭建一個後端服務,主體代碼以下:
const http = require('http'); const Koa = require('koa'); const app = new Koa(); const logger = require('koa-logger'); const bodyparser = require('koa-bodyparser') const onerror = require('koa-onerror'); const errorMiddleware = require('./middlewares/error'); const ipBlackListMiddleware = require('./middlewares/ip_blacklist'); const { host, port, ip_blacklist } = require('./config/index'); // import routes const IndexRoute = require('./routes/index'); const MockRoute = require('./routes/mock'); // error handler onerror(app); app.use(ipBlackListMiddleware(ip_blacklist)); // when post, use x-www-form-urlencoded or json app.use(bodyparser({ enableTypes:['json', 'form', 'text'] })); // use koa-logger app.use(logger()); // routes middleware app.use(IndexRoute.routes(), IndexRoute.allowedMethods()); app.use(MockRoute.routes(), MockRoute.allowedMethods()); // error-handling app.on('error', errorMiddleware()); // create a server const server = http.createServer(app.callback()); // listen port server.listen(port, host, () => { console.log(`mock server is running in http://${host}:${port}`); }); module.exports = server;
大體的一個流程是,導入了項目的npm包,中間件、路由,初始化Koa實例,調用了相關的中間件和路由,最後監聽服務器端口。
若是對Mock不是很熟,咱們大體會這樣作,把相關返回信息寫在JSON文件中或者js文件中,而後經過引入或者讀取相關文件來作這件事
{ "data": { "name": "zjt", "age": 23 }, "success": true, "code": 1, "message": "獲取用戶信息成功" }
定義完返回格式後,咱們能夠經過commonJS的語法用require引入,也能夠經過內置的fs模塊的讀取文件的函數去讀取這部分JSON的內容,而後把它銜接到相關路由上面構成一個Mock API。
形如:
const user_json = require('../mock/json/user.json'); router.get('/json/user', async ctx => { ctx.body = user_json; });
這裏仿照樓上也是相似的。
const user_js = require('../mock/js/user'); router.get('/js/user', async ctx => { ctx.body = user_js; });
這樣作的話,可以知足咱們平常生活中的大部分開發,可是太費勁了,每次咱們都要寫這麼多一坨坨的JSON或者JS文件,咱們但願這個Mock Server可以更加智能一點,本着」簡單、短小精悍「的原則去思考,咱們天然而然會想到引入Mock.JS去作這件事情。
這裏咱們思考一個例子,最多見的就以返回用戶身份信息爲例。咱們就意思下,羅列一下用戶常見的屬性,好比說用戶id、用戶名字、用戶暱稱、用戶生日、用戶地址、用戶郵箱、能量值(也能夠理解成陽光值)、建立時間、更新時間
const Mock = require('mockjs'); const data = Mock.mock({ 'data|4-10': [{ 'id': '@id', 'name': '@cname', 'nickname|1': ['沉魚', '落雁', '閉月', '羞花'], 'birthday': '@date', 'address': '@county(true)', 'email': '@email', 'power|1-5': '★', 'created': '@now', 'updated': '@now' }] }); module.exports = { data, success: true, code: 1, message: '獲取用戶數據成功' };
簡單的講下
'data|4-10'[{}]
: 表示有個數組data,它裏面至少有4個對象,上限10個對象@id
: 表示數據佔位符定義,一個id@name
: 表示數據佔位符定義,一個name'nickname|1': ['沉魚', '落雁', '閉月', '羞花'],
: 表示nickname爲一個字符串,值爲沉魚落雁閉月羞花中的一個。@date
: 表示數據佔位符定義,一個形如1997-06-13
這樣的日期@county(true)
: 表示數據佔位符定義, 一個形如江蘇省 淮安市 金湖縣
這樣的地址@email
: 表示數據佔位符定義,一個郵箱'power|1-5': '★'
: 表示有個字符串,值爲最少1顆星,最多5顆星,其實這個作外賣五分好評或者老師課程評價這種數據展現應景一些@now
: 表示當前時間。最後的效果就是
這裏咱們能夠看出Mock的結果仍是有些不可控性,好比我就想讓它顯示正常點的郵箱、可讀性強一點的段落文字,這裏就要用到文中的沉魚落雁閉月羞花的例子,咱們事先準備好部分結果集讓其Mock數據。
這裏我是結合Mocha(測試框架)、chai(斷言)、supertest(模擬http測試)對Mock的API進行了一個單元測試,具體的以下:
const app = require('../server'); const supertest = require('supertest')(app); const expect = require('chai').expect; describe('mock Server', () => { describe('#GET /', () => { it('should return a response with HTTP code 200', function(done) { supertest .get('/') .expect(200, done); }); }); describe('#GET /mock/js/user', () => { it('response data success should return true', (done) => { supertest .get('/mock/js/user') .expect(200) .end((err, res) => { if (err) { done(err); } const { code, data, message, success } = res.body; expect(res.statusCode).to.equal(200); expect(res.body).to.be.an('object'); expect(code).to.eql(1); expect(data).to.eql({ name: 'ataola', skill: 'node.js' }); expect(message).to.eql('獲取用戶信息成功'); expect(success).to.eql(true); done(); }); }); }); });
站在產品經理的角度,我想,高配版的Mock Server就是打開瀏覽器,有個界面給你點點點進行增刪改查,而後生成一個API,有興趣的童鞋能夠去實現下,溜了溜了。。。
本文選自「Node.JS打鐵」系列文章,項目地址:https://github.com/ataola/node-blacksmith
文中涉及到的項目例子地址:https://github.com/ataola/node-blacksmith/tree/master/code/framework/koa-study/koa-mock
Mock.JS官網: http://mockjs.com/
MockJS 文檔:https://github.com/nuysoft/Mock/wiki
MockJS 示例:http://mockjs.com/examples.html
MockJS語法規範:https://github.com/nuysoft/Mock/wiki/Syntax-Specification
Mock.Mock()的使用:https://github.com/nuysoft/Mock/wiki/Mock.mock()