Fix API dashboard using implicit default HTTP client

This commit is contained in:
世界
2026-09-20 22:24:38 +08:00
parent f5f4995c32
commit c0b8fe8b57
3 changed files with 14 additions and 42 deletions
+2 -11
View File
@@ -92,20 +92,11 @@ Download URL of the dashboard archive (zip).
##### http_client
HTTP client used to download the dashboard, with the same behavior as remote rule-sets.
HTTP client used to download the dashboard.
See [HTTP Client Fields](/configuration/shared/http-client/) for details.
When empty, the default HTTP client is used: the one named by
[`default_http_client`](/configuration/route/#default_http_client), or the first top-level
`http_clients` entry when `default_http_client` is empty.
!!! failure "Implicit default deprecated in sing-box 1.14.0"
When neither `http_clients` nor `default_http_client` is configured, an implicit HTTP
client connecting through the default outbound is used. This implicit default is
deprecated in sing-box 1.14.0 and will be removed in sing-box 1.16.0; define
`http_clients` instead.
Not used when the dashboard directory contains user-provided files.
##### update_interval
+2 -8
View File
@@ -87,17 +87,11 @@ API 密钥。
##### http_client
用于下载仪表板的 HTTP 客户端,行为与远程规则集相同。
用于下载仪表板的 HTTP 客户端。
参阅 [HTTP 客户端字段](/zh/configuration/shared/http-client/)。
留空时使用默认 HTTP 客户端:即由 [`default_http_client`](/zh/configuration/route/#default_http_client)
指定的客户端,或当 `default_http_client` 为空时使用顶级 `http_clients` 的第一项。
!!! failure "隐式默认已在 sing-box 1.14.0 废弃"
当 `http_clients` 与 `default_http_client` 均未配置时,将使用通过默认出站连接的隐式 HTTP 客户端。
该隐式默认已在 sing-box 1.14.0 废弃,并将在 sing-box 1.16.0 移除;请改为定义 `http_clients`。
当仪表板目录包含用户提供的文件时不使用。
##### update_interval
+10 -23
View File
@@ -13,6 +13,7 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/filemanager"
@@ -78,12 +79,18 @@ func (d *dashboard) start() error {
if err != nil && !os.IsNotExist(err) {
return E.Cause(err, "read dashboard directory")
}
transport, err := d.resolveTransport()
status := d.loadState()
if status == dashboardUserProvided {
d.logger.Info("dashboard: serving user-provided files at ", d.path, ", auto-update disabled")
return nil
}
httpClientManager := service.FromContext[adapter.HTTPClientManager](d.ctx)
transport, err := httpClientManager.ResolveTransport(d.ctx, d.logger, common.PtrValueOrDefault(d.options.HTTPClient))
if err != nil {
return E.Cause(err, "create dashboard http client")
}
d.httpClient = &http.Client{Transport: transport}
go d.loopUpdate()
go d.loopUpdate(status)
return nil
}
@@ -95,21 +102,6 @@ func (d *dashboard) close() error {
return nil
}
func (d *dashboard) resolveTransport() (adapter.HTTPTransport, error) {
httpClientManager := service.FromContext[adapter.HTTPClientManager](d.ctx)
if httpClientManager == nil {
return nil, E.New("missing http client manager in context")
}
if d.options.HTTPClient != nil && !d.options.HTTPClient.IsEmpty() {
return httpClientManager.ResolveTransport(d.ctx, d.logger, *d.options.HTTPClient)
}
defaultTransport := httpClientManager.DefaultTransport()
if defaultTransport == nil {
return nil, E.New("default http client transport is not initialized")
}
return defaultTransport, nil
}
func (d *dashboard) serveHTTP(writer http.ResponseWriter, request *http.Request) {
if strings.HasPrefix(request.URL.Path, dashboardRoutePrefix) {
d.fileServer.ServeHTTP(writer, request)
@@ -118,12 +110,7 @@ func (d *dashboard) serveHTTP(writer http.ResponseWriter, request *http.Request)
http.Redirect(writer, request, dashboardRoutePrefix, http.StatusFound)
}
func (d *dashboard) loopUpdate() {
status := d.loadState()
if status == dashboardUserProvided {
d.logger.Info("dashboard: serving user-provided files at ", d.path, ", auto-update disabled")
return
}
func (d *dashboard) loopUpdate(status dashboardStatus) {
var nextUpdate time.Time
if status == dashboardManaged {
nextUpdate = d.lastUpdated.Add(d.updateInterval)