Spaces:
Sleeping
Sleeping
File size: 3,616 Bytes
1de7911 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | package service
import (
"context"
"fmt"
"net/http"
"strings"
"time"
"zencoder-2api/internal/service/provider"
)
// ProxyRequestOptions 代理请求选项
type ProxyRequestOptions struct {
UseProxy bool // 是否使用代理
MaxRetries int // 最大重试次数
RetryDelay time.Duration // 重试延迟
OnError func(error) bool // 错误判断函数,返回true表示需要重试
}
// DefaultProxyRequestOptions 默认代理请求选项
func DefaultProxyRequestOptions() ProxyRequestOptions {
return ProxyRequestOptions{
UseProxy: true,
MaxRetries: 3,
RetryDelay: time.Second,
OnError: isNetworkError,
}
}
// isNetworkError 判断是否为网络错误(可重试的错误)
func isNetworkError(err error) bool {
if err == nil {
return false
}
errStr := err.Error()
// 网络连接错误
if strings.Contains(errStr, "connection refused") ||
strings.Contains(errStr, "connection reset") ||
strings.Contains(errStr, "connection timed out") ||
strings.Contains(errStr, "timeout") ||
strings.Contains(errStr, "network is unreachable") ||
strings.Contains(errStr, "no such host") ||
strings.Contains(errStr, "dial tcp") ||
strings.Contains(errStr, "i/o timeout") ||
strings.Contains(errStr, "EOF") {
return true
}
// SOCKS代理相关错误
if strings.Contains(errStr, "socks connect") ||
strings.Contains(errStr, "proxy") {
return true
}
return false
}
// DoRequestWithProxyRetry 执行带代理重试的HTTP请求
func DoRequestWithProxyRetry(ctx context.Context, req *http.Request, originalProxy string, options ProxyRequestOptions) (*http.Response, error) {
// 首先尝试使用原始代理(如果有的话)
client := provider.NewHTTPClient(originalProxy, 0)
resp, err := client.Do(req)
if err == nil {
// 请求成功,返回结果
return resp, nil
}
// 检查错误是否可重试
if !options.OnError(err) {
return nil, err
}
// 如果不使用代理池,直接返回错误
if !options.UseProxy {
return nil, err
}
proxyPool := provider.GetProxyPool()
if !proxyPool.HasProxies() {
return nil, fmt.Errorf("原始请求失败且无可用代理: %v", err)
}
var lastErr error = err
// 使用代理池进行重试
for i := 0; i < options.MaxRetries; i++ {
// 获取下一个代理
proxyURL := proxyPool.GetNextProxy()
if proxyURL == "" {
break
}
// 创建使用代理的HTTP客户端
proxyClient, clientErr := provider.NewHTTPClientWithProxy(proxyURL, 0)
if clientErr != nil {
lastErr = clientErr
time.Sleep(options.RetryDelay)
continue
}
// 克隆请求(因为request body可能已经被消费)
newReq := req.Clone(ctx)
resp, err := proxyClient.Do(newReq)
if err == nil {
// 请求成功
return resp, nil
}
// 检查错误是否继续重试
if !options.OnError(err) {
return nil, err
}
lastErr = err
time.Sleep(options.RetryDelay)
}
return nil, fmt.Errorf("所有代理重试均失败,最后错误: %v", lastErr)
}
// CreateHTTPClientWithFallback 创建支持代理fallback的HTTP客户端
func CreateHTTPClientWithFallback(originalProxy string, useProxyPool bool) *http.Client {
// 如果不使用代理池,使用原始逻辑
if !useProxyPool {
return provider.NewHTTPClient(originalProxy, 0)
}
// 如果有原始代理,先尝试原始代理
if originalProxy != "" {
client, err := provider.NewHTTPClientWithProxy(originalProxy, 0)
if err == nil {
return client
}
}
// 使用代理池
return provider.NewHTTPClientWithPoolProxy(true, 0)
} |