全网都在搞的评论区、主页等显示IP地址功能
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
背景
近大半年发现很多的应用, 不限于(微博,抖音,知乎、yuque、字节、微信等)都开放了 显示 IP 属地的显示,这个功能挺有趣,同时我也思考了一下,想在自己的项目中使用,现在就写下这篇文章谈谈让我做的实现思路和想法;
话说掘金什么时候出这个功能?
作为前端仔,先给掘金设计一波😀.
实现
就两个问题, 获取ip, 再拿ip地址换地理位置信息(省市区)
下面我们以Node.js为例子
获取IP地址
从 Http header 中可以获取到客户端在请求头中携带的IP地址
头部名词的解释
- X-Forwarded-For:Web 服务器获取访问用户的真实 IP 地址,若存在代理,最左边是最原始客户端的 IP 地址;
在node.js中
koa为例子
在中间件函数中, 获取header里的x-forwarded-for子段
export default (ctx, next) => {
const {
method, body, query, header: { 'x-forwarded-for': ip },
} = ctx.request;
console.log(ip, 'ip地址’)
}
nginx的配置
如果你使用的nginx代理你的服务, 其实上面node里获取的真实ip那个子段, 依赖于nginx的转发。就是这行。
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
子段释义
$proxy_add_x_forwarded_for
记录真实的客户端IP地址,但是服务器中的日志需要有这个变量。
参考链接 nginx官方文档 nginx.org/en/docs/htt…
nginx配置转发伪代码
server {
listen 80;
...
location /api/ {
...
// 代理真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
proxy_set_header Connection "upgrade";
proxy_pass http://127.0.0.1:8001/;
proxy_redirect off;
}
}
ip地址换地理位置
注册高德地图开放平台, 进入控制台
创建一个应用
在应用 创建一个apikey apikey创建好了
使用IP定位API
文档链接 lbs.amap.com/api/webserv…
如下, 传你的apiKey和ip地址即可换取省市区及经纬度
https://restapi.amap.com/v3/ip?key=XXX&ip=你的ip地址
返回示例
{
"status": "1", // 1为成功
"info": "OK",
"infocode": "10000",
"province": "浙江省",
"city": "杭州市",
"adcode": "330100",
"rectangle": "119.8824799,29.95931271;120.5552208,30.52048536"
}
node中使用
koa中间件中使用
const fetch = require('node-fetch');
export default async(ctx, next) => {
const {
method, body, query, header: { 'x-forwarded-for': ip },
} = ctx.request;
const info = await getLocation(ip);
console.log(info, '省市信息’)
// {
// "status": "1",
// "info": "OK",
// "infocode": "10000",
// "province": "浙江省",
// "city": "杭州市",
// "adcode": "330100",
// "rectangle": "119.8824799,29.95931271;120.5552208,30.52048536"
// }
await next()
}
/*
* ip获取省市信息
* @param {} $ip
* @returns 省市信息
*/
async function getLocation($ip) {
// 处理一下ip
const ip = $ip.replace(/::ffff:/g, '').split(',')[0];
// 调用高德地图的
const ipResult = await fetch(`https://restapi.amap.com/v3/ip?key=310d88b1f76599ee6a4b0bd50ba6bbd8&ip=${ip}`).then((res) => res.json()).catch(() => { });
if (data && data.status === '1') {
return ipResult;
}
return null;
}
其他ip换取地理信息方式
github发现一个离线的解析ip的库
Ip2region
ip2region v2.0 - 是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb
数据生成和查询客户端实现。
github链接 (github.com/lionsoul201…)
github.com/lionsoul201…
存储方式 & 业务分析
存储方式
1、存Redis
每次获取ip先从redis里找, 没有再去查询第三方API
2、 搞个ip和地理信息对应表
每次获取ip先从对应表, 没有再去查询第三方API
业务功能分析
评论里的IP信息
例如评论这种功能 , ip和评论绑定,是快照存
(后续变动了不影响之前的评论)。
- 这种每次从
ip和地理信息对应表
查也可以。 - 如果 要求不高, 不考虑后续扩展, 直接加个子段 把地理信息冗余到业务表里吧。
主页的IP信息
主页的位置信息要实时变的
。
加个中间件 每次都去获取当前ip 判断地址变没变?
按一定策略, 在某个接口 加个异步方法,低频率判断。
比如在主页的某个接口,加一个方法,异步判断, 变化了,就更新到用户表。
总结两步
1、异步判断ip地址变化。
2、异步更新到用户表。
结尾
是个有趣的功能,快去加到你的项目里吧🏄🏼♂️🏄🏄♀ developer!
希望掘金也快点出这个功能, 掘友们@掘金产品经理