前端本地开发mock《快照,快照,快照》

133 阅读4分钟

写了一个插件是把接口返回的数据存到indeDB里面,等你这个接口访问不通的时候通过这个插件把上一次成功的数据返回给你,

mock快照链接 这个插件是需要 Tampermonkey 为平台运行

1.请求拦截

重写ajax请求借助轮子ajax-hook

// @require      https://unpkg.com/ajax-hook@3.0.2/dist/ajaxhook.min.js

E1D41AFF-9FB6-4b04-8239-4C46B095AE32.png

这个ah就是ajax-hook的cnd引入的全局变量

  ah.proxy(
    {
      //请求发起前进入
      onRequest: (config, handler) => {
        console.log(config.url);
        handler.next(config);
      },
      //请求发生错误时进入,比如超时;注意,不包括http状态码错误,如404仍然会认为请求成功
      onError: (err, handler) => {
        console.log(err);
        handler.next(err);
      },
      //请求成功后进入
      onResponse: async (response, handler) => {
        console.log(response);
        handler.next(response);
      },
    },
    window
  );

现在请求的拦截都已经好了

2.增删改查indeDB的数据

 let creatUpdateStore = function (name, verson = 1) {
    console.log('creatUpdateStore');
    // 打开数据库
    let request = window.indexedDB.open(name, verson);

    request.onsuccess = function (event) {
      console.log('open success');
    };

    request.onerror = function (event) {
      console.log('open fail');
    };

    request.onupgradeneeded = function (event) {
      let db = event.target.result;
      if (!db.objectStoreNames.contains(name)) {
        // 创建仓库对象(创建表格)
        // 这里我将主键设置为id
        let objectStore = db.createObjectStore(name, {
          keyPath: 'id',
          autoIncrement: true,
        });
      }
    };
  };

  // 往数据库中加数据
  let addDataStore = function (storeName, data, verson) {
    console.log('addDataStore');
    return new Promise((resolve, reject) => {
      let databaseName = storeName;
      let databaseVersion = verson || 1;
      let db;
      let request = indexedDB.open(databaseName, databaseVersion);
      request.onsuccess = function (event) {
        db = event.target.result;
        db = event.target.result;
        // 将数据保存到新建的对象仓库
        let objectStore = db
          .transaction(databaseName, 'readwrite')
          .objectStore(databaseName);

        try {
          objectStore.get(data.id);
          objectStore.put(data);
        } catch (e) {
          if (Array.isArray(data)) {
            data.forEach(function (dataItem) {
              // 添加一条数据
              objectStore.add(dataItem);
            });
            resolve();
          } else {
            // 添加一条数据
            objectStore.add(data);
            resolve();
          }
        }
      };
      request.onupgradeneeded = function (event) {
        let db = event.target.result;
        if (!db.objectStoreNames.contains(storeName)) {
          // 创建仓库对象(创建表格)
          // 这里我将主键设置为id
          let objectStore = db.createObjectStore(storeName, {
            keyPath: 'id',
            autoIncrement: true,
          });
        }
      };
    });
  };

  // 获取数据
  let getStoreData = function (name, key = 1) {
    console.log('getStoreData');
    return new Promise((resolve, reject) => {
      let request = indexedDB.open(name);
      request.onsuccess = function (event) {
        let db = event.target.result;
        let req;
        try {
          req = db.transaction(name, 'readwrite').objectStore(name).get(key); // 这里的“1”也是主键的键值
        } catch (e) {
          reject('用户失败');
        }
        if (!req) {
          return;
        }
        req.onsuccess = function () {
          resolve(req.result.value);
        };
        req.onerror = function () {
          reject('获取失败');
        };
      };
      request.onupgradeneeded = function (event) {
        let db = event.target.result;
        if (!db.objectStoreNames.contains(name)) {
          // 创建仓库对象(创建表格)
          // 这里我将主键设置为id
          let objectStore = db.createObjectStore(name, {
            keyPath: 'id',
            autoIncrement: true,
          });
        }
      };
    });
  };
creatUpdateStore('chenliwen'); //名字随便起嗷

3. 把他们关联到一起

 onResponse: async (response, handler) => {
        const key = handler.xhr.responseURL.replace(/_t=.*/g, ''); // 处理了一下时间戳的问题
        if (response.statusText === 'Gateway Timeout') { // 判断是不是超时引发的错误
          response.status = 200;
          response.statusText = 'OK';
          const res = await getStoreData('chenliwen', key);
          response.response = res;
        } else {
          addDataStore('chenliwen', {
            id: key,
            value: response.response,
          });
        }
        handler.next(response);
      },

