查自己出口 IP 这件事,多数人第一反应是打开一个在线查询站,或者敲一条命令拿回一段纯文本。前者要依赖别人的服务,后者往往只给一个数字、不带归属地。ip-helper 是个挺有意思的折中:一个 Go 写的单文件服务,用同一份离线 IP 库,同时给网页、命令行工具、Telnet 和 FTP 四种入口供数据。

项目由苏洋(soulteary)在 2024 年 12 月开源,MIT 协议,Go 1.23.3 + Gin 1.10,仓库不大(约 385KB),目前 19 星,最后一次提交是 2025 年 3 月。它还有个特别的背景:作者在两篇长文里完整记录了用 AI 辅助从界面设计、Logo 到后端代码、单元测试、文档和性能调优一步步做出来的全过程,交互参考了 CIP.CC 的 IP 查询工具,基础数据来自 IPIP。所以这既是个能跑的小工具,也是一份「AI 辅助做小项目」的过程样本。

ip-helper 项目主视觉:熊猫形象与 Compact and lightweight, privacy first, multi-protocol support, tidy webui 标语

一、四种入口,其实只有一个查询函数

README 把「多协议支持」列在首位,但读源码会发现它的实现克制得近乎取巧:Telnet 与 FTP 并不是完整的协议服务端。程序在启动时用 goroutine 各起一个 TCP 监听器(Telnet 23、FTP 21),连接一进来就取对端 IP、查库、写一行 JSON、然后断开。FTP 那侧稍微做了点伪装——把 JSON 接在 220 欢迎横幅后面,让客户端看起来像是收到了一条服务就绪消息。

换句话说,这两种「协议」更像是给那些只能发起 TCP 连接的旧工具留的门,而不是让你真的登录进去传文件。两个端口都是特权端口,容器部署时要么给足权限、要么做端口映射,这点 README 没写,得上机才知道。

Web 与命令行那侧才是主力。它们共用同一个 FindByIPIP 查询函数,差别只在出口格式——这就是这个项目最核心的一处设计。

ip-helper 请求链路:四种入口、Gin 中间件链、IPDB 数据与 HTML/JSON 响应分流

二、按 User-Agent 决定吐网页还是 JSON

服务不去猜「你想不想要结构化数据」,而是看请求头里是不是命令行工具的标识。fn.go 里维护了一份名单:curl、wget、aria2、python-requests、axios、got、postman,命中就返回 application/json 的极简结构(一个 IP 字段加一个归属地数组);没命中就走 HTML 模板渲染。浏览器打开是完整网页,脚本抓取是干净 JSON,同一个地址两种结果,不用额外加参数或后缀。

HTTP 侧的接口也很薄,五个路由就讲完了:

路由作用返回
GET /自动识别来访 IP 并展示归属地网页或 JSON,取决于 UA
POST /表单里指定 IP,校验通过后跳转到详情路径302 重定向
GET /ip/:ip查询指定 IP 的归属地网页或 JSON
GET /ip只回一个 IP 字符串,适合脚本判断出口地址纯文本
GET /health容器健康检查,返回状态与当前域名JSON

HTML 那侧不是模板引擎,而是把 page.go 里内嵌的一整段静态页面取出来,做字符串替换:%IP_ADDR%、%DATA_1_INFO%、%DOMAIN%、%ONLY_DOMAIN% 这些占位符逐个换成实际值。页面是左右分栏,左边是 AI 生成的熊猫 Logo,右边是查询框、结果卡片和一组可直接复制的命令行示例。有意思的是模板里还留着「数据二」「数据三」两行写着「等待接入」,以及一段被注释掉的「运营商」行——预留了接第二、第三个数据源的位置,但至今没有接上。

ip-helper 指定 IP 查询界面:查询 123.123.123.123 显示中国 北京,下方是命令行查询示例

三、IP 从哪来:转发头、私有段与一份离线库

IPAnalyzerMiddleware 会先把请求解析成一组字段:Gin 拿到的 ClientIP、X-Forwarded-For、X-Real-IP,以及推导出的 RealIP、ProxyIP 与 IsProxy。规则是:X-Forwarded-For 存在时取第一个值当真实 IP,链上出现多个地址就标记经过转发;X-Real-IP 若与推导值不同则覆盖,并把直连地址记为转发端;此外 10 段、172.16~31 段、192.168 段这些私有地址一律标记为「位于转发之后」。

拿到 IP 后交给 ipdb-go,以中文语言参数查询本地库,返回的一串字段会先去重再拼成一行文本——所以网页上「地址」那一栏显示的是「中国 北京」这种概括结果,而不是经纬度和 ASN。数据库文件必须自己准备:程序启动时固定读取 ./data/ipipfree.ipdb,而仓库的 data/ 目录里只有一个 .gitkeep,缺文件会直接打印提示并退出。这也是 README「快速开始」至今写着 TBD 的主要原因。

