diff --git a/api/handler/default.go b/api/handler/default.go index 2a3dfb3..eeff99a 100644 --- a/api/handler/default.go +++ b/api/handler/default.go @@ -233,6 +233,21 @@ func BuildSub(clashType model.ClashType, query validator.SubValidator, template return temp, nil } +func fetchSubscriptionUserInfo(url string, userAgent string) (string, error) { + resp, err := common.Head(url, common.WithUserAgent(userAgent)) + if err != nil { + logger.Logger.Debug("创建 HEAD 请求失败", zap.Error(err)) + return "", err + } + defer resp.Body.Close() + if userInfo := resp.Header.Get("subscription-userinfo"); userInfo != "" { + return userInfo, nil + } + + logger.Logger.Debug("目标 URL 未返回 subscription-userinfo 头", zap.Error(err)) + return "", err +} + func MergeSubAndTemplate(temp *model.Subscription, sub *model.Subscription, igcg bool) { var countryGroupNames []string diff --git a/api/handler/meta.go b/api/handler/meta.go index a697310..6be9fae 100644 --- a/api/handler/meta.go +++ b/api/handler/meta.go @@ -25,6 +25,14 @@ func SubHandler(c *gin.Context) { return } + if len(query.Subs) == 1 { + userInfoHeader, err := fetchSubscriptionUserInfo(query.Subs[0], "clash") + if err != nil { + c.String(http.StatusInternalServerError, err.Error()) + } + c.Header("subscription-userinfo", userInfoHeader) + } + if query.NodeListMode { nodelist := model.NodeList{} nodelist.Proxies = sub.Proxies diff --git a/common/get.go b/common/get.go index 6f06d9d..d5b1525 100644 --- a/common/get.go +++ b/common/get.go @@ -58,3 +58,45 @@ func Get(url string, options ...GetOption) (resp *http.Response, err error) { } return nil, fmt.Errorf("请求失败:%v", err) } + +func Head(url string, options ...GetOption) (resp *http.Response, err error) { + retryTimes := config.Default.RequestRetryTimes + haveTried := 0 + retryDelay := time.Second + + // 解析可选参数(如 User-Agent) + getConfig := GetConfig{} + for _, option := range options { + option(&getConfig) + } + + var req *http.Request + var headResp *http.Response + + for haveTried < retryTimes { + client := &http.Client{} + req, err = http.NewRequest("HEAD", url, nil) + if err != nil { + haveTried++ + time.Sleep(retryDelay) + continue + } + + // 设置 User-Agent(如果提供) + if getConfig.userAgent != "" { + req.Header.Set("User-Agent", getConfig.userAgent) + } + + headResp, err = client.Do(req) + if err != nil { + haveTried++ + time.Sleep(retryDelay) + continue + } + + // HEAD 请求不检查 ContentLength,因为没有响应体 + return headResp, nil + } + + return nil, fmt.Errorf("HEAD 请求失败:%v", err) +}