refactor: 统一请求头处理逻辑到 headers.py

- 新增 src/core/headers.py 集中管理头部处理函数
- 扩展 api_format_metadata.py 添加 extra_headers 和 protected_keys 配置
- 将各 adapter 中重复的头部方法提取到基类,统一调用 headers.py
- 移除 transport.py 中未使用的 build_provider_headers 函数
- 添加 headers 模块的单元测试
This commit is contained in:
fawney19
2026-01-15 22:25:56 +08:00
parent 80887dd2cc
commit ea45918561
17 changed files with 811 additions and 353 deletions

View File

@@ -16,6 +16,7 @@ from src.core.key_capabilities import (
CapabilityConfigMode,
get_user_configurable_capabilities,
)
from src.core.headers import get_header_value
from src.core.logger import logger
# Adapter 检测器类型:接受 headers 和可选的 request_body返回能力需求字典
@@ -87,7 +88,7 @@ class CapabilityResolver:
# 3. 从请求头 X-Require-Capability 获取(显式声明)
if request_headers:
header_caps = request_headers.get("X-Require-Capability", "")
header_caps = get_header_value(request_headers, "X-Require-Capability")
if header_caps:
for cap in header_caps.split(","):
cap = cap.strip()

View File

@@ -6,11 +6,10 @@ Provider 服务模块
from src.services.provider.format import normalize_api_format
from src.services.provider.service import ProviderService
from src.services.provider.transport import build_provider_headers, build_provider_url
from src.services.provider.transport import build_provider_url
__all__ = [
"ProviderService",
"normalize_api_format",
"build_provider_headers",
"build_provider_url",
]

View File

@@ -2,75 +2,18 @@
统一的 Provider 请求构建工具。
负责:
- 根据 endpoint/key 构建标准请求头
- 根据 API 格式或端点配置生成请求 URL
"""
from typing import TYPE_CHECKING, Any, Dict, Optional
from urllib.parse import urlencode
from src.core.api_format_metadata import get_auth_config, get_default_path, resolve_api_format
from src.core.crypto import crypto_service
from src.core.api_format_metadata import get_default_path, resolve_api_format
from src.core.enums import APIFormat
from src.core.logger import logger
if TYPE_CHECKING:
from src.models.database import ProviderAPIKey, ProviderEndpoint
def build_provider_headers(
endpoint: "ProviderEndpoint",
key: "ProviderAPIKey",
original_headers: Optional[Dict[str, str]] = None,
*,
extra_headers: Optional[Dict[str, str]] = None,
) -> Dict[str, str]:
"""
根据 endpoint/key 构建请求头,并透传客户端自定义头。
"""
headers: Dict[str, str] = {}
# api_key 在数据库中是 NOT NULL类型标注为 Optional 是 SQLAlchemy 限制
decrypted_key = crypto_service.decrypt(key.api_key) # type: ignore[arg-type]
# 根据 API 格式自动选择认证头
api_format = getattr(endpoint, "api_format", None)
resolved_format = resolve_api_format(api_format)
auth_header, auth_type = (
get_auth_config(resolved_format) if resolved_format else ("Authorization", "bearer")
)
if auth_type == "bearer":
headers[auth_header] = f"Bearer {decrypted_key}"
else:
headers[auth_header] = decrypted_key
if endpoint.headers:
headers.update(endpoint.headers)
excluded_headers = {
"host",
"authorization",
"x-api-key",
"x-goog-api-key",
"content-length",
"transfer-encoding",
}
if original_headers:
for name, value in original_headers.items():
if name.lower() not in excluded_headers:
headers[name] = value
if extra_headers:
headers.update(extra_headers)
if "Content-Type" not in headers and "content-type" not in headers:
headers["Content-Type"] = "application/json"
return headers
from src.models.database import ProviderEndpoint
def _normalize_base_url(base_url: str, path: str) -> str:
"""