国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從零開始打造 Mock 平臺 - 核心篇

kidsamong / 2116人閱讀

摘要:前言最近一直在搗鼓畢設(shè),準備做的是一個基于前后端開發(fā)的平臺,前期花了很多時間完成了功能模塊的交互。核心代碼就是這么一句。經(jīng)過各種猜想和測試,發(fā)現(xiàn)是模擬有問題。其實用的最終核心思路還是一樣的。

前言

最近一直在搗鼓畢設(shè),準備做的是一個基于前后端開發(fā)的Mock平臺,前期花了很多時間完成了功能模塊的交互?,F(xiàn)在進度推到如何設(shè)計核心功能,也就是Mock數(shù)據(jù)的解析。

根據(jù)之前的需求設(shè)定加上一些思考,用戶可以像寫json一般輕松完成數(shù)據(jù)的mock,也可以通過在mock數(shù)據(jù)模型之上進行構(gòu)建出復(fù)雜的數(shù)據(jù)模型并在項目中引用。

這看似簡單的需求其實需要處理幾個不同的模塊功能以及交互設(shè)計。該如何處理解析不同mock數(shù)據(jù)并進行構(gòu)造?前端交互中模擬數(shù)據(jù)該如何處理?數(shù)據(jù)構(gòu)造時如何加載用戶設(shè)定的數(shù)據(jù)模型?錯誤捕捉與處理?

這些都暫時沒有一個好的處理結(jié)果。因此想要完成核心功能我們需要明確需求,并且通過同類產(chǎn)品是如何處理的,通過閱讀它們的源碼來學習思想并加入。

明確需求

在明確該功能模塊之前我們可以通過模擬流程來明確。

用戶 -> 添加數(shù)據(jù)模型 - > 實時看到構(gòu)造結(jié)構(gòu)

用戶 -> 添加接口 -> 構(gòu)造json格式返回參數(shù) -> 預(yù)覽

構(gòu)造json格式返回參數(shù) 不僅包含返回的正文,同時也設(shè)定了 header 和 method。

閱讀源碼

符合大部分需求的開源項目有

mock.js

easy-mock

eolinker

YAPI

DOCCLEVER

MOCK.JS篇

首先我們需要明確現(xiàn)階段大部門的 Mock 平臺或多或少都是受到 Mock.js 的思想或者是其增強版。

我們可以用下面簡單的 json 通過 Mock.js來構(gòu)造數(shù)據(jù):

example:

{
    "status|0-1": 0, //接口狀態(tài)
    "message": "成功", //消息提示
    "data": {
        "counts":"@integer", //統(tǒng)計數(shù)量
        "totalSubjectType|1-4": [ //4-10意味著可以隨機生成4-10組數(shù)據(jù)
            { 
              "subjectName|regexp": "大數(shù)據(jù)|機器學習|工具", //主題名
              "subjectType|+1": 1 //類型
            }
        ],
        "data":[
            {
                "name": "@name", //用戶名
                "cname":"@cname",
                "email": "@email", //email
                "time": "@datetime" //時間
            }
        ]}
}

返回結(jié)果

{
    "status": 0,
    "message": "成功",
    "data": {
        "counts": 2216619884890228,
        "totalSubjectType": [
            {
                "subjectNameregexp": "大數(shù)據(jù)|機器學習|工具",
                "subjectType": 1
            },
            {
                "subjectNameregexp": "大數(shù)據(jù)|機器學習|工具",
                "subjectType": 2
            },
            {
                "subjectNameregexp": "大數(shù)據(jù)|機器學習|工具",
                "subjectType": 3
            },
            {
                "subjectNameregexp": "大數(shù)據(jù)|機器學習|工具",
                "subjectType": 4
            }
        ],
        "data": [
            {
                "name": "Ruth Thompson",
                "cname": "魯克",
                "email": "z.white@young.gov",
                "time": "1985-02-06 05:45:21"
            }
        ]
    }
}

而且可以通過其 Mock.Random.extend() 來擴展自定義占位符.

example:

Random.extend({
    weekday: function(date) {
        var weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        return this.pick(weekdays);
    },
    sex: function(date) {
        var sexes = ["男", "女", "中性", "未知"];
        return this.pick(sexes);
    }
});

