第二个chrome插件:尝试基于websocket的分布式任务分发模式

0x00 先唠会嗑

这篇文章中提到的chrome插件原型,是为了采集某些网站的数据而制作的。

毕竟在浏览器窗口中采集比通过发送GET/POST请求分析响应结果、调用无头浏览器运行js、**数据加密接口来的更简单

具体代码不方便拿出来分享,只能聊一聊编写的思路。

0x01 流程图介绍

图上客户端代表了安装了chrome插件的chrome浏览器。

具体流程如下:
1.控制台通过websocket服务器给客户端下发任务。
2.客户端打开时,chrome插件自动连接websocket服务器获取任务。
3.客户端采集之后发送到websocket服务器。
4.websocket服务器把获取到的采集内容存储到DB中

0x02 chrome插件

因为具体部分不方便说,所以这里就总结一下这次chrome插件开发中遇到的问题。

background-script.js和content-script.js间无法实现消息传递

最开始打算websocket是在background-script.js中发起链接的,这样可以保持长连接不会受网页关闭的影响而断开。测试的时候已经实现了在background-script.js中连接websocket,但是在background-script.js和content-script.js的消息传递中遇到了问题,两者居然无法互相通信?

经过查阅,我在chrome的官方文档中找到了如何在两者之间建立长连接(不是指websocket)的方法,但我在chrome(v78.0.3904.108)中并未成功建立链接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// content-script.js
var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
if (msg.question == "Who's there?")
port.postMessage({answer: "Madame"});
else if (msg.question == "Madame who?")
port.postMessage({answer: "Madame... Bovary"});
});

// background-script.js
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name == "knockknock");
port.onMessage.addListener(function(msg) {
if (msg.joke == "Knock knock")
port.postMessage({question: "Who's there?"});
else if (msg.answer == "Madame")
port.postMessage({question: "Madame who?"});
else if (msg.answer == "Madame... Bovary")
port.postMessage({question: "I don't get it."});
});
});

最后只能退而求其次,在content-script.js发起websocket链接。(在background-script.js建立的好处是ws链接更隐秘,如果是在content-script.js中建立则会在F12控制台network - ws 中显示出来)

另外推荐在content-script.js中加入对window.onbeforeunload的监听(离开页面事件),websocket服务端在客户端断开时也要做好异常处理。有时候直接刷新页面会导致websocket服务器因为异常断开而崩溃(但nodejs写websocket还是香!)

1
2
3
window.onbeforeunload = function () {
wsClient.close(); // 主动断开连接
}

popup的生命周期

原本以为popup的生命周期和background-script一致。测试后才发现popup的生命周期是浏览器右侧插件小图标点击后,菜单显示到消失的这个过程。关于content-script、background-script、popup之间的关系,可以参考这篇文章:【干货】Chrome插件(扩展)开发全攻略

0x03 websocket

这里用的是node-websocket这个包,非常的简单易用。可以按自己的需求拓展,后面可能会尝试写一个基于这个包的websocket框架,到时候会再开一篇写发明轮子的过程hhh。

控制台和客户端的账号区分

控制台登入时,用户标识为admin。

客户端的用户标识则是 36进制(时间戳+ip(replace掉dot符)+随机数字(100000-999999)),一般情况下这样足够得出一个够短且唯一的标识,如果想要更小的碰撞几率就不断放大随机数字的区间即可。


先写到这吧,月底前会再发一篇记账webapp的开发日记,也没什么想说的,提前给大家拜个早年吧!


评论区