自己部署一个查看公网 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")

非常简单而强大,全年不掉线。