關於使用代理后,后端獲取客戶端IP中遇到的問題(比如.NetCore、Vue、Nginx)


  首先,我們有多種方式獲取本地IP地址,比如:.net core獲取本地Ip地址的方法 ,這種方式與項目類型無關。

  如果后端項目是一個web項目,我們還可以通過HttpContext來獲取后端項目所在服務器的本地IP,而且還能獲取客戶端的IP地址:  

    var connection = HttpContext.Connection;

    //客戶端IP地址(v4和v6)
    var remoteIpAddressIPv4 = connection.RemoteIpAddress?.MapToIPv4()?.ToString();
    var remoteIpAddressIPv6 = connection.RemoteIpAddress?.MapToIPv6()?.ToString();
    //服務端本地IP地址(v4和v6)
    var localIpAddressIPv4 = connection.LocalIpAddress?.MapToIPv4()?.ToString();
    var localIpAddressIPv6 = connection.LocalIpAddress?.MapToIPv6()?.ToString();

  但是現在的web項目應該很少有直接面向客戶端使用的吧,都是中間或多或少有幾個網關或者代理,比如使用nginx:  

    location / {        
        proxy_pass http://localhost:5000;
    }

  或者前端Vue開發時使用了使用http-proxy-middleware做代理:  

  devServer: {
    proxy: {
      '/api': {
        target: process.env.VUE_APP_API_BASE_URL,
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '^/api': '' // 需要rewrite的,
        }
      }
    }
  }

  那么問題來了,一旦客戶端的請求被代理了,那么上面獲取獲取客戶端IP地址的方式就不准確了,因為請求被代理轉發了,這樣它獲取的就是代理端的IP,而不是客戶端的IP,那么怎么解決這個問題呢?

  這就要說到兩個特殊的請求頭了:X-Real-IP 與 X-Forwarded-For

  X-Real-IP:表示真實的IP,但是實際上,它表示多級代理中最后一個代理的IP,可惜的是,它只是被一些組織機構認可,貌似並沒有一個標准的規范。

  X-Forwarded-For:表示請求從客戶端發起后所經過的所有代理的IP地址,這些IP地址使用英文逗號+空格(, )進行分隔,其中第一個就是客戶端的IP地址,形如:  

    X-Forwarded-For: 192.168.128.111, 192.168.128.112, 192.168.128.113

  那么解決這個問題的關鍵就是在代理轉發請求時,我們需要給轉發的請求加上這個X-Forwarded-For請求頭!X-Real-IP可以添加,也可以不添加,只是后端讀取不一樣。

  如果使用的是Nginx:  

    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 如果是代理websocket,還需要下面兩個
        # proxy_set_header Upgrade $http_upgrade;
        # proxy_set_header Connection "upgrade";
    }

  $remote_addr表示上一級代理的IP,如果上一級是客戶端,那么它就表示客戶端的IP,$proxy_add_x_forwarded_for表示將$remote_addr追加到上一級代理的X-Forwarded-For請求頭中,並將追加后的內容作為X-Forwarded-For請求頭轉發到下一級,這樣客戶端的IP就一級一級的轉發到了服務端

  如果是Vue開發過程中使用了http-proxy-middleware做代理:  

  devServer: {
    proxy: {
      '/api': { //如果是API接口
        target: process.env.VUE_APP_API_BASE_URL,
        ws: false,
        changeOrigin: true,
        pathRewrite: {
          '^/api': '' // 需要rewrite的,
        },
        onProxyReq(proxyReq, req, res) {
          //req中默認是攜帶有x-forwarded-for請求頭的,只需添加X-Real-IP請求頭
          req.headers['X-Real-IP'] = req.ip
        }
      },
      '/socket': { //如果是websocket
        target: process.env.VUE_APP_SOCKET_BASE_URL,
        ws: true,
        changeOrigin: true,
        onProxyReqWs(proxyReq, req, socket, options, head) {
          //req中默認是攜帶有x-forwarded-for請求頭的,只需添加X-Real-IP請求頭
          req.headers['X-Real-IP'] = req.ip
        }
      }
    }
  }

  這里onProxyReq是代理普通http接口前會觸發的事件,onProxyReqWs則是代理websocket前會觸發的事件

  接着后端獲取IP可以從下面的規則中獲取:  

    string ip = HttpContext.Request.Headers["X-Real-IP"].ToString();
    if (string.IsNullOrEmpty(ip))
    {
        string ips = HttpContext.Request.Headers["X-Forwarded-For"].ToString();
        ip = ips.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
        if (string.IsNullOrEmpty(ip))
        {
            ip = HttpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString();
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM