HTTP网络通信

Electron程序中,使用HTTP网络通信实际上有两种方式:一种是基于Chromium浏览器提供的XHR或是FetchAPI(推荐),直接在渲染进程中请求数据,这种方式写法比较简单但有一个缺点,浏览器的HTTP请求会受到浏览器的各种安全策略限制;而另一种方式则相对复杂,我们可以使用主进程基于NodeJS的HTTP客户端库发起网络请求,并通过进程间通信的方式和渲染进程交互(当然,主进程的另一个优势是能够实现更多的网络功能,而渲染进程则只能使用HTTP和WebSocket)。

实际开发中,这两种方式都比较常用,这里我们简单介绍一下。

使用FetchAPI请求数据

Web开发中,我们可能会用到JQueryAxios等网络请求库,在Electron的渲染进程中强烈不建议使用这些库。这些库的存在意义在于对不同浏览器版本能够提供基本一致的网络请求支持,而Electron本身就是个自带固定版本Chromium的应用程序,因此没必要使用这些封装库,使用原生的FetchAPI足矣。

下面例子中,我们使用FetchAPI请求了一个GET接口。

app.js

window.addEventListener('load', async () => {
    try {
        const rsp = await fetch('http://localhost:8080/api/v1/getStudentList', {
            method: 'GET'
        });
        const rspJson = await rsp.json();
        console.log(rspJson);
    } catch (err) {
        console.log(err.message);
    }
});

上面代码完全在渲染进程中执行。代码比较简单,这里就不展开介绍了。

使用主进程请求数据

使用主进程请求数据相对复杂,需要用到前面介绍的进程间通信方式,而且NodeJS自带的http模块相对于Chromium浏览器的FetchAPI也显得比较难用,下面是一个例子。

preload.js

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

contextBridge.exposeInMainWorld('electronAPI', {
    getStudentList: () => ipcRenderer.invoke('get-student-list')
});

main.js

const { app, BrowserWindow, ipcMain } = require('electron');
const http = require('http');
const path = require('path');

const asyncGetStudentList = () => {
    return new Promise((resolve, reject) => {
        const req = http.request({
            host: 'localhost',
            port: 8080,
            method: 'GET',
            path: '/api/v1/getStudentList'
        }, (res) => {
            if (res.statusCode !== 200) {
                return reject(new Error('HTTP ' + res.statusCode));
            }
            const rsp_body = [];
            res.on('data', (chunk) => { rsp_body.push(chunk) });
            res.on('end', () => {
                resolve(JSON.parse(Buffer.concat(rsp_body).toString()));
            });
        });
        req.on('error', (err) => { reject(err) });
        req.end();
    });
};

const createWindow = () => {
    // 创建窗口
    const window = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    });

    // 监听渲染进程调用
    ipcMain.handle('get-student-list', async (_event) => {
        return await asyncGetStudentList();
    });

    // 加载HTML文件
    window.loadFile('index.html');
};

app.whenReady().then(() => {
    createWindow();

    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) {
            createWindow();
        }
    })
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

app.js

window.addEventListener('load', async () => {
    const data = await window.electronAPI.getStudentList();
    console.log(data);
});

代码中,我们主要关注主进程中发起HTTP请求的方式。这里我们用到了NodeJS的http模块,我们将其封装为了一个异步函数,并将其暴露给渲染进程调用。由此,我们的页面便可以跳出浏览器的限制,使用本地的网络功能了。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。