Merge pull request #1894 from RedwindA/refactor/enhance-channel-proxy

Refactor: Cache Proxy HTTP Clients with Reset on Channel Updates
This commit is contained in:
Seefs
2025-09-29 12:12:17 +08:00
committed by GitHub
2 changed files with 42 additions and 5 deletions
+3
View File
@@ -8,6 +8,7 @@ import (
"one-api/constant" "one-api/constant"
"one-api/dto" "one-api/dto"
"one-api/model" "one-api/model"
"one-api/service"
"strconv" "strconv"
"strings" "strings"
@@ -633,6 +634,7 @@ func AddChannel(c *gin.Context) {
common.ApiError(c, err) common.ApiError(c, err)
return return
} }
service.ResetProxyClientCache()
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"success": true, "success": true,
"message": "", "message": "",
@@ -894,6 +896,7 @@ func UpdateChannel(c *gin.Context) {
return return
} }
model.InitChannelCache() model.InitChannelCache()
service.ResetProxyClientCache()
channel.Key = "" channel.Key = ""
clearChannelInfo(&channel.Channel) clearChannelInfo(&channel.Channel)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
+39 -5
View File
@@ -7,12 +7,17 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"one-api/common" "one-api/common"
"sync"
"time" "time"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
) )
var httpClient *http.Client var (
httpClient *http.Client
proxyClientLock sync.Mutex
proxyClients = make(map[string]*http.Client)
)
func InitHttpClient() { func InitHttpClient() {
if common.RelayTimeout == 0 { if common.RelayTimeout == 0 {
@@ -28,12 +33,31 @@ func GetHttpClient() *http.Client {
return httpClient return httpClient
} }
// ResetProxyClientCache 清空代理客户端缓存,确保下次使用时重新初始化
func ResetProxyClientCache() {
proxyClientLock.Lock()
defer proxyClientLock.Unlock()
for _, client := range proxyClients {
if transport, ok := client.Transport.(*http.Transport); ok && transport != nil {
transport.CloseIdleConnections()
}
}
proxyClients = make(map[string]*http.Client)
}
// NewProxyHttpClient 创建支持代理的 HTTP 客户端 // NewProxyHttpClient 创建支持代理的 HTTP 客户端
func NewProxyHttpClient(proxyURL string) (*http.Client, error) { func NewProxyHttpClient(proxyURL string) (*http.Client, error) {
if proxyURL == "" { if proxyURL == "" {
return http.DefaultClient, nil return http.DefaultClient, nil
} }
proxyClientLock.Lock()
if client, ok := proxyClients[proxyURL]; ok {
proxyClientLock.Unlock()
return client, nil
}
proxyClientLock.Unlock()
parsedURL, err := url.Parse(proxyURL) parsedURL, err := url.Parse(proxyURL)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -41,11 +65,16 @@ func NewProxyHttpClient(proxyURL string) (*http.Client, error) {
switch parsedURL.Scheme { switch parsedURL.Scheme {
case "http", "https": case "http", "https":
return &http.Client{ client := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
Proxy: http.ProxyURL(parsedURL), Proxy: http.ProxyURL(parsedURL),
}, },
}, nil }
client.Timeout = time.Duration(common.RelayTimeout) * time.Second
proxyClientLock.Lock()
proxyClients[proxyURL] = client
proxyClientLock.Unlock()
return client, nil
case "socks5", "socks5h": case "socks5", "socks5h":
// 获取认证信息 // 获取认证信息
@@ -67,13 +96,18 @@ func NewProxyHttpClient(proxyURL string) (*http.Client, error) {
return nil, err return nil, err
} }
return &http.Client{ client := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr) return dialer.Dial(network, addr)
}, },
}, },
}, nil }
client.Timeout = time.Duration(common.RelayTimeout) * time.Second
proxyClientLock.Lock()
proxyClients[proxyURL] = client
proxyClientLock.Unlock()
return client, nil
default: default:
return nil, fmt.Errorf("unsupported proxy scheme: %s", parsedURL.Scheme) return nil, fmt.Errorf("unsupported proxy scheme: %s", parsedURL.Scheme)