request获取mac地址_【Go】获取用户真实的ip地址

990cdaeb30307d2f58108c043172d81c.png

原文链接:https://blog.thinkeridea.com/201903/go/get_client_ip.html

用户请求到达提供服务的服务器中间有很多的环节,导致服务获取用户真实的 ip 非常困难,大多数的框架及工具库都会封装各种获取用户真实 ip 的方法,在 exnet 包中也封装了各种 ip 相关的操作,其中就包含获取客户端 ip 的方法,比较实用的方法如下:

  • func ClientIP(r *http.Request) string ClientIP 尽最大努力实现获取客户端 IP 的算法。 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
  • func ClientPublicIP(r *http.Request) string ClientPublicIP 尽最大努力实现获取客户端公网 IP 的算法。 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
  • func HasLocalIP(ip net.IP) bool HasLocalIP 检测 IP 地址是否是内网地址
  • func HasLocalIPddr(ip string) bool HasLocalIPddr 检测 IP 地址字符串是否是内网地址
  • func RemoteIP(r *http.Request) string RemoteIP 通过 RemoteAddr 获取 IP 地址, 只是一个快速解析方法。

获取用户真实ip地址

ClientIP 方法 与 ClientPublicIP 方法的实现类似,只是一个按照 http 协议约定获取客户端 ip, 一个按照约定格式查找到公网 ip。

在网络与服务架构、业务逻辑复杂的环境中,按照 http 协议约定的方式,并非总能获取到真实的 ip,在我们的业务中用户流量经由三方多层级转发(都是三方自己实现的http client) ,难免会出现一些纰漏,这时越往后的服务获取用户真实 ip 越加困难,你甚至不知道自己获取的 ip 是否是真实的。

但是我们的客户经由三方转发而来的流量,那么客户极大多数甚至排除测试之外都是公网用户,结合使用 ClientPublicIPClientIP 方法总能更好的获取用户的真实 ip。

// var r *http.Request
ip := exnet.ClientPublicIP(r)
if ip == ""{ip = exnet.ClientIP(r)
}

用上面的方法总能有效的获取用户真实的 ip 地址,下面分析下两个方法的具体实现。

// ClientIP 尽最大努力实现获取客户端 IP 的算法。
// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
func ClientIP(r *http.Request) string {xForwardedFor := r.Header.Get("X-Forwarded-For")ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])if ip != "" {return ip}ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))if ip != "" {return ip}if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {return ip}return ""
}

ClientIP 首先读取 X-Forwarded-For header 中用 , 分隔的第一个ip地址,如果这个地址不存在,就会从 X-Real-Ip header 中获取,如果还是不存在,说明流量并非是由反向代理转发而来,而是客户端直接请求服务,这时通过 http.Request.RemoteAddr 字段截取除去端口号的 ip 地址。

这个方法很简单,就是按照 http 约定的格式获取,其中 X-Forwarded-ForX-Real-Ip header 由反向代理填充,例如 nginx 或 haproxy。

// ClientPublicIP 尽最大努力实现获取客户端公网 IP 的算法。
// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
func ClientPublicIP(r *http.Request) string {var ip stringfor _, ip = range strings.Split(r.Header.Get("X-Forwarded-For"), ",") {ip = strings.TrimSpace(ip)if ip != "" && !HasLocalIPddr(ip) {return ip}}ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))if ip != "" && !HasLocalIPddr(ip) {return ip}if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {if !HasLocalIPddr(ip) {return ip}}return ""
}

ClientPublicIP 很简单,和 ClientIP 方法的读取顺序一样,只是试图中 X-Forwarded-For 列表中找到一个公网ip,如果没有检查 X-Real-Ip 是否是一个公网 ip,其次检查 http.Request.RemoteAddr 是否是公网ip,如果没有找到公网 ip 这返回一个空字符串。

这个方法可以让我们有机会优先获取到用户的公网 ip,往往公网 ip 对我们来说更有价值。

检查ip对否是内网地址

exnet 中还提供了检查 ip 地址是否是内网地址,这在有些情况下非常有用,比如:服务中有些接口只能内网访问,也就是只允许管理员访问(例如动态设定日志级别、查看服务 pprof 信息);我们想隐藏后端服务,只暴露给用户负载均衡(反向代理),用户无法直接访问我们的服务,这些方法及其有用,下面看看具体实现。

我的服务提供了动态设置日志级别,以便服务出现问题,可以第一时间查看调试日志分析具体原因,但是这个接口很危险,不应该暴露给公网,所以会用路由中间件检查请求是否来自公网,来自公网则返回 404。

该方法认为如下地址段都是内网地址:

