preface

About the mock data, online there are many mature solution, but I personally at the time of development, I habitually, simple things, when I get interface document, the first thing I will choose to use the local mock method, benefit is controllable, suitable for in the early stage of development, of course, the advantage is that if the alignment stage, You don’t need to change the address of the interface, just delete the Mock data and you can access the real interface.

demand

  1. You can Mock data locally
  2. Instead of changing the Url again, use the Url agreed upon with the backend

The main flow chart is as follows:

Mock data storage mode

We want it to be an object in a separate JS file from which our mock methods can extract data. We create a JS file named test_data.js

We have an interface called query:user, which contains mock data. We want to be able to pull the mock data when we request the XXX ://query:user interface. When we need to connect to the real interface, we just need to remove the fake data. You can get the real information from the real interface

const data = {
  "query:user": {
    "code": "S_OK"."record": [{"id": "132"."name": "silan"."job": "Front-end Development Engineer"."workTime": "Three years"}]}}Copy the code

Develop the MockRequest constructor

By convention, we need a constructor that takes one argument, which should be an array, to receive the address of the interface to which the mock data is passed

Since you are likely to mock out a lot of interface address data, we need to declare a class in order to make you look like a js veteran and for the code to thrive.

class MockRequest{
      constructor(rules) {
        this.rules = rules // Get the address of the interface with the false data}}Copy the code

Now comes the hard part. We need to define a prototype method that does three things inside:

  1. Use an object as an alternative to XMLHttpRequest and rewrite the open and send methods to use it instead of sending the request
  2. Matches the URL address and gets the mock data if the requested URL address is an address that has the mock data
  3. Matches the URL address and, if it is not an address with mock data, makes an HTTP request for the real interface data

Let’s call this create:

class MockRequest{
      constructor(rules) {
        this.rules = rules // Get the address of the interface with the false data
    }
    create(){
    // Match the Url method
        function matchRules(url) {
            var r = self.rules;
            var result = [];
            for (var i = 0; i < r.length; i++) {
                if (r[i] && url.indexOf(r[i].url) >= 0) { result.push(r[i]); }}if (result.length > 0) {
                return result[0]}}}}Copy the code

Then we add more complex alternatives

class MockRequest {
    constructor(rules) {
        this.rules = rules
    }
    create() {
        let self = this;
        / / to match the url
        function matchRules(url) {
            / /...
        }
        // returnObj has open and send methods
        let returnObj = {
            // onreadystatechange: null,
            open: function (method, url, async) {
                this.url = url;
                this.xhr.open(method, url, async);
            },
            send: function (data) {
                // This points to MockRequestContructor
                let self = this;
                // Retrieve the matched URL
                let rule = matchRules(self.url);
                if (rule) {
                // Pass the mock data to the front end if it matches the mock address
                    setTimeout(function () {
                        self.readyState = 4;
                        self.status = 200;
                        // Get the responseText of the mock data returned
                        if (typeof rule.responseText == "string") {
                            self.responseText = rule.responseText;
                        }  else if (typeof rule.responseText == "object") {
                            self.responseText = JSON.stringify(rule.responseText);
                        }
                        // Trigger the onreadyStatechange method that the user set on the front end, and the front end gets the mock data
                        self.onreadystatechange && self.onreadystatechange();
                    }, 100);

                } else {
                // If it is not a mock address, the native request occursself.xhr.send(data); }}}// The XMLHttpRequest constructor is assigned to _XMLHttpRequest
        let _XMLHttpRequest = window.XMLHttpRequest
        function MockRequestContructor() {
            this.xhr = new _XMLHttpRequest(); 
            // Assign the XMLHttpRequest instance to this.xhr to facilitate the object.defineProperty operation
        }
        // At this point, MockRequestContr is a constructor that binds the properties and methods in returnObj to his prototype
        MockRequestContructor.prototype = returnObj;
        // The front end calls new XMLHttpRequest
        // We have successfully rewritten the MockRequestContructor constructor
        window.XMLHttpRequest = MockRequestContructor; }}Copy the code

At this point, we have actually completed the operation of fetching the mock data. When we pull a URL that has already set the mock data, we return the mock data, and do not send any requests to the target server

All that’s left is implementation

Send request to target server for real data when not mock data address

As we all know, getting the responseText can only be done in onReadyStatechange, whereas currently XMLHttpRequest can only get the mock data, so we’re going to rewrite it with object.defineProperty. Xhr.onreadystatechange =function(){XXXX} =function(){XXXX} =function(){XXXX} =function(){XXXX} =function(){XXXX} =function(){XXXX} =function(){XXXX} =function(){XXXX

        Object.defineProperty(returnObj, "onreadystatechange", {
            get: function () {
                return this.xhr.onreadystatechange;
            },
            set: function (func) {
                var obj = this; Obj = MockRequestContructor
                console.log(obj,func)
                / / if obj. XHR. Onreadystatechange have change, that is true request address
                obj.xhr.onreadystatechange = function (arg) {
                    // This points to the actual data of the HTTP request
                    ReturnObj is the return object. Replace the real value
                    returnObj.readyState =this.readyState;
                    returnObj.status =this.status;
                    returnObj.responseText =this.responseText;
                    returnObj.responseXML =this.responseXML; func(arg); }; }})Copy the code

The complete code


class MockRequest {
    constructor(rules) {
        this.rules = rules
    }
    create() {
        let self = this;
        / / to match the url
        function matchRules(url) {
            let r = self.rules;
            let result = [];
            for (let i = 0; i < r.length; i++) {
                if (r[i] && url.indexOf(r[i].url) >= 0) { result.push(r[i]); }}if (result.length > 0) {
                return result[0]}}// returnObj has open and send methods
        let returnObj = {
            // onreadystatechange: null,
            open: function (method, url, async) {
                this.url = url;
                this.xhr.open(method, url, async);
            },
            send: function (data) {
                // This points to MockRequestContructor
                let self = this;
                // Retrieve the matched URL
                let rule = matchRules(self.url);
                if (rule) {
                    // Pass the mock data to the front end if it matches the mock address
                    setTimeout(function () {
                        self.readyState = 4;
                        self.status = 200;
                        // Get the responseText of the mock data returned
                        if (typeof rule.responseText == "string") {
                            self.responseText = rule.responseText;
                        } else if (typeof rule.responseText == "object") {
                            self.responseText = JSON.stringify(rule.responseText);
                        }
                        // Trigger the onreadyStatechange method that the user set on the front end, and the front end gets the mock data
                        self.onreadystatechange && self.onreadystatechange();
                    }, 100);

                } else {
                    // If it is not a mock address, the native request occursself.xhr.send(data); }}}// Listen for onreadyStatechange changes
        Object.defineProperty(returnObj, "onreadystatechange", {
            get: function () {
                return this.xhr.onreadystatechange;
            },
            set: function (func) {
                var obj = this; Obj = MockRequestContructor
                / / if obj. XHR. Onreadystatechange have change, that is true request address
                obj.xhr.onreadystatechange = function (arg) {
                    // This points to the actual data of the HTTP request
                    ReturnObj is the return object. Replace the real value
                    returnObj.readyState = this.readyState;
                    returnObj.status = this.status;
                    returnObj.responseText = this.responseText;
                    returnObj.responseXML = this.responseXML; func(arg); }; }})// The XMLHttpRequest constructor is assigned to _XMLHttpRequest
        let _XMLHttpRequest = window.XMLHttpRequest
        function MockRequestContructor() {
            this.xhr = new _XMLHttpRequest();
            // Assign the XMLHttpRequest instance to this.xhr to facilitate the object.defineProperty operation
        }
        // At this point, MockRequestContr is a constructor that binds the properties and methods in returnObj to his prototype
        MockRequestContructor.prototype = returnObj;
        // The front end calls new XMLHttpRequest
        // We have successfully rewritten the MockRequestContructor constructor
        window.XMLHttpRequest = MockRequestContructor; }}Copy the code

Used in projects

It only takes two steps

  1. Configure the Mock data
  2. Js files and mock methods that introduce mock data

1. Configure the mock

Configure the mock data in test_data.js where the mock data is placed, and then new MockRequest

const data = {
  "query:user": {
    "code": "S_OK"."record": [{"id": "132"."name": "silan"."job": "Front-end Development Engineer"."workTime": "Three years"}]}}var rules = [];
for (var key in data) {
// Convert to an array
  rules.push({
    url: key,
    responseText: data[key]
  })
}
/ / use the mock
 new MockRequest(rules).create()

Copy the code

2. Introduce mock data JS and mock method JS

<html lang="en">
<head>
  <meta charset="UTF-8">
  <! -- Import file -->
  <! - the mock method -- -- >
  <script src="./mockrequest.js"></script>
  <! - the mock data - >
  <script src="./test_data.js"></script>
  <title>mock</title>
</head>
<body>

  <script>
    var xhr = new XMLHttpRequest();
    / / XHR. Open (' GET 'and' https://www.apiopen.top/journalismApi ') / / here is real interfaces
    xhr.open('GET'.'query:user') // Mock data interface
    xhr.send()

    xhr.onreadystatechange = function (res) {
      if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(JSON.parse(xhr.responseText))
      }
    }
  </script>
</body>
</html>
Copy the code

The test data can be obtained successfully

Then we could try the real data interface, the / / XHR. Open (‘ GET ‘and’ https://www.apiopen.top/journalismApi ‘) uncomment this line, and comment out the mock data request method

It can also be acquired successfully

In vue to obtain other framework projects to use the same method, introduce two JS files on the line, when the debugging phase, the interface address of the debugging comment out on the line, you can get the real data

Write in the last

This article just gives you an idea of how to use an extension of Object.defineProperty, as described in the Nugget Console

Don’t blow out your inspiration and your imagination; don’t be a slave to your models.

Thank you for your attention