zoukankan      html  css  js  c++  java
  • express中是如何处理IP的?

    express获取client_ip

    req.ip // 获取客户端ip
    req.ips // 获取请求经过的客户端与代理服务器的Ip列表
    

    查看源码

    定义获取ip的入口,

    // 源码 request.js  
    defineGetter(req, 'ip', function ip(){
      var trust = this.app.get('trust proxy fn');
      let add = proxyaddr(this, trust);
      return add
    });
    defineGetter(req, 'ips', function ips() {
      var trust = this.app.get('trust proxy fn');
      var addrs = proxyaddr.all(this, trust);
      addrs.reverse().pop()
      return addrs
    });
    

    defineGetter

    Object.defineProperty的封装,所以我们能在req对象上获取到ip。

    trust proxy 的意义

    trust proxy :当用户设置trust proxy的值代表用户认为这些值是代理服务器。那么在获取真实客户端ip的时候就需要进行将这些代理ip过滤掉,
    而this.app.get('trust proxy fn')会生成对应的过滤器,这里的过滤器就是函数,类似于数组的filter的callback。

    如果用户没有设置'trust proxy'this.app.get('trust proxy fn')的返回值如下:

    function trustNone () {
      return false
    }
    

    如果用户没有设置'trust proxy',返回值类似如下:

    function trust (addr) {
        if (!isip(addr)) return false
        var ip = parseip(addr)
        var kind = ip.kind()
        if (kind !== subnetkind) {
          if (subnetisipv4 && !ip.isIPv4MappedAddress()) {
            // Incompatible IP addresses
            return false
          }
          // Convert IP to match subnet IP kind
          ip = subnetisipv4
            ? ip.toIPv4Address()
            : ip.toIPv4MappedAddress()
        }
        return ip.match(subnetip, subnetrange)
    }
    

    这里牵扯到express中的get set方法,源码一并列出:

    // 源码 application.js
    
    // 初始化express的是后运行,默认设置trust proxy 为false, 
    this.set('trust proxy', false);  
    
    // 定义get方法
    methods.forEach(function(method){
      app[method] = function(path){
        if (method === 'get' && arguments.length === 1) {
          return this.set(path); //  调用get运行到这里,相当于调用了set方法
        }
    		......
      };
    });
    // 定义set方法
    app.set = function set(setting, val) {
      if (arguments.length === 1) {
        return this.settings[setting];  //调用set方法运行到这里,相当于返回了settings这个对象中的某个配置
      }
      .....
      this.settings[setting] = val;
      ......
      case 'trust proxy':
      	this.set('trust proxy fn', compileTrust(val));
      ....
    };
    

    经过以上代码的运行,

    则两个方法的作用是用来过滤

    proxyaddr

    这是npm包proxy-addr,express文档中提到的linklocal,loopback,uniquelocal是在这里定义的,上面提到的ip过滤方法也是这个包来生成。

    由函数forward来处理获取ip,事实上使用x-forwarded-for 和 req.connection.remoteAddress的类获取ip。

    function forwarded (req) {
      ....
      var proxyAddrs = parse(req.headers['x-forwarded-for'] || '')
      var socketAddr = req.connection.remoteAddress
      var addrs = [socketAddr].concat(proxyAddrs)
      return addrs
    }
    

    实例

    var express = require('express')
    var app = express()
    app.set('trust proxy','127.0.0.1')
    app.use(function (req,res) {
      if(req.url === '/favicon.ico')return
      res.send({
         ip:req.ip,
         ips:req.ips
      })
      console.log(app.get('trust proxy'));
    })
    app.listen('9090','0.0.0.0')
    

    同时nginx设置代理:

    server {
      listen 8062;
      server_name localhost;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      location / {
        proxy_pass http://127.0.0.1:9090;
      }
    }
    

    此时只有一台代理服务,转发到express的x-forwarded-for为"192.168.1.105",而代理服务器nginx的ip为127.0.0.1,经过forwarded方法处理之后是待过滤的ip数组是 ["127.0.0.1","192.168.1.105"]。

    • 在另一台电脑(内网ip192.168.1.105)访问192.168.1.102(内网本机IP):8062 ,返回:{"ip":"192.168.1.105","ips":["192.168.1.105"]}

    解释:因为trust proxy和nginx的ip一致,所以过滤掉了nginx的ip,剩下的ip中的第一个被认为是客户端ip;因为ips本身是就是客户端ip和代理ip的集合,这里代理nginx被过滤掉了,最后和客户端一样。

    • 去掉 app.set('trust proxy','127.0.0.1')的结果:{"ip":"127.0.0.1","ips":[]}

    解释:没有设置trust proxy,也就是认为没有代理,获取的ip为代理服务器的ip。在此情况下ips为为空数组。

    • 换成 app.set('trust proxy','127.0.0.100/28')的结果:{"ip":"127.0.0.1","ips":[]}

    解释:上面的28为网段的CIDR表示法,CIDR是什么呢?有点像正则匹配一样,举个例子:127.0.0.1没有落在127.0.0.100/28所便是的网段,所以express在使用过滤器的时候没有匹配到,最后返回了第一个ip。没有匹配到代表ips也为空数组;

    • 换成 app.set('trust proxy','127.0.0.100/18')的结果:{"ip":"192.168.1.105","ips":["192.168.1.105"]}

    解释:127.0.0.1 落在了127.0.0.100/18表示的网段,和上面的相反,过滤掉127.0.0.1。

    总结

    程序的逻辑如下:

    1. 如果没有设置trust proxy或者设置trust proxy为false,获取的是ip就是req.connection.remoteAddress
    2. 如果设置了trust proxy ,express会生成对应的过滤函数,过滤[代理ip,x-forwarded-for中的ip],返回结果数组的第一个ip;
    3. ips的处理逻辑类似;
  • 相关阅读:
    jvm基本结构和解析
    多态的意思
    java中对象的简单解读
    double类型和int类型的区别
    python 解析xml文件
    win10不能映射Ubuntu共享文件
    Qt程序打包
    Ubuntu boot分区文件误删,系统无法启动,怎么解
    ubuntu Boot空间不够问题“The volume boot has only 5.1MB disk space remaining”
    Ubuntu 分辨率更改 xrandr Failed to get size of gamma for output default
  • 原文地址:https://www.cnblogs.com/walkermag/p/13288148.html
Copyright © 2011-2022 走看看