在与 Electron 相同的 BrowserWindow 中拥有两个独立的(就历史记录/cookies/本地存储而言)BrowserViews

2023-12-24

假设我有两个BrowserView在相同的BrowserWindow和一个 UI 按钮,允许用户在显示之间切换bv1 or bv2(就像 Firefox、Chrome 等浏览器中的“选项卡”系统一样,允许您在不同页面之间切换):

browserWindow = new BrowserWindow({ width: 1200, height: 600 });

let bv1 = new BrowserView({ webPreferences: { nodeIntegration: false }});
bv1.setBounds({ x: 0, y: 0, width: 1200, height: 600 });
bv1.webContents.loadURL('https://www.twitter.com');

let bv2 = new BrowserView({ webPreferences: { nodeIntegration: false }});
bv2.setBounds({ x: 0, y: 0, width: 1200, height: 600 });
bv2.webContents.loadURL('https://www.twitter.com');

browserWindow.setBrowserView(bv1);

当按下按钮(如浏览器中的“选项卡”)时:

browserWindow.setBrowserView(bv2);

我注意到这两个BrowserView:

  • 共享相同的cookie/localStorage(我不想要!),即如果第一个连接到一个帐户,第二个也将连接到同一个帐户

  • 重新启动 Electron 应用程序后保留历史记录和 cookie(这很好,确实需要!)

问题:如何同时拥有这两个BrowserView 完全孤立就 cookies/localStorage/history 而言(因此bv1可以连接到一个 Twitter 帐户并且bv2到另一个)?


因此,我设法以一种非常非常迂回的方式实现了这一点。有效地会话劫持您自己的会话,在应用程序关闭/打开时保存并加载它。下面的代码带有一些注释,前面有一些有用的链接。这在作为开发运行时以及使用构建应用程序运行时有效。

您可能需要像这样在本地存储 cookie 来研究可能的安全问题。

我在这个答案中唯一没有解决的问题是:

重新启动 Electron 应用程序后保留历史记录


  • Electron-Json-存储包 https://github.com/electron-userland/electron-json-storage- 我们用它来存储/检索cookie。默认存储位置是C:\Users\%user%\AppData\Roaming\%appname%\storage.
  • Electron Cookie 文档 https://electronjs.org/docs/api/cookies
  • Electron 会话文档 https://electronjs.org/docs/api/session- 值得注意的是session.fromPartition docs.

const { app, BrowserWindow, BrowserView, globalShortcut, session } = require('electron');
const eJSONStorage = require('electron-json-storage');

// Our two different sesions, views, and base URL for our 'tabs'.
let bv1Session, bv2Session = session;
let bv1, bv2 = BrowserView;
const appTabUrl = 'https://www.twitter.com';

app.on('ready', () => {
  const width = 1200; const height = 600;
  let b1Active = true;

  // Our browser window
  browserWindow = new BrowserWindow({
    width: width,
    height: height,
  });

  // Our first browser window with it's own session instance.
  bv1Session = session.fromPartition('persist:bv1Session', { cache: true });
  bv1 = createBrowserView(appTabUrl, bv1Session, width, height);
  loadCookieState('view1Cookies', bv1Session);

  // Our second browser window with it's own session instance.
  bv2Session = session.fromPartition('persist:bv2Session', { cache: true });
  bv2 = createBrowserView(appTabUrl, bv2Session, width, height);
  loadCookieState('view2Cookies', bv2Session);

  // Our initial setting of the browserview
  browserWindow.setBrowserView(bv1);

  // Our shortcut listener and basic switch mechanic
  // Set to [CTRL + /] for windows or [CMD + /] for OSX
  globalShortcut.register('CommandOrControl+/', () => {
    b1Active ? browserWindow.setBrowserView(bv2) : browserWindow.setBrowserView(bv1);
    b1Active = !b1Active
  });
});

// When the app closes, exit gracefully.
// Unregister keypress listener, save cookie states, exit the app.
app.on('window-all-closed', () => {
  globalShortcut.unregisterAll();
  saveCookieState('view1Cookies', bv1Session);
  saveCookieState('view2Cookies', bv2Session);
  app.quit();
})

