Express.js:如何获取远程客户端地址

Eri*_*rik 221 ip ip-address node.js express

我不完全理解我应该如何获得远程用户IP地址.

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

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

   if (forwardedIpsStr) {
      IP = forwardedIps = forwardedIpsStr.split(',')[0];  
   }
});
Run Code Online (Sandbox Code Playgroud)

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

ale*_*lex 419

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

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
Run Code Online (Sandbox Code Playgroud)

如果代理不是'你的',我不会相信'x-forwarded-for'标题,因为它可能是欺骗性的.

  • 您需要记住,如果您使用自己的反向代理,则必须将此指令`proxy_set_header X-Forwarded-For $ remote_addr;`放入您的nginx配置中. (35认同)
  • copy-pasta用户请注意:这可以返回以逗号分隔的IP地址列表.我们有一个错误来自开发人员复制它并将结果与​​IP进行比较.也许做一些像`var ip =(req.headers ['x-forwarded-for'] || req.connection.remoteAddress ||'').split(',')[0] .trim();`to获取客户端IP. (28认同)
  • @Rishav ::1 是本地主机的 IPv6 地址 (5认同)
  • 这是正确的,但是在我的情况下我不得不使用方括号(参见上面的编辑)还要确保在nginx配置中启用了x-forwarded-for.奇迹般有效! (2认同)
  • @DavyJones 的代码片段不适用于打字稿,因为任何未列出的 req.headers (包括“X-”标头)都是“string|string[]”类型,并且不能具有“split”方法。可以重写并且应该用类型保护重写 (2认同)

Hao*_*hun 217

虽然@alessioalex的答案有效,但还有另一种方法,如快递指南中的Express背后部分所述.

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

如果您需要比信任x-forwarded-for标头中传递的所有内容更复杂的东西,并且您的代理不会从不受信任的来源中删除预先存在的x-forwarded-for标头,则可以使用更多"信任代理"选项.有关详细信息,请参阅链接指南.

注意:req.ip不适用于我的解决方案.

  • 我的答案更为笼统(不依赖于Express),但如果你使用Express,那确实是更好的方法. (4认同)
  • 您的代理服务器必须将标头"x-forwarded-for"设置为远程地址.例如,对于nginx,您应该在配置文件中使用proxy_set_header X-Forwarded-For $ remote_addr (4认同)
  • 在以 IISnode 作为代理的 IIS 后面,`app.enable('trust proxy')` 也可以使用 `req.ip`。除了我得到了端口 `1.2.3.4:56789`。为了去掉它,我做`var ip = req.ip.split(':')[0]` (3认同)
  • 我觉得这个答案缺乏安全性,需要更新。您应该始终定义应用程序信任的代理。接受的答案至少对欺骗有一点注意。就是说,如果您使用的是Express,使用这样的库是一个更好的解决方案,但是引用的代码不正确并且在链接的资源上找不到。 (2认同)
  • 为什么这会给我`::1`? (2认同)

小智 51

nginx.conf档案中:
proxy_set_header X-Real-IP $remote_addr;

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

请注意,表示小写标题

  • 对我来说,IP地址在`req.headers ['x-real-ip']下可用``甚至在`nginx.conf`标题中用大写字母设置. (8认同)
  • 欢迎来到Stack Overflow!请解释为什么此代码解决了所提出的问题,而不是仅发布一段代码.没有解释,这不是答案. (3认同)
  • @manakor你是对的,nodejs小写标题 (2认同)

Edw*_*rzo 28

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

[Triggered]建立新TCP流时.[socket]是net.Socket类型的对象.通常用户不希望访问此事件.特别是,由于协议解析器如何附加到套接字,套接字将不会发出可读事件.也可以访问套接字request.connection.

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

远程IP地址的字符串表示形式.例如,'74 .125.127.100'或'2001:4860:a005 :: 68'.

在express下,请求对象也是Node http请求对象的一个​​实例,因此这种方法仍然有效.

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

req.ip

返回远程地址,或启用"信任代理" - 上游地址.

req.ips

"信任代理"true,解析"X-Forwarded-For"ip地址列表并返回一个数组,否则返回一个空数组.例如,如果值为"client,proxy1,proxy2",您将收到数组["client","proxy1","proxy2"],其中"proxy2"是最下游的.

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

这就是为什么目前接受的答案表明:

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

req.headers['x-forwarded-for']将相当于快递req.ip.


Hon*_*iao 22

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

你可以使用它

import requestIp from 'request-ip';

app.use(requestIp.mw())

app.use((req, res) => {
  const ip = req.clientIp;
});
Run Code Online (Sandbox Code Playgroud)

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

基本上,

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

用户ip由以下顺序确定:

  1. X-Client-IP
  2. X-Forwarded-For (Header可能会返回多个IP地址,格式为:“客户端IP,代理1 IP,代理2 IP”,所以我们取第一个。)
  3. CF-Connecting-IP (Cloudflare)
  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、Riverbed Stingray)
  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

披露:我与图书馆无关。

  • 非常好@hongbo!值得一提的是,由于节点区分大小写,因此如果想跳过中间件解决方案。 (2认同)

lea*_*ore 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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


Bal*_*ald 7

  1. app.set('trust proxy', true)
  2. 使用req.ipreq.ips按常规方式

  • 这是要走的路。有关详细信息,请参见https://expressjs.com/en/guide/behind-proxies.html。 (2认同)

小智 6

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

您可以使用安装模块

npm i express-ip
Run Code Online (Sandbox Code Playgroud)

用法

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);
});
Run Code Online (Sandbox Code Playgroud)

  • 当链接到您所属的内容时,您*必须在帖子中披露从属关系*。如果您不透露隶属关系,则会被视为垃圾邮件。披露必须明确,但不需要正式(例如,对于您自己的*个人*内容:“在我的网站上……”、“在我的博客上……”等)。请参阅:[**什么表示“良好”的自我推销?**](//meta.stackexchange.com/q/182212)、[有关自我推销的一些提示和建议](/help/promotion)、[什么是自我推销] Stack Overflow 上“垃圾邮件”的确切定义?](//meta.stackoverflow.com/q/260638),以及[什么是垃圾邮件](//meta.stackexchange.com/a/58035)。 (7认同)

小智 5

我知道这个问题已经得到回答,但这是我如何让我的工作。

let ip = req.connection.remoteAddress.split(`:`).pop();
Run Code Online (Sandbox Code Playgroud)