这里有个部署时必须留意的安全点:这些转发头是客户端可以自己伪造的。代码无条件信任 X-Forwarded-For 与 X-Real-IP,如果服务直接暴露在公网,别人带个头就能让页面显示任意 IP 的归属地。放在自己的前置网关后面、由网关统一覆写这两个头,才是合理用法;内网自用则问题不大。

四、配置、鉴权与缓存

配置只有四项,环境变量与命令行参数一一对应,优先级是命令行 › 环境变量 › 默认值,和多数 Go 小工具习惯相反,容易记反:

用途环境变量 / 参数默认值
调试模式(每次请求重新读模板文件)DEBUG / -debugfalse
HTTP 监听端口SERVER_PORT / -port8080
对外域名(用于生成页面里的示例命令与 URL)SERVER_DOMAIN / -domainhttp://localhost:8080
访问令牌TOKEN / -token空(不鉴权)

令牌非空时,鉴权中间件从 URL 查询参数或 X-Token 请求头里取值比对,不通过就回 401。启动日志会在令牌为空时主动提醒你设一个。有个细节值得单独说:/health 注册在所有 r.Use(...) 之前,因此它不受令牌保护——这是刻意的,容器健康检查不该被鉴权挡住,但也就意味着公网实例会暴露当前配置的域名。

其余中间件依次是:ETag 缓存(命中 If-None-Match 直接 304,响应带 Cache-Control: private, max-age=86400)、静态资源(用作者自己的 gin-static)、令牌鉴权、IP 分析;全局还挂了 gzip 并且是 BestCompression 档。前端资源通过 go:embed public 编进二进制,所以分发时可以只有一个可执行文件加一份数据文件。

配置自定义域名后的 ip-helper 界面:URL 与命令行示例都换成自定义域名,地址显示中国 山东 青岛

五、从「一个 main.go」到带测试的小工程

第二篇博客记录的其实是一次重构:最初所有逻辑挤在单个文件里,后来按职责拆成 model/define(常量与结构)、fn(工具函数)、web、telnet、ftp、ip-info、parse-config、page、response 九个包,并且几乎每个源文件都配了对应的 _test.go。文档则交给编辑器里的 AI 生成初稿再迭代。如今 main.go 只剩三十来行:解析配置、初始化 IPDB、拉起两个 TCP 监听,然后把主线程交给 Web 服务。

性能那一步也有实测:作者用 Lighthouse 跑了本地页面,初版四项是 100 / 90 / 96 / 91,优化后四项全部 100,FCP 0.2 秒、LCP 0.3 秒、TBT 0 毫秒、CLS 0。对一个纯静态单页、没有前端框架、只做字符串替换的服务来说,这个结果并不意外,倒是很能说明「别把简单事做复杂」的价值。

Lighthouse 优化后性能报告:性能、无障碍、最佳做法、SEO 四项均为 100 分

六、适合谁,以及别指望它做什么

它适合三类场景:内网里给同事一个自用的 IP / 归属地查询页;CI 或脚本里想同时拿到出口 IP 和归属地、又不想调第三方 API;以及想研究「AI 辅助写代码」到底能走到哪一步的人——两篇博客把每次提示词、每段生成代码、重构和补测试的过程都摊开了,比项目本身信息量还大。

反过来,几个前提得先认清:数据文件要自备,仓库不提供,README 也没有完整的上手步骤;「数据二」「数据三」仍是占位,只有单一 IPIP 数据源,别指望运营商、ASN、经纬度或多库交叉校验;Telnet 与 FTP 是明文且要特权端口,只适合可信内网,不该对公网开放;转发头被无条件信任,公网部署务必放在会覆写这些头的前置网关之后,并设上令牌;项目自 2025 年 3 月后没有新提交,issues 为空,属于「完成后就停在那儿」的小作品,安全更新要自己兜底。

总的来说,这不是要替代 ipinfo 那类服务的产品,而是一件做得很干净的样板:一个明确的小需求、一份离线数据、四种入口、九个包、全套单元测试,再加两篇把过程写透的文章。想给自己的工具箱添个不依赖外部 API 的查询端点,它够用;想要生产级的地理信息服务,那还得另找。


本文整理自公开资料:项目仓库 README、main.go 与 model 各包源码(web / telnet / ftp / ip-info / parse-config / response / fn / page / define)、go.mod、page.go 中的前端模板,以及作者苏洋的两篇《使用 AI 辅助开发一个开源 IP 信息查询工具》系列文章与其界面、性能截图。数据截至 2026 年 11 月,功能与版本以官方仓库为准。配图取自仓库与作者文章,仅做格式统一与尺寸压缩;请求链路图依据源码绘制,原项目中的推广与社群入口均未收录。

本文整理自公开资料并做重写,原始出处:https://github.com/soulteary/ip-helper。文中配图已去除站点叠加水印与推广信息;版权归原作者所有。

Last modification:November 11, 2026
如果觉得我的文章对你有用,请随意赞赏