这篇文章对谁有用?

  • Electron.js 开发者

这篇文章讲什么?

Electron.js 如何实现代理功能。
比如:

界面解释

  • 用户可以输入代理地址到 HTTP_PROXY。
  • 右侧有个开关,"已开启"|"已关闭"
  • 代理设置完了,下方可以"测试代理连通性"

背景信息

我在做 Electron 桌面应用,需要和谷歌 API 交互。翻墙是个问题。
希望 Electron 能直接用我本地的代理 (http://127.0.0.1:1087)

注:本文写于2019年12月27号。
我用的 Electron.js 版本是 6.1.5
我知道最新版是 7,但是安装一直碰到问题,所以没用 7

本文结构

  1. 先讲结论
  2. 给代码
  3. 最后讲过程,可我犯了什么错,也可以跳过不看

先讲结论

用这个:

BrowserWindow.webContents.session.setProxy

文档: https://electronjs.org/docs/api/session

给代码

index.js (Main process) 代码:

const {
  app,
  BrowserWindow,
  ipcMain,
  Menu
} = require('electron')

let win

function createWindow() {
  win = new BrowserWindow({
    width: 820,
    height: 840,
    titleBarStyle: 'hidden',
    frame: false,
    webPreferences: {
      nodeIntegration: true,
    }
  })
}

这一段只是前置条件,帮助理解后面的代码。
只要知道这里有个变量叫 win, 类型是 BrowserWindow 就行了

重点来了,index.js 文件的下半部分


// 设置代理
ipcMain.on('set_proxy', (event, arg) => {
  console.log(arg);
  var { http_proxy } = arg
  win.webContents.session.setProxy({
    proxyRules: http_proxy
  }, function () {
    console.log('代理设置完毕')
  });
})

// 去掉代理
ipcMain.on('remove_proxy', (event, arg) => {
  win.webContents.session.setProxy({});
})

可以看到这里是监听 ipc,如果收到对应名字的事件就运行代码

如果想了解更多 ipcMainipcRender,以下是文档:

https://electronjs.org/docs/api/ipc-main

https://electronjs.org/docs/api/ipc-renderer

怎么使用?

在 Render Process 里:

// 设置代理
set_proxy() {
  window.ipcRenderer.send("set_proxy", {
    http_proxy: this.setting_http_proxy
  });
},

// 取消代理
remove_proxy() {
  window.ipcRenderer.send("remove_proxy");
},

因为我用的是 Vue.js
这2个函数我是写在 methods:

<template>
  
</template>

<script>
export default {
  methods: {
    // 这里
  }
}
</script>

<style>

</style>

还有一件事
前面代码里 window.ipcRenderer 可能看起来很奇怪。
干嘛要带个 window. 在前面?

这是因为我另外有一段:

const {
  ipcRenderer,
} = window.require("electron")

window.ipcRenderer = ipcRenderer;

这就保存到了 window 变量里,render process 里的代码可以很方便的拿到。

因为 webpack 和 node 有干扰(具体原理我也不清楚,没关心)
所以要用 window.require

代码部分到此结束。

以下进入本文第三部分,也是最后一部分:犯过的错

犯过的错

错误1:直接用 axios/request 的 proxy 配置
错误2:环境变量

错误1:直接用 axios/request 的 proxy 配置

一开始我的思路还没转过来,忘记这是桌面应用了。
就去看 Node.js 网络库怎么配置代理。
测试了 axios, requests, superagent, 原生 fetch 和 got.
好像还测了几个其他的名气比较小的库,无一成功。
一开始我以为是自己哪里弄错了。不太理解。后来才想起来一切请求最终都是通过 Chrome 发出去的。这是个桌面应用,我搞错方向了。

错误2:环境变量

我以为设置环境变量 HTTP_PROXY 和 HTTPS_PROXY,
axios, requests 等等库发出去的请求就会尊重这个环境变量。我错了。

简而言之,在这2个错误上浪费了2天时间。

换了个思路,看 Electron 本身这个请求是怎么出去的,应该是在外面这一层,
然后找到了 setProxy,一试,可以。这才解决了问题。

补几个有用的链接:

https://github.com/electron/electron/issues/21050

全文完

感谢阅读