完善初始化更新
This commit is contained in:
70
sproutgate-backend/internal/clientgeo/clientgeo.go
Normal file
70
sproutgate-backend/internal/clientgeo/clientgeo.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package clientgeo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DefaultLookupURL = "https://cf-ip-geo.smyhub.com/api"
|
||||
|
||||
type apiPayload struct {
|
||||
Geo *struct {
|
||||
CountryName string `json:"countryName"`
|
||||
RegionName string `json:"regionName"`
|
||||
CityName string `json:"cityName"`
|
||||
} `json:"geo"`
|
||||
}
|
||||
|
||||
func FormatDisplay(countryName, regionName, cityName string) string {
|
||||
parts := make([]string, 0, 3)
|
||||
for _, s := range []string{countryName, regionName, cityName} {
|
||||
s = strings.TrimSpace(s)
|
||||
if s != "" {
|
||||
parts = append(parts, s)
|
||||
}
|
||||
}
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
// FetchDisplayLocation 使用 cf-ip-geo 的 ?ip= 查询展示用位置(服务端调用,避免浏览器 CORS)。
|
||||
func FetchDisplayLocation(ctx context.Context, lookupURL, ip string) (string, error) {
|
||||
ip = strings.TrimSpace(ip)
|
||||
if ip == "" {
|
||||
return "", nil
|
||||
}
|
||||
base := strings.TrimSuffix(strings.TrimSpace(lookupURL), "/")
|
||||
u, err := url.Parse(base)
|
||||
if err != nil || u.Scheme == "" || u.Host == "" {
|
||||
return "", fmt.Errorf("invalid lookup URL")
|
||||
}
|
||||
q := u.Query()
|
||||
q.Set("ip", ip)
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
client := &http.Client{Timeout: 6 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("geo status %d", resp.StatusCode)
|
||||
}
|
||||
var payload apiPayload
|
||||
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if payload.Geo == nil {
|
||||
return "", nil
|
||||
}
|
||||
return FormatDisplay(payload.Geo.CountryName, payload.Geo.RegionName, payload.Geo.CityName), nil
|
||||
}
|
||||
Reference in New Issue
Block a user