20分钟,实现一个根据ip查询地理信息的接口

代码已上传到 github 仓库,猛击加速访问

之前一直好奇那种根据 ip 显示出城市是怎么做的

恰好最近在做网站访问信息的记录大概搜索了下

首先要根据 ip 获取地理信息那么就需要有地方存 ip 和地理信息的数据,那么这个数据在哪里呢?

目前找到 maxmind 提供ip2地理信息数据但需要注册

注册页面地址

按要求填完注册后登录进入下载数据页面

GeoLite2 数据库是由 MaxMind 提供的一套免费的 IP 地理位置数据库。这套数据库包含了多种类型的数据,包括 ASN(Autonomous System Number,自治系统号)、City(城市)和 Country(国家)。

  1. ASN 数据:ASN 数据库提供了 IP 地址与其所属的自治系统(Autonomous System)之间的映射关系。自治系统是一个在互联网上由一个或多个路由器管理的路由域,它们通常由一个或多个 ISP(Internet Service Provider,互联网服务提供商)管理。ASN 数据库可以帮助你确定 IP 地址的 ISP 所有者。
  2. City 数据:City 数据库提供了 IP 地址与其所在城市之间的映射关系。这个数据库提供了更详细的地理位置信息,包括城市名称、邮政编码、经纬度坐标等。
  3. Country 数据:Country 数据库提供了 IP 地址与其所在国家之间的映射关系。这个数据库提供了国家名称和 ISO 国家代码。
    .mmdb 是 MaxMind DB 格式的文件扩展名,它是由 MaxMind 开发的一种数据库格式,用于存储 IP 地理位置信息。

提供 csv(GeoLite2 City: CSV Format)mmdb(GeoLite2 City) 格式的数据

这里我们下载 mmdb(GeoLite2 City) 数据使用

数据使用

这里使用了 vercel functions 无服务器函数,开发一个接口根据参数来返回解析后的数据

vercel functions

根据 快速开始文档 初始化一个项目

安装 vercel cli pnpm i -g vercel@latest

然后创建一个项目目录 geo-ip2-api

执行 npm init -y 初始化 package.json,写入如下内容后执行 npm i 下载依赖, maxmind 是解析上边 mmdb 数据的库

json 复制代码
{
  "name": "geo-ip2-api",
  "repository": "",
  "license": "MIT",
  "private": true,
  "devDependencies": {
    "@types/node": "^17.0.42",
    "@vercel/node": "^2.9.6",
    "typescript": "^4.7.3"
  },
  "dependencies": {
    "maxmind": "^4.3.19"
  }
}

执行 git init 初始化 git

将下载后的数据解压缩放到项目中 data/GeoLite2-City.mmdb

创建 api/query.ts ,写入如下内容

ts 复制代码
import type { VercelRequest, VercelResponse } from '@vercel/node'
import { readFileSync } from 'fs'
import { join } from 'path';
import maxmind, { CityResponse, Reader } from 'maxmind';

export default async function handler(req: VercelRequest, res: VercelResponse) {
  // 优先获取 query 参数,如果获取不到则获取请求头中的 x-forwarded-for 或 x-real-ip
  let ipStr = req.query?.ip as string || req.headers['x-forwarded-for'] as string || req.headers['x-real-ip'] as string;

  if (!maxmind.validate(ipStr)) {
    return res.json({ code: 1, msg: 'ip 地址格式不正确!' })
  }

  const filePath = join(process.cwd(), 'data', 'GeoLite2-City.mmdb');
  const buffer = readFileSync(filePath);
  const lookup = new Reader<CityResponse>(buffer);
  const ipInfo = lookup.get(ipStr)

  if (!ipInfo) {
    return res.json({ code: 1, msg: `未获取到 ip(${ipStr}) 信息!` })
  }

  return res.json({ code: 0, msg: 'success!', ...ipInfo })
}

本地执行 vercel dev 测试代码,首次需要登录有账号根据提示登录即可,项目首次运行需要回答一些问题一路回车就可以了

因为 GeoLite2-City.mmdb 数据比较大上传完会一直卡住,稍等一些时间停止或者新开窗口运行 vercel dev

显示下图则表示本地运行成功,也可能会有一些其他的输出,显示 Ready! 就认为是成功!

然后浏览器访问 http://localhost:3000/api/query?ip=159.226.171.49 可以看到如下输出

可以看到数据包含了查询 ip 的地理信息,市、国家、地理坐标等,有了这些信息我们就可以分析网站的访问的来源信息

当然这也许不准确因为会有代理、修改请求信息等手段可以改变 ip

但这种我也不是很关心,我只是想记录分析下网站的访问数据做统计图表!

开发完成后可以执行 vercel --prod 进行发布

发布中

发布完成

到这里其实已经实现了一个根据 ip 查询地理信息的接口,我们还可以更完善一些比如将数据格式化一下返回

浏览器输入 https://geo-ip2-api.vercel.app/api/query?ip=159.226.171.49&lang=zh-CN

在项目根目录创建 index.html 这个文件在访问 https://geo-ip2-api.vercel.app/ or http://localhost:3000/ 时会被默认加载!

总结

本文从maxmind获取 ip 地理信息数据库,使用 vercel functions 开发了一个可以在线调用的根据 ip 获取地理信息的接口服务,唯一的缺点是线上仅支持 https 访问!

写到这里的时候忽然想起来,之前有一个需求点击按钮定位到当前用户所在的地区,当时能想到就是使用浏览器提供的能力但是线上需要 https 我们没有功能只能搁置!

当时如果想起来使用 ip 定位实现起来也非常简单,因为并不需要太高的精度

扩展内容

maxmind 官方也为一些语言提供了客户端

猛击访问

使用示例 猛击访问

在线服务

除了上边下载数据本地使用的方式外也提供了在线调用的方法 猛击访问

这里需要关注两点

  1. 访问需要将用户名和密钥使用 Basic access authentication 加密设置 Authorization 进行请求
  2. 只能通过 https 才可以进行访问否则返回 403 错误

获取 id 、生成 key 地址

数据加密方法 js

js 复制代码
function basicAuthEncode(username, password) {
    // 将用户名和密码拼接,并使用冒号分隔
    var credentials = username + ':' + password;
    // 使用 btoa 函数将拼接后的字符串转换为 Base64 编码
    var encodedCredentials = btoa(credentials);
    // 返回编码后的字符串
    return encodedCredentials;
}

返回信息和上边是一样的,因为是通过一份数据源

go 调用

使用 github.com/oschwald/ge...

免费在线服务

ip-api 每分钟 45 次请求写 demo 基本够用了

ipgeolocation 每月 3w 访问

往期文章

相关推荐
PleaSure乐事几秒前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 分钟前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo2 分钟前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v5 分钟前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫6 分钟前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web
贩卖纯净水.11 分钟前
Chrome调试工具(查看CSS属性)
前端·chrome
小码编匠1 小时前
一款 C# 编写的神经网络计算图框架
后端·神经网络·c#
栈老师不回家1 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
AskHarries1 小时前
Java字节码增强库ByteBuddy
java·后端
前端啊龙1 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js