更新302跳转处理逻辑,添加客户端参数以优化规则选择,增强扩展名匹配和文件大小判断,确保代理请求的准确性和稳定性。

This commit is contained in:
wood chen 2025-06-02 06:12:36 +08:00
parent f229455db9
commit 4447e690db
3 changed files with 101 additions and 44 deletions

View File

@ -239,7 +239,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
// 检查是否需要进行302跳转 // 检查是否需要进行302跳转
if h.redirectHandler != nil && h.redirectHandler.HandleRedirect(w, r, pathConfig, decodedPath) { if h.redirectHandler != nil && h.redirectHandler.HandleRedirect(w, r, pathConfig, decodedPath, h.client) {
// 如果进行了302跳转直接返回不继续处理 // 如果进行了302跳转直接返回不继续处理
collector.RecordRequest(r.URL.Path, http.StatusFound, time.Since(start), 0, utils.GetClientIP(r), r) collector.RecordRequest(r.URL.Path, http.StatusFound, time.Since(start), 0, utils.GetClientIP(r), r)
return return

View File

@ -19,9 +19,9 @@ func NewRedirectHandler() *RedirectHandler {
} }
// HandleRedirect 处理302跳转请求 // HandleRedirect 处理302跳转请求
func (rh *RedirectHandler) HandleRedirect(w http.ResponseWriter, r *http.Request, pathConfig config.PathConfig, targetPath string) bool { func (rh *RedirectHandler) HandleRedirect(w http.ResponseWriter, r *http.Request, pathConfig config.PathConfig, targetPath string, client *http.Client) bool {
// 检查是否需要进行302跳转 // 检查是否需要进行302跳转
shouldRedirect, targetURL := rh.shouldRedirect(r, pathConfig, targetPath) shouldRedirect, targetURL := rh.shouldRedirect(r, pathConfig, targetPath, client)
if !shouldRedirect { if !shouldRedirect {
return false return false
@ -33,17 +33,26 @@ func (rh *RedirectHandler) HandleRedirect(w http.ResponseWriter, r *http.Request
} }
// shouldRedirect 判断是否应该进行302跳转并返回目标URL // shouldRedirect 判断是否应该进行302跳转并返回目标URL
func (rh *RedirectHandler) shouldRedirect(r *http.Request, pathConfig config.PathConfig, targetPath string) (bool, string) { func (rh *RedirectHandler) shouldRedirect(r *http.Request, pathConfig config.PathConfig, targetPath string, client *http.Client) (bool, string) {
// 获取文件扩展名 // 获取文件扩展名
ext := strings.ToLower(filepath.Ext(targetPath)) ext := strings.ToLower(filepath.Ext(targetPath))
if ext != "" { if ext != "" {
ext = ext[1:] // 去掉点号 ext = ext[1:] // 去掉点号
} }
// 首先检查扩展名规则是否有302跳转配置 // 使用统一的规则选择逻辑,考虑文件大小
if rule, found, _ := utils.SelectBestRule(client, pathConfig, targetPath); found && rule != nil && rule.RedirectMode {
// 使用选中规则的目标URL进行302跳转
targetURL := rh.buildTargetURL(rule.Target, targetPath, r.URL.RawQuery)
log.Printf("[Redirect] %s -> 使用选中规则进行302跳转: %s", targetPath, targetURL)
return true, targetURL
}
// 如果没有找到合适的规则,检查是否有简单的扩展名匹配(向后兼容)
if rule, found := pathConfig.GetProcessedExtRule(ext); found && rule.RedirectMode { if rule, found := pathConfig.GetProcessedExtRule(ext); found && rule.RedirectMode {
// 使用扩展名规则的目标URL进行302跳转 // 使用扩展名规则的目标URL进行302跳转
targetURL := rh.buildTargetURL(rule.Target, targetPath, r.URL.RawQuery) targetURL := rh.buildTargetURL(rule.Target, targetPath, r.URL.RawQuery)
log.Printf("[Redirect] %s -> 使用扩展名规则进行302跳转: %s", targetPath, targetURL)
return true, targetURL return true, targetURL
} }
@ -51,6 +60,7 @@ func (rh *RedirectHandler) shouldRedirect(r *http.Request, pathConfig config.Pat
if rule, found := pathConfig.GetProcessedExtRule("*"); found && rule.RedirectMode { if rule, found := pathConfig.GetProcessedExtRule("*"); found && rule.RedirectMode {
// 使用通配符规则的目标URL进行302跳转 // 使用通配符规则的目标URL进行302跳转
targetURL := rh.buildTargetURL(rule.Target, targetPath, r.URL.RawQuery) targetURL := rh.buildTargetURL(rule.Target, targetPath, r.URL.RawQuery)
log.Printf("[Redirect] %s -> 使用通配符规则进行302跳转: %s", targetPath, targetURL)
return true, targetURL return true, targetURL
} }
@ -58,6 +68,7 @@ func (rh *RedirectHandler) shouldRedirect(r *http.Request, pathConfig config.Pat
if pathConfig.RedirectMode { if pathConfig.RedirectMode {
// 使用默认目标URL进行302跳转 // 使用默认目标URL进行302跳转
targetURL := rh.buildTargetURL(pathConfig.DefaultTarget, targetPath, r.URL.RawQuery) targetURL := rh.buildTargetURL(pathConfig.DefaultTarget, targetPath, r.URL.RawQuery)
log.Printf("[Redirect] %s -> 使用默认目标进行302跳转: %s", targetPath, targetURL)
return true, targetURL return true, targetURL
} }

View File

@ -183,12 +183,9 @@ func GetFileSize(client *http.Client, url string) (int64, error) {
return resp.ContentLength, nil return resp.ContentLength, nil
} }
// GetTargetURL 根据路径和配置决定目标URL // SelectBestRule 根据文件大小和扩展名选择最合适的规则
func GetTargetURL(client *http.Client, r *http.Request, pathConfig config.PathConfig, path string) (string, bool) { // 返回值: (选中的规则, 是否找到匹配的规则, 是否使用了备用目标)
// 默认使用默认目标 func SelectBestRule(client *http.Client, pathConfig config.PathConfig, path string) (*config.ExtensionRule, bool, bool) {
targetBase := pathConfig.DefaultTarget
usedAltTarget := false
// 获取文件扩展名(使用优化的字符串处理) // 获取文件扩展名(使用优化的字符串处理)
ext := "" ext := ""
lastDotIndex := strings.LastIndex(path, ".") lastDotIndex := strings.LastIndex(path, ".")
@ -196,38 +193,38 @@ func GetTargetURL(client *http.Client, r *http.Request, pathConfig config.PathCo
ext = strings.ToLower(path[lastDotIndex+1:]) ext = strings.ToLower(path[lastDotIndex+1:])
} }
// 如果没有扩展名规则,直接返回默认目标 // 如果没有扩展名规则,返回nil
if len(pathConfig.ExtRules) == 0 { if len(pathConfig.ExtRules) == 0 {
if ext == "" { return nil, false, false
log.Printf("[Route] %s -> %s (无扩展名)", path, targetBase)
}
return targetBase, false
}
// 确保有扩展名规则
if ext == "" {
log.Printf("[Route] %s -> %s (无扩展名)", path, targetBase)
// 即使没有扩展名,也要尝试匹配 * 通配符规则
} }
// 获取文件大小 // 获取文件大小
contentLength, err := GetFileSize(client, targetBase+path) contentLength, err := GetFileSize(client, pathConfig.DefaultTarget+path)
if err != nil { if err != nil {
log.Printf("[Route] %s -> %s (获取文件大小出错: %v)", path, targetBase, err) log.Printf("[SelectRule] %s -> 获取文件大小出错: %v", path, err)
// 如果无法获取文件大小,尝试使用扩展名直接匹配(优化点) // 如果无法获取文件大小,尝试使用扩展名直接匹配
if altTarget, exists := pathConfig.GetProcessedExtTarget(ext); exists { for _, rule := range pathConfig.ExtRules {
usedAltTarget = true // 检查具体扩展名匹配
targetBase = altTarget for _, e := range rule.Extensions {
log.Printf("[Route] %s -> %s (基于扩展名直接匹配)", path, targetBase) if e == ext {
} else if altTarget, exists := pathConfig.GetProcessedExtTarget("*"); exists { log.Printf("[SelectRule] %s -> 基于扩展名直接匹配规则", path)
// 尝试使用通配符 return &rule, true, true
usedAltTarget = true }
targetBase = altTarget }
log.Printf("[Route] %s -> %s (基于通配符匹配)", path, targetBase)
} }
return targetBase, usedAltTarget // 尝试使用通配符规则
for _, rule := range pathConfig.ExtRules {
for _, e := range rule.Extensions {
if e == "*" {
log.Printf("[SelectRule] %s -> 基于通配符匹配规则", path)
return &rule, true, true
}
}
}
return nil, false, false
} }
// 获取匹配的扩展名规则 // 获取匹配的扩展名规则
@ -265,10 +262,10 @@ func GetTargetURL(client *http.Client, r *http.Request, pathConfig config.PathCo
// 如果没有找到匹配的具体扩展名规则,使用通配符规则 // 如果没有找到匹配的具体扩展名规则,使用通配符规则
if len(matchingRules) == 0 { if len(matchingRules) == 0 {
if len(wildcardRules) > 0 { if len(wildcardRules) > 0 {
log.Printf("[Route] %s -> 使用通配符规则", path) log.Printf("[SelectRule] %s -> 使用通配符规则", path)
matchingRules = wildcardRules matchingRules = wildcardRules
} else { } else {
return targetBase, false return nil, false, false
} }
} }
@ -287,20 +284,69 @@ func GetTargetURL(client *http.Client, r *http.Request, pathConfig config.PathCo
// 检查文件大小是否在阈值范围内 // 检查文件大小是否在阈值范围内
if contentLength >= rule.SizeThreshold && contentLength <= rule.MaxSize { if contentLength >= rule.SizeThreshold && contentLength <= rule.MaxSize {
// 找到匹配的规则 // 找到匹配的规则
log.Printf("[Route] %s -> %s (文件大小: %s, 在区间 %s 到 %s 之间)", log.Printf("[SelectRule] %s -> 选中规则 (文件大小: %s, 在区间 %s 到 %s 之间)",
path, rule.Target, FormatBytes(contentLength), path, FormatBytes(contentLength),
FormatBytes(rule.SizeThreshold), FormatBytes(rule.MaxSize)) FormatBytes(rule.SizeThreshold), FormatBytes(rule.MaxSize))
// 检查目标是否可访问(使用带缓存的检查) // 检查目标是否可访问(使用带缓存的检查)
if isTargetAccessible(client, rule.Target+path) { if isTargetAccessible(client, rule.Target+path) {
targetBase = rule.Target return rule, true, true
usedAltTarget = true
} else { } else {
log.Printf("[Route] %s -> %s (回退: 备用目标不可访问)", log.Printf("[SelectRule] %s -> 规则目标不可访问,继续查找", path)
path, targetBase) // 继续查找下一个匹配的规则
continue
}
}
} }
break // 没有找到合适的规则
return nil, false, false
}
// GetTargetURL 根据路径和配置决定目标URL
func GetTargetURL(client *http.Client, r *http.Request, pathConfig config.PathConfig, path string) (string, bool) {
// 默认使用默认目标
targetBase := pathConfig.DefaultTarget
usedAltTarget := false
// 获取文件扩展名(使用优化的字符串处理)
ext := ""
lastDotIndex := strings.LastIndex(path, ".")
if lastDotIndex > 0 && lastDotIndex < len(path)-1 {
ext = strings.ToLower(path[lastDotIndex+1:])
}
// 如果没有扩展名规则,直接返回默认目标
if len(pathConfig.ExtRules) == 0 {
if ext == "" {
log.Printf("[Route] %s -> %s (无扩展名)", path, targetBase)
}
return targetBase, false
}
// 确保有扩展名规则
if ext == "" {
log.Printf("[Route] %s -> %s (无扩展名)", path, targetBase)
// 即使没有扩展名,也要尝试匹配 * 通配符规则
}
// 使用新的统一规则选择逻辑
rule, found, usedAlt := SelectBestRule(client, pathConfig, path)
if found && rule != nil {
targetBase = rule.Target
usedAltTarget = usedAlt
log.Printf("[Route] %s -> %s (使用选中的规则)", path, targetBase)
} else {
// 如果无法获取文件大小,尝试使用扩展名直接匹配(优化点)
if altTarget, exists := pathConfig.GetProcessedExtTarget(ext); exists {
usedAltTarget = true
targetBase = altTarget
log.Printf("[Route] %s -> %s (基于扩展名直接匹配)", path, targetBase)
} else if altTarget, exists := pathConfig.GetProcessedExtTarget("*"); exists {
// 尝试使用通配符
usedAltTarget = true
targetBase = altTarget
log.Printf("[Route] %s -> %s (基于通配符匹配)", path, targetBase)
} }
} }