码桶
发现社区成员的开源项目
proxy.js3.8 KB
/**
* 代理服务器设置
* 读取 settings 表中的代理配置,应用到 axios(后端出站流量统一走 axios),
* 并提供连通性测试。支持 http / https / socks5 协议,可带账号密码鉴权。
*/
const axios = require('axios');
const settings = require('./settings');
/** 读取代理设置 */
async function loadProxySettings() {
const enabled = (await settings.getSetting('proxy_enabled', '0')) === '1';
const ip = await settings.getSetting('proxy_ip', '');
const port = await settings.getSetting('proxy_port', '');
const user = await settings.getSetting('proxy_user', '');
const pass = await settings.getSetting('proxy_pass', '');
const protocol = (await settings.getSetting('proxy_protocol', 'http')).toLowerCase();
return { enabled, ip, port, user, pass, protocol };
}
/** 根据设置拼出代理 URL;信息不全返回 null */
function buildProxyUrl(s) {
if (!s.ip || !s.port) return null;
let auth = '';
if (s.user) {
auth = encodeURIComponent(s.user) + (s.pass ? ':' + encodeURIComponent(s.pass) : '') + '@';
}
return `${s.protocol}://${auth}${s.ip}:${s.port}`;
}
/** 构建 axios 的 http/https agent(socks 协议共用一个 agent) */
async function buildAgents(s) {
const url = buildProxyUrl(s);
if (!url) return null;
if (s.protocol === 'socks5' || s.protocol === 'socks4') {
const { SocksProxyAgent } = require('socks-proxy-agent');
const a = new SocksProxyAgent(url);
return { httpAgent: a, httpsAgent: a };
}
const { HttpsProxyAgent } = require('https-proxy-agent');
const httpsAgent = new HttpsProxyAgent(url);
let httpAgent = httpsAgent;
try {
const { HttpProxyAgent } = require('http-proxy-agent');
httpAgent = new HttpProxyAgent(url);
} catch (e) { /* 仅 https 也能覆盖多数场景 */ }
return { httpAgent, httpsAgent };
}
/** 应用代理到 axios 全局默认 agent;未启用则清除 */
async function applyProxy() {
const s = await loadProxySettings();
if (!s.enabled) {
axios.defaults.httpAgent = undefined;
axios.defaults.httpsAgent = undefined;
axios.defaults.proxy = false;
return { enabled: false };
}
try {
const agents = await buildAgents(s);
if (!agents) return { enabled: true, error: '代理配置不完整(需填写 IP 和端口)' };
axios.defaults.httpAgent = agents.httpAgent;
axios.defaults.httpsAgent = agents.httpsAgent;
axios.defaults.proxy = false; // 禁用 axios 内置代理逻辑,改用上面的 agent
console.log(`[proxy] 已启用代理: ${s.protocol}://${s.ip}:${s.port}`);
return { enabled: true };
} catch (e) {
console.error('[proxy] 应用代理失败:', e.message);
return { enabled: true, error: e.message };
}
}
/** 测试代理连通性:透过代理请求一个外部地址,返回结果 */
async function testProxy(testUrl) {
const s = await loadProxySettings();
const url = buildProxyUrl(s);
if (!url) return { ok: false, msg: '请先填写代理 IP 和端口' };
try {
const agents = await buildAgents(s);
if (!agents) return { ok: false, msg: '代理配置不完整(需填写 IP 和端口)' };
const target = testUrl || 'https://api.ipify.org?format=json';
const resp = await axios.get(target, {
httpAgent: agents.httpAgent,
httpsAgent: agents.httpsAgent,
proxy: false,
timeout: 10000,
});
const body = typeof resp.data === 'string' ? resp.data : JSON.stringify(resp.data);
return { ok: true, msg: `连通成功(HTTP ${resp.status})`, body: body.slice(0, 500) };
} catch (e) {
const detail = e.response ? `HTTP ${e.response.status}` : e.code || e.message;
return { ok: false, msg: '连通失败: ' + detail };
}
}
module.exports = { loadProxySettings, buildProxyUrl, applyProxy, testProxy };