极客手中的利器:Electron

九路 等级 653 0 0

作为一个前端开发人员,你可能已经听说过Electron了,

你知道VS Code是基于这个技术开发的。

不但VS Code,目前一些大热的软件:飞书、Slack、skype的桌面版都是基于这个技术开发的。

即使如此,这也并不足以引起你的重视,

毕竟桌面软件式微,移动端和Web开发才是大方向,你的工作可能根本就不会涉及桌面开发领域的内容。

但我想告诉你的是:

即使工作不会涉及到,也应该学一下Electron,因为它是极客手里的利器,你可以通过他做很多Amazing的事情

本文主要讲讲Electron是什么,以及它能做什么极客工作。

极客手中的利器:Electron

本文大部分内容摘自我的新书《Electron实战——入门、进阶与性能优化》,目前刚刚上市:

京东购买地址: https://item.jd.com/69220543055.html

天猫购买地址: https://detail.tmall.com/item.htm?spm=a230r.1.14.144.38ec66adZeGfZS&id=618291446747&ns=1&abbucket=16

(_市面上还有另外两本关于Electron的书,它们都没有涉及本文中所讲的这些极客知识_)

同时,也欢迎对这个领域知识感兴趣的朋友加我的QQ群:949674481,一起交流

Electron是什么

官方的介绍是:

基于它开发者可以“使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序”。

我们知道 JavaScript,HTML 和 CSS都是前端的技术,前端技术是要用在浏览器中的,

Electron能让开发者这么做,它内部至少有一个浏览器核心。

没错,它内部的浏览器核心就是谷歌的Chromium

你可以把Chromium理解为Chrome的精简版,

Chromium不包含tab页的控制,搜索引擎、书签等等这类东西,

但它包含:排版引擎、渲染引擎、脚本引擎、调试工具等。

它是一个很纯净的浏览器核心(还称不上一个浏览器,只是一个浏览器核心)。

但单单有浏览器核心还不够,

因为开发一个桌面应用还涉及到文件系统访问、进程控制、使用各种网络通信协议等

(浏览器对HTTP协议支持的很好,但对更底层的TCP/IP协议就没什么支持了)

再加上各种常见加解密、集成原生程序模块等需求,

如果自己实现一套库以支持这些需求,显然工作量非常巨大,Electron团队索性把Node.js集成进来了

但这依然不够,

因为Node.js毕竟更善于做服务端的事情,大部分开发者使用Node.js都是在命令行下使用的,

像使用系统菜单、系统级快捷键、剪切板、托盘图标、系统对话框这些能力,

Node.js就显得无能为力了,

所以这部分工作是Electron团队自己用C++实现的,而且各个平台都实现了一遍,以保证跨平台需求。

可以说Chromium、Node.js和一套C++库是构成Electron的三大基石。

当然这样分析有点浮于表面,还有很多细节值得深究,

比如Electron是如何打通Chromium和Node.js的事件循环的、

Electron是如何通过主进程控制各个窗口,以及各个窗口是如何相互通信的等。

这篇文章里我们就先暂且不详细讨论这些内容。

另外,Electron也不是以我分析的这种方式设计演化来的,

它的由来还要从它的一个竞品NW.js说起

NW.js和Electron非常相似,我们前面说的三大基石NW.js也都有。

非但如此,这两个框架还有着极深的渊源,以下内容摘自我书稿的一部分:

2011年左右,中国英特尔开源技术中心的王文睿(Roger Wang)希望能用Node.js来操作WebKit,而创建了node-webkit项目,这就是NW.js的前身。当时的目的并不是用这两个技术来开发桌面GUI应用。  