4.完整代码

// ==UserScript==
// @name         mock快照
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  mock数据快照,会把上一次成功的数据保存起来,等下一次访问报错的时候 把上一次的数据返回给你
// @author       You
// @match        http://*/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license MIT
// @run-at document-start
// @require      https://unpkg.com/ajax-hook@3.0.2/dist/ajaxhook.min.js
// ==/UserScript==

(function () {
  'use strict';
  // 创建/更新一个数据库
  let creatUpdateStore = function (name, verson = 1) {
    console.log('creatUpdateStore');
    // 打开数据库
    let request = window.indexedDB.open(name, verson);

    request.onsuccess = function (event) {
      console.log('open success');
    };

    request.onerror = function (event) {
      console.log('open fail');
    };

    request.onupgradeneeded = function (event) {
      let db = event.target.result;
      if (!db.objectStoreNames.contains(name)) {
        // 创建仓库对象(创建表格)
        // 这里我将主键设置为id
        let objectStore = db.createObjectStore(name, {
          keyPath: 'id',
          autoIncrement: true,
        });
      }
    };
  };

  // 往数据库中加数据
  let addDataStore = function (storeName, data, verson) {
    console.log('addDataStore');
    return new Promise((resolve, reject) => {
      let databaseName = storeName;
      let databaseVersion = verson || 1;
      let db;
      let request = indexedDB.open(databaseName, databaseVersion);
      request.onsuccess = function (event) {
        db = event.target.result;
        db = event.target.result;
        // 将数据保存到新建的对象仓库
        let objectStore = db
          .transaction(databaseName, 'readwrite')
          .objectStore(databaseName);

        try {
          objectStore.get(data.id);
          objectStore.put(data);
        } catch (e) {
          if (Array.isArray(data)) {
            data.forEach(function (dataItem) {
              // 添加一条数据
              objectStore.add(dataItem);
            });
            resolve();
          } else {
            // 添加一条数据
            objectStore.add(data);
            resolve();
          }
        }
      };
      request.onupgradeneeded = function (event) {
        let db = event.target.result;
        if (!db.objectStoreNames.contains(storeName)) {
          // 创建仓库对象(创建表格)
          // 这里我将主键设置为id
          let objectStore = db.createObjectStore(storeName, {
            keyPath: 'id',
            autoIncrement: true,
          });
        }
      };
    });
  };

  // 获取数据
  let getStoreData = function (name, key = 1) {
    console.log('getStoreData');
    return new Promise((resolve, reject) => {
      let request = indexedDB.open(name);
      request.onsuccess = function (event) {
        let db = event.target.result;
        let req;
        try {
          req = db.transaction(name, 'readwrite').objectStore(name).get(key); // 这里的“1”也是主键的键值
        } catch (e) {
          reject('用户失败');
        }
        if (!req) {
          return;
        }
        req.onsuccess = function () {
          resolve(req.result.value);
        };
        req.onerror = function () {
          reject('获取失败');
        };
      };
      request.onupgradeneeded = function (event) {
        let db = event.target.result;
        if (!db.objectStoreNames.contains(name)) {
          // 创建仓库对象(创建表格)
          // 这里我将主键设置为id
          let objectStore = db.createObjectStore(name, {
            keyPath: 'id',
            autoIncrement: true,
          });
        }
      };
    });
  };
  creatUpdateStore('chenliwen');
  ah.proxy(
    {
      //请求发起前进入
      onRequest: (config, handler) => {
        console.log(config.url);
        handler.next(config);
      },
      //请求发生错误时进入,比如超时;注意,不包括http状态码错误,如404仍然会认为请求成功
      onError: (err, handler) => {
        console.log(err);
        handler.next(err);
      },
      //请求成功后进入
      onResponse: async (response, handler) => {
        const key = handler.xhr.responseURL.replace(/_t=.*/g, '');
        if (response.statusText === 'Gateway Timeout') {
          response.status = 200;
          response.statusText = 'OK';
          const res = await getStoreData('chenliwen', key);
          response.response = res;
        } else {
          addDataStore('chenliwen', {
            id: key,
            value: response.response,
          });
        }
        handler.next(response);
      },
    },
    window
  );
})();

待完善

  • 现在是根据地址查询如果一个地址相同不论它的参数是什么返回的都是相同的
  • 可以再根据地址和参数作为唯一条件进行处理

最后示例

成功就是这样的 虽然报错了但是数据都返回给你了

1695368193786.jpg