Electron中的nodeIntegration、preload.js和IPC之间有什么区别?

3
我已经阅读了 Electron 的 上下文隔离, 进程间通信安全 文档,以及此篇有关使用 nodeIntegration 的文章此篇有关 preload.js 的文章。看起来有很多不同的方法可以完成类似的任务,我不确定哪种是最好的(安全、易用等)。
我知道你可以在渲染器进程中简单地启用 nodeIntegration 来访问主进程之外的 Node。但大多数来源都不建议这样做。
这就是我困惑的地方。Electron 文档中的一个示例显示可以像下面这样做。

preload.js

// preload with contextIsolation disabled
window.myAPI = {
  doAThing: () => {}
}

renderer.js

// use the exposed API in the renderer
window.myAPI.doAThing()
可以访问 Node APIs,因此从技术上讲,我可以加载所有的 Node 进程,然后在渲染器中访问它们。
不过,我也了解到了 IPC。 main.js 的一部分。
ipcMain.on('set-title', (event, title) => {
    const webContents = event.sender
    const win = BrowserWindow.fromWebContents(webContents)
    win.setTitle(title)
})

preload.js

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
    setTitle: (title) => ipcRenderer.send('set-title', title)
})

renderer.js

const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
    const title = titleInput.value
    window.electronAPI.setTitle(title)
});

例如,假设我想使用外部npm模块来实现一个函数。我应该将其合并到preload.js中,并从渲染器调用它,还是将其合并到main.js中,在preload.js中使用ipcRenderer创建一个通道以调用该函数,然后再从渲染器中调用它呢?

这个有帮助吗 https://dev59.com/22oMtIcB2Jgan1znjX2J? - customcommander
2个回答

3
你所贴出来的代码选自上下文隔离文档,展示了在电子应用早期版本中(在默认启用上下文隔离前),如何使用通过preload暴露给渲染器的方法和模块。但这不是正确的做法。在 contextisolation = true 的情况下,你需要在preload中使用contextbridge,因为窗口对象被保持隔离。
因此,你应该按照IPC中所示的方式去做,在2022年也是如此。我还会避免使用NodeIntegration,除非你确切知道自己在做什么。
针对你最后一个问题:通常我会采取最小权限原则,赋予渲染器越少的权力越安全。
我将给你一个来自我的最近项目的例子,我需要截屏并将其保存在某个地方。为此,我需要使用Browserwindow.webcontents.capturePage()fs.writeFile() 这两个方法,它们都只能在主进程中使用。将fs.writeFile方法暴露给渲染器肯定存在风险,所以我不这样做。相反,我在主进程中保留我的写入文件系统的逻辑。然而,我想从渲染器(我的UI)中启动截屏。为了尽可能少地暴露内容,我只暴露一个函数,该函数调用preload的contextBridge中的invoke方法,如下所示:
contextBridge.exposeInMainWorld("ipcRenderer", {
  invokeSnap: async (optionsString: string) =>
    await ipcRenderer.invoke("snap", optionsString),
});

在主函数中,我有一个监听器来处理传入的请求:
ipcMain.handle("snap", async (_event, props: string) => {
  // screenshot logic
  return //sth that the renderer will receive back once the process is finished;
});

渲染器发送请求并处理响应或错误,就像这样:
window.ipcRenderer.invokeOpen(JSON.stringify(options))
.then(...)
.catch(...)


作为一个副作用,这会在主进程上产生沉重的负担,对于更大的项目可能是不可取的 - 我不知道。也许更有经验的Electron开发者可以对此做出更多的解释。

在您的情况下,如果不从外部源加载代码,那么这如何成为威胁入口点? - Vass

3
preload.js可以访问Node API,因此我可以加载所有Node进程,然后在我的渲染器中访问它们。但实际上并非总是如此,如果启用了"sandbox",则只能访问Node API的子集。来源:(已加重)。
与沙盒渲染器相关联的预加载脚本仍将具有可用的Node.js API的polyfill子集。
如果您正在使用外部npm模块,并且启用了"sandbox"(可能应该启用),则无法在预加载脚本中导入npm模块,并且必须使用ipc并在主进程中触发它。
如果禁用了"sandbox",并且您可以从渲染器进程完成所需的一切,则建议直接在预加载中导入模块并直接使用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接