345

我不完全明白我应该如何获得远程用户 IP 地址。

假设我有一个简单的请求路由,例如:

app.get(/, function (req, res){
   var forwardedIpsStr = req.header('x-forwarded-for');
   var IP = '';

   if (forwardedIpsStr) {
      IP = forwardedIps = forwardedIpsStr.split(',')[0];  
   }
});

上述方法是否正确获取真实用户 IP 地址还是有更好的方法?那么代理呢?

4

16 回答 16

619

如果您在 NGiNX 之类的代理或您拥有的代理后面运行,那么您应该检查'x-forwarded-for'

var ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress 

如果代理不是“你的”,我不会相信'x-forwarded-for'标题,因为它可以被欺骗。

于 2012-06-01T11:53:33.490 回答
285

虽然@alessioalex 的答案有效,但在Express-guide的Express behind proxies部分中还有另一种方法。

  1. 添加app.set('trust proxy', true)到您的快速初始化代码中。
  2. 当你想获取远程客户端的ip时,使用req.ipreq.ips以通常的方式(好像没有反向代理一样)

选读:

  • 使用req.ipreq.ipsreq.connection.remoteAddress不适用于此解决方案。
  • 'trust proxy'如果您需要比信任标头中传递的所有内容更复杂的东西x-forwarded-for(例如,当您的代理没有从不受信任的来源中删除预先存在的 x-forwarded-for 标头时) ,则可以使用更多选项。有关更多详细信息,请参阅链接指南。
  • 如果您的代理服务器未填充x-forwarded-for标头,则有两种可能性。
    1. 代理服务器不会中继有关请求最初所在位置的信息。在这种情况下,将无法找出请求的最初来源。您需要先修改代理服务器的配置。
      • 例如,如果您使用 nginx 作为反向代理,则可能需要添加proxy_set_header X-Forwarded-For $remote_addr;到您的配置中。
    2. 代理服务器以专有方式(例如,自定义 http 标头)中继有关请求最初来自何处的信息。在这种情况下,这个答案是行不通的。可能有一种自定义方法可以获取该信息,但您需要首先了解该机制。
于 2013-01-31T17:31:43.070 回答
64

nginx.conf文件中:
proxy_set_header X-Real-IP $remote_addr;

node.js服务器文件中:
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

请注意,表示小写标题

于 2013-08-28T07:27:56.053 回答
33

特别是对于节点,http 服务器组件的文档,在事件连接下说:

[触发] 当建立新的 TCP 流时。[The] socket 是一个 net.Socket 类型的对象。通常用户不想访问此事件。特别是,由于协议解析器附加到套接字的方式,套接字不会发出可读事件。也可以在 访问套接字request.connection

所以,这意味着request.connection是一个套接字,根据文档确实有一个socket.remoteAddress属性,根据文档是:

远程 IP 地址的字符串表示形式。例如,“74.125.127.100”或“2001:4860:a005::68”。

在 express 下,request 对象也是 Node http request 对象的一个​​实例,所以这种做法应该还是可以的。

但是,在 Express.js 下,请求已经有两个属性:req.ipreq.ips

请求.ip

返回远程地址,或者启用“信任代理”时 - 上游地址。

请求.ips

“trust proxy”true时,解析“X-Forwarded-For”ip地址列表并返回一个数组,否则返回一个空数组。例如,如果值为 "client, proxy1, proxy2",您将收到数组 ["client", "proxy1", "proxy2"],其中 "proxy2" 是最远的下游。

值得一提的是,根据我的理解,Expressreq.ip是一种比 更好的方法req.connection.remoteAddress,因为req.ip它包含实际的客户端 ip(前提是在 express 中启用了可信代理),而另一个可能包含代理的 IP 地址(如果有一)。

这就是为什么当前接受的答案建议:

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

req.headers['x-forwarded-for']相当于 express req.ip

于 2014-02-06T16:46:07.703 回答
29

如果您可以使用 3rd-party 库。您可以检查request-ip

你可以使用它

import requestIp from 'request-ip';

app.use(requestIp.mw())

app.use((req, res) => {
  const ip = req.clientIp;
});

源码比较长,这里就不复制了,大家可以去https://github.com/pbojinov/request-ip/blob/master/src/index.js查看

基本上,

它在请求中查找特定的标头,如果它们不存在,则回退到一些默认值。

