Из-за чего не работает прокси в AxiOS на Electon JS (в файле preload.js)?
По вводным: создаю приложение на Electon JS, появилась задача использовать прокси в некоторых запросах.
По вводным: взял самый простой пример:
const axios = require("axios"); axios({ method: 'get', url: "https://api.ipify.org/?format=json", proxy: { protocol: "http", host: "11.11.111.111", port: "1111", auth: {username: "username", password: "password"} } }) .then(res => console.log("IP:" + res.data.ip)) .catch(err => console.error(err));
По вводным: этот код работает если поместить в файл js и напрямую запустить через Node.
По вводным: этот код работает если поместь в main.js, стартовый файл Electon JS.
По вводным: но как только я переношу его в preload.js, прокси перестаёт работать и выдаёт реальный IP адрес компьютера.
Сейчас ситуация такая: я уже наладить запросы в preload.js через iПКRenderer, но мне это не очень удобно, делает большую вложенность и вообще хочу понять можно ли это как то обойти и почему так происходит.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
В preload.js у Electron вы попадаете не в обычную Node-среду, а в изолированный мост между renderer и main. Даже если в preload доступен require, сетевой стек может вести себя иначе: часть запросов идет через Chromium/renderer, часть через Node, а настройки proxy у axios работают только для конкретного HTTP(S)-агента. Поэтому нормальная схема для прокси в Electron — держать реальные сетевые запросы в main process, а из preload только вызывать их через безопасный IPC.
Самый надежный вариант: в preload экспортировать метод, а в main.js выполнять axios-запрос с proxy или с httpAgent/httpsAgent. Тогда запрос выполняется в одном понятном окружении, без сюрпризов contextIsolation, sandbox и политики renderer.
/* preload.js */ const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { getIpThroughProxy: () => ipcRenderer.invoke('proxy:get-ip') }); /* main.js */ const { ipcMain } = require('electron'); const axios = require('axios'); ipcMain.handle('proxy:get-ip', async () => { const res = await axios.get('https://api.ipify.org/?format=json', { proxy: { protocol: 'http', host: '11.11.111.111', port: 1111, auth: { username: 'username', password: 'password' } }, timeout: 15000 }); return res.data; });/* preload.js */ const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { getIpThroughProxy: () => ipcRenderer.invoke('proxy:get-ip') }); /* main.js */ const { ipcMain } = require('electron'); const axios = require('axios'); ipcMain.handle('proxy:get-ip', async () => { const res = await axios.get('https://api.ipify.org/?format=json', { proxy: { protocol: 'http', host: '11.11.111.111', port: 1111, auth: { username: 'username', password: 'password' } }, timeout: 15000 }); return res.data; });
Если принципиально нужно выполнять запрос именно из renderer, лучше не рассчитывать на параметр proxy в axios, а настроить прокси на уровне сессии Electron. Например, для окна можно задать proxyRules через session.setProxy, а потом уже делать fetch/axios из renderer. Но это повлияет на сетевой трафик этой сессии, поэтому такой подход удобен, когда прокси нужен всему окну, а не одному запросу.
const { session } = require('electron'); await session.defaultSession.setProxy({ proxyRules: 'http://username:password@11.11.111.111:1111' });const { session } = require('electron'); await session.defaultSession.setProxy({ proxyRules: 'http://username:password@11.11.111.111:1111' });
Я бы оставил запросы в main.js. Это проще отлаживать, безопаснее для логинов прокси и не заставляет тянуть секреты в preload/renderer. Проверьте также, не включен ли sandbox у BrowserWindow, какая версия Electron используется и не подменяется ли axios сборщиком. Для диагностики выведите process.type, process.versions.electron и сделайте контрольный запрос из main, preload и renderer отдельно.