本文已参与「新人创作礼」活动,一起开启掘金创作之路。
用户显示 IP 归属地
公司的 APP 目前也上线了用户IP地址显示的功能,和其他各家也都大差不差。
显示位置:
- 个人中心
- 发表评论时
个人中心
在请求个人信息接口时,通过 IP 地址获取其归属地,并返回前端。实时获取。不保存数据库。
发表评论
在发表评论后,显示该用户的归属地。需要随着评论信息一起保存到数据库中。保存 IP 地址以及归属地。
对于历史数据,因为没有记录,则不进行展示,目前其他 APP 也是如此,比如小红书。
ip2region
使用
采用 mica-ip2region 来实现,它是在 ip2region 基础上又封装了一层,使用更加简便。
实现过程比较简单,代码在 Github 上地址如下:
IPV6 支持
ip2region 本身是不支持 IPV6 的,而且作者本人也说因为时间原因,不会去实现了,所以需要自己去改造。
IP 地址的存储
IP地址如何存储在 MySQL 中,可能首先想到的是 varchar 格式存储,这种方式也是可以的,但不是最好的一种方案。
在 高性能MySQL 第3版中如下写到:
使用 varchar 类型存储需要 15 个字节,但是使用 int 类型进行存储,只需要 4 个字节。那为什么是 int 类型呢?因为一个 int 型的数据占 4 个字节,每个字节 8 位,其范围就是 0~255(2^8-1),而 ipv4 地址可以分成 4 段,每段的范围是 0~255,巧了么不是,刚刚好能存下,所以将其稍微转换一下,就能巧妙的将 IP地址 用最小的空间存在了数据库中了。
MySQL 中提供了互相转换的方法如下:
-- IP 地址 -> int 类型
SELECT INET_ATON('192.168.1.13'); //3232235789
SELECT INET_ATON('12.148.14.131'); //211029635
SELECT INET_ATON('255.255.255.255'); //4294967295
-- int 类型 -> IP 地址
SELECT INET_NTOA(3232235789); //192.168.1.13
SELECT INET_NTOA(3232232222); //192.167.243.30
SELECT INET_NTOA(9999999999); //NULL, 无法转换为 IP 的返回 null
SELECT INET_NTOA(0); //0.0.0.0
- 如果 IP 地址获取不到, 数据库中直接保存为 0 即可.
假设有一张用户表如下:
-- 查询用户的上次登录 IP 地址
SELECT u.name, INET_NTOA(u.last_login_ip) last_login_ip
FROM tb_user AS u
-- 插入一条数据
INSERT INTO tb_user(id,last_login_ip)
VALUES (null, INET_ATON('10.153.25.141'));
\