# IP 归属地解析 :::tip 说明 `src/common/utils/ip2region.py` 基于 [ip2region](https://github.com/lionsoul2014/ip2region) 离线数据库,提供 IP 地址到省市区的归属地查询能力,无需网络请求。`src/common/utils/helpers.py` 中的 `detect_os` 和 `detect_browser` 提供 User-Agent 解析。 ::: ## 核心接口 ### get_ip_location — 获取归属地文本 ```python from common.utils.ip2region import get_ip_location location = get_ip_location("114.114.114.114") # 返回: "中国 江苏省 南京市" location = get_ip_location("8.8.8.8") # 返回: "United States California" location = get_ip_location("10.0.0.1") # 返回: "内网IP" ``` ### get_ip_region — 获取完整区域信息 ```python from common.utils.ip2region import get_ip_region info = get_ip_region("114.114.114.114") # 返回: {"country": "中国", "province": "江苏省", "city": "南京市", "isp": "南京信风", "country_code": "CN"} ``` ## UA 解析 位于 `src/common/utils/helpers.py`: ```python from common.utils.helpers import detect_os, detect_browser # 解析操作系统 os_name = detect_os("Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...") # 返回: "Windows 10.0" # 解析浏览器 browser_name = detect_browser("Mozilla/5.0 ... Chrome/120.0.0.0 ...") # 返回: "Chrome 120.0" ``` ## 应用场景 ### 操作日志记录 ```python # src/common/middleware/operation_log.py ip = get_ip_location(handler.request.remote_ip) os_name = detect_os(ua) browser_name = detect_browser(ua) ``` ### 登录日志记录 ```python # src/common/middleware/login_log.py ip = get_ip_location(handler.request.remote_ip) os_name = detect_os(ua) browser_name = detect_browser(ua) ``` ## 预热机制 ip2region.xdb 文件约 10MB,首次查询时加载。应用启动时预热避免首次请求延迟: ```python # src/bootstrap.py from common.utils.ip2region import preload preload() # 预加载 xdb 文件到内存 ``` ## 降级策略 | 异常场景 | 降级行为 | |:---------|:---------| | xdb 文件不存在 | 返回 `"未知"` | | xdb 加载失败 | 返回 `"未知"` | | 畸形 IP 地址 | 返回 `"未知"` | | 内网/保留地址 | 返回 `"内网IP"` | 所有查询接口均采用 fail-open 降级策略,查询失败绝不向上抛异常,保证日志落库不受影响。 ## xdb 数据库更新 ip2region.xdb 离线数据库需要定期更新以覆盖新增的 IP 段: ```bash # 1. 下载最新 xdb 文件 # GitHub: https://github.com/lionsoul2014/ip2region/tree/master/data # 将 ip2region.xdb 放到 static/ 目录下 # 2. 重启应用即可生效(启动时自动加载) poetry run python app.py --port=8041 ``` :::tip 数据库格式 xdb 是 ip2region 的二进制索引格式,约 10MB,支持微秒级查询。文件路径在 `src/common/utils/ip2region.py` 中配置。 ::: ## 完整日志记录示例 操作日志和登录日志中记录完整的客户端信息: ```python from common.utils.ip2region import get_ip_location from common.utils.helpers import detect_os, detect_browser # 获取客户端信息 ip = handler.request.remote_ip ua = handler.request.headers.get("User-Agent", "") location = get_ip_location(ip) os_name = detect_os(ua) browser_name = detect_browser(ua) # 记录到日志 log_data = { "ip": ip, # "114.114.114.114" "ip_location": location, # "中国 江苏省 南京市" "os": os_name, # "Windows 10.0" "browser": browser_name, # "Chrome 120.0" } ``` ## 总结 IP 归属地解析基于 ip2region 离线数据库,零网络依赖。提供 `get_ip_location`(文本)和 `get_ip_region`(结构化)两个查询接口,配合 `detect_os` / `detect_browser` 为操作日志和登录日志提供完整的客户端身份信息。xdb 文件需定期更新以覆盖新增 IP 段。