如何确定节点中的用户IP地址


349

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

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

22
如果您正在使用Express可以使用req.ip 源- expressjs.com/en/api.html#req.ip
FrickeFresh


16
对于localhost像我一样工作的人,下面所有答案的结果(几乎所有答案都可以)可能会来::1。这让我有些困惑。后来发现这::1是真实的IP地址,是IPV6本地主机的表示法。 Hope this helps someone
Pramesh Bajracharya

Answers:


452

您的request对象中有一个称为的属性connection,它是一个net.Socket对象。net.Socket对象具有一个property remoteAddress,因此您应该能够通过以下调用获取IP:

request.connection.remoteAddress

请参阅httpnet的文档

编辑

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


6
这给我的IP地址不同于whatismyip.com给我的IP地址。为什么会这样呢?
Shamoon

3
我在no.de实例上安装了我的API服务。当我尝试从计算机访问它时,我获得的IP地址为“ 10.2.XXX.YYY”,而我的实际IP为“ 67.250.AAA.BBB”
Shamoon

7
这是request.headers ['X-Forwarded-For']
0x6A75616E 2011年

4
请注意,net.Stream现在是net.Socket,文档位于此处:nodejs.org/api/net.html#net_class_net_socket
2013年

4
对于任何对Heroku感兴趣的人: request.headers['x-forwarded-for']
FueledPublishing 2014年

407
var ip = req.headers['x-forwarded-for'] || 
     req.connection.remoteAddress || 
     req.socket.remoteAddress ||
     (req.connection.socket ? req.connection.socket.remoteAddress : null);

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

该字段的一般格式为:

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

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

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

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

9
但是如何防止这些标头的欺骗呢?
米2014年

8
这通常效果很好,但是由于某种原因,我最近收到了“无法读取未定义的属性'remoteAddress'的错误”错误,因为显然所有内容均为null / undefined,包括req.connection.socket。我不知道为什么/在什么情况下会导致这种情况,但是最好检查是否req.connection.socket存在这种情况,以免在这种情况下服务器崩溃。
马特·布朗

9
最后一行req.connection.socket.remoteAddress抛出错误。小心点。
yAnTar 2014年

11
返回的IP地址为:: 1。为什么?
Bagusflyer '16

3
查看pop()的工作方式,似乎您将要获得最后一个代理,而不是想要的客户端。我错了吗?
米歇尔


31

您可以保持DRY状态,仅使用同时支持IPv4IPv6的节点IPware

安装:

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地址。查看自述文件中的高级选项。


40
“或返回127.0.0.1以指示它无法确定用户的IP地址”“ 127.0.0.1与未知之间有很大的区别……
Nepoxx 2015年

4
:ffff:(not my IP address)从Heroku进行测试时,它为我返回了一些奇怪的信息。@ edmar-miyake的答案对我来说是正确的。
Nilloc 2015年

我想知道如果在'x-forward-for'情况下使用right2left查找,那么IP将是什么。var ip_info = get_ip(req,right_most_proxy = True),因为在某些设置中,客户端IP可能是最正确的IP。
Un33k 2015年

2
这种方法正在clientIp: '::1'为我返回。它似乎不起作用。
JamEngulfer

@JamEngulfer-仅当IP地址通过request.headers []正确传递到您的应用程序时,ipware才有效。示例:AWS LBS以“ x-forwarded-for”发送IP地址,而自定义NginX则使用其他变量。ipware会尽最大努力找出IP地址,但前提是IP已在标头中传递下来。
un33k

19

您可以使用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();
};

希望这可以帮助


2
github.com/pbojinov/request-ip/blob/master/index.js上检查包request-ip的源代码,它检查x-forwarded-for和各种其他标头,以查找流行的负载均衡器,例如AWS ELB,Cloudflare ,Akamai,nginx,Rackspace LB和Riverbed的Stingray
Giorgio

1
null给我回来。
S.M_Emamian

取而代之的是使用同一件事request.headers['x-forwarded-for']
Prathamesh更多

19

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


12

以下功能涵盖了所有情况,将有所帮助

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 , 对我而言介于两者之间。
ThomasReggi

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;


6

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;
}


1
没错,如果要将ip作为字符串,则可以将最后一行替换为:ip = ip.split(':')。slice(-1)[0]
Ahmad Agbaryah

不鼓励仅使用代码的答案。您能解释这个答案比旧的,解释更好的和(更多)建议更多的答案更好吗?
Dan Dascalescu

5

警告:

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

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];

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


所述顶部答案不通过处理这个pop()从阵列,这是比在索引1,其可以得到元件更一般的荷兰国际集团上当通过curl --header "X-Forwarded-For: 1.2.3.4, 5.6.7.8" "https://example.com"
Dan Dascalescu


3

在nodejs中简单地获取远程IP:

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

3

在nginx后面的节点10.14中,您可以通过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;

2

我意识到这已经死了,但这是我写的一个现代的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至少是某些请求通过的代理。


1

如果您使用的是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
}


-7

有同样的问题...我也是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

@Radek如果您验证地址的开头,则它符合规范(请参见en.wikipedia.org/wiki/IPv6_address ctrl-f搜索“ IPv4映射”)ip= (ip.length<15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined))将替换上述代码中的if ...
不同步的

我个人将npm request-ip的getClientIp()包装起来以创建function getClientIp4(req){ var ip=typeof req==='string'?req:getClientIp(req); return (ip.length<15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined)); }接受先前获取的ip或请求对象作为输入并给出ip或未定义的结果
不同步,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.