From c4f6dd0be2729798d4bf6b4f006443c09c36cf0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Mon, 26 Jan 2026 18:30:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8F=8D=E5=90=91=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/webserver/apache/proxy.go | 21 ++++++++++++ pkg/webserver/nginx/proxy.go | 30 +++++++++++++++++ pkg/webserver/types/proxy.go | 1 + web/src/views/website/EditView.vue | 54 ++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) diff --git a/pkg/webserver/apache/proxy.go b/pkg/webserver/apache/proxy.go index 2a624c96..108d5fba 100644 --- a/pkg/webserver/apache/proxy.go +++ b/pkg/webserver/apache/proxy.go @@ -66,6 +66,7 @@ func parseProxyFile(filePath string) (*types.Proxy, error) { contentStr := string(content) proxy := &types.Proxy{ Resolver: []string{}, + Headers: make(map[string]string), Replaces: make(map[string]string), } @@ -114,6 +115,17 @@ func parseProxyFile(filePath string) (*types.Proxy, error) { proxy.Replaces[sm[1]] = sm[2] } + // 解析自定义请求头 (排除 Host) + headerPattern := regexp.MustCompile(`RequestHeader\s+set\s+(\S+)\s+"([^"]+)"`) + headerMatches := headerPattern.FindAllStringSubmatch(contentStr, -1) + for _, hm := range headerMatches { + headerName := hm[1] + headerValue := hm[2] + if headerName != "Host" { + proxy.Headers[headerName] = headerValue + } + } + return proxy, nil } @@ -241,6 +253,15 @@ func generateProxyConfig(proxy types.Proxy) string { sb.WriteString(" \n") } + // 自定义请求头 + if len(proxy.Headers) > 0 { + sb.WriteString(" \n") + for name, value := range proxy.Headers { + sb.WriteString(fmt.Sprintf(" RequestHeader set %s \"%s\"\n", name, value)) + } + sb.WriteString(" \n") + } + // 响应内容替换 if len(proxy.Replaces) > 0 { sb.WriteString(" \n") diff --git a/pkg/webserver/nginx/proxy.go b/pkg/webserver/nginx/proxy.go index 7f5d5143..eecdac0e 100644 --- a/pkg/webserver/nginx/proxy.go +++ b/pkg/webserver/nginx/proxy.go @@ -77,6 +77,7 @@ func parseProxyFile(filePath string) (*types.Proxy, error) { proxy := &types.Proxy{ Location: strings.TrimSpace(matches[1]), Resolver: []string{}, + Headers: make(map[string]string), Replaces: make(map[string]string), } @@ -146,6 +147,23 @@ func parseProxyFile(filePath string) (*types.Proxy, error) { proxy.Replaces[sfm[1]] = sfm[2] } + // 解析自定义请求头 + standardHeaders := map[string]bool{ + "Host": true, "X-Real-IP": true, "X-Forwarded-For": true, + "X-Forwarded-Proto": true, "Upgrade": true, "Connection": true, + "Early-Data": true, "Accept-Encoding": true, + } + headerPattern := regexp.MustCompile(`proxy_set_header\s+(\S+)\s+"?([^";]+)"?;`) + headerMatches := headerPattern.FindAllStringSubmatch(blockContent, -1) + for _, hm := range headerMatches { + headerName := strings.TrimSpace(hm[1]) + headerValue := strings.TrimSpace(hm[2]) + // 排除标准头 + if !standardHeaders[headerName] { + proxy.Headers[headerName] = headerValue + } + } + return proxy, nil } @@ -269,6 +287,18 @@ func generateProxyConfig(proxy types.Proxy) string { sb.WriteString(" proxy_cache_valid 404 1m;\n") } + // 自定义请求头 + if len(proxy.Headers) > 0 { + for name, value := range proxy.Headers { + // 变量值不加引号 + if strings.HasPrefix(value, "$") { + sb.WriteString(fmt.Sprintf(" proxy_set_header %s %s;\n", name, value)) + } else { + sb.WriteString(fmt.Sprintf(" proxy_set_header %s \"%s\";\n", name, value)) + } + } + } + // 响应内容替换 if len(proxy.Replaces) > 0 { sb.WriteString(" proxy_set_header Accept-Encoding \"\";\n") diff --git a/pkg/webserver/types/proxy.go b/pkg/webserver/types/proxy.go index 9002207c..2c621bb5 100644 --- a/pkg/webserver/types/proxy.go +++ b/pkg/webserver/types/proxy.go @@ -12,6 +12,7 @@ type Proxy struct { 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 + Headers map[string]string `form:"headers" json:"headers"` // 自定义请求头,如: map["X-Custom-Header"] = "value" Replaces map[string]string `form:"replaces" json:"replaces"` // 响应内容替换,如: map["/old"] = "/new" } diff --git a/web/src/views/website/EditView.vue b/web/src/views/website/EditView.vue index 67c9c426..249cb3b1 100644 --- a/web/src/views/website/EditView.vue +++ b/web/src/views/website/EditView.vue @@ -303,6 +303,7 @@ const addProxy = () => { buffering: true, resolver: [], resolver_timeout: 5 * 1000000000, // 5秒,以纳秒为单位 + headers: {}, replaces: {} }) } @@ -845,6 +846,59 @@ const removeCustomConfig = (index: number) => { + {{ $gettext('Custom Request Headers') }} + + + + : + + + {{ $gettext('Remove') }} + + + + {{ $gettext('Add Request Header') }} + + {{ $gettext('Response Content Replacement') }}