fix: accept form payloads for chunk uploads
This commit is contained in:
+28
-3
@@ -7,7 +7,8 @@ from urllib.parse import unquote
|
|||||||
|
|
||||||
from typing import Optional, Tuple, Union
|
from typing import Optional, Tuple, Union
|
||||||
|
|
||||||
from fastapi import APIRouter, Form, UploadFile, File, Depends, HTTPException
|
from fastapi import APIRouter, Form, Request, UploadFile, File, Depends, HTTPException
|
||||||
|
from pydantic import BaseModel, ValidationError
|
||||||
from starlette import status
|
from starlette import status
|
||||||
|
|
||||||
from apps.admin.dependencies import share_required_login
|
from apps.admin.dependencies import share_required_login
|
||||||
@@ -233,8 +234,30 @@ async def download_file(key: str, code: str, ip: str = Depends(ip_limit["error"]
|
|||||||
chunk_api = APIRouter(prefix="/chunk", tags=["切片"])
|
chunk_api = APIRouter(prefix="/chunk", tags=["切片"])
|
||||||
|
|
||||||
|
|
||||||
|
async def parse_body_model(request: Request, model_class: type[BaseModel]):
|
||||||
|
content_type = request.headers.get("content-type", "").lower()
|
||||||
|
try:
|
||||||
|
if "application/x-www-form-urlencoded" in content_type or "multipart/form-data" in content_type:
|
||||||
|
payload = dict(await request.form())
|
||||||
|
else:
|
||||||
|
payload = await request.json()
|
||||||
|
return model_class.model_validate(payload)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise HTTPException(status_code=422, detail=e.errors())
|
||||||
|
except Exception:
|
||||||
|
raise HTTPException(status_code=400, detail="请求体格式错误")
|
||||||
|
|
||||||
|
|
||||||
|
async def parse_init_chunk_upload(request: Request) -> InitChunkUploadModel:
|
||||||
|
return await parse_body_model(request, InitChunkUploadModel)
|
||||||
|
|
||||||
|
|
||||||
|
async def parse_complete_upload(request: Request) -> CompleteUploadModel:
|
||||||
|
return await parse_body_model(request, CompleteUploadModel)
|
||||||
|
|
||||||
|
|
||||||
@chunk_api.post("/upload/init/", dependencies=[Depends(share_required_login)])
|
@chunk_api.post("/upload/init/", dependencies=[Depends(share_required_login)])
|
||||||
async def init_chunk_upload(data: InitChunkUploadModel):
|
async def init_chunk_upload(data: InitChunkUploadModel = Depends(parse_init_chunk_upload)):
|
||||||
# 服务端校验:根据 total_chunks * chunk_size 计算理论最大上传量
|
# 服务端校验:根据 total_chunks * chunk_size 计算理论最大上传量
|
||||||
total_chunks = (data.file_size + data.chunk_size - 1) // data.chunk_size
|
total_chunks = (data.file_size + data.chunk_size - 1) // data.chunk_size
|
||||||
max_possible_size = total_chunks * data.chunk_size
|
max_possible_size = total_chunks * data.chunk_size
|
||||||
@@ -444,7 +467,9 @@ async def get_upload_status(upload_id: str):
|
|||||||
"/upload/complete/{upload_id}", dependencies=[Depends(share_required_login)]
|
"/upload/complete/{upload_id}", dependencies=[Depends(share_required_login)]
|
||||||
)
|
)
|
||||||
async def complete_upload(
|
async def complete_upload(
|
||||||
upload_id: str, data: CompleteUploadModel, ip: str = Depends(ip_limit["upload"])
|
upload_id: str,
|
||||||
|
data: CompleteUploadModel = Depends(parse_complete_upload),
|
||||||
|
ip: str = Depends(ip_limit["upload"]),
|
||||||
):
|
):
|
||||||
# 获取上传基本信息
|
# 获取上传基本信息
|
||||||
chunk_info = await UploadChunk.filter(upload_id=upload_id, chunk_index=-1).first()
|
chunk_info = await UploadChunk.filter(upload_id=upload_id, chunk_index=-1).first()
|
||||||
|
|||||||
Reference in New Issue
Block a user