mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-07 17:08:33 +08:00
fix: use dual-stack fallback for proxy probe
This commit is contained in:
@@ -48,10 +48,10 @@ const (
|
||||
// 某些 AI API 专用代理只允许访问特定域名,因此需要多个备选
|
||||
var probeURLs = []struct {
|
||||
url string
|
||||
parser string // "ip-api" or "httpbin"
|
||||
parser string // "ip-api" or "ipify"
|
||||
}{
|
||||
{"http://ip-api.com/json/?lang=zh-CN", "ip-api"},
|
||||
{"http://httpbin.org/ip", "httpbin"},
|
||||
{"http://api64.ipify.org?format=json", "ipify"},
|
||||
}
|
||||
|
||||
type proxyProbeService struct {
|
||||
@@ -119,8 +119,8 @@ func (s *proxyProbeService) probeWithURL(ctx context.Context, client *http.Clien
|
||||
switch parser {
|
||||
case "ip-api":
|
||||
return s.parseIPAPI(body, latencyMs)
|
||||
case "httpbin":
|
||||
return s.parseHTTPBin(body, latencyMs)
|
||||
case "ipify":
|
||||
return s.parseIPify(body, latencyMs)
|
||||
default:
|
||||
return nil, latencyMs, fmt.Errorf("unknown parser: %s", parser)
|
||||
}
|
||||
@@ -165,18 +165,17 @@ func (s *proxyProbeService) parseIPAPI(body []byte, latencyMs int64) (*service.P
|
||||
}, latencyMs, nil
|
||||
}
|
||||
|
||||
func (s *proxyProbeService) parseHTTPBin(body []byte, latencyMs int64) (*service.ProxyExitInfo, int64, error) {
|
||||
// httpbin.org/ip 返回格式: {"origin": "1.2.3.4"}
|
||||
func (s *proxyProbeService) parseIPify(body []byte, latencyMs int64) (*service.ProxyExitInfo, int64, error) {
|
||||
var result struct {
|
||||
Origin string `json:"origin"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, latencyMs, fmt.Errorf("failed to parse httpbin response: %w", err)
|
||||
return nil, latencyMs, fmt.Errorf("failed to parse ipify response: %w", err)
|
||||
}
|
||||
if result.Origin == "" {
|
||||
return nil, latencyMs, fmt.Errorf("httpbin: no IP found in response")
|
||||
if result.IP == "" {
|
||||
return nil, latencyMs, fmt.Errorf("ipify: no IP found in response")
|
||||
}
|
||||
return &service.ProxyExitInfo{
|
||||
IP: result.Origin,
|
||||
IP: result.IP,
|
||||
}, latencyMs, nil
|
||||
}
|
||||
|
||||
@@ -71,24 +71,24 @@ func (s *ProxyProbeServiceSuite) TestProbeProxy_Success_IPAPI() {
|
||||
require.Equal(s.T(), "CC", info.CountryCode)
|
||||
}
|
||||
|
||||
func (s *ProxyProbeServiceSuite) TestProbeProxy_Success_HTTPBinFallback() {
|
||||
func (s *ProxyProbeServiceSuite) TestProbeProxy_Success_IPifyFallback() {
|
||||
s.setupProxyServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// ip-api 失败
|
||||
if strings.Contains(r.RequestURI, "ip-api.com") {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
// httpbin 成功
|
||||
if strings.Contains(r.RequestURI, "httpbin.org") {
|
||||
// ipify 成功
|
||||
if strings.Contains(r.RequestURI, "api64.ipify.org") {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = io.WriteString(w, `{"origin": "5.6.7.8"}`)
|
||||
_, _ = io.WriteString(w, `{"ip": "5.6.7.8"}`)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
}))
|
||||
|
||||
info, latencyMs, err := s.prober.ProbeProxy(s.ctx, s.proxySrv.URL)
|
||||
require.NoError(s.T(), err, "ProbeProxy should fallback to httpbin")
|
||||
require.NoError(s.T(), err, "ProbeProxy should fallback to ipify")
|
||||
require.GreaterOrEqual(s.T(), latencyMs, int64(0), "unexpected latency")
|
||||
require.Equal(s.T(), "5.6.7.8", info.IP)
|
||||
}
|
||||
@@ -110,8 +110,8 @@ func (s *ProxyProbeServiceSuite) TestProbeProxy_InvalidJSON() {
|
||||
_, _ = io.WriteString(w, "not-json")
|
||||
return
|
||||
}
|
||||
// httpbin 也返回无效响应
|
||||
if strings.Contains(r.RequestURI, "httpbin.org") {
|
||||
// ipify 也返回无效响应
|
||||
if strings.Contains(r.RequestURI, "api64.ipify.org") {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = io.WriteString(w, "not-json")
|
||||
return
|
||||
@@ -151,17 +151,17 @@ func (s *ProxyProbeServiceSuite) TestParseIPAPI_Failure() {
|
||||
require.ErrorContains(s.T(), err, "rate limited")
|
||||
}
|
||||
|
||||
func (s *ProxyProbeServiceSuite) TestParseHTTPBin_Success() {
|
||||
body := []byte(`{"origin": "9.8.7.6"}`)
|
||||
info, latencyMs, err := s.prober.parseHTTPBin(body, 50)
|
||||
func (s *ProxyProbeServiceSuite) TestParseIPify_Success() {
|
||||
body := []byte(`{"ip": "2001:db8::1"}`)
|
||||
info, latencyMs, err := s.prober.parseIPify(body, 50)
|
||||
require.NoError(s.T(), err)
|
||||
require.Equal(s.T(), int64(50), latencyMs)
|
||||
require.Equal(s.T(), "9.8.7.6", info.IP)
|
||||
require.Equal(s.T(), "2001:db8::1", info.IP)
|
||||
}
|
||||
|
||||
func (s *ProxyProbeServiceSuite) TestParseHTTPBin_NoIP() {
|
||||
body := []byte(`{"origin": ""}`)
|
||||
_, _, err := s.prober.parseHTTPBin(body, 50)
|
||||
func (s *ProxyProbeServiceSuite) TestParseIPify_NoIP() {
|
||||
body := []byte(`{"ip": ""}`)
|
||||
_, _, err := s.prober.parseIPify(body, 50)
|
||||
require.Error(s.T(), err)
|
||||
require.ErrorContains(s.T(), err, "no IP found")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user