优化代理管理与增加请求日志系统

代理优化(P0+P1):
- 修复极验失败后代理刷新空操作bug(共享ProxyManager+白名单参数)
- 极验请求超时从(3.05,12)调大到(10,30)
- 白名单sync_ip加全局锁防并发限流,保留多个出口IP应对漂移
- 代理池缓存共享:Condition防并发获取+mark_bad移除坏代理
- 适配代理API的JSON响应格式(code/data/白名单错误)
- 简化代理验证只验斗鱼主站,减少日志噪音
- 获取代理前主动同步白名单(解决ow=1模式不报白名单错误的问题)
- 每次重试重新检测出口IP并同步白名单

请求日志系统:
- 新增HttpLogger记录请求/响应详情到JSONL文件
- login.py的_request和proxy.py的verify_proxy_url接入日志
- 新增/api/logs路由查看和清空HTTP详情日志
- 前端新增请求日志页面(筛选/搜索/分页/自动刷新/详情查看)

其他:
- 添加pysocks依赖支持SOCKS5代理
- gitignore添加*.log
This commit is contained in:
yml2213
2026-06-23 00:50:57 +08:00
parent 8fdf8d4b69
commit da2fedd484
14 changed files with 1015 additions and 159 deletions
+2 -1
View File
@@ -6,7 +6,7 @@ from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from .database import init_db
from .routers import auth, users, accounts, login, proxy, cookies
from .routers import auth, users, accounts, login, proxy, cookies, logs
@asynccontextmanager
@@ -37,6 +37,7 @@ app.include_router(accounts.router)
app.include_router(login.router)
app.include_router(proxy.router)
app.include_router(cookies.router)
app.include_router(logs.router)
@app.get("/api/health")
+46
View File
@@ -0,0 +1,46 @@
"""请求日志路由 - 查看 HTTP 请求/响应详情日志"""
from fastapi import APIRouter, Depends, Query
from typing import Optional
from ..deps import get_current_user
from ..permissions import has_permission
from utils.http_logger import read_http_logs, clear_http_logs
router = APIRouter(prefix="/api/logs", tags=["日志"])
@router.get("/http")
def list_http_logs(
limit: int = Query(50, ge=1, le=500),
offset: int = Query(0, ge=0),
category: Optional[str] = None,
level: Optional[str] = None,
keyword: Optional[str] = None,
current=Depends(get_current_user),
):
"""查看 HTTP 请求/响应详情日志(需要审计日志查看权限)"""
if not has_permission(current.role, "audit:view"):
# 运营也可以查看请求日志(用于排查登录问题)
if not has_permission(current.role, "login:batch"):
return {"items": [], "total": 0, "message": "无权限"}
items, total = read_http_logs(
limit=limit,
offset=offset,
category=category,
level=level,
keyword=keyword,
)
return {"items": items, "total": total}
@router.delete("/http")
def clear_http_logs_api(current=Depends(get_current_user)):
"""清空 HTTP 请求/响应详情日志"""
if not has_permission(current.role, "audit:view"):
if not has_permission(current.role, "login:batch"):
return {"success": False, "message": "无权限"}
count = clear_http_logs()
return {"success": True, "cleared": count}
+19 -18
View File
@@ -11,7 +11,7 @@ from sqlalchemy.orm import Session
from core.douyu import DouyuLogin
from core.models import Account, ProxyConfig as DouyuProxyConfig
from core.douyu.proxy import resolve_working_proxy
from core.douyu.proxy import resolve_working_proxy, get_proxy_manager
from ..models import Account as AccountModel, LoginTask, ProxyConfig as ProxyConfigModel
from ..permissions import has_permission
@@ -47,6 +47,17 @@ class LoginBatchRunner:
self._counter_lock = threading.Lock()
self._completed = 0
# 共享代理管理器(带锁,避免并发白名单限流;极验失败时可刷新代理)
self._shared_proxy_manager = None
if proxy_config and proxy_config.enabled and proxy_config.api_url:
wl_uid = proxy_config.whitelist_uid or "" if proxy_config.whitelist_enabled else ""
wl_ukey = proxy_config.whitelist_ukey or "" if proxy_config.whitelist_enabled else ""
self._shared_proxy_manager = get_proxy_manager(
proxy_config.api_url,
whitelist_uid=wl_uid,
whitelist_ukey=wl_ukey,
)
def stop(self):
self._stop.set()
@@ -62,7 +73,7 @@ class LoginBatchRunner:
解析代理配置,返回 (proxy_dict, message)。
- 静态代理:直接返回 dict
- API代理:调用 resolve_working_proxy 预检,自动同步白名单
- API代理:通过共享 ProxyManager(带已验证代理池缓存)获取,自动同步白名单
- 无代理:返回 (None, '')
"""
if not self.proxy_config or not self.proxy_config.enabled:
@@ -73,23 +84,12 @@ class LoginBatchRunner:
proxy_url = self.proxy_config.http or self.proxy_config.https
return {'http': proxy_url, 'https': proxy_url}, f'使用静态代理: {proxy_url}'
# API代理:预检获取可用代理
if self.proxy_config.api_url:
whitelist_uid = ''
whitelist_ukey = ''
if self.proxy_config.whitelist_enabled:
whitelist_uid = self.proxy_config.whitelist_uid or ''
whitelist_ukey = self.proxy_config.whitelist_ukey or ''
proxy_url, msg = resolve_working_proxy(
api_url=self.proxy_config.api_url,
whitelist_uid=whitelist_uid,
whitelist_ukey=whitelist_ukey,
log_func=self._push_log,
)
# API代理:通过共享代理管理器获取(优先从已验证代理池复用)
if self._shared_proxy_manager:
proxy_url = self._shared_proxy_manager.get_proxy()
if proxy_url:
return {'http': proxy_url, 'https': proxy_url}, msg
return None, msg
return {'http': proxy_url, 'https': proxy_url}, f'使用API代理: {proxy_url}'
return None, '代理不可用'
return None, ''
@@ -144,6 +144,7 @@ class LoginBatchRunner:
proxy=proxy_dict,
max_geetest_retries=self.max_geetest_retries,
max_proxy_retries=self.max_proxy_retries,
proxy_manager=self._shared_proxy_manager,
)
result = loginer.login()