From a9d55dc2cf77265c18b57e08a3b8223a05db75e2 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Mon, 3 Aug 2026 22:45:17 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=A2=84=E8=A7=88=E8=A7=86=E9=A2=91URL?= =?UTF-8?q?=E7=AD=BE=E5=90=8D=20=E2=80=94=20=E7=A7=81=E6=9C=89bucket?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E9=A2=84=E7=AD=BE=E5=90=8DURL=E9=81=BF?= =?UTF-8?q?=E5=85=8D403=E9=BB=91=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/app/api/routes/generation_preview.py | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/api/app/api/routes/generation_preview.py b/apps/api/app/api/routes/generation_preview.py index 5e9414a70..eeebe3ed1 100755 --- a/apps/api/app/api/routes/generation_preview.py +++ b/apps/api/app/api/routes/generation_preview.py @@ -8,6 +8,7 @@ from __future__ import annotations import logging from app.auth import AuthenticatedUser, get_current_user +from app.core.storage import get_storage_service from app.core.task_enqueue import ( GLOBAL_PENDING_LIMIT, USER_PENDING_LIMIT, @@ -63,6 +64,22 @@ def _mark_task_failed(repo, task, reason: str) -> None: logger.exception("[预览生成] 标记任务失败时异常: task_id=%s", task.id) +def _sign_video_url(raw_url: str) -> str: + """为私有 OSS bucket 的视频 URL 生成预签名下载链接。 + + 有效期 2 小时,签名失败时降级返回原始 URL。 + """ + if not raw_url: + return "" + try: + storage = get_storage_service() + signed = storage.get_download_url(raw_url, expires_seconds=7200) + return signed or raw_url + except Exception: + logger.warning("[预览] URL签名失败,降级返回原始URL: %s", raw_url[:100], exc_info=True) + return raw_url + + def _to_preview_response(task, generated_videos: list | None = None) -> PreviewGenerationTaskResponse: """将领域任务对象转换为预览响应 DTO。 @@ -78,7 +95,9 @@ def _to_preview_response(task, generated_videos: list | None = None) -> PreviewG file_size = 0 if generated_videos: first_video = generated_videos[0] - video_url = getattr(first_video, "file_url", "") or "" + raw_url = getattr(first_video, "file_url", "") or "" + # P0 修复:私有 bucket 需要预签名 URL,否则前端 403 → 黑屏 + video_url = _sign_video_url(raw_url) duration = float(getattr(first_video, "duration", 0.0) or 0.0) file_size = int(getattr(first_video, "file_size", 0) or 0)