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') }}
+
+
+ {
+ const newName = (e.target as HTMLInputElement).value
+ const oldName = String(headerName)
+ if (newName && newName !== oldName) {
+ proxy.headers[newName] = proxy.headers[oldName]
+ delete proxy.headers[oldName]
+ }
+ }
+ "
+ />
+ :
+ (proxy.headers[String(headerName)] = v)"
+ />
+
+ {{ $gettext('Remove') }}
+
+
+ {
+ if (!proxy.headers) proxy.headers = {}
+ proxy.headers[`X-Custom-${Object.keys(proxy.headers).length}`] = ''
+ }
+ "
+ >
+ {{ $gettext('Add Request Header') }}
+
+
{{ $gettext('Response Content Replacement') }}