console.log(Random.weekday());  // 結(jié)果: Saturday
console.log(Mock.mock("@weekday"));  // 結(jié)果: Tuesday
console.log(Random.sex());  // 結(jié)果: 男
console.log(Mock.mock("@sex"));  // 結(jié)果: 未知

來延伸所需進的拓展。

這個可以將自定義數(shù)據(jù)模型先進行解析,然后通過extend將其加入。

easy-mock

easy-mock 是我參考的主要項目之一,它的UI交互非常符合我的設(shè)定,而且作為開源項目可以從它的源碼中學到很多。

直接來看它提供接口編輯的頁面

{
  data: {
    img: function({
      _req,
      Mock
    }) {
      return _req.body.fileName + "_" + Mock.mock("@image")
    }
  }
}

可以從上得之它既可以處理Mock數(shù)據(jù)模擬也可以處理函數(shù),而且它內(nèi)部有一套能處理req的內(nèi)容。

先是在源碼中找了一下,找到幾個疑似點,但是不確定,還是在本地裝好環(huán)境,主要是需要按照redis.然后啟動服務(wù)去打幾個斷點輸出。

根據(jù)經(jīng)驗先確定 controllersmock.js 應(yīng)該是處理數(shù)據(jù)模擬的地方。通過瀏覽源碼并分析,最終定位于 297行處的代碼

    await redis.lpush("mock.count", api._id)
    if (jsonpCallback) {
      ctx.type = "text/javascript"
      ctx.body = `${jsonpCallback}(${JSON.stringify(apiData, null, 2)})`
        .replace(/u2028/g, "u2028")
        .replace(/u2029/g, "u2029") // JSON parse vs eval fix. https://github.com/rack/rack-contrib/pull/37
    } else {
      ctx.body = apiData
    }

首先是看到最終返回的 apiData 。用過 koa 或者 express 都應(yīng)該清楚 ctx.body 的含義。然后我在上面寫了句 console.log(apiData)。

然后在瀏覽器端發(fā)送請求??聪?node 端輸出和瀏覽器端拿到的數(shù)據(jù),基本可以肯定最終輸出就是這個。

然后我們往上翻,可以看到這么一段代碼:

 const vm = new VM({
        timeout: 1000,
        sandbox: {
          Mock: Mock,
          mode: api.mode,
          template: new Function(`return ${api.mode}`) // eslint-disable-line
        }
      })
      console.log("數(shù)據(jù)驗證")
      console.log(mode)
      vm.run("Mock.mock(new Function("return " + mode)())") // 數(shù)據(jù)驗證,檢測 setTimeout 等方法
      apiData = vm.run("Mock.mock(template())") // 解決正則表達式失效的問題

通過查詢了解到 VM 是一個沙盒,可以運行不受信任的代碼。

大概就能了解 easy-mock 通過 vm 沙盒模式運行 mode 代碼解析后返回結(jié)果。

核心代碼就是 Mock.mock( template ) 這么一句。根據(jù)數(shù)據(jù)模板生成模擬數(shù)據(jù)。

通過查文檔了解 template 是可以直接內(nèi)部寫函數(shù)然后執(zhí)行的。

這樣解析的難度大大下降,發(fā)現(xiàn)原來并沒有特別復(fù)雜的,依舊是依賴了 Mock.js 的原生方法。

然后我們可以看到 easy-mock 另一的操作就是可以獲取 請求參數(shù)_req。也就是可以通過以下代碼來根據(jù)請求參數(shù)返回指定數(shù)據(jù)。

{
  success: true,
  data: {
    default: "hah",
    _req: function({
      _req
    }) {
      return _req
    },
    name: function({
      _req
    }) {
      return _req.query.name || this.default
    }
  }
}

_req 一看就是從請求參數(shù)中獲得的對象。

Mock.js是沒有這個對象的,我們來找找源碼中是哪里注入了這個對象。

還是在 mock.js 這個文件中第234行處找到

   Mock.Handler.function = function (options) {
      const mockUrl = api.url.replace(/{/g, ":").replace(/}/g, "") // /api/{user}/{id} => /api/:user/:id
      options.Mock = Mock
      options._req = ctx.request
      options._req.params = util.params(mockUrl, mockURL)
      options._req.cookies = ctx.cookies.get.bind(ctx)
      return options.template.call(options.context.currentContext, options)
    }