10.0.0.0/8
169.254.0.0/16
172.16.0.0/12
172.17.0.0/12
172.18.0.0/12
172.19.0.0/12
172.20.0.0/12
172.21.0.0/12
172.22.0.0/12
172.23.0.0/12
172.24.0.0/12
172.25.0.0/12
172.26.0.0/12
172.27.0.0/12
172.28.0.0/12
172.29.0.0/12
172.30.0.0/12
172.31.0.0/12
192.168.0.0/16
// HasLocalIPddr 检测 IP 地址字符串是否是内网地址
func HasLocalIPddr(ip string) bool {return HasLocalIP(net.ParseIP(ip))
}// HasLocalIP 检测 IP 地址是否是内网地址
func HasLocalIP(ip net.IP) bool {for _, network := range localNetworks {if network.Contains(ip) {return true}}return ip.IsLoopback()
}

两个检查方法实现差异仅接受参数类型不一致,检查过程都是逐个对比内网 ip 段是否包含该ip地址,如果不包含则判断该地址是否是回环地址。

获取反向代理ip

如何判断改地址来自反向代理服务器呢,不同的反向代理实现都有些差异,4 层反向代理甚至可以提供用户的真实 ip(http.Request.RemoteAddr 是用户的ip,而不是反向代理的), 而隐藏自己的ip,这里说一下常见的方法。

往往 http.Request.RemoteAddr 保存最后一个连接服务的客户端 ip,我们获取反向代理的ip地址,最简单有效的方法就是通过 http.Request.RemoteAddr 获取, exnet 中提供了 RemoteIP 的快捷方法,实现如下:

// RemoteIP 通过 RemoteAddr 获取 IP 地址, 只是一个快速解析方法。
func RemoteIP(r *http.Request) string {if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {return ip}return ""
}

这是一个非常方便的脚手架,它仅仅切分 http.Request.RemoteAddr 的 ip 和端口,并返回有效的ip地址,但却可以简化我们的编写业务代码。

转载:

本文作者: 戚银(thinkeridea)

本文链接: https://blog.thinkeridea.com/201903/go/get_client_ip.html

版权声明: 本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/276450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iPhone开发四剑客之《Objective-C基础教程》

iPhone 开发四剑客之《Objective-C 基础教程》 Objective-C 语言是 C 语言的一个扩展集,许多(可能是大多数)具备 Mac OS X 外观的应用程序都是使用该语言开发的。它以 C 语言为基础,添加了一些微妙但意义重大的特性。 苹果公司为…

keras训练完以后怎么预测_还在使用“龟速”的单显卡训练模型?动动手,让TPU节省你的时间...

点击上方关注,All in AI中国本文将介绍如何使用Keras和Google CoLaboratory与TPU一起训练LSTM模型,与本地计算机上的GPU相比,这样训练能大大缩短训练时间。很长一段时间以来,我都在单张GTX 1070显卡上训练我的模型,它的…

手把手教你写个小程序定时器管理库

