自己部署一个查看公网 IP 的服务
之前一直都是使用的别人的 API 来去天气的当前地点,后来那个 API 挂了,导致我没这个数据了
其他的 要么做的太小 不能保证服务可用性,要么有CORS策略,web 嵌入是做不了的
另外 就是想通过最简单的 api,来快速获取IP。
所以干脆自己整一个吧。
Maxmind
Maxmind 可以提供 GeoIP® data
,算是一家独大的了 而且 Free plan 已经足够大多数场景使用了 数据也很准确
但使用其产品还是有些限制的,需要申请 license,文件数据更新也是个问题。
所以还是只能再调用在线的 API 了,好在足够使用。
接来下,就要想一下,高可用的服务 建设在哪里了。
Cloudflare Worker
想了一下,即可以免费使用 又可以保证服务可用性的,而且还轻量化部署的,只有 cloudflare worker 了。
worker 收到请求后 解析参数 然后再去请求 maxmind 的 API。最终再返回数据。
嗯 非常好,接下来就是 代码实现了。
因为 最终代码其实挺简单的,所以就不传到 Github 上了。
API
GEO IP
const maxmind = async (ipv4) => {
let init = {
headers: {
"Authorization": authenticateUser(account, license)
}
}
const resp = await fetch(`https://geolite.info/geoip/v2.1/city/${ipv4}?pretty`, init);
return resp.text();
}
Basic auth
function authenticateUser(user, password) {
var token = user + ":" + password;
var hash = btoa(token);
return "Basic " + hash;
}
CORS 公开策略
const cors_permit = (acHeaders) => {
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
"Access-Control-Max-Age": "86400"
};
return {
headers: {
...corsHeaders,
"Access-Control-Allow-Headers": acHeaders
}
}
}
Main
对于快速查看公网IP的请求,可以直接通过 cloudflare 现成的方法来去快速返回,避免调用 Maxmind 的 API(有限制)。
const ip = request.headers.get("CF-Connecting-IP");
const ipcountry = request.headers.get("cf-ipcountry");
switch (pathname) {
case "/": return new Response(ip);
default: return new Response(`pathname: ${pathname}, search: ${search}`);
}
对于 公共 API(/json
),只需要封装几个关键参数就可以了,例如:ip,国家,城市,经纬度
// maxmind account
const account = "your_account";
const license = "your_secret_licnse";
export default {
// The fetch handler is invoked when this worker receives a HTTP(S) request
// and should return a Response (optionally wrapped in a Promise)
async fetch(request, env, ctx) {
const url = new URL(request.url);
const {pathname, search} = url;
switch (pathname) {
case "/json": {
let mt = await maxmind(ip);
let mj = JSON.parse(mt);
let acHeaders = request.headers.get("Access-Control-Request-Headers")
let _json = {
ip,
ipcountry,
country: mj.country ? mj.country.names.en : null,
city: mj.city ? mj.city.names.en : mj.city,
latitude: mj.location.latitude,
longitude: mj.location.longitude
};
return new Response(JSON.stringify(_json), cors_permit(acHeaders));
}
default: return new Response(`pathname: ${pathname}, search: ${search}`);
}
}
};
总结
例如我想在一个 Linux 中查看当前的公网IP,我只需要执行 一个 curl 就可以了。
curl ip.waynecommand.com
如果我想把地理位置集成到我的服务里,或者别的服务里,那我就可以直接调用
request.get("https://ip.waynecommand.com/json")
非常简单而强大,全年不掉线。