中国英特尔开源技术中心大力支持了这个项目,不但允许王文睿分出一部分精力来做这个开源项目,还给了他招聘名额,允许他招聘其他工程师来一起完成这个项目。
2012年,故事的另一个主角赵成(Cheng Zhao)加入到王文睿的小组,并对node-webkit项目做出了大量的改进。
后来赵成离开了中国英特尔开源技术中心,帮助github团队尝试把node-webkit应用到Atom编辑器上,但由于当时node-webkit还并不稳定,且node-webkit项目的走向也不受赵成的控制,这个尝试最终以失败告终。
但赵成和github团队并没有放弃,而是着手开发另一个类似node-webkit的项目:Atom Shell,这个项目就是Electron的前身,赵成在这个项目上倾注了大量的心血,这也是这个项目后来广受欢迎的关键因素之一,再后来github把这个项目开源出来,最终更名为Electron。
你可能从没听说过这两个名字,但开源界就是有这么一批“英雄”,他们不为名利而来,甘做软件行业发展的铺路石,值得这个领域的所有从业者尊敬。

这些技术(三大基石)组合在一起,不但能开发出大型商业应用的桌面客户端,

而且也为一些极客应用提供了很大的便利性。下面我们把典型的几个拿出来聊聊:

注入脚本

Electron内部拥有一个完整得浏览器核心,

你可以用程序操纵这个浏览器核心,让它加载一个第三方网页,比如:淘宝的生意参谋、网易云音乐、gitee等,

但单单加载这些网页,并没有什么稀奇的,毕竟在浏览器里也能加载这些网页。

最有意思的是,你还可以给这些网页注入脚本,比如像下面这样,注入一个Js文件到目标网页:

let win = new BrowserWindow({
 webPreferences: { 
   preload: path.join(appPath, 'yourPreload.js'),
   nodeIntegration: true 
 }
});
win.loadURL('https://www.baidu.com/');

如果你只希望注入一两句代码,也可以通过如下形式注入脚本:

let decryptStr = await this.win.webContents.executeJavaScript(`window.__allen_decrypt('${encryptStr}')`);

这些脚本是在目标网页的作用域下执行的,与目标网页的工程师自己写的代码没什么区别。

想象一下,你如果想调用目标网页的某个服务端接口,你是不是应该考虑如何模拟token,如何跨域等等

现在你只需要在脚本里直接写调用接口的逻辑就可以了。

另外,如果你不喜欢目标网页的页面样式,你也可以直接注入一段样式脚本,代码如下:

let key = await win.webContents.insertCSS("html, body {  background-color: #f00 !important; }");
//await win.webContents.removeInsertedCSS(key); //在未来的某个时刻,还可以移除掉这个样式的作用

值得一提的是,你注入的脚本还可以访问Node.js的API

也就是说,你在脚本中获取到了目标网页的资源后,可以直接写到你本地文件里。

突破同源策略

注入了脚本,获取到了受限的资源,你可能希望把这些资源提交到你自己的服务器上,

或者你可能希望在注入的脚本里,访问另一个网站的API,以获取更多的资源,

这个时候,如果没做特殊配置的话,同源策略就会起作用,限制你这么干,

浏览器往往会报如下错误:

Access to XMLHttpRequest at 'https://www.domain1.com/aggsite/AggStats' from origin 'http://www.domain2.com:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

“同源策略”是浏览器的一个安全功能,

“同源”是指如果两个页面的协议(http/https)、端口和主机都相同,则两个页面具有相同的源。

同源策略规定不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。

只有同一个源的脚本才具备读写cookie、session、ajax等的操作的权限。

在Electron中突破同源策略,就是一两个配置的事情,代码如下:

let win = new BrowserWindow({
    width: 800,height: 600,
    webPreferences: {
        nodeIntegration: true,
        webSecurity: false, //此参数禁用当前窗口的同源策略
    }
})
win.loadURL('https://www.baidu.com/');

这样设置之后,浏览器的所有同源策略限制就全部失效了。

如果你只是希望在https域下访问http的资源,那么你可以不用关掉整个同源策略,

只需要把allowRunningInsecureContent这个配置设置为true即可(它同样也是webPreferences下的一个属性)

