有些网站需要根据用户的位置,自动选择不同的语言,或者根据不同的国家,设置不同的时间显示方式,又或者跳转到不同的服务器路由。对于这个问题,我们该如何实现呢?这里我们讲一些非付费的方式,土豪请自我忽略。

方法一:根据客户端的语言来判断

这种方法是利用用户使用的浏览器的语言偏好来判断,这个方法简单快速,但是这个显然是不准确的。

var language = navigator.language; //navigator 中的language表示客户端用户偏好的第一语言,而languages是浏览器的语言列表,如果是zh-CN,则表示是中文,而en-US则表示美国。

方法二:利用header 里的Accept-Language来判断

一般网页发送到服务器时,会携带一个Accept-Language的头部信息,它可以通过逗号分割来携带多国语言。第一个会是首选的语言,其它语言会携带一个“q”值,来表示用户对该语言的喜好程度(0~1)。 这个方法和上面的同样是不准确的。

string languages = HttpContext.Request.Headers["Accept-Language"]; C#获取

方法三:利用IP地址来判断

根据客户端的IP地址来确定是相对来说比较准确的方法。原理就是通过IP地址所在的区域确定国家信息,互联网构建时的IP地址区域分配是有一定的数据规划的,不同的区域给的IP地址会是一段一段的,通过这个段位数据的字典查询就能知道客户所在的区域了。这个也是有可能不准确,比如当通过VPN来访问时,或者代理访问时都有可能不准确,但相对来说,这种情况少见,也是可以接受的。

直接通过第三方服务来获取信息

比较强大的第三库,不得不推荐MaxMind的GeoIP®Databases and Services,他们有自己的IP库,提供各种准确的接口,付费的可以根据定位很准确,不付费的只可以模糊定位到国家,不过已经符合我们的需求。

javascript端的实现过程可以查看文档:

https://dev.maxmind.com/geoip/geolocate-an-ip/client-side-javascript

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div>目前所在:<span id="result"></span></div><script src="//geoip-js.com/js/apis/geoip2/v2.1/geoip2.js" type="text/javascript"></script><script>var test = (function () {var onSuccess = function (geoipResponse) {/* There's no guarantee that a successful response object* has any particular property, so we need to code defensively. */if (!geoipResponse.country.iso_code) {return;}/* ISO country codes are in upper case. */var code = geoipResponse.country.iso_code.toLowerCase();document.getElementById('result').innerHTML = code;};var onError = function (error) {};return function () {geoip2.country(onSuccess, onError);};}());test();</script>
</body></html>

那如果是自己实现该怎么做呢?

关键是两个问题:一个是IP地址的获取 ,另外一个是IP区域数据库的获取。

IP地址的获取

IP地址在后端一般都有提供,如C# ASP.NET的可以通过如下的方式获取:

/// <summary>
/// 获取客户端IP地址
/// </summary>
/// <returns>若失败则返回回送地址</returns>
public static string GetIP()
{//如果客户端使用了代理服务器,则利用HTTP_X_FORWARDED_FOR找到客户端IP地址string userHostAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString().Split(',')[0].Trim();//否则直接读取REMOTE_ADDR获取客户端IP地址if (string.IsNullOrEmpty(userHostAddress)){userHostAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];}//前两者均失败,则利用Request.UserHostAddress属性获取IP地址,但此时无法确定该IP是客户端IP还是代理IPif (string.IsNullOrEmpty(userHostAddress)){userHostAddress = HttpContext.Current.Request.UserHostAddress;}//最后判断获取是否成功,并检查IP地址的格式(检查其格式非常重要)if (!string.IsNullOrEmpty(userHostAddress) && IsIP(userHostAddress)){return userHostAddress;}return "127.0.0.1";
}/// <summary>
/// 检查IP地址格式
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static bool IsIP(string ip)
{return System.Text.RegularExpressions.Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
}

以上引用了 https://www.cnblogs.com/stay-foolish/archive/2012/05/01/2475071.html,里面提到了为何如此获取的原因,有相关的知识可以参考。里面还提供了进一步知识的文章:
https://community.broadcom.com/symantecenterprise/communities/community-home/librarydocuments/viewdocument?DocumentKey=9d18fc06-b229-4c4a-8ca5-7386d0870c01&CommunityKey=1ecf5f55-9545-44d6-b0f4-4e4a7f5f5e68&tab=librarydocuments

