Files
nl-im-service/internal/utils/ip_location.go
2025-12-03 11:00:47 +08:00

164 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* package utils
* 作用IP归属地查询工具
* 说明使用第三方API查询IP归属地信息
*/
package utils
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
)
// IPLocationInfo IP归属地信息
type IPLocationInfo struct {
Country string `json:"country"` // 国家
Region string `json:"region"` // 省份
City string `json:"city"` // 城市
ISP string `json:"isp"` // 运营商
FullLocation string `json:"full_location"` // 完整归属地
}
// 缓存结构(简单内存缓存)
var (
ipCache = make(map[string]*IPLocationInfo)
cacheTimeout = 24 * time.Hour
)
/**
* GetIPLocation
* 功能获取IP归属地信息
* @param ip IP地址
* @returns 归属地信息字符串
*/
func GetIPLocation(ip string) string {
// 排除本地IP
if isLocalIP(ip) {
return "本地"
}
// 检查缓存
if info, ok := ipCache[ip]; ok {
return info.FullLocation
}
// 查询IP归属地
info := queryIPLocation(ip)
if info != nil {
// 构建完整归属地字符串
parts := []string{}
if info.Country != "" {
parts = append(parts, info.Country)
}
if info.Region != "" {
parts = append(parts, info.Region)
}
if info.City != "" {
parts = append(parts, info.City)
}
if info.ISP != "" {
parts = append(parts, info.ISP)
}
if len(parts) > 0 {
info.FullLocation = strings.Join(parts, " ")
} else {
info.FullLocation = "未知"
}
// 存入缓存
ipCache[ip] = info
return info.FullLocation
}
return "未知"
}
/**
* isLocalIP
* 功能判断是否为本地IP
*/
func isLocalIP(ip string) bool {
// 本地回环地址
if ip == "127.0.0.1" || ip == "localhost" || ip == "::1" {
return true
}
// 内网地址
if strings.HasPrefix(ip, "192.168.") ||
strings.HasPrefix(ip, "10.") ||
strings.HasPrefix(ip, "172.16.") ||
strings.HasPrefix(ip, "172.17.") ||
strings.HasPrefix(ip, "172.18.") ||
strings.HasPrefix(ip, "172.19.") ||
strings.HasPrefix(ip, "172.20.") ||
strings.HasPrefix(ip, "172.21.") ||
strings.HasPrefix(ip, "172.22.") ||
strings.HasPrefix(ip, "172.23.") ||
strings.HasPrefix(ip, "172.24.") ||
strings.HasPrefix(ip, "172.25.") ||
strings.HasPrefix(ip, "172.26.") ||
strings.HasPrefix(ip, "172.27.") ||
strings.HasPrefix(ip, "172.28.") ||
strings.HasPrefix(ip, "172.29.") ||
strings.HasPrefix(ip, "172.30.") ||
strings.HasPrefix(ip, "172.31.") {
return true
}
return false
}
/**
* queryIPLocation
* 功能查询IP归属地使用ip-api.com免费API
*/
func queryIPLocation(ip string) *IPLocationInfo {
// 使用ip-api.com免费API限制每分钟45次请求
url := fmt.Sprintf("http://ip-api.com/json/%s?lang=zh-CN&fields=status,message,country,regionName,city,isp", ip)
client := &http.Client{
Timeout: 3 * time.Second,
}
resp, err := client.Get(url)
if err != nil {
return nil
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil
}
var result struct {
Status string `json:"status"`
Message string `json:"message"`
Country string `json:"country"`
Region string `json:"regionName"`
City string `json:"city"`
ISP string `json:"isp"`
}
if err := json.Unmarshal(body, &result); err != nil {
return nil
}
if result.Status != "success" {
return nil
}
return &IPLocationInfo{
Country: result.Country,
Region: result.Region,
City: result.City,
ISP: result.ISP,
}
}