乐趣区

关于前端:基于-electron-实现简单易用的抓包mock-工具

背景

常常咱们要去看一些页面所收回的申请时,常常会用到 Charles 做为抓包工具来进行接口抓取,但一方面市面是很多抓包工具都是免费或者无奈二次开发的。以后咱们团队大多数用的也都是 Charles,然而对于个别老手来说,单纯想抓个包或者批改和接口返回数据,间接上手 Charles 不论配置老本和学习老本都绝对较高。所以咱们有必要本人依照本人最爽的状态来撸一个适宜本人的抓包工具。

后果

基于以上诉求,咱们本人从新设计并批改了交互,搞了一个合乎咱们诉求,应用简略的桌面端抓包工具。自身这个插件是能够集成到 utools 外面的,然而因为很多波及到外部的性能,咱们没法通过 utools 进行公布,所以咱们本人做了一个能够应用 utools 所有生态的工具箱 Rubick。此次抓包工具也是基于 Rubick 的插件工具。

试玩地址:

Rubick: https://github.com/clouDr-f2e…

抓包插件:https://github.com/clouDr-f2e…

这次咱们先不看代码,间接来看咱们实现的抓包工具的成果:

反对 HTTP/HTTPS 申请抓取。

反对接口 mock

只须要将须要 mock 的接口,右击退出 mock 即可实现对接口数据的mock 动作,后续所有接口申请将会走到该 mock 场景:

反对代理转发

如何应用

首先咱们须要 clone Rubick 工具箱,他是一个基于 Electron 的相似于 utools 的工具箱,
仓库地址:Rubick: https://github.com/clouDr-f2e… 而后能够本地运行:

npm i
npm run dev

之后咱们会看到这样的界面:

如果相熟 utools 的同学,能够间接略过前面的步骤了。

而后再 clone 下 rubick-network 插件,所有准备就绪后,间接复制 rubick-network 下的 plugin.jsonrubick 输入框 抉择新建插件即可看到插件信息:

而后开启插件,即可进行搜寻应用!

相比 utools 而言,rubick 最大的劣势是 开源!!! 欢送社区一起建设欠缺 rubick

技术实现

当前咱们再来介绍一下是如何实现这样一款抓包代理工具的。在实现抓包代理工具之前,首先大家须要去自学一下对于 nodejs 实现代理 的一些知识点,这里举荐几篇不错的文章:

HTTP 代理原理及实现(一)

HTTP 代理原理及实现(二)

简略来讲就是要实现一个中间人,用户通过设置代理,网络申请就会通过中间人代理,再发往正式服务器。

这种中间人的实现形式有两种。

一种为一般的 HTTP 代理,通过 Node.js 开启一个 HTTP 服务,并将咱们的浏览器或手机设置到该服务所在的 ip 和端口,那么 HTTP 流量就会通过该代理,从而实现数据的拦挡。

对于非 HTTP 申请,比方 HTTPS, 或其余应用层申请。能够通过在 Node.js 中开启一个 TCP 服务,监听 CONNECT 申请,因为应用层也是基于传输层的,所以数据在达到应用层之前会首先通过传输层,从而咱们能实现传输层数据监听。

然而对于 CONNECT 捕抓到的申请,无奈获取到 HTTP 相干的信息,包含头信息等,这对个别的前端剖析作用不大,那么想要真正监听 HTTPS,还须要反对证书相干的验证。

对于证书如何生成网上也有很多教程,这里就不在赘述,能够自行百度。不过看了一圈他人的设计,本人再入手实现一个 http 代理服务就是轻而易举的事件了,然而为了更加快捷的实现性能,这里咱们抉择了 anyproxy 作为根底服务,站在伟人的肩膀上进行开发。

anyproxy 装置后提供了一个 websocket 服务,咱们只须要监听 websocket 端口对代理过去的数据进行动静展现即可:

function initWs(wsPort = 8002, path = 'do-not-proxy') {if(!WebSocket){throw (new Error('WebSocket is not supported on this browser'));
  }

  const wsClient = new WebSocket(`ws://localhost:${wsPort}/${path}`);
  wsClient.onerror = (error) => {console.error(error);
  };

  wsClient.onopen = (e) => {console.info('websocket opened:', e);
  };

  wsClient.onclose = (e) => {console.info('websocket closed:', e);
  };

  return wsClient;
}

// 链接 websocket
const connectWs = () => {const wsClient = ws.initWs();
  wsClient.addEventListener('message', (e) => {const data = JSON.parse(e.data);
    store.commit('addRecord', data.content);
  });
}

然而 anyproxy 仅仅提供 node 端的能力,所以正好 electron 能够应用 nodejs 能力,也就是咱们能够借助 electron 来实现 nodejs 能力。这里因为咱们是插件化的,所以参考 utools 的设计,实现形式如下:

// preload.js
const AnyProxy = require('anyproxy');

const options = {
  port: 8001,
  webInterface: {
    enable: true,
    webPort: 8002
  },
  forceProxyHttps: true,
  wsIntercept: false, // 不开启 websocket 代理
  silent: true
};

class Network {constructor() {this.mockList = [];
    this.proxyServer = null;
  }
  initNetwork(op, {
    beforeSendRequest,
    beforeSendResponse,
    success,
    onRecord,
  }) {if (op === 'start') {if (!this.proxyServer || !this.proxyServer.recorder) {
        const _this = this;
        options.rule = {*beforeSendRequest(requestDetail) {if (beforeSendRequest) {return beforeSendRequest(requestDetail);
            }
            return requestDetail
          },
          *beforeSendResponse (requestDetail, responseDetail) {if (beforeSendResponse) {return beforeSendResponse(requestDetail, responseDetail);
            }
            return responseDetail;
          }
        };
        this.proxyServer = new AnyProxy.ProxyServer(options);
        this.proxyServer.once('ready', () => {console.log('启动实现');
          success && success(this.proxyServer);
        });
      }
      this.proxyServer.start();} else {AnyProxy.utils.systemProxyMgr.disableGlobalProxy('http');
      AnyProxy.utils.systemProxyMgr.disableGlobalProxy('https');
      this.proxyServer.close();
      success && success();}
  }
  getIPAddress() {const interfaces = require('os').networkInterfaces();
    for (const devName in interfaces) {const iface = interfaces[devName];
      for (let i = 0; i < iface.length; i++) {const alias = iface[i];
        if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {return alias.address;}
      }
    }
  }
}

只须要在 preload.js 中加上 anyproxy 服务的实现,即可实现咱们的诉求!

结语

什么是 rubick ?

基于 electron 的工具箱,媲美 utools 的开源插件,已实现 utools 大部分的 API 能力,所以能够做到无缝适配 utools 开源的插件。之所以做这个工具箱一方面是 utools 自身并未开源,然而公司外部的工具库又无奈公布到 utools 插件中,所以为了既要享受 utools 生态又要有定制化需要,咱们本人参考 utools 设计,做了 Rubick.

欢送大家给rubick pr 和提 issue 帮忙咱们欠缺

Rubick: https://github.com/clouDr-f2e…

相干参考:

HTTP 代理原理及实现(一)

HTTP 代理原理及实现(二)

Electron + Vue 实现一个代理客户端

退出移动版