相关文章推荐
有胆有识的椰子  ·  Pandas ...·  7 月前    · 
风流的啄木鸟  ·  python ...·  1 年前    · 
爱运动的毛豆  ·  使用hifiasm组装hifi基因组的方法介 ...·  1 年前    · 
乐观的针织衫  ·  Windows编译opencv库-腾讯云开发 ...·  1 年前    · 
安静的电影票  ·  因果推断:效应估计的常用方法及工具变量讨论- ...·  2 年前    · 
Code  ›  javascript - 如何在 Electron 中正确使用 preload.js -
require main函数 electron
https://segmentfault.com/q/1010000042988141
英姿勃勃的日记本
1 年前
segmentfault segmentfault
注册登录
问答 博客 标签 活动
发现
✓ 使用“Bing”搜本站 使用“Google”搜本站 使用“百度”搜本站 站内搜索
注册登录
  1. 首页
  2. 问答
  3. Stack Overflow 翻译
  4. 问答详情

如何在 Electron 中正确使用 preload.js

社区维基
1
发布于
2022-12-06
新手上路,请多包涵

我正在尝试在我的 renderer 进程中使用 Node 模块(在本例中为 fs ),如下所示:

 // main_window.js
const fs = require('fs')
function action() {
    console.log(fs)

注意: action 函数在我按下 main_window 中的按钮时被调用。

但这给出了一个错误:

 Uncaught ReferenceError: require is not defined
    at main_window.js:1

我可以 按照这个接受的答案的建议 解决这个问题,方法是在初始化 main.js 时将这些行添加到我的 main_window :

 // main.js
main_window = new BrowserWindow({
    width: 650,
    height: 550,
    webPreferences: {
        nodeIntegration: true

但是, 根据文档,这不是最好的做法,我应该创建一个 preload.js 文件并在那里加载这些节点模块,然后在我的所有 renderer 中使用它 --- 过程。像这样:

main.js :

 main_window = new BrowserWindow({
    width: 650,
    height: 550,
    webPreferences: {
        preload: path.join(app.getAppPath(), 'preload.js')

preload.js :

 const fs = require('fs')
window.test = function() {
    console.log(fs)

main_window.js :

 function action() {
    window.test()

现在我的问题是,我应该在 --- 中编写我的 renderer 进程的大部分代码是不是违反直觉的 preload.js (因为仅在 preload.js 可以访问 Node 模块),然后只调用每个 renderer.js 文件中的函数(例如这里, main_window.js )?我在这里不明白什么?

原文由 Amir Shabani 发布,翻译遵循 CC BY-SA 4.0 许可协议

Stack Overflow 翻译 javascript node.js electron
阅读 683
2 个回答
得票 最新
社区维基
1
发布于
2022-12-06
✓ 已被采纳

编辑 2022

我已经 发表了一篇关于 Electron 历史的大型文章 (安全性在整个 Electron 版本中发生了怎样的变化)以及 Electron 开发人员可以采取的其他安全注意事项,以确保在新应用程序中正确使用预加载文件。

编辑 2020

正如另一位用户所问,让我在下面解释我的答案。

在 Electron 中使用 preload.js 的正确方法是在您的应用程序可能需要的任何模块周围公开白名单包装器 require 。

安全方面,暴露 require 或您通过 require 调用您的 preload.js 评论- 更多解释(请参阅我 的)。如果您的应用程序加载远程内容时尤其如此,很多人都会这样做。

为了正确地做事,您需要在您的 BrowserWindow 上启用很多选项,正如我在下面详述的那样。设置这些选项会强制您的电子应用程序通过 IPC(进程间通信)进行通信,并将两个环境相互隔离。像这样设置您的应用程序可以让您验证后端中可能是 require 模块的任何内容,客户端不会对其进行篡改。

下面,您将找到一个简短示例,说明我所说的内容以及它在您的应用程序中的外观。如果您是新手,我可能建议您使用 secure-electron-template (我是其作者),它在构建电子应用程序时从一开始就融入了所有这些安全最佳实践。

此页面 还提供了有关使用 preload.js 制作安全应用程序时所需架构的详细信息。

const {
  BrowserWindow,
  ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
async function createWindow() {
  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false, // is default value after Electron v5
      contextIsolation: true, // protect against prototype pollution
      enableRemoteModule: false, // turn off remote
      preload: path.join(__dirname, "preload.js") // use a preload script
  // Load app
  win.loadFile(path.join(__dirname, "dist/index.html"));
  // rest of code..
app.on("ready", createWindow);
ipcMain.on("toMain", (event, args) => {
  fs.readFile("path/to/file", (error, data) => {
    // Do something with file contents
    // Send result back to renderer process
    win.webContents.send("fromMain", responseObj);

预加载.js

 const {
    contextBridge,
    ipcRenderer
} = require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
    "api", {
        send: (channel, data) => {
            // whitelist channels
            let validChannels = ["toMain"];
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, data);
        receive: (channel, func) => {
            let validChannels = ["fromMain"];
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender`
                ipcRenderer.on(channel, (event, ...args) => func(...args));

索引.html

 <!doctype html>
<html lang="en-US">
    <meta charset="utf-8"/>
    <title>Title</title>
</head>
    <script>
        window.api.receive("fromMain", (data) => {
            console.log(`Received ${data} from main process`);
        window.api.send("toMain", "some data");
    </script>
</body>
</html>

并非所有官方文档中的内容都可以在您的代码的任何地方直接实现。您必须对环境和流程有简明的了解。

环境/过程描述主要的更接近操作系统(低级别)的 API。这些包括文件系统、基于操作系统的通知弹出窗口、任务栏等。这些都是通过 Electron 的核心 API 和 Node.js 的组合实现的预加载最近的一个 _附录_,目的是防止主要环境中可用的强大 API 泄漏。有关详细信息,请参阅 Electron v12 变更日志 和 问题 #23506 。渲染器现代网络浏览器的 API,例如 DOM 和前端 JavaScript(高级)。这是通过 Chromium 实现的。

上下文隔离和节点集成

设想contextIsolationnodeIntegration评论一个falsefalse不需要预加载。 Node.js 在 Main 中可用,但在 Renderer 中不可用。乙falsetrue不需要预加载。 Node.js 在 Main 和 Renderer 中可用。Ctruefalse需要预加载。 Node.js 在 Main 和 Preload 中可用,但在 Renderer 中不可用。 默认。 推荐。丁truetrue需要预加载。 Node.js 在 Main、Preload 和 Renderer 中可用。

如何正确使用预加载?

您必须使用 Electron 的进程间通信 (IPC) 才能让 Main 进程和 Renderer 进程进行通信。

  • 在 主 进程中,使用:
  • BrowserWindow.webContents.send() 向渲染器发送消息的方法
  • ipcMain.handle() 从渲染器接收消息的方法
  • 在 Preload 进程中,将 用户定义的端点 暴露给 Renderer 进程。
  • 在 Renderer 进程中,使用暴露的 用户定义端点 来:
  • 发消息给主
  • 接收来自 Main 的消息
  • * Sending messages to Renderer * `window` is an object which is an instance of `BrowserWindow` * `data` can be a boolean, number, string, object, or array window.webContents.send( 'custom-endpoint', data ); * Receiving messages from Renderer ipcMain.handle( 'custom-endpoint', async ( event, data ) => { console.log( data )
    const { contextBridge, ipcRenderer } = require('electron')
    contextBridge.exposeInMainWorld( 'api', {
        send: ( channel, data ) => ipcRenderer.invoke( channel, data ),
        handle: ( channel, callable, event, data ) => ipcRenderer.on( channel, callable( event, data ) )
     * Sending messages to Main
     * `data` can be a boolean, number, string, object, or array
    api.send( 'custom-endpoint', data )
     * Receiving messages from Main
    api.handle( 'custom-endpoint', ( event, data ) => function( event, data ) {
        console.log( data )
    }, event);
    

    使用承诺怎么样?

    尽可能遵守对相同流程/环境的承诺。您对 main 的承诺应该保留在 main 上。您对 渲染器 的承诺也应该保留在渲染器上。不要做出从 main-to-preload-to-renderer 跳转的承诺。

    您的大部分业务逻辑仍应位于 Main 或 Renderer 端,但绝不能位于 Preload 中。这是因为 Preload 几乎只是一种媒介。预载应该非常小。

     
    推荐文章
    有胆有识的椰子  ·  Pandas dataframe数据处理方法速度比较_pandas千万行数据筛选要多久-CSDN博客
    7 月前
    风流的啄木鸟  ·  python QHBoxLayout怎么居中_mob649e815375e5的技术博客_51CTO博客
    1 年前
    爱运动的毛豆  ·  使用hifiasm组装hifi基因组的方法介绍_生信技术的博客-CSDN博客
    1 年前
    乐观的针织衫  ·  Windows编译opencv库-腾讯云开发者社区-腾讯云
    1 年前
    安静的电影票  ·  因果推断:效应估计的常用方法及工具变量讨论-阿里云开发者社区
    2 年前
    今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
    删除内容请联系邮箱 2879853325@qq.com
    Code - 代码工具平台
    © 2024 ~ 沪ICP备11025650号