package proxyutil import ( "encoding/json" "fmt" "net/http" "net/url" "time" ) // ProxyTestResult 代理测试结果 type ProxyTestResult struct { Success bool `json:"success"` Location string `json:"location"` IP string `json:"ip"` Error string `json:"error,omitempty"` } // IPApiResponse ip-api.com 响应结构 type IPApiResponse struct { Status string `json:"status"` Country string `json:"country"` CountryCode string `json:"countryCode"` Region string `json:"region"` RegionName string `json:"regionName"` City string `json:"city"` Query string `json:"query"` Message string `json:"message"` } // TestProxy 测试代理连通性并获取归属地 func TestProxy(proxyURL string) (*ProxyTestResult, error) { normalized, err := Normalize(proxyURL) if err != nil { return nil, fmt.Errorf("代理地址格式错误: %w", err) } // 解析代理 URL parsedProxy, err := url.Parse(normalized) if err != nil { return nil, fmt.Errorf("解析代理错误: %w", err) } // 创建带代理的客户端 client := &http.Client{ Transport: &http.Transport{ Proxy: http.ProxyURL(parsedProxy), }, Timeout: 15 * time.Second, } // 请求 IP 查询接口 resp, err := client.Get("http://ip-api.com/json/") if err != nil { return &ProxyTestResult{Success: false, Error: err.Error()}, nil } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return &ProxyTestResult{Success: false, Error: fmt.Sprintf("HTTP %d", resp.StatusCode)}, nil } var ipInfo IPApiResponse if err := json.NewDecoder(resp.Body).Decode(&ipInfo); err != nil { return &ProxyTestResult{Success: false, Error: "解析响应失败: " + err.Error()}, nil } if ipInfo.Status != "success" { return &ProxyTestResult{Success: false, Error: "查询失败: " + ipInfo.Message}, nil } return &ProxyTestResult{ Success: true, Location: ipInfo.CountryCode, IP: ipInfo.Query, }, nil }