Electron 会话管理
浏览器向 Web 服务器发出的一系列请求被称为会话,Electron 提供的 session API 就是用于管理浏览器会话的,包括浏览器缓存、本地存储(localstorage、cookie、indexdb等)、网络代理、设备权限、请求拦截、插件安装的等。
有两种方法可以拿到 session 实例:
session.defaultSession
应用的默认 sessionsomeWebContents.session
某个 webContents 使用的 session
默认情况下,整个 Electron 软件使用同一个 session 对象,创建窗口(BrowserWindow)时,如果没有在 webPreferences 中指定 session,那么就会使用默认 session 对象:
const win = new BrowserWindow({ width: 400, height: 300 })
win.loadURL('https://www.baidu.com')
console.log(session.defaultSession === win.webContents.session) // true
webPreferences 中两个属性可以创建不同的 session:
session
:指定一个 session 对象partition
:指定 partition 字符串
// 指定一个 session 对象
const newSession = session.fromPartition('new')
const win = new BrowserWindow({ width: 400, height: 300, webPreferences: { session: newSession } })
win.loadURL('https://www.baidu.com')
console.log(session.defaultSession === win.webContents.session) // false
console.log(win.webContents.session === newSession) // true
// 指定 partition 字符串
win = new BrowserWindow({ width: 400, height: 300, webPreferences: { partition: 'new' } })
win.loadURL('https://www.baidu.com')
console.log(session.defaultSession === win.webContents.session) // false
当同时使用 session 和 partition 的时候,session 的优先级更高。接下来看看如何创建 session:
创建 session
提供的 fromPartition
方法可以用于创建 Session 对象,那么 partition 是什么意思呢?字面含义为:
隔墙,隔板;(化学)分离层;(计算机)存储分区;(数学)分割
即通过分隔标识符来创建唯一的 Session 实例,用法如下:
const s1 = session.fromPartition('hello', { cache: false })
const s2 = session.fromPartition('world')
const s3 = session.fromPartition('hello', { cache: true })
console.log(s1 === s2) // false
console.log(s1 === s3) // true
可以看到,该函数需要两个参数:
partition
:字面意思是分隔、隔板,用于区分是否是同一个会话options
:配置项,目前里面只有一个cache
字段表示是否开启缓存
这种语法有点类似于 ES6 中 Symbol 的用法:
用 Symbol.for()
方法创建的的 symbol 会被放入一个全局 symbol 注册表中。Symbol.for()
并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。假如是,则会直接返回上次存储的那个。否则,它会再新建一个。
如果 partition 以 persist:
开头,那么整个应用的所有页面都会使用这个持久化的 session,否则页面会使用一个存储在内存当中的 session,可以通过 isPersistent
方法判断是否是持久化的 session,Electron 默认的 session 是持久化的:
session.defaultSession.isPersistent() // true
使用 session
session 模块看起来非常抽象,初学者往往不知道有什么用,其实 session 的能力非常强大,接下来通过案例的方式为大家讲解 session 模块的常用 API。
设置代理
什么是代理,当电脑 A 无权限访问网络,电脑 B 可以上网,将电脑 A 连接电脑 B,然后通过 B 来上网,那么 B 就是 A 的代理服务器。常见的代理服务器有 http 代理、https 代理、socks 代理。
win = new BrowserWindow({ width: 400, height: 300 })
win.loadURL('https://www.ip138.com')
如果在本地开启了代理,
win.webContents.session.setProxy({
proxyRules: 'socks5://127.0.0.1:13659',
})
win.webContents.session.resolveProxy('https://www.baidu.com')
.then((info) => console.log(info))
如果未使用代理,返回 DIRECT
,如果使用代理,返回 SOCKS5 127.0.0.1:13659
页面缓存
正常情况下,浏览器使用缓存机制来提升页面加载速度,内存和硬盘里面都会有一个缓存区,内存的缓冲区叫做 memory cache,硬盘的缓冲区叫做 disk cache,我们创建一个窗口,加载百度首页,首次加载是没有缓存的,所有资源全部通过发送 http 请求获取:
如果你在短时间快速刷新(cmd+R),会看到,大部分的资源都变成从 memory cache 中获取的:
如果隔一段时间刷新,内存中的部分缓存会过期,但有些资源在是 disk cache 中还能查到:
你可能会好奇:什么时候会命中 memory cache ,什么时候回命中 disk cache?这个问题知乎上面有人问过,由于浏览器内部实现非常复杂,没有人能够解释清楚背后的具体逻辑。控制台里面的缓存来源,据说是一个开发者一时兴起加的。再回到 session 模块来,如果在创建的时候,指定了 cache 为 false:
const newSession = session.fromPartition('new', { cache: false })
win = new BrowserWindow({ width: 400, height: 300, webPreferences: { session: newSession } })
经过多次刷新,发现无论怎样 disk cache 都没了,只剩下 memory cache 了:
所以 session 中的 cache 是用于控制是否缓存到硬盘,而并非完全禁用所有缓存(包括内存缓存、代码缓存等),表现行为有点类似于浏览器的隐私模式。所以下面的两个 API 可以暂时理解为对硬盘缓存的操作:
getCacheSize
:获取缓存大小clearCache
:清空缓存
除了上述缓存之外,还有很多的缓存种类,开发中一般用不到,了解即可:
clearHostResolverCache
:清空 host 缓存clearAuthCache
:清空 http 认证缓存clearCodeCaches
:清空代码缓存setCodeCachePath
:设置代码缓存路径
资源加载
设置和获取预加载的脚本,:
setPreloads
:设置 preload 脚本getPreloads
:获取 preload 脚本
一般情况下,preload 脚本是在 webPreferences 中设置的,
const win = new BrowserWindow({
width: 400,
height: 300,
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
},
})
win.loadURL('https://www.baidu.com')
不过只能设置一个 preload 文件,通过 session 提供的 setPreloads 方法,不仅可以设置多个,而且执行顺序在比 webPreferences 更靠前,例如 preload/index.js
中打印 preload,preload/p1.js
中打印 p1,preload/p2.js
中打印 p2:
const newSession = session.fromPartition('new', { cache: false })
const win = new BrowserWindow({
width: 400,
height: 300,
webPreferences: {
session: newSession,
preload: path.join(__dirname, '../preload/index.js'),
},
})
win.loadURL('https://www.baidu.com')
const preloads = newSession.getPreloads()
console.log(preloads) // []
newSession.setPreloads([
path.join(__dirname, '../preload/p1.js'),
path.join(__dirname, '../preload/p2.js'),
])
console.log(newSession.getPreloads())
/*
[
'/Users/keliq/electron-desktop/src-apis/session/preload/p1.js',
'/Users/keliq/electron-desktop/src-apis/session/preload/p2.js'
]
*/
最终的效果是:
本地存储
存储相关的操作:
getStoragePath
:获取存储的路径(内存会话则返回 null)clearStorageData
:清空本地存储数据(可以指定 origin 和存储类型)flushStorageData
:将所有的存储数据持久化到磁盘
代码演示:
const newSession = session.fromPartition('new', { cache: false })
console.log(newSession.getStoragePath()) // null
const newSession = session.fromPartition('new', { cache: true })
console.log(newSession.getStoragePath()) // null
const newSession = session.fromPartition('persist:new', { cache: false })
console.log(newSession.getStoragePath()) // ~/Library/Application Support/electron-desktop/Partitions/new
const newSession = session.fromPartition('persist:new', { cache: true })
console.log(newSession.getStoragePath()) // ~/Library/Application Support/electron-desktop/Partitions/new
可以看到,如果以 persist:
开头,那么是存在实际存储路径的,通过 getStoragePath
方法拿到具体路径后,进入发现有四个目录:
- Cache
- Code Cache
- Local Storage
- blob_storage
其中 Cache 目录就是用于存放硬盘缓存数据的,后面的 clearStorageData
和 flushStorageData
方法也是针对于这个目录进行操作的。另外,getStoragePath
方法也可以直接用 session.storagePath
属性替代,效果一样。
权限控制
session.defaultSession.setDisplayMediaRequestHandler((request, callback) => {
desktopCapturer.getSources({ types: ['screen'] }).then((sources) => {
callback({ video: sources[0] })
})
})
插件管理
Electron 中也可以加载 Chrome 插件,提供了 4 个方法:
loadExtension
:加载插件removeExtension
:移除插件getExtension
:根据 id 获取插件getAllExtensions
:查看所有插件
还有 3 个对应的事件:
extension-loaded
:插件加载事件extension-unloaded
:插件卸载事件extension-ready
:插件就绪事件
文件下载
downloadURL
方法可以初始化一个下载,然后在 will-download
事件当中拿到 download-item 对象,可以定制下载行为。还可以通过 createInterruptedDownload
来实现断点续传的效果。
操作 cookie
可以拿到所有的 cookie,包括 http-only 的也能拿到,常用方法有:
get
:获取 cookieset
:设置 cookieremove
:删除 cookieflushStore
:写入磁盘
另外,changed
事件还可以监听 cookie 发生变化,包括添加、删除、修改或者过期。
转载自:https://juejin.cn/post/7246671793032331320