// Helper method to generate a browser view.
function createBrowserView(url, session, width, height) {
  let browserView = new BrowserView({
    webPreferences: {
      nodeIntegration: false,
      nodeIntegrationInWorker: false,
      session: session
    }
  });
  browserView.setBounds({ x: 0, y: 0, width: width, height: height });
  browserView.webContents.loadURL(url);
  return browserView;
}

// Method that takes a session name, and our current session to save its state.
function saveCookieState(sessionName, currentSession) {
  currentSession.cookies.get({}, (_, cookies) => {
    cookies.forEach(cookie => {
      // URL is a required paramater, take it from the domain with a little parsing.
      // Twitter always uses HTTPS otherwise, we would need to check for http vs https too.
      const cDomain = !cookie.domain.startsWith('.') ? `.${cookie.domain}` : cookie.domain;
      cookie.url = `https://www${cDomain}`
    });
    // Save the set of cookies against the session name.
    eJSONStorage.set(sessionName, cookies, err => {
      if (err) {
        throw err;
      }
    });
  });
}

// Method that loads a session based on its name, into a session created by us.
function loadCookieState(sessionName, currentSession) {
  eJSONStorage.get(sessionName, (error, cookieData) => {
    // Check for empty object returned, this means no saved sessions.
    if (Object.entries(cookieData).length === 0) {
      return;
    }
    if (error) {
      throw error;
    }
    // If we have saved sessions and no errors, load the sessions.
    cookieData.forEach(cookie => currentSession.cookies.set(cookie, error => {
      if (error) console.error(error);
    }));
  });
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在与 Electron 相同的 BrowserWindow 中拥有两个独立的(就历史记录/cookies/本地存储而言)BrowserViews 的相关文章

  • 茉莉花节点没有输出

    我是 JavaScript Node js 和 jasmine 的新手 我正在尝试运行 Node Craftsman Book 一书中的测试 FilesizeWatcher 我创建了 package json 文件并运行 npm insta
  • 使用 javascript 调用 ViewComponent

    我有一个带有几个视图组件的网页 当我单击这些组件时 我会为其打开一个简单的编辑器 请参见下图 如果我编辑文本并按 Enter 键 我想重新渲染视图组件而不是孔页面 是否可以使用 javascript 调用视图组件来获得此行为 通过更新 您现
  • 邮件附件媒体类型错误 Gmail API

    我正在尝试通过 Javascript 客户端中的 Gmail API 发送带有附加 jpeg 文件的消息 到目前为止我写的代码如下 ajax type POST url https www googleapis com upload gma
  • 如何制作像Stackoverflow一样的可折叠评论框

    我正在构建一个网站 并且有一个状态更新列表 我希望允许用户为列表中的每个项目撰写评论 但是我正在尝试实现一个类似于堆栈溢出工作方式的用户界面 特别是可折叠的评论表单 列表 用户在其中单击对列表中的特定状态更新添加评论 并且在列表中的该项目下
  • 如何在CKEditor 5中监听焦点事件

    我想听一下 CKEditor 5 中的焦点事件 我认为这样的事情会起作用 但回调从未被调用 document querySelector editable ClassicEditor create el then editor gt edi
  • ExtJS 4:克隆商店

    我正在尝试找出如何克隆Ext data Store不保留旧的参考 让我用一些代码更好地解释一下 这是源商店 var source Ext create Ext data Store fields name age data name foo
  • twitter bootstrap css 在 chrome 扩展中发生冲突

    我正在使用 bootstrap 来编写我正在编写的 chrome 扩展 当作为内容脚本导入时 CSS 似乎与我正在查看的许多网站发生冲突 即使在谷歌搜索结果页面中 想知道我是否可以做些什么来将其范围限制为我使用内容脚本注入的 dom 元素
  • 如何在 JavaScript 中构建一个计算数组中出现次数的对象?

    我想计算数组中某个数字出现的频率 例如 在Python中我可以使用Collections Counter创建一个字典 记录某个项目在列表中出现的频率 据我所知 JavaScript 是这样的 var array 1 4 4 5 5 7 va
  • 阻止特定 URL 进行测试的最佳方法是什么?

    我正在使用 Google Chrome 和 Fiddler 版本 4 4 观察一个网站 该页面正在使用 AJAX 来更新其数据 我想阻止特定的 URL 以测试如果它不起作用会发生什么 阻止 URL 最简单的方法是什么 你希望发生什么 转到自
  • 带有嵌入式 Ruby 的 Javascript:如何安全地将 ruby​​ 值分配给 javascript 变量

    我在页面的 javascript 块中有这一行 res foo 处理这种情况的最佳方法是什么 ruby var里面有单引号吗 否则会破坏 JavaScript 代码 我想我会用红宝石JSON http json org ruby var 上
  • NodeJS 无法加载 css 文件

    所以我正在尝试制作一个 NodeJS 服务器 并且我尝试保留尽可能少的附加组件 但是 我遇到了一个问题 我似乎无法加载任何内容CSS我调用的文件HTML文件 该调用似乎确实由服务器处理 但它不会显示在浏览器中 My 网络服务器 js fil
  • Rxjs 可观察等待直到满足某些条件

    我有以下重试逻辑来重试操作 对于单个请求来说它工作得很好 对于多个正在进行的请求 我想在重试之前等待现有的重试逻辑完成 handleError errors Observable
  • 对数字和字母元素的数组进行排序(自然排序)

    假设我有一个数组 var arr 1 5 ahsldk 10 55 3 2 7 8 1 2 75 abc huds 我尝试对其进行排序 我得到了类似的东西 1 1 10 2 2 3 5 55 7 75 8 abc ahsldk huds 注
  • Web浏览器控件:如何捕获文档事件?

    我正在使用 WPF 的 WebBrowser 控件加载一个简单的网页 在这个页面上我有一个锚点或一个按钮 我想在我的应用程序后面的代码中 即在 C 中 捕获该按钮的单击事件 WebBrowser 控件是否有办法捕获加载页面元素上的单击事件
  • 在外部单击时关闭弹出 div

    我有一个弹出 div 仅在单击特定按钮时显示 单击同一按钮时它甚至会隐藏 我的问题是 我还想在单击外部任何地方时隐藏 div 我无法这样做 因为弹出 div 位于主包装类内部 并且无法通过在包装类上使用 click 事件并使其隐藏来做到这一
  • 如何在 OpenLayers 3 中删除监听器

    我做了一个copy https gis stackexchange com questions 178222 how to delete a listener in openlayers 3我在 stackoverflow 上提出的问题 因
  • 如何为 ng-repeat orderBy 创建回调?

    寻找一种方法让 AngularJS 的 ng repeat orderBy 过滤器在完成渲染后执行回调 Markup div table thead tr th Name th th Age th tr thead tbody tr tr
  • 单击react.js 切换列表的背景颜色

    我正在尝试创建一个具有以下功能的列表 悬停时更改列表项的背景颜色 单击时更改列表项的背景颜色 在单击的元素之间切换背景颜色 即列表中只有一个元素可以具有 clicked 属性 我已经执行了 onhover 1 和 2 功能 但无法实现第三个
  • nvd3.js - 无法更改折线图中线条的颜色

    我正在尝试更改 nvd3 折线图不同线条的颜色here http nvd3 org livecode index html codemirrorNav但我无法理解该怎么做 我想将示例中的 2 条线的颜色更改为绿色和青色 我试过 nv add
  • html5 canvas 使用图像作为蒙版

    是否可以使用具有形状的图像作为整个画布或画布内图像的蒙版 我想将图像放置在画布中 并在图像上添加蒙版 然后将其另存为新图像 您可以使用 source in globalCompositeOperation 将黑白图像用作蒙版 首先 将蒙版图

随机推荐