feat: 阿里云 OSS 迁移至腾讯云 COS + 完善部署配置

COS 迁移:
- 后端签名服务改为 COS HMAC-SHA1 表单直传签名
- config.py: OSS_* 配置项替换为 COS_SECRET_ID/KEY/REGION/BUCKET_NAME/CDN_DOMAIN
- upload.py: UploadPolicyResponse 改为 COS 字段
- 前端 useOSSUpload hook: FormData 字段改为 COS 格式
- 前端 api.ts: UploadPolicyResponse 类型对齐

部署配置:
- docker-compose.yml: 新增 Nginx + 前端容器,数据卷宿主机持久化
- Nginx: HTTPS + HTTP/2 + SSE 长连接 + API/前端反向代理
- backup.sh: PostgreSQL 每日备份 → 本地 + COS
- .env.example: 更新为 COS 配置模板

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-02-10 10:28:13 +08:00
co-authored by Claude Opus 4.6
parent f02b3f4098
commit 8ab2d869fc
11 changed files with 313 additions and 121 deletions
+16 -8
View File
@@ -1,13 +1,15 @@
"""
文件上传 API
"""
from fastapi import APIRouter, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
from app.services.oss import generate_upload_policy, get_file_url
from app.config import settings
from app.models.user import User
from app.api.deps import get_current_user
router = APIRouter(prefix="/upload", tags=["文件上传"])
@@ -19,10 +21,12 @@ class UploadPolicyRequest(BaseModel):
class UploadPolicyResponse(BaseModel):
"""传凭证响应"""
access_key_id: str
"""COS 直传凭证响应"""
q_sign_algorithm: str
q_ak: str
q_key_time: str
q_signature: str
policy: str
signature: str
host: str
dir: str
expire: int
@@ -49,11 +53,12 @@ class FileUploadedResponse(BaseModel):
@router.post("/policy", response_model=UploadPolicyResponse)
async def get_upload_policy(
request: UploadPolicyRequest,
current_user: User = Depends(get_current_user),
):
"""
获取 OSS 直传凭证
获取 COS 直传凭证
前端使用此凭证直接上传文件到阿里云 OSS,无需经过后端。
前端使用此凭证直接上传文件到腾讯云 COS,无需经过后端。
文件类型说明:
- script: 脚本文档 (docx, pdf, xlsx, txt, pptx)
@@ -87,9 +92,11 @@ async def get_upload_policy(
)
return UploadPolicyResponse(
access_key_id=policy["accessKeyId"],
q_sign_algorithm=policy["q_sign_algorithm"],
q_ak=policy["q_ak"],
q_key_time=policy["q_key_time"],
q_signature=policy["q_signature"],
policy=policy["policy"],
signature=policy["signature"],
host=policy["host"],
dir=policy["dir"],
expire=policy["expire"],
@@ -100,6 +107,7 @@ async def get_upload_policy(
@router.post("/complete", response_model=FileUploadedResponse)
async def file_uploaded(
request: FileUploadedRequest,
current_user: User = Depends(get_current_user),
):
"""
文件上传完成回调