From 01288981368f01760d5b143bffcb413387ca57e2 Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 2 Apr 2026 18:12:44 +0800 Subject: [PATCH] =?UTF-8?q?docs(proxy,loadbalance):=20=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E8=8B=B1=E6=96=87=E6=B3=A8=E9=87=8A=E4=B8=BA=E4=B8=AD=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 internal/proxy 和 internal/loadbalance 模块的英文注释翻译为中文, 保持项目注释语言一致性。 Co-Authored-By: Claude --- internal/loadbalance/balancer.go | 136 ++++++++++++++-------------- internal/proxy/health.go | 112 +++++++++++------------ internal/proxy/proxy.go | 149 +++++++++++++++---------------- 3 files changed, 197 insertions(+), 200 deletions(-) diff --git a/internal/loadbalance/balancer.go b/internal/loadbalance/balancer.go index a57560f..5a03932 100644 --- a/internal/loadbalance/balancer.go +++ b/internal/loadbalance/balancer.go @@ -1,10 +1,10 @@ -// Package loadbalance provides load balancing algorithms for the Lolly HTTP server. +// Package loadbalance 负载均衡包为 Lolly HTTP 服务器提供负载均衡算法。 // -// This package implements various load balancing strategies including round-robin, -// weighted round-robin, least connections, and IP hash. All implementations are -// concurrency-safe using atomic operations. +// 本包实现了多种负载均衡策略,包括轮询(round-robin)、 +// 权重轮询(weighted round-robin)、最少连接(least connections)和 IP 哈希(IP hash)。 +// 所有实现都使用原子操作来保证并发安全。 // -// Example usage: +// 使用示例: // // targets := []*Target{ // {URL: "http://backend1:8080", Weight: 1, Healthy: true}, @@ -22,84 +22,83 @@ import ( "sync/atomic" ) -// Target represents a backend server target for load balancing. -// All fields are designed for concurrent access using atomic operations -// where applicable. +// Target 表示负载均衡的后端服务器目标。 +// 所有字段都设计为使用原子操作进行并发访问(如适用)。 type Target struct { - // URL is the target address, e.g., "http://backend1:8080" + // URL 是目标地址,例如 "http://backend1:8080" URL string - // Weight is the weight of this target for weighted algorithms. - // Higher weight means more requests will be routed to this target. + // Weight 是此目标在权重算法中的权重值。 + // 权重越高,表示有更多请求会被路由到此目标。 Weight int - // Healthy indicates whether this target is healthy and available. - // Use atomic operations to read/write this field concurrently. + // Healthy 表示此目标是否健康可用。 + // 并发读写此字段时应使用原子操作。 Healthy bool - // Connections tracks the current number of active connections. - // Use atomic operations to modify this field concurrently. + // Connections 跟踪当前活跃连接数。 + // 并发修改此字段时应使用原子操作。 Connections int64 } -// Balancer is the interface for load balancing algorithms. -// Implementations must be safe for concurrent use. +// Balancer 是负载均衡算法的接口。 +// 实现必须是并发安全的。 type Balancer interface { - // Select chooses a target from the provided list based on the - // algorithm's strategy. Returns nil if no healthy targets are available. + // Select 根据算法策略从提供的列表中选择一个目标。 + // 如果没有健康目标可用,返回 nil。 Select(targets []*Target) *Target } -// RoundRobin implements simple round-robin load balancing. -// It distributes requests evenly across all healthy targets in sequence. +// RoundRobin 实现简单的轮询负载均衡。 +// 它按顺序将请求均匀分配到所有健康目标上。 type RoundRobin struct { - // counter is incremented atomically for each request + // counter 原子地为每个请求递增 counter uint64 } -// NewRoundRobin creates a new round-robin load balancer. +// NewRoundRobin 创建一个新的轮询负载均衡器。 func NewRoundRobin() *RoundRobin { return &RoundRobin{} } -// Select chooses the next target in round-robin order. -// Only healthy targets are considered. Returns nil if no healthy targets exist. +// Select 选择轮询顺序中的下一个目标。 +// 只考虑健康目标。如果没有健康目标则返回 nil。 func (r *RoundRobin) Select(targets []*Target) *Target { healthy := filterHealthy(targets) if len(healthy) == 0 { return nil } - // Atomically increment and get the counter value + // 原子地递增并获取计数器值 idx := atomic.AddUint64(&r.counter, 1) - 1 return healthy[idx%uint64(len(healthy))] } -// WeightedRoundRobin implements weighted round-robin load balancing. -// Targets with higher weights receive proportionally more requests. +// WeightedRoundRobin 实现权重轮询负载均衡。 +// 权重越高的目标接收成比例更多的请求。 type WeightedRoundRobin struct { - // counter is incremented atomically for each request + // counter 原子地为每个请求递增 counter uint64 } -// NewWeightedRoundRobin creates a new weighted round-robin load balancer. +// NewWeightedRoundRobin 创建一个新的权重轮询负载均衡器。 func NewWeightedRoundRobin() *WeightedRoundRobin { return &WeightedRoundRobin{} } -// Select chooses a target based on weight distribution. -// Only healthy targets are considered. Returns nil if no healthy targets exist. +// Select 基于权重分布选择目标。 +// 只考虑健康目标。如果没有健康目标则返回 nil。 func (w *WeightedRoundRobin) Select(targets []*Target) *Target { healthy := filterHealthy(targets) if len(healthy) == 0 { return nil } - // Calculate total weight + // 计算总权重 totalWeight := 0 for _, t := range healthy { if t.Weight <= 0 { - totalWeight += 1 // Minimum weight of 1 + totalWeight += 1 // 最小权重为 1 } else { totalWeight += t.Weight } @@ -109,11 +108,11 @@ func (w *WeightedRoundRobin) Select(targets []*Target) *Target { return nil } - // Use atomic counter to determine position in weight distribution + // 使用原子计数器确定权重分布中的位置 idx := atomic.AddUint64(&w.counter, 1) - 1 pos := int(idx % uint64(totalWeight)) - // Find target at the calculated position + // 找到计算位置处的目标 currentWeight := 0 for _, t := range healthy { weight := t.Weight @@ -126,21 +125,21 @@ func (w *WeightedRoundRobin) Select(targets []*Target) *Target { } } - // Fallback to last target (should not reach here) + // 回退到最后一个目标(不应到达这里) return healthy[len(healthy)-1] } -// LeastConnections implements least connections load balancing. -// It selects the target with the fewest active connections. +// LeastConnections 实现最少连接负载均衡。 +// 它选择活跃连接数最少的目标。 type LeastConnections struct{} -// NewLeastConnections creates a new least-connections load balancer. +// NewLeastConnections 创建一个新的最少连接负载均衡器。 func NewLeastConnections() *LeastConnections { return &LeastConnections{} } -// Select chooses the target with the minimum connection count. -// Only healthy targets are considered. Returns nil if no healthy targets exist. +// Select 选择连接数最少的目标。 +// 只考虑健康目标。如果没有健康目标则返回 nil。 func (l *LeastConnections) Select(targets []*Target) *Target { var selected *Target var minConns int64 = -1 @@ -150,7 +149,7 @@ func (l *LeastConnections) Select(targets []*Target) *Target { continue } - // Atomically read the connection count + // 原子地读取连接计数 conns := atomic.LoadInt64(&t.Connections) if selected == nil || conns < minConns { @@ -162,31 +161,31 @@ func (l *LeastConnections) Select(targets []*Target) *Target { return selected } -// IPHash implements IP hash-based load balancing. -// It consistently routes requests from the same client IP to the same target. +// IPHash 实现基于 IP 哈希的负载均衡。 +// 它将来自同一客户端 IP 的请求始终路由到同一目标。 type IPHash struct{} -// NewIPHash creates a new IP hash load balancer. +// NewIPHash 创建一个新的 IP 哈希负载均衡器。 func NewIPHash() *IPHash { return &IPHash{} } -// Select chooses a target based on the hash of the client IP. -// Only healthy targets are considered. Returns nil if no healthy targets exist. -// The clientIP parameter should be the client's IP address as a string. +// Select 基于客户端 IP 的哈希值选择目标。 +// 只考虑健康目标。如果没有健康目标则返回 nil。 +// clientIP 参数应该是客户端的 IP 地址字符串。 func (i *IPHash) Select(targets []*Target) *Target { return i.SelectByIP(targets, "") } -// SelectByIP chooses a target based on the hash of the provided IP address. -// Only healthy targets are considered. Returns nil if no healthy targets exist. +// SelectByIP 基于提供的 IP 地址的哈希值选择目标。 +// 只考虑健康目标。如果没有健康目标则返回 nil。 func (i *IPHash) SelectByIP(targets []*Target, clientIP string) *Target { healthy := filterHealthy(targets) if len(healthy) == 0 { return nil } - // Hash the client IP + // 对客户端 IP 进行哈希 h := fnv.New64a() h.Write([]byte(clientIP)) hash := h.Sum64() @@ -195,8 +194,8 @@ func (i *IPHash) SelectByIP(targets []*Target, clientIP string) *Target { return healthy[idx] } -// filterHealthy returns a new slice containing only healthy targets. -// This is a helper function used by load balancing implementations. +// filterHealthy 返回仅包含健康目标的新切片。 +// 这是负载均衡实现使用的辅助函数。 func filterHealthy(targets []*Target) []*Target { healthy := make([]*Target, 0, len(targets)) for _, t := range targets { @@ -207,33 +206,32 @@ func filterHealthy(targets []*Target) []*Target { return healthy } -// IncrementConnections atomically increments the connection count for a target. -// This should be called when a new connection is established. +// IncrementConnections 原子地增加目标的连接计数。 +// 当新连接建立时应调用此函数。 func IncrementConnections(t *Target) { atomic.AddInt64(&t.Connections, 1) } -// DecrementConnections atomically decrements the connection count for a target. -// This should be called when a connection is closed. +// DecrementConnections 原子地减少目标的连接计数。 +// 当连接关闭时应调用此函数。 func DecrementConnections(t *Target) { atomic.AddInt64(&t.Connections, -1) } -// IsHealthy atomically reads the health status of a target. +// IsHealthy 原子地读取目标的健康状态。 func IsHealthy(t *Target) bool { - // Healthy is a bool, which is safe to read without atomic operations - // but for consistency with the setter, we could use atomic - // For bool, simple read is safe in Go's memory model + // Healthy 是 bool 类型,在 Go 的内存模型中无需原子操作即可安全读取 + // 但为了与 setter 保持一致,我们可以使用原子操作 + // 对于 bool,简单的读取是安全的 return t.Healthy } -// SetHealthy atomically sets the health status of a target. -// Note: In Go, bool operations are not directly atomic. -// This function provides a synchronized way to update health status. -// For true atomic operations on bool, consider using atomic.Bool (Go 1.19+) -// or sync.RWMutex. For this implementation, we use direct assignment -// which is typically sufficient when combined with proper synchronization -// at the caller level. +// SetHealthy 原子地设置目标的健康状态。 +// 注意:在 Go 中,bool 操作不能直接是原子的。 +// 此函数提供了同步更新健康状态的方式。 +// 对于 bool 的真正原子操作,请考虑使用 atomic.Bool(Go 1.19+) +// 或 sync.RWMutex。对于本实现,我们使用直接赋值 +// 当与调用层的适当同步结合时,这通常是足够的。 func SetHealthy(t *Target, healthy bool) { t.Healthy = healthy } diff --git a/internal/proxy/health.go b/internal/proxy/health.go index 6b722fa..b8eed70 100644 --- a/internal/proxy/health.go +++ b/internal/proxy/health.go @@ -1,8 +1,8 @@ // Package proxy provides reverse proxy functionality for the Lolly HTTP server. // -// This file implements health checking for backend targets, supporting both -// active health checks (periodic HTTP probes) and passive health checks -// (marking targets unhealthy based on observed failures). +// 此文件实现了针对后端目标的健康检查功能,支持 +// 主动健康检查(定期 HTTP 探测)和被动健康检查 +//(基于观察到的失败标记目标为不健康)。 // //go:generate go test -v ./... package proxy @@ -18,14 +18,14 @@ import ( "rua.plus/lolly/internal/loadbalance" ) -// HealthChecker performs health checks on backend targets. -// It supports both active (periodic HTTP probes) and passive (failure-based) -// health checking modes. +// HealthChecker 对后端目标执行健康检查。 +// 它支持主动(定期 HTTP 探测)和被动(基于失败的) +// 两种健康检查模式。 // -// The checker runs in a background goroutine when started, periodically -// sending HTTP GET requests to each target's health check endpoint. -// Targets responding with 2xx status codes are marked as healthy; -// timeouts, connection failures, or non-2xx responses mark them as unhealthy. +// 当启动后,检查器在后台 goroutine 中运行,定期 +// 向每个目标的健康检查端点发送 HTTP GET 请求。 +// 返回 2xx 状态码的目标被标记为健康; +// 超时、连接失败或非 2xx 响应将其标记为不健康。 // // Example usage: // @@ -54,15 +54,15 @@ type HealthChecker struct { mu sync.RWMutex } -// NewHealthChecker creates a new HealthChecker with the specified targets and configuration. -// The configuration defines the check interval, timeout, and health check path. +// NewHealthChecker 使用指定的目标和配置创建一个新的 HealthChecker。 +// 配置定义了检查间隔、超时和健康检查路径。 // -// Default values are applied if not specified in the config: -// - Interval: 10 seconds -// - Timeout: 5 seconds +// 如果配置中未指定,将应用默认值: +// - Interval: 10 秒 +// - Timeout: 5 秒 // - Path: "/health" // -// The returned HealthChecker is not started; call Start() to begin health checks. +// 返回的 HealthChecker 尚未启动;调用 Start() 开始健康检查。 func NewHealthChecker(targets []*loadbalance.Target, cfg *config.HealthCheckConfig) *HealthChecker { interval := cfg.Interval if interval <= 0 { @@ -92,11 +92,11 @@ func NewHealthChecker(targets []*loadbalance.Target, cfg *config.HealthCheckConf } } -// Start begins the background health check process. -// It launches a goroutine that periodically checks all targets at the configured interval. -// Start is idempotent; calling it on an already running checker has no effect. +// Start 启动后台健康检查进程。 +// 它启动一个 goroutine,按照配置的间隔定期检查所有目标。 +// Start 是幂等的;在已运行的检查器上调用它不会产生任何效果。 // -// The health check process continues until Stop() is called. +// 健康检查进程将持续运行,直到调用 Stop()。 func (h *HealthChecker) Start() { if h.running.Load() { return @@ -106,9 +106,9 @@ func (h *HealthChecker) Start() { go h.run() } -// Stop halts the background health check process. -// It signals the background goroutine to stop and waits for it to complete. -// Stop is idempotent; calling it on a stopped checker has no effect. +// Stop 停止后台健康检查进程。 +// 它向后台 goroutine 发送停止信号并等待其完成。 +// Stop 是幂等的;在已停止的检查器上调用它不会产生任何效果。 func (h *HealthChecker) Stop() { if !h.running.Load() { return @@ -118,11 +118,11 @@ func (h *HealthChecker) Stop() { close(h.stopCh) } -// run is the main health check loop running in a background goroutine. -// It performs an initial check on all targets, then enters a loop that -// checks targets at regular intervals until stopped. +// run 是在后台 goroutine 中运行的主要健康检查循环。 +// 它对所有目标执行初始检查,然后进入循环, +// 以固定间隔检查目标,直到被停止。 func (h *HealthChecker) run() { - // Perform initial health check + // 执行初始健康检查 h.checkAll() ticker := time.NewTicker(h.interval) @@ -138,8 +138,8 @@ func (h *HealthChecker) run() { } } -// checkAll performs health checks on all configured targets. -// It checks each target concurrently using goroutines to minimize latency. +// checkAll 对所有配置的目标执行健康检查。 +// 它使用 goroutines 并发检查每个目标以最小化延迟。 func (h *HealthChecker) checkAll() { var wg sync.WaitGroup @@ -154,23 +154,23 @@ func (h *HealthChecker) checkAll() { wg.Wait() } -// checkTarget performs a health check on a single target. -// It sends an HTTP GET request to the target's health check endpoint -// and updates the target's Healthy status based on the response. +// checkTarget 对单个目标执行健康检查。 +// 它向目标的健康检查端点发送 HTTP GET 请求 +// 并根据响应更新目标的 Healthy 状态。 // -// A target is considered healthy if: -// - The HTTP request succeeds -// - The response status code is between 200 and 299 +// 目标被认为健康,如果满足以下条件: +// - HTTP 请求成功 +// - 响应状态码在 200 到 299 之间 // -// A target is marked unhealthy if: -// - The connection fails -// - The request times out -// - The response status code is not 2xx +// 目标被标记为不健康,如果满足以下条件: +// - 连接失败 +// - 请求超时 +// - 响应状态码不是 2xx func (h *HealthChecker) checkTarget(target *loadbalance.Target) { - // Build health check URL + // 构建健康检查 URL url := target.URL + h.path - // Prepare request and response + // 准备请求和响应 req := fasthttp.AcquireRequest() resp := fasthttp.AcquireResponse() defer fasthttp.ReleaseRequest(req) @@ -180,16 +180,16 @@ func (h *HealthChecker) checkTarget(target *loadbalance.Target) { req.Header.SetMethod(fasthttp.MethodGet) req.Header.Set("User-Agent", "Lolly-HealthChecker/1.0") - // Perform health check with timeout + // 执行带超时的健康检查 err := h.client.DoTimeout(req, resp, h.timeout) if err != nil { - // Connection failed or timeout - mark as unhealthy + // 连接失败或超时 - 标记为不健康 loadbalance.SetHealthy(target, false) return } - // Check status code - 2xx is healthy + // 检查状态码 - 2xx 为健康 statusCode := resp.StatusCode() if statusCode >= 200 && statusCode < 300 { loadbalance.SetHealthy(target, true) @@ -198,44 +198,44 @@ func (h *HealthChecker) checkTarget(target *loadbalance.Target) { } } -// MarkUnhealthy marks a target as unhealthy. -// This method is intended for passive health checking, where the proxy -// marks targets as unhealthy based on observed failures during request handling. +// MarkUnhealthy 将目标标记为不健康。 +// 此方法用于被动健康检查,代理根据请求处理过程中 +// 观察到的失败将目标标记为不健康。 // -// Example usage in proxy error handling: +// 在代理错误处理中的使用示例: // // if err := forwardRequest(target, req, resp); err != nil { // healthChecker.MarkUnhealthy(target) -// // Try another target or return error +// // 尝试其他目标或返回错误 // } // -// Note: To mark a target as healthy again, the active health check -// must succeed. There is no MarkHealthy method - health status can only -// be positively restored through successful health checks. +// 注意:要再次将目标标记为健康,主动健康检查 +// 必须成功。没有 MarkHealthy 方法 - 健康状态只能通过 +// 成功的健康检查积极恢复。 func (h *HealthChecker) MarkUnhealthy(target *loadbalance.Target) { loadbalance.SetHealthy(target, false) } -// IsRunning returns true if the health checker is currently running. +// IsRunning 如果健康检查器当前正在运行,则返回 true。 func (h *HealthChecker) IsRunning() bool { return h.running.Load() } -// GetInterval returns the configured check interval. +// GetInterval 返回配置的检查间隔。 func (h *HealthChecker) GetInterval() time.Duration { h.mu.RLock() defer h.mu.RUnlock() return h.interval } -// GetTimeout returns the configured check timeout. +// GetTimeout 返回配置的检查超时时间。 func (h *HealthChecker) GetTimeout() time.Duration { h.mu.RLock() defer h.mu.RUnlock() return h.timeout } -// GetPath returns the configured health check path. +// GetPath 返回配置的健康检查路径。 func (h *HealthChecker) GetPath() string { h.mu.RLock() defer h.mu.RUnlock() diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 45962e2..4fffa3d 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -1,10 +1,9 @@ -// Package proxy provides reverse proxy functionality for the Lolly HTTP server. +// Package proxy 反向代理包,为 Lolly HTTP 服务器提供反向代理功能。 // -// This package implements a high-performance reverse proxy using fasthttp.HostClient -// for connection pooling and automatic keep-alive management. It supports load balancing, -// WebSocket forwarding, custom headers, and comprehensive timeout configurations. +// 该包使用 fasthttp.HostClient 实现高性能反向代理,支持连接池和自动 keep-alive 管理。 +// 支持负载均衡、WebSocket 转发、自定义请求头/响应头和全面的超时配置。 // -// Example usage: +// 使用示例: // // targets := []*loadbalance.Target{ // {URL: "http://backend1:8080", Weight: 1, Healthy: true}, @@ -26,7 +25,7 @@ // log.Fatal(err) // } // -// // Use p.ServeHTTP as fasthttp request handler +// // 使用 p.ServeHTTP 作为 fasthttp 请求处理器 // //go:generate go test -v ./... package proxy @@ -43,8 +42,8 @@ import ( "rua.plus/lolly/internal/loadbalance" ) -// Proxy represents a reverse proxy instance that forwards HTTP requests to backend targets. -// It manages connection pools for each target and provides load balancing capabilities. +// Proxy 表示反向代理实例,负责将 HTTP 请求转发到后端目标。 +// 它为每个后端目标管理连接池,并提供负载均衡功能。 type Proxy struct { targets []*loadbalance.Target clients map[string]*fasthttp.HostClient // key: target URL @@ -53,16 +52,16 @@ type Proxy struct { mu sync.RWMutex } -// NewProxy creates a new reverse proxy instance with the given configuration and targets. -// It initializes the load balancer based on the config and creates HostClients for each target. +// NewProxy 使用给定的配置和后台目标创建一个新的反向代理实例。 +// 它根据配置初始化负载均衡器,并为每个后端目标创建 HostClient。 // -// Parameters: -// - cfg: Proxy configuration including timeouts, headers, and load balancing strategy -// - targets: List of backend targets to proxy requests to +// 参数: +// - cfg: 代理配置,包括超时时间、请求头和负载均衡策略 +// - targets: 要代理请求的后端目标列表 // -// Returns: -// - *Proxy: Configured proxy instance ready to serve requests -// - error: Non-nil if initialization fails (invalid config, no healthy targets, etc.) +// 返回值: +// - *Proxy: 配置完成并可处理请求的代理实例 +// - error: 初始化失败时非空(无效配置、没有健康目标等) func NewProxy(cfg *config.ProxyConfig, targets []*loadbalance.Target) (*Proxy, error) { if cfg == nil { return nil, errors.New("proxy config is nil") @@ -72,7 +71,7 @@ func NewProxy(cfg *config.ProxyConfig, targets []*loadbalance.Target) (*Proxy, e return nil, errors.New("no proxy targets provided") } - // Create balancer based on configuration + // 根据配置创建负载均衡器 balancer, err := createBalancer(cfg.LoadBalance) if err != nil { return nil, err @@ -85,7 +84,7 @@ func NewProxy(cfg *config.ProxyConfig, targets []*loadbalance.Target) (*Proxy, e config: cfg, } - // Initialize HostClient for each target + // 为每个后端目标初始化 HostClient for _, target := range targets { if target.URL == "" { continue @@ -98,7 +97,7 @@ func NewProxy(cfg *config.ProxyConfig, targets []*loadbalance.Target) (*Proxy, e return p, nil } -// createBalancer creates a load balancer based on the configured algorithm. +// createBalancer 根据配置的算法创建负载均衡器。 func createBalancer(algorithm string) (loadbalance.Balancer, error) { switch algorithm { case "round_robin", "": @@ -114,9 +113,9 @@ func createBalancer(algorithm string) (loadbalance.Balancer, error) { } } -// createHostClient creates a fasthttp.HostClient for a target URL. +// createHostClient 为后台目标 URL 创建 fasthttp.HostClient。 func createHostClient(targetURL string, timeout config.ProxyTimeout) *fasthttp.HostClient { - // Parse host and scheme from target URL + // 从目标 URL 解析主机和协议 addr := targetURL isTLS := false @@ -127,7 +126,7 @@ func createHostClient(targetURL string, timeout config.ProxyTimeout) *fasthttp.H isTLS = true } - // Remove path if present, keep only host:port + // 如果存在路径则移除,只保留 host:port if idx := strings.Index(addr, "/"); idx != -1 { addr = addr[:idx] } @@ -148,52 +147,52 @@ func createHostClient(targetURL string, timeout config.ProxyTimeout) *fasthttp.H return client } -// ServeHTTP handles the incoming HTTP request by forwarding it to a selected backend target. -// It implements the fasthttp request handler interface. +// ServeHTTP 通过将传入的 HTTP 请求转发到选定的后端目标来处理请求。 +// 实现了 fasthttp 请求处理器接口。 // -// The method: -// 1. Selects a target using load balancing -// 2. Prepares the request (modifies headers) -// 3. Forwards the request to the backend -// 4. Copies the response back to the client +// 处理流程: +// 1. 使用负载均衡选择目标 +// 2. 准备请求(修改请求头) +// 3. 将请求转发到后端 +// 4. 将响应复制回客户端 // -// If no healthy targets are available, returns 502 Bad Gateway. -// If the backend request fails, returns appropriate error response. +// 如果没有可用的健康目标,返回 502 Bad Gateway。 +// 如果后端请求失败,返回相应的错误响应。 func (p *Proxy) ServeHTTP(ctx *fasthttp.RequestCtx) { - // Select target using load balancer + // 使用负载均衡器选择目标 target := p.selectTarget(ctx) if target == nil { ctx.Error("Bad Gateway: no healthy upstream", fasthttp.StatusBadGateway) return } - // Get the client for selected target + // 获取所选目标的客户端 client := p.getClient(target.URL) if client == nil { ctx.Error("Bad Gateway: upstream client unavailable", fasthttp.StatusBadGateway) return } - // Increment connection count for least_connections tracking + // 增加连接计数(用于最少连接数负载均衡) loadbalance.IncrementConnections(target) defer loadbalance.DecrementConnections(target) - // Check if this is a WebSocket upgrade request + // 检查是否为 WebSocket 升级请求 if isWebSocketRequest(ctx) { p.handleWebSocket(ctx, target, client) return } - // Prepare request + // 准备请求 req := &ctx.Request - // Modify request headers + // 修改请求头 p.modifyRequestHeaders(ctx, target) - // Perform the proxy request + // 执行代理请求 err := client.Do(req, &ctx.Response) if err != nil { - // Handle different error types + // 处理不同类型的错误 if errors.Is(err, fasthttp.ErrTimeout) { ctx.Error("Gateway Timeout", fasthttp.StatusGatewayTimeout) } else if errors.Is(err, fasthttp.ErrConnectionClosed) { @@ -204,13 +203,13 @@ func (p *Proxy) ServeHTTP(ctx *fasthttp.RequestCtx) { return } - // Modify response headers + // 修改响应头 p.modifyResponseHeaders(ctx) } -// selectTarget selects a backend target using the configured load balancer. -// It extracts the client IP from the request for IP hash balancing. -// Returns nil if no healthy targets are available. +// selectTarget 使用配置的负载均衡器选择后端目标。 +// 对于 IP 哈希负载均衡,从请求中提取客户端 IP。 +// 如果没有可用的健康目标则返回 nil。 func (p *Proxy) selectTarget(ctx *fasthttp.RequestCtx) *loadbalance.Target { p.mu.RLock() balancer := p.balancer @@ -221,7 +220,7 @@ func (p *Proxy) selectTarget(ctx *fasthttp.RequestCtx) *loadbalance.Target { return nil } - // For IPHash balancer, extract client IP + // 对于 IPHash 负载均衡器,提取客户端 IP if ipHash, ok := balancer.(*loadbalance.IPHash); ok { clientIP := getClientIP(ctx) return ipHash.SelectByIP(targets, clientIP) @@ -230,9 +229,9 @@ func (p *Proxy) selectTarget(ctx *fasthttp.RequestCtx) *loadbalance.Target { return balancer.Select(targets) } -// getClientIP extracts the client IP address from the request context. +// getClientIP 从请求上下文中提取客户端 IP 地址。 func getClientIP(ctx *fasthttp.RequestCtx) string { - // Check X-Forwarded-For header first + // 首先检查 X-Forwarded-For 请求头 if xff := ctx.Request.Header.Peek("X-Forwarded-For"); len(xff) > 0 { ips := strings.Split(string(xff), ",") if len(ips) > 0 { @@ -240,12 +239,12 @@ func getClientIP(ctx *fasthttp.RequestCtx) string { } } - // Check X-Real-IP header + // 检查 X-Real-IP 请求头 if xri := ctx.Request.Header.Peek("X-Real-IP"); len(xri) > 0 { return string(xri) } - // Fall back to RemoteAddr + // 回退到 RemoteAddr if addr := ctx.RemoteAddr(); addr != nil { if tcpAddr, ok := addr.(*net.TCPAddr); ok { return tcpAddr.IP.String() @@ -256,7 +255,7 @@ func getClientIP(ctx *fasthttp.RequestCtx) string { return "" } -// getClient returns the HostClient for a given target URL. +// getClient 返回给定目标 URL 对应的 HostClient。 func (p *Proxy) getClient(targetURL string) *fasthttp.HostClient { p.mu.RLock() client := p.clients[targetURL] @@ -264,18 +263,18 @@ func (p *Proxy) getClient(targetURL string) *fasthttp.HostClient { return client } -// modifyRequestHeaders modifies the request headers before forwarding to backend. -// It adds standard proxy headers and applies custom header configurations. +// modifyRequestHeaders 在转发到后端之前修改请求头。 +// 添加标准代理请求头并应用自定义请求头配置。 func (p *Proxy) modifyRequestHeaders(ctx *fasthttp.RequestCtx, target *loadbalance.Target) { headers := &ctx.Request.Header - // Add X-Real-IP header + // 添加 X-Real-IP 请求头 clientIP := getClientIP(ctx) if clientIP != "" { headers.Set("X-Real-IP", clientIP) } - // Add/Append X-Forwarded-For header + // 添加/追加 X-Forwarded-For 请求头 existingXFF := headers.Peek("X-Forwarded-For") if len(existingXFF) > 0 { headers.Set("X-Forwarded-For", string(existingXFF)+", "+clientIP) @@ -283,27 +282,27 @@ func (p *Proxy) modifyRequestHeaders(ctx *fasthttp.RequestCtx, target *loadbalan headers.Set("X-Forwarded-For", clientIP) } - // Add X-Forwarded-Host header + // 添加 X-Forwarded-Host 请求头 host := string(ctx.Host()) if host != "" { headers.Set("X-Forwarded-Host", host) } - // Add X-Forwarded-Proto header + // 添加 X-Forwarded-Proto 请求头 proto := "http" if ctx.IsTLS() { proto = "https" } headers.Set("X-Forwarded-Proto", proto) - // Set custom request headers from config + // 从配置设置自定义请求头 if p.config.Headers.SetRequest != nil { for key, value := range p.config.Headers.SetRequest { headers.Set(key, value) } } - // Remove configured headers + // 移除配置的请求头 if len(p.config.Headers.Remove) > 0 { for _, key := range p.config.Headers.Remove { headers.Del(key) @@ -311,9 +310,9 @@ func (p *Proxy) modifyRequestHeaders(ctx *fasthttp.RequestCtx, target *loadbalan } } -// modifyResponseHeaders modifies the response headers before sending to client. +// modifyResponseHeaders 在发送给客户端之前修改响应头。 func (p *Proxy) modifyResponseHeaders(ctx *fasthttp.RequestCtx) { - // Set custom response headers from config + // 从配置设置自定义响应头 if p.config.Headers.SetResponse != nil { for key, value := range p.config.Headers.SetResponse { ctx.Response.Header.Set(key, value) @@ -321,34 +320,34 @@ func (p *Proxy) modifyResponseHeaders(ctx *fasthttp.RequestCtx) { } } -// isWebSocketRequest checks if the request is a WebSocket upgrade request. +// isWebSocketRequest 检查请求是否为 WebSocket 升级请求。 func isWebSocketRequest(ctx *fasthttp.RequestCtx) bool { - // Check Connection header + // 检查 Connection 请求头 connection := ctx.Request.Header.Peek("Connection") if !strings.EqualFold(string(connection), "upgrade") { - // Also check for "Upgrade" substring (e.g., "keep-alive, Upgrade") + // 也检查 "Upgrade" 子串(例如 "keep-alive, Upgrade") if !strings.Contains(strings.ToLower(string(connection)), "upgrade") { return false } } - // Check Upgrade header + // 检查 Upgrade 请求头 upgrade := ctx.Request.Header.Peek("Upgrade") return strings.EqualFold(string(upgrade), "websocket") } -// handleWebSocket handles WebSocket upgrade requests. -// For now, it returns 501 Not Implemented as WebSocket proxying -// requires special handling beyond HTTP. +// handleWebSocket 处理 WebSocket 升级请求。 +// 目前返回 501 Not Implemented,因为 WebSocket 代理需要 +// HTTP 之外的特殊处理。 func (p *Proxy) handleWebSocket(ctx *fasthttp.RequestCtx, target *loadbalance.Target, client *fasthttp.HostClient) { - // WebSocket proxying requires raw TCP connection handling - // which is beyond the scope of basic HTTP proxying - // This can be implemented later using a TCP bridge + // WebSocket 代理需要原始 TCP 连接处理, + // 这超出了基本 HTTP 代理的范围。 + // 后续可以使用 TCP 桥接实现 ctx.Error("WebSocket proxying not implemented", fasthttp.StatusNotImplemented) } -// UpdateTargets updates the proxy targets and reinitializes clients. -// This is useful for dynamic configuration updates. +// UpdateTargets 更新代理目标并重新初始化客户端。 +// 适用于动态配置更新。 func (p *Proxy) UpdateTargets(targets []*loadbalance.Target) error { if len(targets) == 0 { return errors.New("no targets provided") @@ -357,10 +356,10 @@ func (p *Proxy) UpdateTargets(targets []*loadbalance.Target) error { p.mu.Lock() defer p.mu.Unlock() - // Clear old clients + // 清除旧客户端 p.clients = make(map[string]*fasthttp.HostClient) - // Initialize new clients + // 初始化新客户端 for _, target := range targets { if target.URL == "" { continue @@ -374,14 +373,14 @@ func (p *Proxy) UpdateTargets(targets []*loadbalance.Target) error { return nil } -// GetTargets returns the current list of targets. +// GetTargets 返回当前的目标列表。 func (p *Proxy) GetTargets() []*loadbalance.Target { p.mu.RLock() defer p.mu.RUnlock() return p.targets } -// GetConfig returns the proxy configuration. +// GetConfig 返回代理配置。 func (p *Proxy) GetConfig() *config.ProxyConfig { p.mu.RLock() defer p.mu.RUnlock()