如果你设置webSecurity为false了,那么allowRunningInsecureContent会自动设置为true。

读写HttpOnly标记的Cookie

由于浏览器每次与服务端的交互,都会携带同域下的所有Cookie,

所以网站开发者往往会把标记用户身份的信息(比如用户token)放到Cookie里。

一般情况下,前端开发工程师可以使用document.cookie访问浏览器里存储的同域的Cookie,

但也有例外,凡标记了HttpOnly的Cookie,通过这种方式都是访问不到的。

网站开发者之所以这么做,主要是为了防止跨站脚本攻击(XSS)和跨站请求攻击(CSRF)

跨站脚本攻击(XSS,是Cross Site Scripting的缩写),一旦网站允许用户提交内容,并且会在网站的某些页面上显示用户提交的内容,比如留言或者博客,那么不做防范的话,就有可能受到跨站脚本攻击。恶意用户会在提交内容时在内容中夹带一些恶意JavaScript脚本,当其他用户访问页面时,浏览器会运行这些恶意脚本,恶意脚本有可能会窃取用户的Cookie、页面上的用户隐私信息等,并发送到恶意用户的服务器。他们可以通过这些窃取来的信息模拟用户身份完成非法操作。这就是跨站脚本攻击。  
跨站请求攻击(CSRF,是Cross Site Request Forgery的缩写),当用户登录了自己信赖的网站后,用户身份信息(token)会被保存保存在用户的浏览器上,后来用户又不小心打开了一个恶意网站,这个恶意网站可能会要求浏览器请求用户信赖的网站(通过iframe等形式),如果用户信赖的网站没有做安全防范的话,可能会被恶意网站获取到用户的敏感信息(token),从而给用户带来伤害。

但这个限制在Electron面前也不值一提,我们可以通过下面这种方式读写受限访问的Cookie:

//获取Cookie
async function(name) {
    let cookies = await remote.session.defaultSession.cookies.get({name});
    if(cookies.length>0) return cookies[0].value;
    else return '';
}
//设置Cookie
async function(cookie) {
    await remote.session.defaultSession.cookies.set(cookie);
}

通过这种方式,无论Cookie有没有设置HttpOnly属性,都可以成功读写。

转发/修改请求

有的时候你不单单是希望给第三方网页附加代码逻辑,

而是希望侵入式的修改第三方网站自身的代码逻辑。

但往往第三方的JavaScript代码是在一个闭包作用域内执行的

你的代码没办法注入到这个作用域内,去访问作用域内的变量或方法

碰到这样的状况该怎么办呢?

此时,你第一步要做的,就是分析清楚它的脚本是如何执行的,是哪个脚本文件执行的。

这个过程是一个非常有趣的过程,不可避免的你要用到谷歌浏览器的开发者调试工具,

如果对方的代码是压缩过的,你可能还要给它“美化”一下,再逐步调试(如下图)。

极客手中的利器:Electron

搞清楚逻辑之后,就把他的脚本文件下载下来,然后在这个文件中加上你的逻辑,

你的逻辑可能就是粗暴的把它闭包作用域内的变量暴露到window对象上。

这样你注入的脚本,就可以访问这个变量了。

(这个过程有很多技巧,因为与Electron无关,我就不展开了)

修改完这个脚本文件后,把这个脚本文件host到你自己的一个服务器上,

然后通过Electron,把网页加载这个脚本文件的请求,转发到你自己的服务器上去,

这个转发请求的代码如下:

win.webContents.session.webRequest.onBeforeRequest({ urls: ["https://*/*"] }, async (details, cb) => {
    if (details.url === 'https://g.alicdn.com/dt/op-mc/vendors.js') {
        cb({ redirectURL: 'http://domain.com/vendors.js' });
    } else {
        cb({})
    }
});

当这个网页再试图加载这个脚本时,得到的结果,将是你修改过的脚本。

有些网站,对一些敏感数据保护的很好,客户端请求这些数据时,得到的是服务端加密过的数据,

