Golang 實現 IP 全球定位

在 Golang 開發中,如何快速獲取 IP 地址的地理位置?無論是安全審計、日誌分析,訪問控制,還是資產測繪,網絡空間搜索等等都可能需要 IP 定位。本篇文章將介紹常見幾種 Golang IP 定位方案,幫助你選擇最合適的方法。

IP 全球定位系統

IP 定位系統是利用多種數據庫,如全球城市數據庫、多語言支持庫、IP 地址數據庫以及地圖服務等資源來精準確定用戶位置。藉助於 IP 地理定位 API,我們能夠依據所提供的 IP 地址獲取詳細的地理位置數據,包括但不限於國家、地區、郵政編碼、經緯度座標、域名及互聯網服務提供商(ISP)信息等。另一方面,W3C 地理定位 API 由萬維網聯盟(W3C)開發,旨在提供一種標準化的方式來探測客戶端的地理位置。例如最常見的來源不外是 IP 地址,WiFi,藍牙 MAC 地址,無線射頻識別(RFID)WiFi 連接的位置等。地理編碼與地理位置是息息相關的,通過查詢相關的地理數據庫來獲取相關位置的地理座標 (經緯度)。總的來說,我們可以通過這些方法來獲取地理位置信息。

使用在線 API 服務(最簡單有錢就行)

在線 API 是最簡單的方式,適合低查詢量、對數據實時性要求高的場景。

常見的 IP 定位 API:

示例代碼(IPinfo API):

package main
import (
    "encoding/json"
    "fmt"
    "net/http"
)
type IPInfo struct {
    City     string `json:"city"`
    Region   string `json:"region"`
    Country  string `json:"country"`
    IP       string `json:"ip"`
    HostName string `json:"hostname"`
    Loc      string `json:"loc"`
    Org      string `json:"org"`
    Postal   string `json:"postal"`
    Timezone string `json:"timezone"`
    Readme   string `json:"readme"`
    Anycast  bool   `json:"anycast"`
}
func main() {
    ip := "8.8.8.8"
    resp, err := http.Get("https://ipinfo.io/" + ip + "/json")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()
    var info IPInfo
    if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
        fmt.Println("Decode error:", err)
        return
    }
    fmt.Printf("IP: %s, City: %s, Region: %s, Country: %s\n", info.IP, info.City, info.Region, info.Country)
}

✅ 優點

❌ 缺點

使用本地 IP 數據庫

如果你的應用不想依賴外部 API,可以使用本地 IP 數據庫,例如:

使用 MaxMind GeoLite2

package main
import (
    "fmt"
    "log"
    "net"
    "github.com/oschwald/geoip2-golang"
)
func main() {
    db, err := geoip2.Open("GeoIP2-City.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    ip := net.ParseIP("81.2.69.142")
    record, err := db.City(ip)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names["pt-BR"])
    if len(record.Subdivisions) > 0 {
        fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names["en"])
    }
    fmt.Printf("Russian country name: %v\n", record.Country.Names["ru"])
    fmt.Printf("ISO country code: %v\n", record.Country.IsoCode)
    fmt.Printf("Time zone: %v\n", record.Location.TimeZone)
    fmt.Printf("Coordinates: %v, %v\n", record.Location.Latitude, record.Location.Longitude)
}

✅ 優點

❌ 缺點

結合 BGP 和 ASN 數據(適合運營商分析)

如果你想查詢 IP 歸屬的網絡運營商(ASN 數據),可以使用:

package main
import (
	"fmt"
	"log"
	"net"
	"github.com/ipinfo/go/v2/ipinfo"
)
func main() {
	const token = "YOUR_TOKEN"
	client := ipinfo.NewClient(nil, nil, token)
	const ip_address = "8.8.8.8"
	info, err := client.GetIPInfo(net.ParseIP(ip_address))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(info)
}

✅ 適用於

輕量級 IP 庫(適合小型項目)

如果不想使用 API,也不想下載幾十 MB 或者幾 GB 的大數據庫,可以使用輕量級 IP 庫

package main
import (
	"github.com/ip2location/ip2location-go"
	"fmt"
)
func main() {
	r, err := ip2location.OpenRegionInfo("./IP2LOCATION-ISO3166-2.CSV")
	if err != nil {
		fmt.Print(err)
		return
	}
	res, err := r.GetRegionCode("US", "California")
	if err != nil {
		fmt.Print(err)
		return
	}
	fmt.Printf("region code: %s\n", res)
}

✅ 優點

❌ 缺點

總結:哪種方案適合?

JTdhOR

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/2yfP9MucnPaDaaS2yHyvtg