霖雨寺
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import mimetypes
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request, status
|
||||
from starlette.datastructures import UploadFile
|
||||
|
||||
from app.config import oss_settings
|
||||
from app.schemas import UploadResponse
|
||||
|
||||
|
||||
router = APIRouter(prefix="/uploads", tags=["uploads"])
|
||||
|
||||
MAX_IMAGE_SIZE = 5 * 1024 * 1024
|
||||
ALLOWED_IMAGE_TYPES = {"image/jpeg", "image/png", "image/webp", "image/gif"}
|
||||
|
||||
|
||||
def get_public_url(object_key: str) -> str:
|
||||
if oss_settings.public_base_url:
|
||||
return f"{oss_settings.public_base_url.rstrip('/')}/{object_key}"
|
||||
|
||||
endpoint = oss_settings.endpoint.replace("https://", "").replace("http://", "").rstrip("/")
|
||||
return f"https://{oss_settings.bucket_name}.{endpoint}/{object_key}"
|
||||
|
||||
|
||||
def build_object_key(filename: str | None, folder: str) -> str:
|
||||
suffix = Path(filename or "").suffix.lower()
|
||||
if not suffix:
|
||||
suffix = mimetypes.guess_extension("image/jpeg") or ".jpg"
|
||||
|
||||
safe_folder = folder.strip("/ ") or oss_settings.upload_prefix
|
||||
return f"{oss_settings.upload_prefix.strip('/')}/{safe_folder}/{uuid4().hex}{suffix}"
|
||||
|
||||
|
||||
@router.post("/images", response_model=UploadResponse)
|
||||
async def upload_image(request: Request) -> UploadResponse:
|
||||
if not oss_settings.is_configured:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="OSS 配置未完成,请先填写 app/config.py 中的 OSS 配置。",
|
||||
)
|
||||
|
||||
form = await request.form()
|
||||
file = form.get("file")
|
||||
folder_value = form.get("folder")
|
||||
folder = str(folder_value) if folder_value else "products"
|
||||
|
||||
if not isinstance(file, UploadFile):
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="请选择要上传的图片")
|
||||
|
||||
content_type = file.content_type or "application/octet-stream"
|
||||
if content_type not in ALLOWED_IMAGE_TYPES:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="只支持上传图片文件")
|
||||
|
||||
data = await file.read()
|
||||
if len(data) > MAX_IMAGE_SIZE:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="图片大小不能超过 5MB")
|
||||
|
||||
try:
|
||||
import oss2
|
||||
except ImportError as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="缺少 oss2 依赖,请先安装 requirements.txt 中的依赖。",
|
||||
) from exc
|
||||
|
||||
object_key = build_object_key(file.filename, folder)
|
||||
auth = oss2.Auth(oss_settings.access_key_id, oss_settings.access_key_secret)
|
||||
bucket = oss2.Bucket(auth, oss_settings.upload_endpoint, oss_settings.bucket_name)
|
||||
bucket.put_object(object_key, data, headers={"Content-Type": content_type})
|
||||
|
||||
return UploadResponse(url=get_public_url(object_key), object_key=object_key)
|
||||
Reference in New Issue
Block a user