Electron 开发:获取当前客户端 IP
一、背景与需求
1. 项目背景
客户端会自启动一个服务,Web/后端服务通过 IP + port 请求以操作客户端接口
2. 初始方案与问题
2.1. 初始方案:通过代码获取本机 IP
- /**
- * 获取局域网 IP
- * @returns {string} 局域网 IP
- */
- export function getLocalIP(): string {
- const interfaces = os.networkInterfaces()
- for (const name of Object.keys(interfaces)) {
- for (const iface of interfaces[name] || []) {
- if (iface.family === 'IPv4' && !iface.internal) {
- log.info('获取局域网 IP:', iface.address)
- return iface.address
- }
- }
- }
- log.warn('无法获取局域网 IP,使用默认 IP: 127.0.0.1')
- return '127.0.0.1'
- }
复制代码 2.2. 遇到的问题
如果设备开启了代理,可能获取的是代理 IP,导致后端请求失败
二、解决方案设计
1. 总体思路
- 获取本机所有 IP
- 遍历 IP + port 请求客户端服务接口
- 成功响应即为目标 IP
- 缓存有效 IP,避免频繁请求
2. 获取所有可能的 IP
使用 Node.js 的 os.networkInterfaces() 获取所有可用 IP- private getAllPossibleIPs(): string[] {
- const interfaces = os.networkInterfaces()
- const result: string[] = []
- for (const name of Object.keys(interfaces)) {
- const lowerName = name.toLowerCase()
- if (lowerName.includes('vmware')
- || lowerName.includes('virtual')
- || lowerName.includes('vpn')
- || lowerName.includes('docker')
- || lowerName.includes('vethernet')) {
- continue
- }
- for (const iface of interfaces[name] || []) {
- if (iface.family === 'IPv4' && !iface.internal) {
- result.push(iface.address)
- }
- }
- }
- return result
- }
复制代码 3. 遍历 IP 请求验证
轮询所有 IP,尝试访问客户端服务,验证是否可用- private async testIPsParallel(ips: string[]): Promise<string | null> {
- if (ips.length === 0)
- return null
- return new Promise((resolve) => {
- const globalTimeout = setTimeout(() => {
- resolve(null)
- }, this.TIMEOUT * 1.5)
- const controllers = ips.map(() => new AbortController())
- let hasResolved = false
- let completedCount = 0
- const testIP = (ip: string, index: number) => {
- const controller = controllers[index]
- axios.get(`http://${ip}:${PORT}/api/task-server/ip`, {
- timeout: this.TIMEOUT,
- signal: controller.signal,
- })
- .then(() => {
- if (!hasResolved) {
- hasResolved = true
- clearTimeout(globalTimeout)
- controllers.forEach((c, i) => {
- if (i !== index)
- c.abort()
- })
- resolve(ip)
- }
- })
- .catch(() => {
- if (!hasResolved) {
- completedCount++
- if (completedCount >= ips.length) {
- clearTimeout(globalTimeout)
- resolve(null)
- }
- }
- })
- }
- ips.forEach(testIP)
- })
- }
复制代码 4. 添加缓存策略
对成功的 IP 进行缓存,设定缓存有效时间,避免重复请求- private cachedValidIP: string | null = null
- private lastValidationTime = 0
- private readonly CACHE_VALID_DURATION = 24 * 60 * 60 * 1000
复制代码 三、完整代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |