我有一个简单的Node.js程序在我的机器上运行,我想获得我的程序正在运行的PC的本地IP地址。我如何在Node.js中获得它?


当前回答

这是对已接受答案的修改,它不考虑vEthernet IP地址,如Docker等。

/**
 * Get local IP address, while ignoring vEthernet IP addresses (like from Docker, etc.)
 */
let localIP;
var os = require('os');
var ifaces = os.networkInterfaces();
Object.keys(ifaces).forEach(function (ifname) {
   var alias = 0;

   ifaces[ifname].forEach(function (iface) {
      if ('IPv4' !== iface.family || iface.internal !== false) {
         // Skip over internal (i.e. 127.0.0.1) and non-IPv4 addresses
         return;
      }

      if(ifname === 'Ethernet') {
         if (alias >= 1) {
            // This single interface has multiple IPv4 addresses
            // console.log(ifname + ':' + alias, iface.address);
         } else {
            // This interface has only one IPv4 address
            // console.log(ifname, iface.address);
         }
         ++alias;
         localIP = iface.address;
      }
   });
});
console.log(localIP);

这将返回一个类似192.168.2.169的IP地址,而不是10.55.1.1。

其他回答

这里有一个简洁的小命令行,它实现了这个功能:

const ni = require('os').networkInterfaces();
Object
  .keys(ni)
  .map(interf =>
    ni[interf].map(o => !o.internal && o.family === 'IPv4' && o.address))
  .reduce((a, b) => a.concat(b))
  .filter(o => o)
  [0];

下面是前面例子的一个变种。它会小心过滤掉VMware接口等。如果你不传递索引,它会返回所有地址。否则,您可能希望将其默认值设置为0,然后传递null以获取所有值,但您将整理这些。如果想要添加的话,还可以为regex过滤器传入另一个参数。

function getAddress(idx) {

    var addresses = [],
        interfaces = os.networkInterfaces(),
        name, ifaces, iface;

    for (name in interfaces) {
        if(interfaces.hasOwnProperty(name)){
            ifaces = interfaces[name];
            if(!/(loopback|vmware|internal)/gi.test(name)){
                for (var i = 0; i < ifaces.length; i++) {
                    iface = ifaces[i];
                    if (iface.family === 'IPv4' &&  !iface.internal && iface.address !== '127.0.0.1') {
                        addresses.push(iface.address);
                    }
                }
            }
        }
    }

    // If an index is passed only return it.
    if(idx >= 0)
        return addresses[idx];
    return addresses;
}

根据注释,以下是当前版本Node.js的工作原理:

var os = require('os');
var _ = require('lodash');

var ip = _.chain(os.networkInterfaces())
  .values()
  .flatten()
  .filter(function(val) {
    return (val.family == 'IPv4' && val.internal == false)
  })
  .pluck('address')
  .first()
  .value();

上面一个答案的注释缺少对values()的调用。看起来os.networkInterfaces()现在返回一个对象而不是数组。

调用ifconfig是非常依赖于平台的,而且网络层知道套接字所在的IP地址,所以最好是询问它。

Node.js并没有公开这样做的直接方法,但是你可以打开任何套接字,并询问正在使用的本地IP地址。例如,打开www.google.com的套接字:

var net = require('net');
function getNetworkIP(callback) {
  var socket = net.createConnection(80, 'www.google.com');
  socket.on('connect', function() {
    callback(undefined, socket.address().address);
    socket.end();
  });
  socket.on('error', function(e) {
    callback(e, 'error');
  });
}

使用情况:

getNetworkIP(function (error, ip) {
    console.log(ip);
    if (error) {
        console.log('error:', error);
    }
});

这些信息可以在os.networkInterfaces()中找到,这是一个对象,它将网络接口名称映射到它的属性(例如,一个接口可以有几个地址):

'use strict';

const { networkInterfaces } = require('os');

const nets = networkInterfaces();
const results = Object.create(null); // Or just '{}', an empty object

for (const name of Object.keys(nets)) {
    for (const net of nets[name]) {
        // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
        // 'IPv4' is in Node <= 17, from 18 it's a number 4 or 6
        const familyV4Value = typeof net.family === 'string' ? 'IPv4' : 4
        if (net.family === familyV4Value && !net.internal) {
            if (!results[name]) {
                results[name] = [];
            }
            results[name].push(net.address);
        }
    }
}
// 'results'
{
  "en0": [
    "192.168.1.101"
  ],
  "eth0": [
    "10.0.0.101"
  ],
  "<network name>": [
    "<ip>",
    "<ip alias>",
    "<ip alias>",
    ...
  ]
}
// results["en0"][0]
"192.168.1.101"