MockJS Ajax拦截原理

4,483 阅读1分钟

mockJS实现拦截,是模拟了XMLHttpRequest对象。重写open、send等方法,方法调用时,只是普通函数的调用,不会发送真正的请求。

MockJS使用

  1. 引入mockjs
  <script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.1-beta3/mock.js"></script>
  1. 拦截匹配 url 的 Ajax 请求,根据数据模板生成模拟数据,并作为响应数据返回。
  Mock.mock('mock/news', 'GET', {
      'list|1-10': [{
          'id|+1': 1,
          'name': "@cname"
      }]
  })

  1. 请求 url,获得模拟数据
  axios.get('mock/news').then(res => {
    console.log(res) // res为json格式的模拟数据
  })

Ajax拦截原理

  1. 覆盖原生 XMLHttpRequest
  • ajax请求会创建XMLHttpRequest对象,覆盖原生XMLHttpRequest,ajax请求时,就会调用我们写的函数了

(源码:/src/mock.js)

  MockXMLHttpRequest = require('./mock/xhr')
  Mock.mock = function(rurl, rtype, template) {
      ...
      if (XHR) window.XMLHttpRequest = MockXMLHttpRequest
      ...
  }

如上,调用Mock.mock方法的时候,会执行 window.XMLHttpRequest = MockXMLHttpRequest,覆盖原生 XMLHttpRequest。

下面来看 MockXMLHttpRequest构造函数

  1. 模拟原生 XMLHttpRequest

(源码:/mock/xhr/xhr.js)

  function MockXMLHttpRequest() {
      // 初始化 custom 对象,用于存储自定义属性
      this.custom = {
          events: {},
          requestHeaders: {},
          responseHeaders: {}
      }
  }
  Util.extend(MockXMLHttpRequest.prototype, {
      open: function(method, url, async, username, password) {
          var that = this
  
          Util.extend(this.custom, {
              method: method,
              url: url,
              async: typeof async === 'boolean' ? async : true,
              username: username,
              password: password,
              options: {
                  url: url,
                  type: method
              }
          })
          ......
      },
      timeout: 0,
      withCredentials: false,
      upload: {},
      send: function send(data) {
          var that = this
          this.custom.options.body = data
          ......
          that.response = that.responseText = JSON.stringify(
              convert(that.custom.template, that.custom.options),//根据数据模板生成json模拟数据
              null, 4
          )
      },
      abort: function abort() {
          // 拦截 XHR
          this.readyState = MockXMLHttpRequest.UNSENT
          this.dispatchEvent(new Event('abort', false, false, this))
          this.dispatchEvent(new Event('error', false, false, this))
      }
  })

上面是部分删减源码,摆出来只是为了表达:open、send、abort等函数,或者属性也好,都是自己写出来的普通函数和属性

比如open函数,主要就是把method和url保存到变量中。send函数,把生成的模拟数据赋值给response和responseText

这样,响应数据就是用户设置的模拟数据。

ajax请求发生时,请求根本没有发出,只是调用了几个自己写的普通函数,得到了返回数据而已。