mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 03:07:20 +08:00
feat: 优化代理缓存设置
This commit is contained in:
@@ -12,6 +12,38 @@ import (
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// parseDurationToSeconds 将时长字符串转换为秒数
|
||||
// 支持格式: "10s", "5m", "1h", "1d"
|
||||
func parseDurationToSeconds(duration string) int {
|
||||
duration = strings.TrimSpace(duration)
|
||||
if duration == "" {
|
||||
return 600 // 默认 10 分钟
|
||||
}
|
||||
|
||||
// 提取数字和单位
|
||||
re := regexp.MustCompile(`^(\d+)([smhd]?)$`)
|
||||
matches := re.FindStringSubmatch(duration)
|
||||
if matches == nil {
|
||||
return 600
|
||||
}
|
||||
|
||||
value, _ := strconv.Atoi(matches[1])
|
||||
unit := matches[2]
|
||||
|
||||
switch unit {
|
||||
case "s", "":
|
||||
return value
|
||||
case "m":
|
||||
return value * 60
|
||||
case "h":
|
||||
return value * 3600
|
||||
case "d":
|
||||
return value * 86400
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
// proxyFilePattern 匹配代理配置文件名 (200-299)
|
||||
var proxyFilePattern = regexp.MustCompile(`^(\d{3})-proxy\.conf$`)
|
||||
|
||||
@@ -104,7 +136,24 @@ func parseProxyFile(filePath string) (*types.Proxy, error) {
|
||||
|
||||
// 解析 CacheEnable
|
||||
if regexp.MustCompile(`CacheEnable`).MatchString(contentStr) {
|
||||
proxy.Cache = true
|
||||
proxy.Cache = &types.CacheConfig{
|
||||
Valid: make(map[string]string),
|
||||
NoCacheConditions: []string{},
|
||||
UseStale: []string{},
|
||||
Methods: []string{},
|
||||
}
|
||||
|
||||
// 解析 CacheDefaultExpire
|
||||
expirePattern := regexp.MustCompile(`CacheDefaultExpire\s+(\d+)`)
|
||||
if em := expirePattern.FindStringSubmatch(contentStr); em != nil {
|
||||
seconds, _ := strconv.Atoi(em[1])
|
||||
minutes := seconds / 60
|
||||
if minutes > 0 {
|
||||
proxy.Cache.Valid["any"] = fmt.Sprintf("%dm", minutes)
|
||||
} else {
|
||||
proxy.Cache.Valid["any"] = fmt.Sprintf("%ds", seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 Substitute (响应内容替换)
|
||||
@@ -243,10 +292,20 @@ func generateProxyConfig(proxy types.Proxy) string {
|
||||
}
|
||||
|
||||
// Cache 配置
|
||||
if proxy.Cache {
|
||||
if proxy.Cache != nil {
|
||||
sb.WriteString(" <IfModule mod_cache.c>\n")
|
||||
sb.WriteString(fmt.Sprintf(" CacheEnable disk %s\n", location))
|
||||
sb.WriteString(" CacheDefaultExpire 600\n")
|
||||
|
||||
// 从 Valid 中获取默认过期时间
|
||||
expireSeconds := 600 // 默认 10 分钟
|
||||
if len(proxy.Cache.Valid) > 0 {
|
||||
// 取第一个值作为默认过期时间
|
||||
for _, duration := range proxy.Cache.Valid {
|
||||
expireSeconds = parseDurationToSeconds(duration)
|
||||
break
|
||||
}
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf(" CacheDefaultExpire %d\n", expireSeconds))
|
||||
sb.WriteString(" </IfModule>\n")
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,70 @@ func parseProxyFile(filePath string) (*types.Proxy, error) {
|
||||
// 解析 proxy_cache
|
||||
cachePattern := regexp.MustCompile(`proxy_cache\s+(\S+);`)
|
||||
if cm := cachePattern.FindStringSubmatch(blockContent); cm != nil && cm[1] != "off" {
|
||||
proxy.Cache = true
|
||||
proxy.Cache = &types.CacheConfig{
|
||||
Valid: make(map[string]string),
|
||||
NoCacheConditions: []string{},
|
||||
UseStale: []string{},
|
||||
Methods: []string{},
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_valid
|
||||
cacheValidPattern := regexp.MustCompile(`proxy_cache_valid\s+([^;]+);`)
|
||||
cacheValidMatches := cacheValidPattern.FindAllStringSubmatch(blockContent, -1)
|
||||
for _, cvm := range cacheValidMatches {
|
||||
parts := strings.Fields(cvm[1])
|
||||
if len(parts) >= 2 {
|
||||
// 最后一个是时长,前面的是状态码
|
||||
duration := parts[len(parts)-1]
|
||||
codes := strings.Join(parts[:len(parts)-1], " ")
|
||||
proxy.Cache.Valid[codes] = duration
|
||||
} else if len(parts) == 1 {
|
||||
// 只有时长,表示 any
|
||||
proxy.Cache.Valid["any"] = parts[0]
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_bypass / proxy_no_cache
|
||||
bypassPattern := regexp.MustCompile(`proxy_cache_bypass\s+([^;]+);`)
|
||||
if bm := bypassPattern.FindStringSubmatch(blockContent); bm != nil {
|
||||
proxy.Cache.NoCacheConditions = strings.Fields(bm[1])
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_use_stale
|
||||
useStalePattern := regexp.MustCompile(`proxy_cache_use_stale\s+([^;]+);`)
|
||||
if usm := useStalePattern.FindStringSubmatch(blockContent); usm != nil {
|
||||
proxy.Cache.UseStale = strings.Fields(usm[1])
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_background_update
|
||||
bgUpdatePattern := regexp.MustCompile(`proxy_cache_background_update\s+(on|off);`)
|
||||
if bgm := bgUpdatePattern.FindStringSubmatch(blockContent); bgm != nil {
|
||||
proxy.Cache.BackgroundUpdate = bgm[1] == "on"
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_lock
|
||||
lockPattern := regexp.MustCompile(`proxy_cache_lock\s+(on|off);`)
|
||||
if lm := lockPattern.FindStringSubmatch(blockContent); lm != nil {
|
||||
proxy.Cache.Lock = lm[1] == "on"
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_min_uses
|
||||
minUsesPattern := regexp.MustCompile(`proxy_cache_min_uses\s+(\d+);`)
|
||||
if mum := minUsesPattern.FindStringSubmatch(blockContent); mum != nil {
|
||||
proxy.Cache.MinUses, _ = strconv.Atoi(mum[1])
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_methods
|
||||
methodsPattern := regexp.MustCompile(`proxy_cache_methods\s+([^;]+);`)
|
||||
if mm := methodsPattern.FindStringSubmatch(blockContent); mm != nil {
|
||||
proxy.Cache.Methods = strings.Fields(mm[1])
|
||||
}
|
||||
|
||||
// 解析 proxy_cache_key
|
||||
keyPattern := regexp.MustCompile(`proxy_cache_key\s+"?([^";]+)"?;`)
|
||||
if km := keyPattern.FindStringSubmatch(blockContent); km != nil {
|
||||
proxy.Cache.Key = strings.TrimSpace(km[1])
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 resolver
|
||||
@@ -272,10 +335,60 @@ func generateProxyConfig(proxy types.Proxy) string {
|
||||
sb.WriteString(fmt.Sprintf(" proxy_buffering %s;\n", lo.If(proxy.Buffering, "on").Else("off")))
|
||||
|
||||
// Cache 配置
|
||||
if proxy.Cache {
|
||||
if proxy.Cache != nil {
|
||||
sb.WriteString(" proxy_cache cache_one;\n")
|
||||
sb.WriteString(" proxy_cache_valid 200 302 10m;\n")
|
||||
sb.WriteString(" proxy_cache_valid 404 1m;\n")
|
||||
|
||||
// 缓存时长
|
||||
if len(proxy.Cache.Valid) > 0 {
|
||||
for codes, duration := range proxy.Cache.Valid {
|
||||
if codes == "any" {
|
||||
sb.WriteString(fmt.Sprintf(" proxy_cache_valid %s;\n", duration))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf(" proxy_cache_valid %s %s;\n", codes, duration))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 默认缓存时长
|
||||
sb.WriteString(" proxy_cache_valid 200 302 10m;\n")
|
||||
sb.WriteString(" proxy_cache_valid 404 1m;\n")
|
||||
}
|
||||
|
||||
// 不缓存条件
|
||||
if len(proxy.Cache.NoCacheConditions) > 0 {
|
||||
conditions := strings.Join(proxy.Cache.NoCacheConditions, " ")
|
||||
sb.WriteString(fmt.Sprintf(" proxy_cache_bypass %s;\n", conditions))
|
||||
sb.WriteString(fmt.Sprintf(" proxy_no_cache %s;\n", conditions))
|
||||
}
|
||||
|
||||
// 过期缓存使用策略
|
||||
if len(proxy.Cache.UseStale) > 0 {
|
||||
sb.WriteString(fmt.Sprintf(" proxy_cache_use_stale %s;\n", strings.Join(proxy.Cache.UseStale, " ")))
|
||||
}
|
||||
|
||||
// 后台更新
|
||||
if proxy.Cache.BackgroundUpdate {
|
||||
sb.WriteString(" proxy_cache_background_update on;\n")
|
||||
}
|
||||
|
||||
// 缓存锁
|
||||
if proxy.Cache.Lock {
|
||||
sb.WriteString(" proxy_cache_lock on;\n")
|
||||
}
|
||||
|
||||
// 最小请求次数
|
||||
if proxy.Cache.MinUses > 0 {
|
||||
sb.WriteString(fmt.Sprintf(" proxy_cache_min_uses %d;\n", proxy.Cache.MinUses))
|
||||
}
|
||||
|
||||
// 缓存方法
|
||||
if len(proxy.Cache.Methods) > 0 {
|
||||
sb.WriteString(fmt.Sprintf(" proxy_cache_methods %s;\n", strings.Join(proxy.Cache.Methods, " ")))
|
||||
}
|
||||
|
||||
// 自定义缓存键
|
||||
if proxy.Cache.Key != "" {
|
||||
sb.WriteString(fmt.Sprintf(" proxy_cache_key \"%s\";\n", proxy.Cache.Key))
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义请求头
|
||||
|
||||
@@ -2,13 +2,42 @@ package types
|
||||
|
||||
import "time"
|
||||
|
||||
// CacheConfig 缓存配置
|
||||
type CacheConfig struct {
|
||||
// 缓存时长,状态码 -> 时长,如: {"200 302": "10m", "404": "1m", "any": "5m"}
|
||||
Valid map[string]string `form:"valid" json:"valid"`
|
||||
|
||||
// 不缓存条件 (proxy_cache_bypass + proxy_no_cache)
|
||||
// 常用值: "$cookie_nocache", "$arg_nocache", "$http_pragma", "$http_authorization"
|
||||
NoCacheConditions []string `form:"no_cache_conditions" json:"no_cache_conditions"`
|
||||
|
||||
// 过期缓存使用策略 (proxy_cache_use_stale)
|
||||
// 可选值: "error", "timeout", "updating", "http_500", "http_502", "http_503", "http_504"
|
||||
UseStale []string `form:"use_stale" json:"use_stale"`
|
||||
|
||||
// 后台更新 (proxy_cache_background_update)
|
||||
BackgroundUpdate bool `form:"background_update" json:"background_update"`
|
||||
|
||||
// 缓存锁 (proxy_cache_lock),防止缓存击穿
|
||||
Lock bool `form:"lock" json:"lock"`
|
||||
|
||||
// 最小请求次数 (proxy_cache_min_uses),请求 N 次后才缓存
|
||||
MinUses int `form:"min_uses" json:"min_uses"`
|
||||
|
||||
// 缓存方法 (proxy_cache_methods),默认 GET HEAD
|
||||
Methods []string `form:"methods" json:"methods"`
|
||||
|
||||
// 自定义缓存键 (proxy_cache_key)
|
||||
Key string `form:"key" json:"key"`
|
||||
}
|
||||
|
||||
// Proxy 反向代理配置
|
||||
type Proxy struct {
|
||||
Location string `form:"location" json:"location" validate:"required"` // 匹配路径,如: "/", "/api", "~ ^/api/v[0-9]+/"
|
||||
Pass string `form:"pass" json:"pass" validate:"required"` // 代理地址,如: "http://example.com", "http://backend"
|
||||
Host string `form:"host" json:"host"` // 代理 Host,如: "example.com"
|
||||
SNI string `form:"sni" json:"sni"` // 代理 SNI,如: "example.com"
|
||||
Cache bool `form:"cache" json:"cache"` // 是否启用缓存
|
||||
Cache *CacheConfig `form:"cache" json:"cache"` // 缓存配置,nil 表示禁用缓存
|
||||
Buffering bool `form:"buffering" json:"buffering"` // 是否启用缓冲
|
||||
Resolver []string `form:"resolver" json:"resolver"` // 自定义 DNS 解析器配置,如: ["8.8.8.8", "ipv6=off"]
|
||||
ResolverTimeout time.Duration `form:"resolver_timeout" json:"resolver_timeout"` // DNS 解析超时时间,如: 5 * time.Second
|
||||
|
||||
Reference in New Issue
Block a user