背景凹凸曼是个小程序开发者,他要在小程序实现秒杀倒计时。于是他不假思索,写了以下代码:Page({init: function () {clearInterval(this.timer)this.timer setInterval(() > {// 倒计时计算逻辑console.log(setInterval)})}, })可是&…

[New Portal]Windows Azure Virtual Machine (14) 在本地制作数据文件VHD并上传至Azure(1)

《Windows Azure Platform 系列文章目录》 之前的内容里,我介绍了如何将本地的Server 2012中文版 VHD上传至Windows Azure,并创建基于该Server 2012 VHD的虚拟机。 我们知道,VHD不仅仅可以保存操作系统,而且可以保存数据文件。 如…

python 退出程序_Python:用Ctrl+C解决终止多线程程序的问题!(建议收藏)

前言:今天为大家带来的内容是Python:用CtrlC解决终止多线程程序的问题!文章中的代码具有不错的参考意义,希望在此能够帮助到各位!(多数代码用图片的方式呈现出来,方便各位观看与收藏)出发点:前段时间&#…

若川知乎高赞:有哪些必看的 JS 库?

欢迎星标我的公众号,回复加群,长期交流学习我的知乎回答目前2w阅读量,270赞,现在发到公众号声明原创。必看的js库?只有当前阶段值不值看。我从去年7月起看一些前端库的源码,历时一年才写了八篇《学习源码整…

基于EasyUI的Web应用程序及过去一年的总结

前言 一个多月之前已经提交了离职申请,好在领导都已经批准了,过几天就办理手续了,在此感谢领导的栽培与挽留,感谢各位同事在工作中的给我的帮助,离开这个团队确实有一些不舍,不为别的,只因为这个…

快速使用Vue3最新的15个常用API

之前我写了一篇博客介绍了Vue3的新特性,简单了解了一下Vue3都有哪些特色,并且在文末带大家稍微体验了一下Vue3中 Compsition API 的简单使用上一篇文章地址:紧跟尤大的脚步提前体验Vue3新特性,你不会还没了解过Vue3吧因为这个月的…

超级马里奥代码_任天堂的源码泄露,揭示超级马里奥的前世之生

被黑客盯上的任天堂任天堂遭到了史上最大规模的黑客攻击,Wii 完整源码、设计以及《宝可梦》多部作品的信息遭到泄露,而此次泄露事件的后续影响似乎也爆发了出来。《马里奥赛车》和《超级马里奥世界2》(耀西岛)的早期原型视频,以及《超级马里奥…

漫画 | 前端发展史的江湖恩怨情仇

时间总是过得很快, 似乎快得让人忘记了昨天,前端WEB领域的发展更是如此,转眼间已是近30年,时光荏苒,初心不变,在一代又一代前端人的努力下,前端已经是互联网不可或缺的一部分。然而很多前端打工…

10 个你可能还不知道 VS Code 使用技巧

经常帮一些同学 One-on-One 地解决问题,在看部分同学使用 VS Code 的时候,有些蹩脚,实际上一些有用的技巧能够提高我们的日常工作效率。NO.1一、重构代码VS Code 提供了一些快速重构代码的操作,例如:将一整段代码提取为…

构建安全的Xml Web Service系列之如何察看SoapMessage

上一篇文章地址:构建安全的Xml Web Service系列一之初探使用Soap头 (5-22 12:53) 要分析Xml Web Service的安全性,首先要解决的问题是我们能了解和清楚Soap消息的格式和内容,如果获得不了SoapMessage,分析如何能构建安全Xml w…

前端高效开发必备的 js 库梳理

之前有很多人问学好前端需要学习哪些 js 库, 主流框架应该学 vue 还是 react ? 针对这些问题, 笔者来说说自己的看法和学习总结.首先我觉得在学习任何知识之前必须要有一个明确的学习目标, 知道自己为什么要学它, 而不是看网上说的一股脑的给你灌输各种知识, 让你学习各种库, …

交叉报表crosstab隐藏列名显示_SAP软件 报表查询之 输出格式设置

SAP不仅是功能强大、逻辑严谨的ERP软件,还提供了强大的报表查询功能。SAP的ALV报表展示功能是SAP的一大特点,实现了类似于EXCEL的功能。使用好ALV报表功能可以方便用户从SAP中取到想要的数据,尤其是财务用户。大家在使用SAP报表时&#xff0c…

seo每日一贴_白杨SEO:我看ZAC的外贸SEO应该怎样做?(策略篇)

前言:这是白杨SEO公众号更新第64篇。本该写写头条SEO啥的,最近在师徒培训讲站内SEO时有旁听同学提到后面讲讲谷歌SEO怎么样,因为谷歌全世界搜索市场占有率,所以外贸SEO最主要还是做谷歌SEO。以白杨特意又去了前辈ZAC的SEO每日一贴…

[转]网页栅格系统研究(2):蛋糕的切法

[出自]http://lifesinger.org/blog/2008/10/grid-system-2/首先澄清一个应用场景问题。研究(1)中指出,对于结构复杂的网站,不少设计师们喜欢采用960固定宽度布局。但要注意的是,960并不是万能钥匙,大部分网…

Vue3响应式原理

关注若川视野,回复"pdf" 领取资料,回复"加群",可加群长期交流学习本文结构- 关于Vue3- Vue2响应式原理回顾- Vue3响应式方案- Vue3响应式原理- 手写mini版Vue3响应式本文共计:2349字2图预计阅读时间&#xff…

找准切入点,调试看源码,事半功倍

关注若川视野,回复"pdf" 领取资料,回复"加群",可加群长期交流学习最近写了很多源码分析相关的文章,React、Vue 都有,想把我阅读源码的一些心得分享给大家。React:React 架构的演变 - 从…

Android布局大全

Android的界面是有布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当于建筑里的砖瓦。组件按照布局的要求依次排列,就组成了用户所看见的界面。 所有的布局方式都可以归类为ViewGroup的5个类别,即ViewGroup的5个直接子类…

java实现加减乘除运算符随机生成十道题并判断对错_2020年Java面试题(3年的工作总结),最全的知识点总结...

这份Java面试题整整花了三个月的时间来整理,都是自己再工作中总结出来,记住多少就写多少,希望这份资料可以帮助你们,文末有其余部分资料的领取方式.Redis12道面试题1.什么是Redis?答:Remote Dictionary Ser…