客户端执行解密后,再使用这些数据。

对于这类网站,Electron的这个能力,无疑是非常有力的。

当然,你也可以考虑使用service worker来办这个事儿,甚至可以自己在客户端模拟一个响应,不用再经由你的服务器转发了。

如果你没有自己的服务器,也可以通过Node.js的能力,自己在软件里起一个localhost的服务。

反“防盗链”

有的时候,你可能只是想把目标网站的一些静态资源嵌入到你的应用程序中,

比如:图片或者视频

然而如果目标网站已经做了防盗链的工作,你这个功能可能就没那么容易实现了。

防盗链的主要目的有两个:一个是版权问题,别人未经授权就使用你的资源,

另一个是流量压力的问题,盗链产生了大量的请求,这些请求对于网站运营者来说没任何价值。

防盗链最常见的做法就是识别HTTP的Refer请求头,这个请求头代表着发起请求时前一个网页的地址,

网站运维工程师会根据这个Refer请求头来推测出当前请求是否为一个盗链请求,

(判断这个Refer请求头的内容是不是自己域名下的一个地址)

Electron允许开发者监听发起请求的事件,并允许开发者在发起请求前修改请求头

我们可以在这个事件里修改这个Refer请求头,代码如下:

let session = window.webContents.session;
let requestFilter = { urls: ["http://*/*", "https://*/*"] };
session.webRequest.onBeforeSendHeaders(
    requestFilter,
    (details, callback) => {
      if (details.resourceType == "image" && details.method == "GET") {
        delete details.requestHeaders["Referer"]; //这里我直接删掉了这个请求头,也可以修改成其他内容
      }
      callback({ requestHeaders: details.requestHeaders });
    }
);

给应用植入socks5代理科学上网

Chrome本身是支持代理的

使用Electron你可以通过编程的方式把你的代理内置到你的应用程序中

这样你的用户就可以自由的访问国外的一些网站了

这部分的技术我不多做介绍了,书里写了。

最后

我曾经用Electron开发过一个文章发布工具,可以把文章一键发布到:博客园、CSDN、简书、大鱼号、头条号等

不过很久没维护了,希望以后有时间再重写一版。

收藏
评论区

相关推荐

