You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron无Node集成+上下文隔离下Blob转主进程存文件报错

Electron上下文隔离模式下Blob跨进程传输报错的解决方案

问题原因

启用上下文隔离与禁用Node集成后,通过IPC将Blob对象从渲染进程传递到主进程时,会触发Uncaught (in promise) Error: An object could not be cloned错误。这是因为Blob属于浏览器环境特有的对象,无法通过Electron的IPC通道完成自动克隆序列化。

解决步骤

核心思路是将不可序列化的Blob转换为可通过IPC传输的ArrayBuffer,在主进程中再转为Node.js的Buffer进行文件写入,同时修复原代码中的异步逻辑缺陷。

1. 修改渲染进程代码(renderer.js)

将Blob转换为ArrayBuffer后再调用主进程的写入方法,同时修正Promise链式调用的逻辑:

function exportToExcelFile(tableID, anchorID, exportFilename) {
    let format = 'xlsx';
    let anchor = $$('#' + anchorID + '-' + format);
    ExcellentExport.convert({
            anchor: anchor[0],
            filename: exportFilename,
            format: format
        }, [{
            name: 'Sheet1',
            from: {
                table: $$('#' + tableID)[0]
            }
    }]);
    
    // Get path, open save dialog and save file
    window.electron.getPath()
        .then((appDataPath) => {
            const dialogConfig = {
                filters: [{
                    name: 'Excel',
                    extensions: ['xlsx']
                }],
                defaultPath: appDataPath + '/' + exportFilename
            };
            return electron.openDialog('showSaveDialogSync', dialogConfig);
        })
        .then(filepath => {
            if (!filepath) return;
            return fetch(anchor.attr('href'))
                .then(res => res.blob())
                .then(blob => ({ filepath, arrayBuffer: blob.arrayBuffer() }));
        })
        .then(async ({filepath, arrayBuffer}) => {
            if (!arrayBuffer) return;
            return electron.writeFile(filepath, await arrayBuffer);
        })
        .then(message => {
            if (message) app.dialog.alert(message.text, message.title);
        })
        .catch(result => console.log(result));
}

2. 修正主进程代码(main.js)

  • 修复getPath方法缺失返回值的问题
  • 接收ArrayBuffer并转换为Node.js Buffer,使用异步fs.promises.writeFile确保结果正确返回:
// ... 其他代码不变

app.whenReady().then(() => {
    createWindow();
    
    ipcMain.handle('dialog', (event, method, params) => {
        return dialog[method](params);
    });
  
    ipcMain.handle('getPath', () => {
        return app.getPath('documents'); // 添加return语句
    });
    
    ipcMain.handle('writeFile', async (event, filepath, arrayBuffer) => {
        const message = {};
        try {
            const buffer = Buffer.from(arrayBuffer); // ArrayBuffer转Node.js Buffer
            await fs.promises.writeFile(filepath, buffer); // 异步写入保证结果正确
            message.text = filepath;
            message.title = 'Table saved to';
        } catch (err) {
            message.text = err.message;
            message.title = 'Error Saving Table';
        }
        return message;
    });
});

3. preload.js无需修改

原preload.js的IPC暴露逻辑保持不变,ArrayBuffer属于IPC支持的传输类型,可直接传递。

关键说明

  • Electron的IPC支持传输的序列化类型包括:原始类型、ArrayBuffer、TypedArray、普通对象(仅含可序列化属性)等,Blob不在此列,因此必须转换格式。
  • 使用fs.promises.writeFile替代回调版本的fs.writeFile,确保异步操作完成后再返回结果,避免原代码中提前返回空message的问题。

内容的提问来源于stack exchange,提问作者fnllc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 22:35:27