Files
codexautopool/backend/internal/proxyutil/test_proxy.go

78 lines
1.9 KiB
Go

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
}