【问题标题】:How to determine a user's IP address in node如何在节点中确定用户的IP地址
【发布时间】:2011-12-27 19:34:33
【问题描述】:

如何确定控制器内给定请求的 IP 地址?例如(快递):

app.post('/get/ip/address', function (req, res) {
    // need access to IP address here
})

【问题讨论】:

  • 如果你使用 Express,你可以使用 req.ip source - expressjs.com/en/api.html#req.ip
  • 对于那些在localhost 工作的人 - 就像我一样,下面所有答案的结果(几乎所有答案都有效)可能来自::1。这让我困惑了一段时间。后来发现::1是真实IP地址,是localhost的IPV6符号。 Hope this helps someone

标签: node.js ip


【解决方案1】:

在您的request 对象中有一个名为socket 的属性,它是一个net.Socket 对象。 net.Socket 对象有一个属性remoteAddress,因此您应该能够通过此调用获取 IP:

request.socket.remoteAddress

(如果您的节点版本低于 13,请使用已弃用的 request.connection.remoteAddress

编辑

正如@juand 在 cmets 中指出的那样,如果服务器在代理后面,则获取远程 IP 的正确方法是 request.headers['x-forwarded-for']

【讨论】:

  • 这给了我一个不同于 whatismyip.com 给我的 IP 地址。为什么会这样?
  • 我的 API 服务安装在 no.de 实例上。当我尝试从我的计算机访问它时,我得到一个 IP 地址“10.2.XXX.YYY”,而我的真实世界 IP 是“67.250.AAA.BBB”
  • 它是 request.headers['X-Forwarded-For']
  • 请注意,net.Stream 现在是 net.Socket,文档位于此处:nodejs.org/api/net.html#net_class_net_socket
  • 对 Heroku 感兴趣的任何人:request.headers['x-forwarded-for']
【解决方案2】:
var ip = req.headers['x-forwarded-for'] ||
     req.socket.remoteAddress ||
     null;

请注意,有时您可以在req.headers['x-forwarded-for'] 中获得多个 IP 地址。此外,x-forwarded-for 标头不会始终设置,这可能会引发错误。

字段的一般格式为:

x-forwarded-for: client, proxy1, proxy2, proxy3

其中的值是一个逗号+空格分隔的 IP 地址列表,最左边的是原始客户端,以及传递请求的每个连续代理添加它接收请求的 IP 地址。在此示例中,请求通过proxy1proxy2,然后是proxy3proxy3 显示为请求的远程地址。

这是Arnav Gupta 建议的解决方案,Martin 在下面的 cmets 中针对未设置 x-forwarded-for 的情况提出了建议:

var ip = (req.headers['x-forwarded-for'] || '').split(',').pop().trim() || 
         req.socket.remoteAddress

使用现代 JS 的建议:

  • 仅在设置时处理x-forwarded-for,如果设置,则取第一个地址
  • 其他参数使用optional chaining (?.)
const parseIp = (req) =>
    req.headers['x-forwarded-for']?.split(',').shift()
    || req.socket?.remoteAddress

console.log(parseIp(req))
// => 127.0.0.1

【讨论】:

  • 如何防止这些标头被欺骗?
  • 这通常效果很好,但由于某种原因,我最近收到错误“无法读取未定义的属性'remoteAddress'”,因为显然所有内容都是空/未定义的,包括req.connection.socket。我不确定为什么/什么条件会导致这种情况,但最好检查 req.connection.socket 是否存在以避免发生这种情况时您的服务器崩溃。
  • 最后一行 req.connection.socket.remoteAddress 抛出错误。小心点。
  • 返回的ip地址为::1。为什么?
  • 查看 pop() 的工作方式,您似乎将获得最后一个代理,而不是您想要的客户端。我错了吗?
【解决方案3】:

如果使用快递...

req.ip

我正在查找这个然后我就像等待,我正在使用快递。呵呵。

【讨论】:

【解决方案4】:

您可以保持 DRY,只使用支持 IPv4IPv6node-ipware。 p>

安装:

npm install ipware

在您的 app.js 或中间件中:

var getIP = require('ipware')().get_ip;
app.use(function(req, res, next) {
    var ipInfo = getIP(req);
    console.log(ipInfo);
    // { clientIp: '127.0.0.1', clientIpRoutable: false }
    next();
});

它会尽力获取用户的IP地址或返回127.0.0.1表示无法确定用户的IP地址。查看 README 文件以了解高级选项。

【讨论】:

  • " 或者返回127.0.0.1表示无法确定用户的IP地址" 127.0.0.1和unknown有很大区别...
  • 从 Heroku 测试时,它返回了一些奇怪的东西 :ffff:(not my IP address)。 @edmar-miyake 的回答对我来说很有效。
  • 我想知道如果您在“x-forwarded-for”案例中使用 right2left 查找,IP 会是什么。 var ip_info = get_ip(req, right_most_proxy=True),在某些设置中,客户端 IP 可能是最正确的 IP。
  • 该方法为我返回clientIp: '::1'。它似乎不起作用。
  • @JamEngulfer - ipware 仅在 IP 地址通过 request.headers[ ] 正确传递给您的应用程序时才有效。示例:AWS LBS 在“x-forwarded-for”中发送 IP 地址,而自定义 NginX 许多使用其他变量。 ipware 会尽最大努力找出 IP 地址,但前提是 IP 已在标头中传递。
【解决方案5】:

您可以使用request-ip 来检索用户的IP 地址。它处理了很多不同的边缘情况,其中一些在其他答案中提到。

披露:我创建了这个模块

安装:

npm install request-ip

在您的应用中:

var requestIp = require('request-ip');

// inside middleware handler
var ipMiddleware = function(req, res, next) {
    var clientIp = requestIp.getClientIp(req); // on localhost > 127.0.0.1
    next();
};

希望对你有帮助

【讨论】:

  • github.com/pbojinov/request-ip/blob/master/index.js 检查包 request-ip 的源代码,它检查 x-forwarded-for 和各种其他流行负载均衡器(如 AWS ELB、Cloudflare、Akamai、nginx、Rackspace)的标头LB 和 Riverbed 的黄貂鱼
  • 它为我返回null
  • 同样的东西使用request.headers['x-forwarded-for']
【解决方案6】:

request.headers['x-forwarded-for'] || request.connection.remoteAddress

如果有x-forwarded-for 标头,则使用该标头,否则使用.remoteAddress 属性。

x-forwarded-for 标头添加到通过为 HTTPHTTPS 设置的负载平衡器(或其他类型的代理)的请求(也可以添加当使用 代理协议TCP 级别进行平衡时,此标头用于请求)。这是因为request.connection.remoteAddress 属性将包含负载均衡器的私有 IP 地址,而不是客户端的公共 IP 地址。通过使用 OR 语句,按上述顺序检查是否存在 x-forwarded-for 标头,如果存在则使用它,否则使用 request.connection.remoteAddress

【讨论】:

  • request.connection 已弃用,请改用套接字。
【解决方案7】:

以下功能涵盖了所有案例将有所帮助

var ip;
if (req.headers['x-forwarded-for']) {
    ip = req.headers['x-forwarded-for'].split(",")[0];
} else if (req.connection && req.connection.remoteAddress) {
    ip = req.connection.remoteAddress;
} else {
    ip = req.ip;
}console.log("client IP is *********************" + ip);

【讨论】:

  • 请注意,我的 ips 之间有一个 ,
  • 在所有答案中,我认为这个是最好的。它是全面的,防御性编码为“三思而后行”。
  • request.connection 已弃用,请改用套接字
【解决方案8】:

获取ip地址有两种方式:

  1. let ip = req.ip

  2. let ip = req.connection.remoteAddress;

但上述方法存在问题。

如果您在 Nginx 或任何代理后面运行您的应用程序,则每个 IP 地址都是 127.0.0.1

所以,获取用户IP地址的最佳解决方案是:-

let ip = req.header('x-forwarded-for') || req.connection.remoteAddress;

【讨论】:

    【解决方案9】:

    警告:

    不要盲目地将其用于重要的速率限制:

    let ip = request.headers['x-forwarded-for'].split(',')[0];
    

    很容易被欺骗:

    curl --header "X-Forwarded-For: 1.2.3.4" "https://example.com"
    

    在这种情况下,用户的真实 IP 地址将是:

    let ip = request.headers['x-forwarded-for'].split(',')[1];
    

    我很惊讶没有其他答案提到这一点。

    【讨论】:

    • top answer 确实通过数组中的pop()ing 来处理这个问题,这比在索引 1 处获取元素更通用,可以通过curl --header "X-Forwarded-For: 1.2.3.4, 5.6.7.8" "https://example.com" 获取fooled
    【解决方案10】:

    function getCallerIP(request) {
        var ip = request.headers['x-forwarded-for'] ||
            request.connection.remoteAddress ||
            request.socket.remoteAddress ||
            request.connection.socket.remoteAddress;
        ip = ip.split(',')[0];
        ip = ip.split(':').slice(-1); //in case the ip returned in a format: "::ffff:146.xxx.xxx.xxx"
        return ip;
    }

    【讨论】:

    • 你是对的,如果你想要ip作为字符串,那么你可以将最后一行替换为:ip = ip.split(':').slice(-1)[0]跨度>
    • 不鼓励使用纯代码的答案。你能解释一下这个答案比旧的、更好的解释和(更多)赞成的answers 更好吗?
    【解决方案11】:

    在节点 10.14 中,在 nginx 后面,您可以通过 nginx 标头请求它来检索 ip,如下所示:

    proxy_set_header X-Real-IP $remote_addr;
    

    然后在你的 app.js 中:

    app.set('trust proxy', true);
    

    之后,无论您希望它出现在哪里:

    var userIp = req.header('X-Real-IP') || req.connection.remoteAddress;
    

    【讨论】:

      【解决方案12】:

      我都试过了,还是不行,

      console.log(clientIp);
      console.log(req.ip);
      
      console.log(req.headers['x-forwarded-for']);
      console.log(req.connection.remoteAddress);
      console.log(req.socket.remoteAddress);
      console.log(req.connection.socket.remoteAddress.split(",")[0]);
      

      当我在 Nginx 代理后面运行 Express 应用程序时,您必须将应用程序变量 trust proxy 设置为 true。 Express 提供了一些其他信任代理值,您可以在他们的文档中查看这些值,但以下步骤对我有用。

      1. app.set('trust proxy', true) 在您的 Express 应用中。

      app.set('trust proxy', true);

      1. 在 Nginx 中添加 proxy_set_header X-Forwarded-For $remote_addr 服务器块的配置。
        location /  {
                      proxy_pass    http://localhost:3001;
                      proxy_http_version 1.1;
                      proxy_set_header Upgrade $http_upgrade;
                      proxy_set_header Connection 'upgrade';
                      proxy_set_header Host $host;
                      proxy_set_header X-Forwarded-For $remote_addr;  # this line
                      proxy_cache_bypass $http_upgrade; 
              }
      
      1. 您现在可以从 req.header('x-forwarded-for') 或 req.connection.remoteAddress; ipfilter 的完整代码
      module.exports =  function(req, res, next) {
          let enable = true; // true/false
          let blacklist = ['x.x.x.x'];
          let whitelist = ['x.x.x.x'];
          let clientIp = req.header('x-forwarded-for') || req.connection.remoteAddress;
          if (!clientIp) {
              return res.json('Error');
          }
          if (enable
              && paths.some((path) => (path === req.originalUrl))) {
      
              let blacklist = blacklist || [];
              if (blacklist.some((ip) => clientIp.match(ip) !== null)) {
                  return res.json({ status: 401, error: 'Your IP is black-listed !'});
              }
              let whitelist = whitelist || [];
              if (whitelist.length === 0 || whitelist.some((ip) => clientIp.match(ip) !== null)) {
                  next();
                  return;
              } else {
                  return res.json({ status: 401, error: 'Your IP is not listed !'});
              }
          }
          next();
      };
      

      【讨论】:

      • 谢谢你!这最终是让我启动并运行的原因——对 nginx.conf 的修改(奇怪的是,没有其他人提到过)。
      【解决方案13】:

      如果您使用的是 express 版本 3.x 或更高版本,您可以使用信任代理设置 (http://expressjs.com/api.html#trust.proxy.options.table),它将遍历 x-forwarded-for 标头中的地址链并将最新的 ip 放入将您未配置为可信代理的链放入 req 对象的 ip 属性中。

      【讨论】:

        【解决方案14】:

        如果你有多个 IP,这对我有用:

        var ipaddress = (req.headers['x-forwarded-for'] || 
        req.connection.remoteAddress || 
        req.socket.remoteAddress || 
        req.connection.socket.remoteAddress).split(",")[0];

        【讨论】:

          【解决方案15】:

          在nodejs中简单获取远程ip:

          var ip = req.header('x-forwarded-for') || req.connection.remoteAddress;
          

          【讨论】:

            【解决方案16】:

            req.connection 已被弃用 since node@12.12.0。使用 req.connection.remoteAddress 获取客户端 IP 可能仍然有效,但不鼓励使用。

            幸运的是,req.socket.remoteAddress 从 node@0.5.10 就一直存在,是一个完美的替代品:

            远程 IP 地址的字符串表示形式。例如,'74.125.127.100''2001:4860:a005::68'。如果套接字被销毁(例如,如果客户端断开连接),则值可能是 undefined

            【讨论】:

              【解决方案17】:

              如果您使用的是 express.js,那么,

              app.post('/get/ip/address', function (req, res) {
                    res.send(req.ip);
              })
              

              【讨论】:

                【解决方案18】:

                var ipaddress = (req.headers['x-forwarded-for'] || 
                req.connection.remoteAddress || 
                req.socket.remoteAddress || 
                req.connection.socket.remoteAddress).split(",")[0];

                【讨论】:

                • 这个问题已经有了广为接受的答案。为什么这个代码示例比他们好?请添加更多解释。
                【解决方案19】:

                我意识到这已经被回答到死了,但这是我编写的一个现代 ES6 版本,它遵循基于 airbnb 的 eslint 标准。

                const getIpAddressFromRequest = (request) => {
                  let ipAddr = request.connection.remoteAddress;
                
                  if (request.headers && request.headers['x-forwarded-for']) {
                    [ipAddr] = request.headers['x-forwarded-for'].split(',');
                  }
                
                  return ipAddr;
                };
                

                X-Forwarded-For 标头可能包含以逗号分隔的代理 IP 列表。顺序是 client,proxy1,proxy2,...,proxyN。在现实世界中,人们实现了可以在此标头中提供他们想要的任何内容的代理。如果您在负载均衡器或其他设备后面,您至少可以相信列表中的第一个 IP 至少是某个请求通过的任何代理。

                【讨论】:

                  【解决方案20】:

                  如果您使用的是 Graphql-Yoga,您可以使用以下功能:

                  const getRequestIpAddress = (request) => {
                      const requestIpAddress = request.request.headers['X-Forwarded-For'] || request.request.connection.remoteAddress
                      if (!requestIpAddress) return null
                  
                      const ipv4 = new RegExp("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
                  
                      const [ipAddress] = requestIpAddress.match(ipv4)
                  
                      return ipAddress
                  }

                  【讨论】:

                    【解决方案21】:

                    我在 nginx 后面使用 express 和

                    req.headers.origin
                    

                    帮我搞定了

                    【讨论】:

                      【解决方案22】:

                      我将它用于 ipv4 格式

                      req.connection.remoteAddress.split(':').slice(-1)[0]
                      

                      【讨论】:

                        【解决方案23】:
                            const express = require('express')
                            const app = express()
                            const port = 3000
                        
                            app.get('/', (req, res) => {
                            var ip = req.ip
                            console.log(ip);
                            res.send('Hello World!')
                            })
                        
                           // Run as nodejs ip.js
                            app.listen(port, () => {
                            console.log(`Example app listening at http://localhost:${port}`)
                            })
                        

                        【讨论】:

                          【解决方案24】:

                          这里有很多优点,但没有什么是全面的,所以这是我最终使用的:

                          function getIP(req) {
                            // req.connection is deprecated
                            const conRemoteAddress = req.connection?.remoteAddress
                            // req.socket is said to replace req.connection
                            const sockRemoteAddress = req.socket?.remoteAddress
                            // some platforms use x-real-ip
                            const xRealIP = req.headers['x-real-ip']
                            // most proxies use x-forwarded-for
                            const xForwardedForIP = (() => {
                              const xForwardedFor = req.headers['x-forwarded-for']
                              if (xForwardedFor) {
                                // The x-forwarded-for header can contain a comma-separated list of
                                // IP's. Further, some are comma separated with spaces, so whitespace is trimmed.
                                const ips = xForwardedFor.split(',').map(ip => ip.trim())
                                return ips[0]
                              }
                            })()
                            // prefer x-forwarded-for and fallback to the others
                            return xForwardedForIP || xRealIP || sockRemoteAddress || conRemoteAddress
                          }
                          

                          【讨论】:

                            【解决方案25】:

                            我们可以在 node js 中检查这段代码

                            const os       = require('os');
                            var interfaces = os.networkInterfaces();
                            
                            var addresses = [];
                            
                            for (var k in interfaces) {
                            
                                for (var k2 in interfaces[k]) {
                            
                                    var address = interfaces[k][k2];
                            
                                    if ( (address.family === 'IPv4' || address.family === 'IPv6')  && 
                                        !address.internal) {
                            
                                        addresses.push(address.address);
                            
                                    }
                                }
                            }
                            console.log(addresses);
                            

                            【讨论】:

                            • 一个好的答案将始终包括解释为什么这会解决问题,以便 OP 和任何未来的读者可以从中学习。
                            【解决方案26】:

                            有同样的问题...我也是 javascript 新手,但我用 req.connection.remoteAddress 解决了这个问题;这给了我 IP 地址(但采用 ipv6 格式 ::ffff.192.168.0.101 ),然后 .slice 删除前 7 个数字。

                            var ip = req.connection.remoteAddress;
                            
                            if (ip.length < 15) 
                            {   
                               ip = ip;
                            }
                            else
                            {
                               var nyIP = ip.slice(7);
                               ip = nyIP;
                            }
                            

                            【讨论】:

                            • 这不是一个好方法,因为 ipv6 不仅仅是 7 位数字 + IPv4,而且可以完全不同。
                            • @Radek 如果您验证地址的开头,它符合规范(请参阅en.wikipedia.org/wiki/IPv6_address ctrl-f 搜索“IPv4-mapped”)ip= (ip.length&lt;15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined)) 将替换 if... in以上代码
                            • 我亲自从 npm request-ip 包装 getClientIp() 以创建 function getClientIp4(req){ var ip=typeof req==='string'?req:getClientIp(req); return (ip.length&lt;15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined)); },它接受以前获取的 ip 或请求对象作为输入并给出 ip 或未定义的结果
                            猜你喜欢
                            • 1970-01-01
                            • 2021-09-22
                            • 1970-01-01
                            • 2018-03-11
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多