feat: 为出站请求统一接入 HTTP 代理

This commit is contained in:
2026-08-14 16:08:39 +08:00
parent 3dc2aeb3a2
commit fabca9510d
23 changed files with 213 additions and 14 deletions
+27 -1
View File
@@ -8,9 +8,11 @@
「通用 / 仅抓取 / 仅交易 / 仅网关 / 仅交易 worker」分区标注,各进程只读自己那部分。
"""
import socket
from fnmatch import fnmatchcase
from functools import lru_cache
from pathlib import Path
from typing import Literal
from urllib.parse import quote, urlsplit
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -88,6 +90,8 @@ class Settings(BaseSettings):
proxy_server: str | None = None
proxy_username: str | None = None
proxy_password: str | None = None
# 逗号分隔的直连主机名或通配符。服务间请求不应绕到公网代理。
proxy_bypass: str = "localhost,127.0.0.1,::1,rakuten-api,rakuten-trading,rakuten-gateway"
# ---- OpenTelemetry traces(通用,可选;默认关闭)----
# 启用后把抓取-解析链路以 span 导出到 OTLP/HTTP endpoint,用于排查"抓到
@@ -192,6 +196,8 @@ class Settings(BaseSettings):
proxy["username"] = self.proxy_username
if self.proxy_password:
proxy["password"] = self.proxy_password
if self.proxy_bypass.strip():
proxy["bypass"] = self.proxy_bypass
return proxy
@property
@@ -205,9 +211,29 @@ class Settings(BaseSettings):
scheme, _, rest = self.proxy_server.partition("://")
if not rest:
return self.proxy_server
credentials = f"{self.proxy_username}:{self.proxy_password or ''}"
credentials = f"{quote(self.proxy_username, safe='')}:{quote(self.proxy_password or '', safe='')}"
return f"{scheme}://{credentials}@{rest}"
def proxy_bypasses(self, url: str) -> bool:
"""目标 URL 的主机是否应绕过外部代理。"""
host = urlsplit(url).hostname
if not host:
return False
normalized_host = host.rstrip(".").lower()
for raw_pattern in self.proxy_bypass.split(","):
pattern = raw_pattern.strip().rstrip(".").lower()
if not pattern:
continue
if pattern.startswith("."):
suffix = pattern[1:]
if normalized_host == suffix or normalized_host.endswith(f".{suffix}"):
return True
continue
if fnmatchcase(normalized_host, pattern):
return True
return False
@property
def auth_state_path(self) -> Path:
"""登录态目录的绝对路径,不存在时创建"""