fix: IP格式校验用field_validator替代model_validator

model_validator(mode='after')抛出ValueError时FastAPI不能正确序列化为422
→ 导致500 TypeError: Object of type ValueError is not JSON serializable
改用field_validator(mode='before')由Pydantic正常捕获返回422
This commit is contained in:
Your Name
2026-05-30 22:44:26 +08:00
parent 463841a740
commit d19f5af807
+11 -9
View File
@@ -14,7 +14,7 @@ import socket
import bcrypt
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel, Field, model_validator
from pydantic import BaseModel, Field, field_validator
from server.api.dependencies import get_db
from server.api.auth_jwt import get_current_admin
@@ -841,15 +841,16 @@ _DOMAIN_RE = re.compile(r"^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-
class IpAllowlistRequest(BaseModel):
ips: list[str] = Field(..., min_length=1, max_length=100, description="IP or hostname list")
@model_validator(mode="after")
def validate_ips(self):
for raw in self.ips:
@field_validator("ips", mode="before")
@classmethod
def validate_ips(cls, v: list[str]) -> list[str]:
for raw in v:
ip = raw.strip()
if not ip:
continue
if not (_IP_RE.match(ip) or _DOMAIN_RE.match(ip)):
raise ValueError(f"无效的 IP/CIDR/域名: {ip}")
return self
return v
class SubscriptionParseRequest(BaseModel):
@@ -938,15 +939,16 @@ class IpAllowlistSaveRequest(BaseModel):
subscription_url: Optional[str] = None # None = don't change; "" = clear
enabled: Optional[bool] = None # None = don't change
@model_validator(mode="after")
def validate_manual_ips(self):
for raw in self.manual_ips:
@field_validator("manual_ips", mode="before")
@classmethod
def validate_manual_ips(cls, v: list[str]) -> list[str]:
for raw in v:
ip = raw.strip()
if not ip:
continue
if not (_IP_RE.match(ip) or _DOMAIN_RE.match(ip)):
raise ValueError(f"无效的 IP/CIDR/域名: {ip}")
return self
return v
@router.post("/ip-allowlist", response_model=dict)