Files
surugaya/app/core/errors.py
T
2026-06-08 16:09:13 +08:00

79 lines
2.5 KiB
Python

"""应用异常定义:所有业务异常均继承自 AppError
错误码规范:
- 1xxx: 请求/鉴权错误
- 2xxx: 浏览器资源错误
- 3xxx: Cloudflare/反爬相关错误
- 4xxx: 页面解析错误
"""
class AppError(Exception):
"""应用基础异常,携带错误码、HTTP 状态码和是否可重试信息"""
def __init__(
self,
message: str,
code: str,
err_code: int,
retryable: bool = False,
status_code: int = 400,
headers: dict[str, str] | None = None,
):
super().__init__(message)
self.message = message
self.code = code
self.err_code = err_code
self.retryable = retryable
self.status_code = status_code
self.headers = headers
class AuthenticationError(AppError):
"""鉴权失败(Bearer Token 无效或缺失)"""
def __init__(self, message: str = "Invalid credentials"):
super().__init__(
message=message,
code="AUTH_INVALID",
err_code=1001,
retryable=False,
status_code=401,
headers={"WWW-Authenticate": "Bearer"},
)
class BrowserUnavailableError(AppError):
"""浏览器不可用(未启用或启动失败)"""
def __init__(self, message: str = "Browser pool is unavailable"):
super().__init__(message=message, code="BROWSER_UNAVAILABLE", err_code=2001, retryable=True)
class ResourceBusyError(AppError):
"""浏览器资源繁忙(获取页面槽位超时)"""
def __init__(self, message: str = "Timed out while waiting for a browser slot"):
super().__init__(message=message, code="RESOURCE_BUSY", err_code=2002, retryable=True)
class CloudflareChallengeError(AppError):
"""Cloudflare 挑战未在规定时间内通过"""
def __init__(self, message: str = "Cloudflare challenge did not clear in time"):
super().__init__(message=message, code="CLOUDFLARE_CHALLENGE", err_code=3001, retryable=True)
class UpstreamBlockedError(AppError):
"""上游请求被 Cloudflare 阻断(如 1020/403 错误)"""
def __init__(self, message: str = "The upstream request was blocked"):
super().__init__(message=message, code="UPSTREAM_BLOCKED", err_code=3002, retryable=True)
class ScrapeParseError(AppError):
"""页面解析失败"""
def __init__(self, message: str = "Failed to parse the target page"):
super().__init__(message=message, code="PARSE_ERROR", err_code=4001, retryable=False)