一、前言

前文 Nginx 解决WebApi跨域二次请求以及Vue单页面问题 当中虽然解决了跨域问题带来的二次请求,但也产生了一个新的问题,就是如果需要获取用户IP的时候,获取的IP地址总是本机地址。

二、原因

由于Nginx反向代理后,在应用中取得的IP都是反向代理服务器的IP,取得的域名也是反向代理配置的Url的域名。

三、解决方案

解决该问题,需要在Nginx反向代理配置中添加一些配置信息,目的将客户端的真实IP和域名传递到应用程序中。同时,也要修改获取IP地址的方法。

但是需要注意的是,通过Nginx反向代理后,如果访问IP通过了几层代理,可能取得的IP地址是这种格式:clientIP,proxy1,proxy2

如果需要将IP地址插入到数据库的话,需要做防止注入。因此要对上述的IP地址的格式进行截取。

3.1 Nginx 配置如下

    server {
listen 9461; # 监听端口号
server_name localhost 192.168.88.22; # 访问地址
location / {
root 项目路径; # 例如:E:/Publish/xxx/;
index index.html; # 此处用于处理 Vue、Angular、React 使用H5 的 History时 重写的问题
if (!-e $request_filename) {
rewrite ^(.*) /index.html last;
break;
}
} # 代理服务端接口
location /api {
proxy_pass http://localhost:9460/api;# 代理接口地址
# Host配置以及域名传递
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

3.2 C#代码获取真实IP方法

#region Ip(客户端IP地址)

/// <summary>
/// 客户端IP地址
/// </summary>
public static string Ip
{
get
{
var result = string.Empty;
if (HttpContext.Current != null)
{
result = GetWebClientIp();
}
if (string.IsNullOrWhiteSpace(result))
{
result = GetLanIp();
}
return result;
}
} /// <summary>
/// 获取Web客户端的IP
/// </summary>
/// <returns></returns>
private static string GetWebClientIp()
{
var ip = GetWebProxyRealIp() ?? GetWebRemoteIp();
foreach (var hostAddress in Dns.GetHostAddresses(ip))
{
if (hostAddress.AddressFamily == AddressFamily.InterNetwork)
{
return hostAddress.ToString();
}
}
return string.Empty;
} /// <summary>
/// 获取Web远程IP
/// </summary>
/// <returns></returns>
private static string GetWebRemoteIp()
{
try
{
return HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] ??
HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"] ?? "";
}
catch (Exception e)
{
return string.Empty;
}
} /// <summary>
/// 获取Web代理真实IP
/// </summary>
/// <returns></returns>
private static string GetWebProxyRealIp()
{
var request = HttpContext.Current.Request;
string ip = request.Headers.Get("x-forwarded-for"); if (string.IsNullOrEmpty(ip) || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
{
ip = request.Headers.Get("Proxy-Client-IP");
} if (string.IsNullOrEmpty(ip) || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
{
ip = request.Headers.Get("WL-Proxy-Client-IP");
} if (string.IsNullOrEmpty(ip) || string.Equals("unknown", ip, StringComparison.OrdinalIgnoreCase))
{
ip = request.UserHostAddress;
} if (string.IsNullOrEmpty(ip))
{
return string.Empty;
}
// 可能存在如下格式:X-Forwarded-For: client, proxy1, proxy2
if (ip.Contains(", "))
{
// 如果存在多个反向代理,获得的IP是一个用逗号分隔的IP集合,取第一个
// X-Forwarded-For: client 第一个
string[] ips = ip.Split(new string[1] {", "}, StringSplitOptions.RemoveEmptyEntries);
var i = 0;
for (i = 0; i < ips.Length; i++)
{
if (ips[i] != "")
{
// 判断是否为内网IP
if (false == IsInnerIp(ips[i]))
{
IPAddress realIp;
if (IPAddress.TryParse(ips[i], out realIp) && ips[i].Split('.').Length == 4)
{
//合法IP
return ips[i];
} return "";
}
}
} ip = ips[0];// 默认获取第一个IP地址
} return ip; } /// <summary>
/// 判断IP地址是否为内网IP地址
/// </summary>
/// <param name="ip">IP地址</param>
/// <returns></returns>
private static bool IsInnerIp(string ip)
{
bool isInnerIp = false;
ulong ipNum = Ip2Ulong(ip); /**
* 私有IP
* A类:10.0.0.0-10.255.255.255
* B类:172.16.0.0-172.31.255.255
* C类:192.168.0.0-192.168.255.255
* 当然,还有127这个网段是环回地址
*/ ulong aBegin = Ip2Ulong("10.0.0.0");
ulong aEnd = Ip2Ulong("10.255.255.255");
ulong bBegin = Ip2Ulong("172.16.0.0");
ulong bEnd = Ip2Ulong("10.31.255.255");
ulong cBegin = Ip2Ulong("192.168.0.0");
ulong cEnd = Ip2Ulong("192.168.255.255"); isInnerIp = IsInner(ipNum, aBegin, aEnd) || IsInner(ipNum, bBegin, bEnd) || IsInner(ipNum, cBegin, cEnd) ||
ip.Equals("127.0.0.1");
return isInnerIp;
} /// <summary>
/// 将IP地址转换为Long型数字
/// </summary>
/// <param name="ip">IP地址</param>
/// <returns></returns>
private static ulong Ip2Ulong(string ip)
{
byte[] bytes = IPAddress.Parse(ip).GetAddressBytes();
ulong ret = 0;
foreach (var b in bytes)
{
ret <<= 8;
ret |= b;
} return ret;
} /// <summary>
/// 判断用户IP地址转换为Long型后是否在内网IP地址所在范围
/// </summary>
/// <param name="userIp">用户IP</param>
/// <param name="begin">开始范围</param>
/// <param name="end">结束范围</param>
/// <returns></returns>
private static bool IsInner(ulong userIp, ulong begin, ulong end)
{
return (userIp >= begin) && (userIp <= end);
} /// <summary>
/// 获取局域网IP
/// </summary>
/// <returns></returns>
private static string GetLanIp()
{
foreach (var hostAddress in Dns.GetHostAddresses(Dns.GetHostName()))
{
if (hostAddress.AddressFamily == AddressFamily.InterNetwork)
{
return hostAddress.ToString();
}
}
return string.Empty;
}
#endregion

Nginx 反向代理获取真实IP问题的更多相关文章

  1. php nginx反向代理获取真实ip的教程

    php nginx反向代理获取真实ip的教程 <pre> location /getip { proxy_pass http://newmiracle.cn/ip.php; } proxy ...

  2. 后端Apache获取前端Nginx反向代理的真实IP地址 (原创贴-转载请注明出处)

    ====================说在前面的话==================== 环境:前段Nginx是反向代理服务器:后端是Apache是WEB项目服务器 目的:让后端Apapche获取 ...

  3. nginx 反向代理 取得真实IP和域名

    nginx反向代理后,在应用中取得的ip都是反向代理服务器的ip,取得的域名也是反向代理配置的url的域名,解决该问题,需要在nginx反向代理配置中添加一些配置信息,目的将客户端的真实ip和域名传递 ...

  4. JAVA中经过nginx反向代理获取客户端ip并获取相关坐标等信息

    关于搜狐新浪ip库查询接口的使用 直接输出访客ip及所在城市: <script src="http://pv.sohu.com/cityjson?ie=utf-8" > ...

  5. nginx反向代理获取用户真实ip

    nginx做反向代理时,默认的配置后端获取到的ip都是来自于nginx,如何转发用户的真实ip到后端程序呢?如是是java后端,用request.getRemoteAddr();获取到的是nginx的 ...

  6. 阿里云SLB后Nginx、Tomcat获取真实IP

    一.SLB后Nginx如何获取真实IP 前提:nginx作为slb获取真实ip是使用 http_realip_module,默认一键安装包安装的nginx没有安装这个模块需要重新重新编译nginx并加 ...

  7. Nginx 反向代理获取设备真实的IP地址

    package com.das.common.util; import org.apache.commons.lang3.StringUtils; import org.springframework ...

  8. 关于.net core使用nginx做反向代理获取客户端ip的问题

    1.正常情况下.net core获取客户端ip是比较简单的 /// <summary> /// 获取客户Ip /// </summary> /// <param name ...

  9. nginx 4层tcp代理获取真实ip

    举个例子,Nginx 中的代理配置假如是这样配置的: location / { proxy_http_version 1.1; proxy_set_header X-Real-IP $remote_a ...

随机推荐

  1. 修改 docker image 安装目录 (解决加载大image时报错:"no space left on device")

    修改 docker image 安装目录 (解决加载大image时报错:"no space left on device" ) 基于Ubuntu16.04 docker版本: 17 ...

  2. hdu4932 Miaomiao&#39;s Geometry (BestCoder Round #4 枚举)

    题目链接:pid=4932" style="color:rgb(202,0,0); text-decoration:none">http://acm.hdu.edu ...

  3. Linux CentOS完全卸载PHP

    很无语,CentOS居然php版本才5.1.6,很多开源的CMS无法安装. 查看php版本命令: #php -v 下面的命令是删除不干净的 #yum remove php 因为使用这个命令以后再用 # ...

  4. Ubuntu 编译安装 OpenCV 3.1

    目标系统:Ubuntu 16.04-64bit OpenCV 版本:opencv-3.1.0 安装步骤 安装 cmake.sudo apt-get isntall cmake cmake-qt-gui ...

  5. 在Eclipse中如何关联源代码

    我们就以Struts2框架为例,展示在Eclipse中如何关联源代码.例如,在Struts2框架的学习中,我们有时需要查看ActionSupport这个类的源码,这个时候就要在Eclipse中关联源代 ...

  6. javaWeb超链接(href)请求-特殊字符处理

    写在前面: 最近在项目中,遇到一个问题,在点击一个超链接时,页面报错.通过浏览器调试就可以知道发送的请求参数是不完整的,因为参数中含有特殊字符.所以就报错啦~~ 原代码,不能正确发送含有特殊字符的参数 ...

  7. Linux网络配置。Win10能ping虚拟机但虚拟机ping不通Win10,关闭Win10防火墙就好。

    仅主机模式:配置VMnet1与虚拟机在同一个网段 ifconfig查看网卡名: ifconfig ens33 192.168.1.2: ifconfig查看是否配置成功: 在Windows物理机上pi ...

  8. php通过system()调用Linux命令问题

    最近在做php和linux crontab的联调,发现php在linux下的权限问题需要引起注意,调试问题的过程中发现有许多问题前人说的比较零散,我在这里汇总,顺带抛砖引玉一下. 1.$result= ...

  9. C++模板显式实例化,隐式实例化,特化(具体化,偏特化)辨析

    最近再次看C++ PRIMER PLUS的时候看到这个部分感觉讲得很烂,前后口径不一致,所以写个辨析让自己明白的同时也希望对此不太清楚的朋友能搞懂. 总结一下,C++只有模板显式实例化(explici ...

  10. dataGrideView的使用

    总的连接地址:http://group.cnblogs.com/topic/40730.html 微软解说:https://msdn.microsoft.com/zh-cn/library/syste ...