通過閱讀 MockJS 的源碼,了解到 Handler是處理數(shù)據(jù)模板的地方,打個斷點再輸出一次可以發(fā)現(xiàn)其實是在 Mock.mock(new Function("return " + mode)())" 之后傳入的參數(shù)。

options._req = ctx.request 這句代碼告訴了我們所謂的 _req是從哪里來的。

因此這個技術(shù)點我們也了解了是怎么做的,那么剩下一個靈活的支持 restful 通過閱讀源碼發(fā)現(xiàn)其實也沒怎么處理,只是用 pathToRegexp 進行了一次驗證。它先是在 middlewares/index.js 中 的 mockFilter 進行了路徑正則。

static mockFilter (ctx, next) {
    console.log(ctx.path)
    const pathNode = pathToRegexp("/mock/:projectId(.{24})/:mockURL*").exec(ctx.path)
    console.log(pathNode)
    if (!pathNode) ctx.throw(404)
    if (blackProjects.indexOf(pathNode[1]) !== -1) {
      ctx.body = ctx.util.refail("接口請求頻率太快,已被限制訪問")
      return
    }
    console.log("通過篩選")

    ctx.pathNode = {
      projectId: pathNode[1],
      mockURL: "/" + (pathNode[2] || "")
    }

    return next()
  }

然后通過存在 redis 里的接口內(nèi)容再進行了驗證匹配。

const { query, body } = ctx.request
    const method = ctx.method.toLowerCase()
    const jsonpCallback = query.jsonp_param_name && (query[query.jsonp_param_name] || "callback")
    let { projectId, mockURL } = ctx.pathNode
    console.log("ctx.pathNode", ctx.pathNode)
    const redisKey = "project:" + projectId
    let apiData, apis, api
    console.log("通過URL匹配檢驗")
    apis = await redis.get(redisKey)
    console.log(apis)
    if (apis) {
      apis = JSON.parse(apis)
      console.log("pure apis", apis)
    } else {
      apis = await MockProxy.find({ project: projectId })
      console.log("find projectId", apis)
      if (apis[0]) await redis.set(redisKey, JSON.stringify(apis), "EX", 60 * 30)
    }

    if (apis[0] && apis[0].project.url !== "/") {
      mockURL = mockURL.replace(apis[0].project.url, "") || "/"
    }

    api = apis.filter((item) => {
      const url = item.url.replace(/{/g, ":").replace(/}/g, "") // /api/{user}/{id} => /api/:user/:id
      return item.method === method && pathToRegexp(url).test(mockURL)
    })[0]
    console.log("api",api)

    if (!api) ctx.throw(404)

基本不匹配的路徑請求都是在 item.method === method && pathToRegexp(url).test(mockURL) 這句代碼里被攔截的。

非常優(yōu)秀的代碼。通讀下來,加上斷點對其思路邏輯學到了很多。

eolinker

它的后端代碼是 PHP 的,這就略過不看了。

YAPI

它的核心后端處理代碼是在 mockServer.js

