摘要:注意廣告警告廣告警告廣告警告在一個應用的開發周期中一般前端與后端都是并行開發的各自完成自己的開發工作后進行聯調聯調通過再進行提測發布開發過程中前端都會以后端提供的文檔作為標準模擬返回數據以確保在開發中就保證功能的完整性而關于如何更好的進行業
注意! 廣告警告! 廣告警告! 廣告警告!
在一個web應用的開發周期中, 一般前端與后端都是并行開發的, 各自完成自己的開發工作后進行聯調, 聯調通過再進行提測/發布.
開發過程中, 前端都會以后端提供的 api 文檔作為標準, mock 模擬 api 返回數據, 以確保在開發中就保證功能的完整性.
而關于如何更好的進行 mock, 業界/開源社區可謂有相當多質量上乘的解決方案, 如easy-mock, yapi等.
但是越是大而全的工具很多時候功能會超越需求非常多, 要簡單實現 mock api 的需求其實也有非常多小而美工具庫可以使用.
而本文主要介紹 mock-server 這個工具的使用
選用 mock-server 的主要原因除了是我開發的使用比較簡單之外, 更多的是滿足了下文提到的一些開發需求, 如果你也有同樣的需求而還沒找到解決方案的話, 不妨試用一下.
可選全局安裝, 安裝完成過后, 就可以通過mock命令啟動來 mock server
npm install -g mock-server-local mock -h # 即安裝成功 # 用 -d 指定mock數據配置目錄, 為空時默認為當前目錄 `.` mock -d ./mock # 用 -p 指定server的端口, 默認為8888, 如果8888被占用會端口號+1, 直至端口可用 # 注意如果指定了端口號, 但是端口號被占用的話, 會拋出錯誤 mock -d ./mock -p 8080
個人比較習慣在項目中進行安裝, 并通過npm script啟動, 而 mock 數據也存放在項目當中, 通過 git 等版本管理工具在項目成員當中共享, 假設項目目錄為proj
// proj/package.json { // ... "script": { "mock": "mock -d ./mock -p 8080" } // ... }
# 本地安裝 npm install mock-server-local --save-dev # 啟動mock server npm run mock > mock@1.8.9 mock /path/to/proj > mock -d ./mock -p 8080 you can access mock server: http://127.0.0.1:8080 http://ww.xx.yy.zz:8080 you can access mock server view: http://127.0.0.1:8080/view http://ww.xx.yy.zz:8080/view
就這樣 mock server 就已經啟動了, 訪問127.0.0.1:8080/view即可看到 mock server 的控制頁面
就下來就是調整代理, 把應用的請求轉發到 mock server 進行處理
如果你使用webpack來構建你的項目, 那你只需要改動一下webpack.devServer的配置即可
假設我們的業務域名為target.mock.com, 而接口基本都是target.mock.com/api/**, 可以這樣進行配置
devServer: { proxy: { "/api": { target: "http://127.0.0.1:8080", // mock server headers: { host: "target.mock.com" // 業務域名 }, onProxyReq: function(proxyReq, req, res) { proxyReq.setheader("host", "target.mock.com"); // 業務域名 } } } }
接著在開發中, 啟動 webpack 之后, 發出的請求/api/**都會被轉發到
而如果應用本身不使用 webpack 或其他帶 server 功能的打包工具, 可以使用代理工具進行請求轉發
如果是用 Chrome 瀏覽器調試應用, 可以下載SwitchyOmega一類可配置, 把特定域名的請求進行轉發
使用微信開發者工具的話, 可直接設置代理, 設置 -> 代理設置 -> 勾選手動設置代理 -> 填寫代理配置
推薦使用 whistle, fiddler 一類功能完整代理工具, 類似配置如下
target.mock.com/api 127.0.0.1:8080 # 接口請求轉發到mock server target.mock.com www.xx.yy.zz # 頁面從正常的開發測試機ip中獲取, 或本地調試服務器mock 數據配置
mock server 的配置是根據 mock 目錄的目錄結構生成的, 假設需要進行 mock 的 api 接口完整的 url 為target.mock.com/api/login
而且需要模擬以下三種情況的數據返回
登錄失敗, 返回錯誤碼-1 及錯誤信息
登錄成功, 返回錯誤碼 0 和用戶信息, 且要帶上登錄態 cookie
請求時間超過 8 秒, 導致前端請求超時
那么目錄結構與數據配置文件應該如下所示
|- proj |- mock |- target.mock.com |- api |- login |- 登錄成功 |- 登錄失敗 |- 請求超時 // 登錄失敗 // proj/mock/target.mock.com/api/login/登錄失敗/data.js module.exports = { code: -1, msg: "登錄失敗!" }; // 登錄成功 // proj/mock/target.mock.com/api/login/登錄成功/data.js module.exports = { code: 0, msg: "登錄成功", username: "ahui" }; // proj/mock/target.mock.com/api/login/登錄成功/http.js module.exports = { header: { "Set-Cookie": "token=123456789;" } }; // 請求超時 // proj/mock/target.mock.com/api/login/請求超時/data.js module.exports = {}; // proj/mock/target.mock.com/api/login/請求超時/http.js module.exports = { delay: 8 };
根據上面目錄配置, 訪問 mock server 頁面的 mock 面板127.0.0.1:8080/view/mocks, 就可以看到以下頁面
現在我們只需要勾選其中一個狀態, 然后發出請求即可
mock完成之后就可以愉快編寫業務邏輯了
mock 配置詳解看了上面的例子應該也就大致可以了解到, data.js里面定義接口返回的數據. 而http.js, 顧名思義就是定義 http 請求相關行為的, 例如可以定義響應頭, http 狀態碼, 請求耗時等.
data 同時也支持使用 json 文件, 非 js/json 文件的一律當 json 格式處理, 而 http 則只支持通過 js 文件定義
http.js可選配置如下
module.exports = { delay: 8, // 耗時8秒 status: 200 // http狀態碼 header: { // ... http響應頭 } }
而data.js除了可以簡單定義返回數據之外, 還可以直接返回模板, 如
module.exports = `Document 這個是由mock server返回的模板 `;
并且可以返回一個方法, 通過腳本邏輯來處理最終要返回的數據
// ctx: https://koajs.com/#context module.exports = function(ctx) { // 邏輯處理 return { data: {}, // 響應數據 header: {}, // 如有需要可以配置, 同http.js#header delay: 0.1, // 如有需要可以配置, 同http.js#delay status: 200 // 如有需要可以配置, 同http.js#status }; }; // 如果當中有異步邏輯, 請返回promise, 或直接使用async方法 module.exports = async function(ctx) { // 異步邏輯處理 await asyncFn(); return { data: {}, // 響應數據 header: {}, // 如有需要可以配置, 同http.js#header delay: 0.1, // 如有需要可以配置, 同http.js#delay status: 200 // 如有需要可以配置, 同http.js#status }; };代理線上數據
在開發過程可能出現這樣的場景, 一期項目已經開發完了, 現在進行二期迭代的開發工作, 這個時候由于之前的接口后臺已經都實現, 二期開發中只想對新增的 api 進行 mock
這個時候可以修改一下代理工具的配置, 把不同接口的請求轉發到不同的服務器
# 新增接口轉發至mock server target.mock.com/api/new1 127.0.0.1:8080 target.mock.com/api/new2 127.0.0.1:8080 # 其余接口直接使用線上/測試機數據 target.mock.com ww.xx.yy.zz
又或者可以直接使用 mock server 提供的簡單的代理功能, 只需要在 mock 目錄個目錄下新建proxy.js文件
|- proj |- mock |- proxy.js // proj/mock/proxy.js module.exports = { target.mock.com: "https://ww.xx.yy.zz" // 這里可以指定ip也可以指定域名, 但是需要注意協議類型是必須要帶上的 }
這樣配置之后, 在代理工具中就可以直接把所有的target.mock.com的請求都直接轉發到 mock server
當對應請求的 url 并沒有勾選任何一個返回狀態, 或根本沒有配置對應的 url 時, mock server 都會幫助我們把請求轉發到目標 ip
假設沒有配置proxy.js的話, 對于沒有命中的 url 請求, 會根據 host 直接請求線上的資源或接口
模板接口調試 & 微信登錄支持在非前后端分離的架構中, 很常會出現這樣的需求, 應用的入口即是后端接口, 后端會進行鑒權, 拼接模板內容和數據, 然后直接返回頁面給到前端進行展示.
這樣的場景 mock server 可以很簡單通過data.js中導出方法的方式來處理
const fs = require("fs"); module.exports = async ctx => { let html = ""; let template = fs.readFileSync("path/to/html/template/index.ejs"); // 舉例ejs, 實際可以處理任何模板引擎 // 這里處理模板的語法 // 1. 處理類似include的拼接模板的語法 // 2. 處理類似<%= =>插入變量/數據的語法 // 3. 等等等等.... html = processedHtml; return { data: html, header: { "Set-Cookie": "SESSIONID=123123123123;" }; }; };
這樣子我們就可以進行模板接口的調試了. 再回到我們的上一個例子
我們希望可以使用線上已有接口和數據狀態(如開戶數據)
也希望使用后端的登錄態(這樣后續的接口調用也能通過鑒權), 但也同時希望可以調試本地模板呢?
比較直觀的方式是, 本地修改模板然后把模板改動上傳到開發服務器, 然后直接請求開發服務器進行調試
但是改動比較多, 需要頻繁調試的話, 或許使用 mock server 也是一個不錯的選擇. 更進一步, 如果是微信 h5 且后端的登錄鑒權接入了微信登錄呢?
我們來分析一下如何使用 mock server 滿足這樣的調試述求, h5 微信登錄基本的流程如下
請求線上/開發測試服務器接口
接口返回 http 狀態碼 302 并帶上 Location 頭, 跳轉到微信 url
請求微信 url 會返回 301 再回跳我們的業務域名
回跳我們的業務域名時, 即再次請求服務器接口, 獲取微信登錄 code 進行業務登錄
返回登錄態及 html 頁面
上面的流程中, 其實需要介入只有最后一步而已, 就是獲取到登錄態并返回需要調試的 html 模板內容即可
而前面的步驟, 完全可以通過在data.js中實現簡單的代理完成
// 微信登錄/data.js const httpProxy = require("http-proxy"); const fs = require("fs"); const path = require("path"); proxy = httpProxy.createServer({ secure: false }); async function req({ req, res }) { proxy.web(req, res, { target: { protocol: "https:", host: "ww.xx.yy.zz", // 目標服務器 port: 443, pfx: fs.readFileSync(path.resolve(process.cwd(), "cert/cert.p12")), // 如果服務器是https需要生成證書 passphrase: "password" }, selfHandleResponse: true }); return new Promise((resolve, reject) => { proxy.once("proxyRes", function(proxyRes, req, res) { let body = []; let size = 0; function onData(chunk) { body.push(chunk); size += chunk.length; } proxyRes.on("data", onData).once("end", () => { proxyRes.off("data", onData); body = Buffer.concat(body, size); resolve({ header: proxyRes.headers, data: body, status: proxyRes.statusCode }); }); }); }); } module.exports = async function(ctx) { // 登錄態 const res = await req(ctx); const header = res.header; res.header = Object.keys(header).reduce((c, k) => { let nk = k .split("-") .map(v => v.charAt(0).toUpperCase() + v.slice(1)) .join("-"); c[nk] = header[k]; return c; }, {}); if (res.header["Set-Cookie"]) { // 如果有Set-Cookie header, 則要處理返回本地模板 // 這里處理模板的語法 // 1. 處理類似include的拼接模板的語法 // 2. 處理類似<%= =>插入變量/數據的語法 // 3. 等等等等.... res.data = template; // 這里需要注意, 目標服務器可能會返回gzip過后的數據 // 如果不對Content-Encoding和Content-Length進行處理的話 // 會導致響應中Content-Length和實際內榮長度不一致而出錯 res.header["Content-Encoding"] = "identity"; delete res.header["Content-Length"]; } return res; };
這樣我們就可以對具體的接口模板進行調試了
寫在最后重復造輪子不易, 且造且珍惜
如果大家有mock api的需求的話, 不妨也試用一下 mock-server
如果覺得 mock-server 還不錯, 或者解決了mock的一些痛點, 不妨賞個star
最后, 用得不爽或發現bug, 懇請提issue!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109613.html
摘要:如何去解決這些問題前后端分離大部分的互聯網公司都分成了前端團隊和后端團隊。方案一采用架構業界很多公司會采用,單頁應用的架構,這種架構是天然的前后端分離的。方案二淘寶的大前端方案中途島上圖是淘寶基于的前后端分離分層,以及的職責范圍。 我們遇到了什么問題? 1.前端無法調試后端未完成的 API:如果后端同學還沒有完成 API 開發,那么前端同學就不能對這個 API 進行開發。之前我們都是在...
摘要:前后端的界限是按照瀏覽器和服務器的劃分。前后端彼此互不關聯。關于作者本文部分圖片段落參考文章實踐中的前后端分離。淘寶前后端分離實踐本文源碼詳見服務端代碼。 一、起源 (故事純屬虛構,如有雷同,純屬巧合)傳說在很久很久以前,我們有志之士有了個創業的想法,于是乎開始了自己的創業之夢,但是人手不足啊,于是乎所有角色老子一個人全包了: Roles: PM, DBA, RD, FED, Des...
閱讀 3722·2021-11-17 09:33
閱讀 2744·2021-09-22 15:12
閱讀 3351·2021-08-12 13:24
閱讀 2449·2019-08-30 11:14
閱讀 1738·2019-08-29 14:09
閱讀 1330·2019-08-26 14:01
閱讀 3067·2019-08-26 13:49
閱讀 1782·2019-08-26 12:16