1. 程式人生 > >Mockjs原理簡析

Mockjs原理簡析

前言

有一個前後端分離的專案用到過Mockjs,後端提供了資料格式,前端通過模擬介面的返回資料,進行頁面的渲染,有一段時間,百思不得其解,這個外掛是怎麼把ajax請求給攔下來的,網上搜索了一番,資料甚少,未果。
後來有一天,不知道怎麼的突然想到,如果把ajax方法請求改寫了,在傳送請求之前提供一個回撥是不是能實現這個功能?

思路

  • 準備環境
    • 從最方便的jquery入手,打算改寫$.ajax
  • 需要解決的問題主要有
    • $.ajax即將被改寫,所以要自己實現一個傳送請求的xhr方法(又懶得寫封裝的ajax方法,於是把$.ajax快取起來,以待後用)
    • 如何去匹配將被攔截的請求地址
    • 攔截了請求之後,如何把預先準備好的資料當做請求成功後的資料
  • 程式碼實現

    let Mock = {
      // 儲存匹配規則
      rules: new Map(),
      // 快取ajax方法
      ajax: $.ajax,
      mock(url, data) {
        this.rules.set(url, data)
      }
    }
    
    // 改寫ajax方法
    $.ajax = function(options) {
      Mock.ajax({
        url: options.url,
        beforeSend(XHR) {
          let data = Mock.rules.get(options.url)
          // 找到規則攔截請求,並執行回撥(return false時會攔截請求)
    data && options.success(data) return !data }, success(data) { // 找不到規則,正常傳送請求 options.success(data) } }) } // 測試 Mock.mock('/a', { a: 1, b: 2 }) $.ajax({ url: '/a', success(data) { console.log(data, 1) } }) $.ajax({ url: '/b', success(data) { console.
    log(data, 2) } })
  • 功能檢測
    • 以上程式碼可直接拷貝至控制欄執行,我們可以看到只發送了b請求,a請求被攔截了下來,同時我們也能拿到所預期的資料
    • 至於Mockjs隨機資料的功能,我們暫不考慮

總結

  • 之後我也粗略看了下Mockjs原始碼,它也是改寫了jquery和zepto的$.ajax方法所實現,這就意味著如果是自己用原生js封裝的ajax方法,是不能攔截的
    如下,是一個原生js的ajax方法,有興趣可以自己去檢測一下:

    var Ajax={
        get: function(url, fn) {
            var xhr = new XMLHttpRequest();  // XMLHttpRequest物件用於在後臺與伺服器交換資料          
            xhr.open('GET', url, true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { // readyState == 4說明請求已完成
                    fn.call(this, xhr.responseText);  //從伺服器獲得資料
                }
            };
            xhr.send();
        },
        post: function (url, data, fn) {         // datat應為'a=a1&b=b1'這種字串格式,在jq裡如果data為物件會自動將物件轉成這種字串格式
            var xhr = new XMLHttpRequest();
            xhr.open("POST", url, true);
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");  // 新增http頭,傳送資訊至伺服器時內容編碼型別
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {  // 304未修改
                    fn.call(this, xhr.responseText);
                }
            };
            xhr.send(data);
        }
    }
  • 很多公司源於方便已經提供了自己專門的mock服務平臺,以供前端開發者更快捷的模擬資料,搭建教程我會在另一篇文章中講述