前端Javascript获取的话,需要通过一些提供该类服务的网站API来获取,具体可以查看文章:

https://www.delftstack.com/zh/howto/javascript/get-ip-address-javascript/

1.   https://api.ipify.org?format=json  //只返回地址信息
2.   https://ipinfo.io/json  //还会返回国家地区信息,但每天有次数限制
3.   https://ipgeolocation.abstractapi.com/v1/?api_key=<your_api_key>

对于上面的第2个API是可以直接拿到国家信息的,如果可以接受这个限制,那就可以直接通过这个来达到目的。

IP区域信息库的获取

IP的区域库信息可以在apnic的官方网站上可以下载 http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest

apnic|KR|ipv4|27.35.0.0|65536|20100324|allocated
apnic|CN|ipv4|27.36.0.0|262144|20100323|allocated
apnic|CN|ipv4|27.40.0.0|524288|20100323|allocated
apnic|IN|ipv4|27.48.0.0|65536|20100311|allocated
apnic|PH|ipv4|27.49.0.0|65536|20100311|allocated
apnic|PH|ipv4|27.50.0.0|1024|20100611|allocated
apnic|IN|ipv4|27.50.4.0|1024|20100311|allocated
apnic|AU|ipv4|27.50.8.0|1024|20160913|allocated
apnic|JP|ipv4|27.50.12.0|1024|20100317|allocated
apnic|ID|ipv4|27.50.16.0|4096|20100311|allocated
apnic|HK|ipv4|27.50.32.0|2048|20100316|allocated
apnic|CN|ipv4|27.50.40.0|2048|20110412|allocated
apnic|SG|ipv4|27.50.48.0|4096|20100317|allocated
apnic|AU|ipv4|27.50.64.0|8192|20100317|allocated
apnic|JP|ipv4|27.50.96.0|8192|20110304|allocated
apnic|CN|ipv4|27.50.128.0|32768|20100317|allocated
apnic|TW|ipv4|27.51.0.0|65536|20100312|allocated

在IP库中,所有的IP不分国家,按照IP的顺序从上而下排列着;

   apnic|CN|ipv4|222.126.128.0|32768|20060830|allocated-    -    -        -         -    |    |    |        |         |    |    |    |        |         +----- 代表着该IP段下有32768个地址|    |    |        +--------------- IP地址|    |    +------------------------ ipv4|    +----------------------------- CN代表中国+---------------------------------- 代表apnic那么为什么`222.126.128.0`下有`32768`个地址呢,是怎么计算的呢?
