步骤一:引入必要的库
Node.js 是一个单线程的 JavaScript 运行时环境,但有时候我们需要执行一些系统命令或运行其他程序。这时就需要用到 child_process 模块。
child_process 模块允许 Node.js 应用程序创建子进程,这些子进程可以执行系统命令、运行其他脚本或程序,并与父进程进行通信。
这样做的好处
执行系统命令:比如执行
ls、git等命令行工具运行 CPU 密集型任务:避免阻塞 Node.js 主线程
与其他语言编写的程序交互:比如调用 Python 或 C++ 程序
提高应用性能:通过多进程充分利用多核 CPU
实际应用如下:
import os from 'os'
import { execSync } from 'child_process'步骤二:构造相关函数
function getNetworkInfo() {
let ssid = '未知'
let ipv4 = '127.0.0.1'
try {
const interfaces = os.networkInterfaces()
for (const interfaceName of Object.keys(interfaces)) {
for (const iface of interfaces[interfaceName]) {
if (iface.family === 'IPv4' && !iface.internal) {
ipv4 = iface.address
break
}
}
if (ipv4 !== '127.0.0.1') break
}
} catch (error) {
console.error('[网络信息] 获取IPv4地址失败:', error)
}
try {
const output = execSync('netsh wlan show interfaces', { encoding: 'utf-8' })
const ssidMatch = output.match(/SSID\s+:\s(.+)/)
if (ssidMatch && ssidMatch[1]) {
ssid = ssidMatch[1].trim()
}
} catch (error) {
console.error('[网络信息] 获取WiFi名称失败:', error)
}
return { ssid, ipv4 }
}说明:
os.networkInterfaces() 是 Node.js 内置方法,返回对象,键 = 网卡名称(Windows:以太网、WLAN;Mac/Linux:en0、eth0、wlan0),值 = 当前网卡的所有网络地址数组,包含 IPv4、IPv6、MAC、是否内网等信息
返回数据示例:
{
WLAN: [
{ address: '192.168.1.100', family: 'IPv4', internal: false },
{ address: 'fe80::xxxx', family: 'IPv6', internal: false }
],
lo: [{ address: '127.0.0.1', family: 'IPv4', internal: true }] // 本地回环网卡
}第一层循环:遍历所有网卡名称
for (const interfaceName of Object.keys(interfaces))取出所有网卡名(WLAN、lo、以太网等)逐个遍历
第二层循环:遍历单网卡下的所有地址
for (const iface of interfaces[interfaceName])一个网卡会同时拥有 IPv4、IPv6 多个地址,循环逐个判断
筛选条件(关键判断)
if (iface.family === 'IPv4' && !iface.internal) {
ipv4 = iface.address
break
}两个筛选规则:
family === 'IPv4':只拿 IPv4 地址,跳过 IPv6;!iface.internal:internal=true代表本机内部回环地址(就是127.0.0.1),直接排除,只取物理网卡真实局域网地址。
匹配成功,把地址赋值给变量 ipv4,跳出当前网卡的地址循环
拿到合法 IP 就终止外层循环
if (ipv4 !== '127.0.0.1') break只要拿到的 IP 不是本地回环地址,直接跳出网卡外层循环,不再遍历剩余网卡,取第一个符合条件的网卡 IP
但是有一下潜在的问题
变量 ipv4 未提前初始化
如果遍历全程没匹配到网卡,
ipv4会是undefined,后续使用会报错。多网卡场景判断简陋
电脑同时插网线 + 连 WiFi 双网卡时,只会取遍历顺序靠前的网卡 IP,无法指定网卡。
没有过滤虚拟网卡(虚拟机、VPN、虚拟适配器)
虚拟网卡的
internal同样为false,会被误判选中。
所以修改尝试函数的结构:
try {
const interfaces = os.networkInterfaces()
for (const interfaceName of Object.keys(interfaces)) {
for (const iface of interfaces[interfaceName]) {
if (iface.family === 'IPv4' && !iface.internal) {
ipv4 = iface.address
break
}
}
if (ipv4 !== '127.0.0.1') break
}
} catch (error) {
console.error('[网络信息] 获取IPv4地址失败:', error)
}最后
app.listen(PORT, () => {
const { ssid, ipv4, interfaceName, allIPs } = getNetworkInfo()
console.log('='.repeat(64))
console.log('TypeDance 打字训练平台 - 合并部署模式 - JTZJ')
console.log('Designed by YeRanHvril(HAUITEUT)')
console.log('='.repeat(64))
console.log(`WiFi名称: ${ssid}`)
console.log(`网卡名称: ${interfaceName}`)
console.log(`IPv4地址: ${ipv4}`)
if (allIPs.length > 1) {
console.log('可用地址列表:')
allIPs.forEach(c => {
const tag = c.isWiFi ? '[WiFi]' : c.isPhysical ? '[物理]' : '[其他]'
console.log(` ${tag} ${c.ip} (${c.interface})`)
})
}
console.log(`服务地址: http://localhost:${PORT}`)
console.log(`局域网访问: http://${ipv4}:${PORT}/`)
console.log(`前端页面: http://localhost:${PORT}/`)
console.log(`管理后台: http://localhost:${PORT}/*******.html`)
console.log(`API 接口: http://localhost:${PORT}/*******/`)
console.log(`数据文件: ${DATA_FILE}`)
console.log(`默认管理员: t************************************n`)
console.log('密码由官方分发,请妥善保存')
console.log('='.repeat(64))
// 初始化令牌缓存
initTokenCache()
})