You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

3.6 KiB

修复项目素材 API 文件 URL 返回问题

日期: 2026-02-12
类型: Bug 修复
影响范围: 后端 API - 项目素材模块

问题描述

/api/v1/projects/{project_id}/resources 接口上传 footage(实拍)素材后,返回的 fileUrlthumbnailUrl 字段为相对路径(如 project_resource_footage/xxx.mp4),而非完整的访问 URL(如 https://oss.example.com/project_resource_footage/xxx.mp4)。

前端无法直接使用相对路径访问文件,导致素材预览失败。

根因分析

  1. ProjectResourceResponse Schema 直接返回数据库存储的相对路径
  2. 未使用 build_file_url() 函数转换为完整 URL
  3. 其他模块(如 ScreenplayResponseAttachmentResponse)已使用 @computed_field 自动转换

解决方案

ProjectResourceResponse Schema 中添加 @computed_field,自动将相对路径转换为完整 URL:

from pydantic import computed_field
from app.core.storage import build_file_url

class ProjectResourceResponse(BaseModel):
    # 内部字段存储相对路径
    file_url: str = Field(..., description="文件相对路径(内部使用)")
    thumbnail_url: Optional[str] = Field(None, description="缩略图相对路径(内部使用)")
    
    # 计算字段返回完整 URL
    @computed_field(alias="fileUrl")
    @property
    def full_file_url(self) -> str:
        """动态生成完整文件访问 URL"""
        return build_file_url(self.file_url)
    
    @computed_field(alias="thumbnailUrl")
    @property
    def full_thumbnail_url(self) -> Optional[str]:
        """动态生成完整缩略图访问 URL"""
        return build_file_url(self.thumbnail_url) if self.thumbnail_url else None

技术细节

修改文件

  • server/app/schemas/project_resource.py

工作原理

  1. 数据库存储相对路径(便于域名变更和多环境部署)
  2. Schema 序列化时自动调用 build_file_url() 转换为完整 URL
  3. API 响应中 fileUrlthumbnailUrl 字段返回完整 URL

优势

  • 统一模式: 与 ScreenplayResponseAttachmentResponse 保持一致
  • 自动转换: 所有使用该 Schema 的接口自动生效
  • 易维护: 域名变更时只需修改配置,无需改代码

影响范围

受影响接口

  • POST /api/v1/projects/{project_id}/resources - 上传素材
  • GET /api/v1/resources/{resource_id} - 获取素材详情
  • PATCH /api/v1/resources/{resource_id} - 更新素材
  • GET /api/v1/projects/{project_id}/resources - 获取项目素材列表
  • GET /api/v1/projects/{project_id}/resources?element_tag_id={tag_id} - 获取标签素材列表

兼容性

  • 向后兼容:前端已期望接收完整 URL
  • 无需数据迁移:数据库继续存储相对路径
  • 无需前端改动:返回格式符合前端预期

验证方法

# 1. 上传 footage 素材
curl -X POST "http://localhost:8000/api/v1/projects/{project_id}/resources" \
  -H "Authorization: Bearer {token}" \
  -F "file=@test.mp4" \
  -F "name=测试视频" \
  -F "type=footage"

# 2. 检查响应中的 fileUrl 字段
# ✅ 正确: "fileUrl": "https://oss.example.com/project_resource_footage/xxx.mp4"
# ❌ 错误: "fileUrl": "project_resource_footage/xxx.mp4"

相关文件

  • Schema: server/app/schemas/project_resource.py
  • API: server/app/api/v1/project_resources.py
  • 工具函数: server/app/core/storage.py (build_file_url)

参考

  • 类似实现: server/app/schemas/screenplay.py (ScreenplayResponse)
  • 类似实现: server/app/schemas/attachment.py (AttachmentResponse)