用户 ip 由以下顺序确定:

  1. X-Client-IP
  2. X-Forwarded-For(Header 可能会返回多个 IP 地址,格式为:“client IP, proxy 1 IP, proxy 2 IP”,所以我们取第一个。)
  3. CF-Connecting-IP(云闪)
  4. Fastly-Client-Ip(转发到云功能时快速 CDN 和 Firebase 托管标头)
  5. True-Client-Ip(Akamai 和 Cloudflare)
  6. X-Real-IP(Nginx 代理/FastCGI)
  7. X-Cluster-Client-IP(Rackspace LB,河床黄貂鱼)
  8. X-Forwarded,Forwarded-ForForwarded(#2 的变体)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

如果找不到 IP 地址,它将返回null.

披露:我与图书馆无关。

于 2020-04-03T02:45:16.977 回答
19
  1. 添加app.set('trust proxy', true)
  2. 使用req.ipreq.ips以通常的方式
于 2017-07-31T12:18:33.357 回答
10

这只是此答案的附加信息。

如果您正在使用nginx,您将添加proxy_set_header X-Real-IP $remote_addr;到站点的位置块。/etc/nginx/sites-available/www.example.com例如。这是一个示例服务器块。

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    location / {
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_pass http://127.0.1.1:3080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

重新启动后nginx,您将能够访问node/express应用程序路由中的 ipreq.headers['x-real-ip'] || req.connection.remoteAddress;

于 2019-05-09T22:42:15.010 回答
6

我为此编写了一个包。您可以将其用作快速中间件。我的包在这里发布:https ://www.npmjs.com/package/express-ip

您可以使用安装模块

npm i express-ip

用法

const express = require('express');
const app = express();
const expressip = require('express-ip');
app.use(expressip().getIpInfoMiddleware);

app.get('/', function (req, res) {
    console.log(req.ipInfo);
});
于 2018-11-21T11:00:41.330 回答
5

我知道这个问题已经得到解答,但这就是我的工作方式。

let ip = req.connection.remoteAddress.split(`:`).pop();
于 2019-01-25T19:59:38.463 回答
4

根据Express behind proxies,如果您配置正确,req.ip则已考虑反向代理。trust proxy因此它比req.connection.remoteAddress从网络层获得并且不知道代理要好。

于 2017-01-03T21:51:59.700 回答
2

这对我来说比其他人更好。我的网站落后于 CloudFlare,它似乎需要cf-connecting-ip.

req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress

没有在代理后面测试 Express,因为它没有说明这个cf-connecting-ip标题。

于 2017-04-09T03:28:49.500 回答
2

就我而言,与解决方案类似,我最终使用了以下x-forwarded-for方法:

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

x-forwarded-for标头将继续添加从源到最终目标服务器的 IP 路由,因此如果您需要检索源客户端的 IP,这将是数组的第一项

于 2020-01-31T20:09:19.643 回答
1

var ip = req.connection.remoteAddress;

ip = ip.split(':')[3];

于 2018-02-01T14:06:08.813 回答
1

headers 对象拥有您需要的一切,只需执行以下操作:

var ip = req.headers['x-forwarded-for'].split(',')[0];
于 2018-05-03T20:20:04.103 回答
1

支持 can-flare、nginx 和 x-real-ip

var user_ip;

    if(req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
      let first = req.headers['cf-connecting-ip'].split(', ');
      user_ip = first[0];
    } else {
      let user_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }
于 2019-08-21T15:06:32.177 回答
-1

将所有witk @kakopappa解决方案以及morgan客户端IP地址的日志记录放在一起:

morgan.token('client_ip', function getId(req) {
    return req.client_ip
});
const LOG_OUT = ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" :client_ip'
self.app.use(morgan(LOG_OUT, {
    skip: function(req, res) { // custom logging: filter status codes
        return res.statusCode < self._options.logging.statusCode;
    }
}));

// could-flare, nginx and x-real-ip support
var getIpInfoMiddleware = function(req, res, next) {
    var client_ip;
    if (req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
        var first = req.headers['cf-connecting-ip'].split(', ');
        client_ip = first[0];
    } else {
        client_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }
    req.client_ip = client_ip;
    next();
};
self.app.use(getIpInfoMiddleware);
于 2019-11-20T18:05:30.243 回答