使用函数计算获取 IP 地址信息
背景
博客评论区支持 IP 地区显示后,虽然可以通过请求体拿到 IP,但是要查询对应的地区仍然需要单独的服务。
将其独立出来有以下几点理由
- 一些免费的 IP 接口并不稳定(如
ip-api.com
有可能在国内访问受限) - IP 接口来源众多,有些免费、有些可以免费体验但是要定期更新密钥、有些则收费,如果需要长时间使用需要定期维护接口列表,放在博客中需要跟随博客发版
- 该功能不仅仅适用于博客场景,在一些别的地方也会用到,应该解耦出来
而选择函数计算的理由如下
- 博客评论并不是特别频繁,大部分情况没有流量,需要 弹性 提供服务
- 并且经常性的接口维护每次重新部署比较麻烦(每次可能部署时间比改的时间还长),可以利用函数计算的 Web IDE
- 免费额度的请求量足以应付博客评论区的需要,而 IP 本身数据量较小,CDN 费用也很低
广告
配置
需要配置的项目并不多
- runtime:首先由于使用 js 实现,因此选择选择函数计算 nodejs runtime。
- 内存规格:本身没有复杂的计算功能,因此选择最小规格(128 MB)即可(如果处理过慢可以适当调大)
- 单实例并发度:如果存在并发场景,每个请求的处理实际上只是在等待 IO,对机器本身性能要求不高,因此可以考虑允许一个实例同时承载 50 个并发请求(如果发生频繁的故障可以考虑调小)
- 环境变量:部分接口需要用到密钥,配置在环境变量中避免泄露
代码
这里共实现了两个接口
- IP-API.com - Geolocation API
- 全球IP归属地查询_IP地址查询_IP地理位置库查询【杭州节点】(限时免费)【最新版】_大数据可视化_IP地址_数据API-云市场-阿里云 (aliyun.com)
const axios = require("axios"); const { env } = require('process'); const { APPCODE } = env; async function ipApi(ip) { const res = (await axios.get(`http://ip-api.com/json/${ip}?fields=66842623&lang=zh-CN`)).data; return { success: res.status === "success", ip, continent: res.continent, country: res.country, region: res.regionName, city: res.city, mobile: res.mobile, proxy: res.proxy, lat: res.lat, lon: res.lon, } } async function aliyunApi(ip) { const res = (await axios.get(`http://api01.aliyun.venuscn.com/ip?ip=${ip}`, { headers: { "Authorization": `APPCODE ${APPCODE}`, } })).data; return { success: res.ret === 200, ip, country: res.data.country, region: res.data.region, city: res.data.city, } } const apis = [ ipApi, aliyunApi, ] exports.handler = async (req, resp, context) => { const ip = !!req.queries.ip ? req.queries.ip : req.clientIP console.log(ip); var result = { ip } for (const f of apis) { try { const res = await f(ip); console.log("call", f, res) if (!!res && res.success) { result = { ...result, ...res }; break; } } catch (e) { console.log(f, "got error", e.message); } } resp.send(JSON.stringify(result)) }