有了之前的閱讀經(jīng)驗很快找到處理 Mock 數(shù)據(jù)的地方

  let res;

        res = interfaceData.res_body;
        try {
            if (interfaceData.res_body_type === "json") {
                res = mockExtra(
                    yapi.commons.json_parse(interfaceData.res_body),
                    {
                        query: ctx.request.query,
                        body: ctx.request.body,
                        params: Object.assign({}, ctx.request.query, ctx.request.body)                     
                    }
                );
                try {
                    res = Mock.mock(res);
                } catch (e) {
                    yapi.commons.log(e, "error")
                }
            }
            

非常簡單粗暴的處理方法。。。

對增強功能比較好奇在, 于是在 commonmock-extra.js 里找到了 mock(mockJSON, context) 方法。根據(jù)參數(shù)其實就能了解綁定上下文然后做了一些動作。這里就不展開詳細。等之后開發(fā)的時候用到再去細讀。因為這是做了其自己的增強的Mock功能,而暫時不需要這方面的考慮。

DOClecer

這個項目是國內(nèi)一個創(chuàng)業(yè)團隊做的,我也加入了其官方群。雖然還沒有用過。不過不妨礙閱讀其源碼了解思路。不過講道理這個代碼組織風格是挺糟糕的。。。

而且源碼中不止一次出現(xiàn)了eval... 于是放棄參考。

寫個小模塊開心一下

通過閱讀以上項目的源碼,其實主要是前三個,感覺可以完成自己想要的需求了。那么先寫一個小的來作為基礎(chǔ)模塊。

export const mock = async(ctx: any) => {
  console.log("mock")
  console.log(ctx)
  console.log(ctx.params)
  const method = ctx.request.method.toLowerCase()
  // let { projectId, mockURL } = ctx.pathNode
  // 獲取接口路徑內(nèi)容
  console.log("ctx.pathNode", ctx.pathNode)
  // 匹配內(nèi)容是否一致
  console.log("驗證內(nèi)容中...")
  // 模擬數(shù)據(jù)
  Mock.Handler.function = function (options: any) {
    console.log("start Handle")
    options.Mock = Mock
    // 傳入 request cookies,方便使用
    options._req = ctx.request
    return options.template.call(options.context.currentContext, options)
  }
  console.log("Mock.Handler", Mock.Handler.function)
//   const testMode = `{
//     "title": "Syntax Demo",
//     "string1|1-10": "★",
//     "string2|3": "value",
//     "number1|+1": 100,
//     "number2|1-100": 100,
//     "number3|1-100.1-10": 1,
//     "number4|123.1-10": 1,
//     "number5|123.3": 1,
//     "number6|123.10": 1.123,
//     "boolean1|1": true,
//     "boolean2|1-2": true,
//     "object1|2-4": {
//         "110000": "北京市",
//         "120000": "天津市",
//         "130000": "河北省",
//         "140000": "山西省"
//     },
//     "object2|2": {
//         "310000": "上海市",
//         "320000": "江蘇省",
//         "330000": "浙江省",
//         "340000": "安徽省"
//     },
//     "array1|1": ["AMD", "CMD", "KMD", "UMD"],
//     "array2|1-10": ["Mock.js"],
//     "array3|3": ["Mock.js"],
//     "function": function() {
//         return this.title
//     }
// }`
const testMode = `{success :true, data: { default: "hah", _req: function({ _req }) { return _req }, name: function({ _req }) { return _req.query.name || this.default }}}`
  const vm = new VM({
    timeout: 1000,
    sandbox: {
      Mock: Mock,
      mode: testMode,
      template: new Function(`return ${testMode}`)
    }
  })
  vm.run("Mock.mock(new Function("return " + mode)())") // 數(shù)據(jù)驗證,檢測 setTimeout 等方法, 順便將內(nèi)部的函數(shù)執(zhí)行了
  // console.log(Mock.Handler.function(new Function("return " + testMode)()))
  const apiData = vm.run("Mock.mock(template())")
  console.log("apiData2333" , apiData)
  let result
  switch (method) {
    case "get":
      result = success({"msg": "你調(diào)用了get方法"})
      break;
    case "post":
      result = success({"msg": "你調(diào)用了post方法"})
      break;
    case "put" :
      result = success({"msg": "你調(diào)用了put方法"})
      break;
    case "patch" :
      result = success({"msg": "你調(diào)用了patch方法"})
      break;
    case "delete" :
      result = success({"msg": "你調(diào)用了delete方法"})
      break;
    default:
      result = error()
  }
  // console.log(result)
  return ctx.body = result
}

這里調(diào)試的遇到一些問題,主要是一開始測試的時候發(fā)現(xiàn) Mock 只將規(guī)則的數(shù)據(jù)模擬出,發(fā)現(xiàn) function 類型的函數(shù)都沒執(zhí)行,一開始定位以為是Mock.Handler.function 在 ts 中未執(zhí)行。于是在里面寫了一個輸出,發(fā)現(xiàn)的確沒有。經(jīng)過各種猜想和測試,發(fā)現(xiàn)是模擬mode有問題。

一開始我是這么寫的

const testcode = {
    "array1|1": ["AMD", "CMD", "KMD", "UMD"],
    "array2|1-10": ["Mock.js"],
    "array3|3": ["Mock.js"],
    "function": function() {
        return this.title
    }
}

事實上應(yīng)該這么寫

const testcode = `{
    "array1|1": ["AMD", "CMD", "KMD", "UMD"],
    "array2|1-10": ["Mock.js"],
    "array3|3": ["Mock.js"],
    "function": function() {
        return this.title
    }
}`

參照 easy-mock 的思路可以實現(xiàn)一個基礎(chǔ)的 Mock數(shù)據(jù)解析器,而且可以根據(jù) koa 的特性同時支持 _req 的一些參數(shù),這里先不加進去。

如何支持自定義的數(shù)據(jù)模型也有了基本的思路,在之前沒有考慮 redis 情況下還是用傳統(tǒng)的數(shù)據(jù)庫查詢。具體實現(xiàn)等后期再搗鼓出來再寫出來。

結(jié)尾

通過這兩天的學習,總算把一個Mock的核心模塊該如何實現(xiàn)的思路給理順了。

其實無論你是用戶自定義數(shù)據(jù),比如

{
  "user": User, // User是用戶自定義的數(shù)據(jù)類型
   "string2|3": "value",
   "number1|+1": 100,
    _req: function({
      _req
    }) {
      return _req
    },
    name: function({
      _req
    }) {
      return _req.query.name || this.default
    }
}

還是 Mock.js 原生的語法,你最終轉(zhuǎn)換過來需要執(zhí)行的是一樣的內(nèi)容,無非是在其轉(zhuǎn)換前需要做一定的處理。只有搞懂了基本的數(shù)據(jù)模擬實現(xiàn),基本上你可以將各個參數(shù)都做定制化。比如有的平臺會將用戶自己編寫的函數(shù)一起和 json 拼接。其實用的最終核心思路還是一樣的。

參考資料

Mock.js使用

mockjs官方文檔

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/107191.html

相關(guān)文章

  • 從零開始打造 Mock 平臺 - 核心

    摘要:前言最近一直在搗鼓畢設(shè),準備做的是一個基于前后端開發(fā)的平臺,前期花了很多時間完成了功能模塊的交互。核心代碼就是這么一句。經(jīng)過各種猜想和測試,發(fā)現(xiàn)是模擬有問題。其實用的最終核心思路還是一樣的。 前言 最近一直在搗鼓畢設(shè),準備做的是一個基于前后端開發(fā)的Mock平臺,前期花了很多時間完成了功能模塊的交互。現(xiàn)在進度推到如何設(shè)計核心功能,也就是Mock數(shù)據(jù)的解析。 根據(jù)之前的需求設(shè)定加上一些思考...

    he_xd 評論0 收藏0
  • 從零開始打造 Mock 平臺 - 核心

    摘要:前言最近一直在搗鼓畢設(shè),準備做的是一個基于前后端開發(fā)的平臺,前期花了很多時間完成了功能模塊的交互。核心代碼就是這么一句。經(jīng)過各種猜想和測試,發(fā)現(xiàn)是模擬有問題。其實用的最終核心思路還是一樣的。 前言 最近一直在搗鼓畢設(shè),準備做的是一個基于前后端開發(fā)的Mock平臺,前期花了很多時間完成了功能模塊的交互。現(xiàn)在進度推到如何設(shè)計核心功能,也就是Mock數(shù)據(jù)的解析。 根據(jù)之前的需求設(shè)定加上一些思考...

    kbyyd24 評論0 收藏0
  • 前端之從零開始系列

    摘要:只有動手,你才能真的理解作者的構(gòu)思的巧妙只有動手,你才能真正掌握一門技術(shù)持續(xù)更新中項目地址求求求源碼系列跟一起學如何寫函數(shù)庫中高級前端面試手寫代碼無敵秘籍如何用不到行代碼寫一款屬于自己的類庫原理講解實現(xiàn)一個對象遵循規(guī)范實戰(zhàn)手摸手,帶你用擼 Do it yourself!!! 只有動手,你才能真的理解作者的構(gòu)思的巧妙 只有動手,你才能真正掌握一門技術(shù) 持續(xù)更新中…… 項目地址 https...

    Youngdze 評論0 收藏0
  • 從零開始打造 Mock 平臺 - 功能模塊

    摘要:重要功能一些擴展的重要功能將在這里一點點從零開始進行思考。假設(shè)現(xiàn)在的數(shù)據(jù)是這樣的演示項目接口示例超長字符串測試項目描述前端工程師宋青樹后端工程師獲取接口描述增加接口描述刪除接口描述更新接口描述我們需要將里面所有的字段數(shù)組去除。 前言 二月初想想這個月還得搗鼓一篇文章,也沒啥好的想法那還是記錄一下畢設(shè)的一些思路吧。 重要功能 一些擴展的重要功能將在這里一點點從零開始進行思考。 項目導入導...

    CloudDeveloper 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<