"""文件上传 & 静态文件访问""" import os import uuid from fastapi import APIRouter, UploadFile, File, HTTPException, status from fastapi.responses import FileResponse router = APIRouter(prefix="/upload", tags=["文件上传"]) # Docker: os.getcwd() = /app → /app/uploads → host:backend/uploads BASE_DIR = os.environ.get("PROJECT_ROOT", os.getcwd()) UPLOAD_DIR = os.path.join(BASE_DIR, "uploads") os.makedirs(UPLOAD_DIR, exist_ok=True) ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif", "bmp", "webp", "pdf", "doc", "docx", "xls", "xlsx", "zip", "rar", "7z"} MAX_SIZE = 50 * 1024 * 1024 # 50MB @router.post("/") async def upload_file(file: UploadFile = File(...)) -> dict: """上传文件 → 保存到 uploads/uuid.ext → 返回可访问 URL""" if not file.filename: raise HTTPException(status_code=400, detail="文件名为空") ext = file.filename.rsplit(".", 1)[-1].lower() if "." in file.filename else "" if ext not in ALLOWED_EXTENSIONS: raise HTTPException(status_code=400, detail=f"不支持的文件类型: .{ext}") # 检查大小 content = await file.read() if len(content) > MAX_SIZE: raise HTTPException(status_code=400, detail="文件超过 50MB 限制") await file.seek(0) os.makedirs(UPLOAD_DIR, exist_ok=True) filename = f"{uuid.uuid4().hex}.{ext}" filepath = os.path.join(UPLOAD_DIR, filename) with open(filepath, "wb") as f: f.write(await file.read()) return {"url": f"/api/v1/upload/files/{filename}"} @router.get("/files/{filename}") async def serve_file(filename: str): """直接返回物理文件""" filepath = os.path.join(UPLOAD_DIR, filename) if not os.path.exists(filepath): raise HTTPException(status_code=404, detail="文件不存在") return FileResponse(filepath)