那么我们需要根据下一个IP判断,如上图所示下一个IP是
`apnic|PH|ipv4|222.127.0.0|32768|20060913|allocated`
PH是菲律宾,说明这个IP就是菲律宾了。`apnic|CN|ipv4|222.126.128.0|32768|20060830|allocated`
`apnic|PH|ipv4|222.127.0.0|32768|20060913|allocated`IP:
IP是Internet Protocol(网际互连协议)的缩写,是TCP/IP体系中的网络层协议;
`IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数`;
所有a,b,c,d都有2的32次方随机匹配地址数。
所以:
从`222.126.128.0`到`222.127.0.0`,有多少种可能?
`a相同,b=126到b=127地址数加1,c=128到c=0剩余128个选择,d有256种选择`
`计算公式=1*128*256=32768个地址`我们还可以这么假设,
由于c*d=256*256=65536,当`apnic|CN|ipv4|222.160.0.0|131072|20031212|allocated`中`131072`大于65536说明,a.b.*.*也就是222.160.*.*无论都两个整数是什么,都属于中国IP; 并且由于131072=65536*2,说明b+1后的a.b+1.*.*也就是222.161.*.*全部是中国IP;
那么这个结果正确吗,让我们从IP库数据看下:
`apnic|CN|ipv4|222.160.0.0|131072|20031212|allocated`
`apnic|CN|ipv4|222.162.0.0|65536|20031212|allocated`
下一条数据222.162.0.0,所以我们的假设是正确的。虽然不知道为什么Apnic没有把222.162.0.0一并合并到222.160.0.0,但是我们的假设是正确的,第五位的数字代表着基于当前IP按正顺序下的地址数。所以我们可以这么处理数据:
`首先判断第五位的数字,``如果第五位数字超过65536,`
`代表a.b.*.*都是中国IP,如果是65536的N倍,那么代表着`
a.b.*.*
a.b+1.*.*
....
a.b+n-1.*.*
`全部都是中国IP,可以标记为ALL, 后续比较前两位就可以判断是否是中国IP`。
存储数据结构为:
{a: {b: "all",b+1: "all",....b+n-1: "all"}
}`如果第五位数字不超过65536呢?`
apnic|CN|ipv4|1.2.16.0|4096|20110412|allocated
apnic|CN|ipv4|1.2.32.0|8192|20110412|allocated
apnic|CN|ipv4|1.2.64.0|16384|20110412|allocatedIP转换十进制(a.b.c.d)= a*256^3+b*256^2+c*256+d
这里以当前IP转化为十进制为起始范围,加上第五位地址书为终止范围。
如果要判断的IP转化的十进制数后,判断是否在这个范围内,范围内则为中国IP;
并且同一个a.b,后面会有多端地址,如:
apnic|CN|ipv4|14.1.0.0|1024|20110414|allocated
apnic|JP|ipv4|14.1.4.0|1024|20100910|allocated
apnic|JP|ipv4|14.1.8.0|2048|20100910|allocated
apnic|AU|ipv4|14.1.16.0|1024|20100916|allocated
apnic|HK|ipv4|14.1.20.0|1024|20100920|allocated
apnic|CN|ipv4|14.1.24.0|1024|20151214|allocated
中间还掺杂着其他国家的IP,所以需要分段存储如下:
存储数据结构为:
{a: {b: ["16777472-16777728""16777728-16778240""16779264-16781312""16785408-16793600"]}
}`全部数据存储在Redis里面,2小时有效期(再次读取自动生成的IP库更新数据),结构如下:`
{a: {b: "all",b+1: "all",....b+n-1: "all",b: ["16777472-16777728""16777728-16778240""16779264-16781312""16785408-16793600"]}
}
那么如何根据以上的数据判断一个IP是否属于国内IP呢?
`首先根据a查询是否存在,再根据b查询是否存在;`
`如果b存在,如果是all, 直接返回true;`
`如果是数组,需要判断地址是否存在于数组中的某一个范围内,存在就返回true;`
`其他返回false;`这样的话,查询效率变得快了很多。
每次被查询的IP结果也会被存储在redis中,下次查询同样的IP,可以直接返回结果。

从上面的信息可以看到,我们只要解析出中国大陆CN(还有澳门MO,台湾TW和香港HK)就可以判断是国内还是国外了。

补充一下关于如何判断的算法问题

对于此列表,我们可以将其解析为数值来判断即可,IP地址本身就是一个32位的数值,那对于列表中的数据,因为它本身是一个范围,我们需要两个数据来判断,当给定一个IP地址,将其转为数值,然后用减法运算即可算出,在语言里,用位运算,可轻易将IP转为数值:

function IpAddressToNumber(IPAddr)
{string[] IPAddrArr = IpAddr.split('.');int IpAddr_Number = 0;for(int i = 0;i < 4;i++){IpAddr_Number += (Convert.ToInt32(IPAddrArr[i]) << (4 - i - 1));}
}

我们使用同样的方法,对列表中的每一行解析一下(列表中给出了IP的起始值和增量值),得到两个数据,在给定一个IP时,将其转为数值后比较:

if (UserIpNumber - ListStartIpNumber < ListIncreNumber){//Match This List output Result
}