极客手中的利器:Electron
作为一个前端开发人员,你可能已经听说过Electron(https://www.electronjs.org/)了, 你知道VS Code是基于这个技术开发的。 不但VS Code,目前一些大热的软件:飞书、Slack、skype的桌面版都是基于这个技术开发的。 即使如此,这也并不足以引起你的重视, 毕竟桌面软件式微,移动端和Web开发才是大方向
记录一次electron踩坑
Vue2.x版本 https://github.com/dmhsq/electronvuedmhsq(https://github.com/dmhsq/electronvuedmhsq) 或者 https://github.com/dmhsq/electronvue/tree/main/template(https://github.com
cookie和session的详解与区别
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。 本章将系统地讲述Cookie与Session机制,并比较说明什么时候不能用Cookie,什么时候不能用Session。 1.1  C
【Electron】electron-vue 借助 element-ui UI 库助力桌面应用开发
前面文章我们讲过 electron 让可以用 HTML、JS、CSS 开发桌面应用程序。而 electronvue 是一个结合了 electron 与 vue 的套件。这样我们就能方便地使用 vue 快速开发桌面应用。但是,vue 只是在 js 这层面做了大量的便捷的操作。对 UI 并未过多涉及。此时如果您在开发过程中自己实现一套统一主题的 UI 视觉效果
JavaScript中本地存储的方式有哪些?
(https://imghelloworld.osscnbeijing.aliyuncs.com/1f907f0895e2be23aa56604dd42e3626.png) 一、方式 javaScript本地缓存的方法我们主要讲述以下四种: cookie sessionStorage loc
Chrome 中 Set-Cookie SameSite 问题
关于 “Chrome 修改对未设置 SameSite 的 cookie,视作 SameSite:Lax 处理的变更” 的问题,目前看,最妥善的解决方案还是按照规矩办事儿,目前 Chrome 是行动最快的,而 FireFox 和 Edge 也在积极跟进,持支持态度。 影响范围: 如果你的项目中有如下跨域场景: 1. 跨域的 ajax
PHP Cookie与Session的使用与区别
Cookie与SessionCookie和session是目前使用的两种存储机制。cookie是从一个WEB页到下一个WEB页面的数据传送方法,cookie存储在客户端;Session是让数据在页面中持续有效的一个传递方法,session存储在服务器端。掌握了cookie与session这两个技术,在WEB网站页面间信息传递的安全性是
【Electron】第一个用 Electron 开发的桌面应用程序
2020 年注定是不平凡的一年,全国人民饱受疫情的困扰。好在目前已经抗疫已经取得关键性的成功。自己也好很久没有更新自己的博客。中年危机下,博主也在寻找自己的方向。坚信方向比努力更重要。这不,最近突然想开发一款至力于服务 PHP 开发者的工具。这款工具呢也是目前我经常会用到的一些功能。比如,JSON 美化、MD5 加密、正则、URL 重写、HOSTS 管理、经
11个基于vue的UI框架_U.R.M.L
Element UI 来自中国,由与 Mint UI 相同的开发者所创建。Element UI 是用于 Web 和桌面应用程序的桌面 UI 工具包,如果你需要开发 Electron 应用,这个库会是你的理想之选。 iView 是一个 UI 工具包,其中包含简洁又设计优雅的小部件和各种组件。iView 团队维护非常及时,最近一次的更新在19年3
(win环境)使用Electron打造一个桌面应用翻译小工具
初始化项目npm init 修改package.json "name": "trans", "version": "1.0.0", "main": "main.js", "license": "MIT", "scripts": "start": "electron .", "build":"electronpackager . ove
electron:桌面应用程序的革命
“ 你也许不了解electron,但你应该了解或使用过atom、vscode、xmin zend,没错他们所使用的开发技术就是electon,通过前端技术开发桌面应用程序,刚开始接触electron时,考虑最多的是性能问题,不过作为一个vscode、xmin zen重度使用者的我来说,基本上对其性能的担心减少了很多,并且发现了基于vue框架构造electro
从零使用electron搭建桌面端可视化编辑器
之前有朋友希望我基于H5Dooring开发一款桌面端应用, 最近刚好有时间, 就花了小半天时间从零使用electron开发了桌面端的离线软件Dooringelectron. 因为之前用electron比较少, 今天刚好学了一下, 也基本把前后端打通了, 文末我会放dooringelectron的github地址供大家参考学习. 如果大家有更好的方案, 可以随
Java面试真题解析火爆全网,讲的太透彻了
8.15 一面 (60min) 自我介绍,为什么投客户端 python和java有什么区别 java内存模型 gc讲讲 http https区别 cookie,session https握手过程 对称非对称加密算法?哪个效率高? tcp握手要三次,挥手要几次,为什么 进程和线程,描述一下 进程通信方式 线程同步
BAT这种大厂履历意味着什么?面试篇
8.15 一面 (60min) 自我介绍,为什么投客户端 python和java有什么区别 java内存模型 gc讲讲 http https区别 cookie,session https握手过程 对称非对称加密算法?哪个效率高? tcp握手要三次,挥手要几次,为什么 进程和线程,描述一下 进程通信方式 线程同步
Cookie和Session
Cookie是浏览器(User Agent)访问一些网站后,这些网站存放在客户端的一组数据,用于使网站等跟踪用户,实现用户自定义功能。 Cookie的Domain和Path属性标识了这个Cookie是哪一个网站发送给浏览器的;Cookie的Expires属性标识了Cookie的有效时间,当Cookie的有效时间过了之后,这些数据就被自动删除了。 如 果不设置