网站如何判断客户端是在国内还是国外相关推荐

  1. html自动识别pc手机跳转,网站根据访问客户端设备UA(PC和手机移动)自动判断跳转代码...

    网站根据访问客户端设备UA(PC和手机移动)自动判断跳转代码 以下代码是插入到手机模板中 var system = { win: false, mac: false, xll: false }; va ...

  2. 判断客户端是电脑还是手机

    用php判断客户端是手机还是电脑?其实很简单,通过浏览器访问网站时,浏览器会向服务器发送UA即(用户代理).不同浏览器或者同一浏览器的不同版本.手机浏览器.电脑浏览器的UA都是不一样的.我们只要写代程 ...

  3. 判断客户端是否安装FlashPlayer及版本

    判断客户端是否安装flashplayer及版本 在项目中有时需要用到Flash,为了给用户最好的体验这就需要知道客户端是否已安装了 FlashPlayer插件,如没有安装则将给出提示及安装路径以便用户 ...

  4. 第三方浏览器h5 android测试,H5案例分享:使用JS判断客户端、浏览器、操作系统类型...

    使用JS判断客户端.浏览器.操作系统类型 一.JS判断客户端类型 JS判断客户端是否是iOS或者Android手机移动端 通过判断浏览器的userAgent,用正则来判断手机是否是ios和Androi ...

  5. openwrt监控linux,OpenWRT上判断客户端在线个数

    OpenWRT上判断客户端在线个数,有两种方式: 一.通过DHCP client分配列表 (缺点:client列表会根据超时时间刷新,一般超时时间为12h,) 二.通过arp缓存列表/proc/net ...

  6. JS判断访问设备(userAgent)加载不同页面 JS判断客户端操作系统类型(platform)

    //平台.设备和操作系统var system ={win : false,mac : false,xll : false};//检测平台var p = navigator.platform;syste ...

  7. JS判断客户端是手机还是PC的2个代码

    Javascript 判断客户端是否为 PC 还是手持设备,有时候项目中需要用到,很方便的检测,源生的哦,方法一共有两种 1.第一种: 复制代码代码如下: function IsPC() {     ...

  8. PHP:判断客户端是否使用代理服务器及其匿名级别

    要判断客户端是否使用代理服务器,可以从客户端所发送的环境变量信息来判断. 具体来说,就是看HTTP_VIA字段,如果这个字段设置了,说明客户端使用了代理服务器. 匿名级别可以参考下表来判断. 给出一个 ...

  9. iOS开发 - 获取网关IP,运营商,位置,可判断是在国内还是国外

    你也许会有一个需求,需要判断当前网络的IP地址是在国内还是国外,也许你需要判断连接的Wi-Fi运营商是哪家的,虽然网上也有方法,但是却写得很简单,没有进行深入的说明,所以今天博主重新整理,给大家一个方 ...

最新文章

  1. android系统底层驱动多个物理按键上报同一个键值给app层,app层如何区分
  2. JS判断字符串变量是否含有某个字串的方法
  3. python经济_python生成器——懒到欠揍,但很经济
  4. 计算机网络中常见拓扑结构及特点,常见的网络拓扑结构有哪些?并说明其优缺点....
  5. POJ3728 THE MERCHANT LCA RMQ DP
  6. 【报告分享】中国营销数字化行业趋势报告:全渠道时代,品牌商如何抓住消费者?(附下载链接)...
  7. 51单片机仿真——蜂鸣器
  8. ENVI监督分类中SVM(支持向量机)工具
  9. ubuntu18.04双系统卸载并重装
  10. Cocoscreator 3.01 ios平台Facebook登陆
  11. SSM-Mybatis的Mapper.xml配置文件
  12. Android O 新特性和行为变更总结
  13. Unity学习笔记 球形全景图平面像素坐标与三维坐标系上的坐标之间的转换
  14. 浅谈一下汽车行业中的OTA/FOTA/SOTA
  15. Linux--DNS域名解析服务
  16. 《敦煌》—— 读后总结
  17. [考研信息] 2020年考研重要时间节点
  18. IP网络农村应急广播系统方案
  19. qt大作业——消灭星星
  20. CCS TMSC6748 报错Error connecting to the target: (Error -600 @ 0x0)

热门文章

  1. 多普达S900 使用详细说明(使用技巧大全)
  2. Excel中插入Word文档图片链接
  3. 计算机,我该学什么?
  4. 屁股决定脑袋--是否可以把0603电容更换为0402的电容
  5. matlab中strcmp函数的使用
  6. Stack Overflow简单介绍
  7. 20155209 20155230 《信息安全技术》实验四 木马及远程控制技术
  8. python 图像填充颜色_Opencv:在轮廓图像中填充颜色
  9. 项目添加到服务器报错,基于github+travis自动部署vue项目到远端服务器
  10. 零知识证明学习(三)—— 非交互式零知识证明(zkSNARKs)