|

掌握 API 文件上传: multipart/form-data 完整指南与 Sora 2 实战示例

API 文件上传是开发者在调用 AI 视频生成、图像处理等接口时经常遇到的技术需求。本文将系统讲解 multipart/form-data 编码方式的工作原理,并以 Sora 2 图生视频 API 为例,帮助你掌握 API 文件上传的核心技能。

核心价值: 读完本文,你将完全理解 multipart/form-data 的底层机制,学会使用 curl -F 命令进行文件上传,并能独立实现 Sora 2 等 AI API 的图片上传功能。

api-file-upload-multipart-form-data-guide 图示


API 文件上传核心知识

在深入代码之前,我们需要理解为什么 API 文件上传需要使用特殊的编码方式。

为什么需要 multipart/form-data

当你通过 API 发送普通的文本数据时,可以使用简单的 application/x-www-form-urlencoded 编码。然而,这种方式在处理文件时存在严重问题:

编码类型 适用场景 文件处理能力 效率
application/x-www-form-urlencoded 简单键值对 ❌ 不适合 二进制需 URL 转义,效率低
application/json 结构化数据 ⚠️ 需 Base64 编码 体积增大 33%
multipart/form-data 文件上传 ✅ 原生支持 无需编码,高效

multipart/form-data 是 1998 年 RFC 2388 标准提出的方案,专门解决 HTTP 协议中混合发送文本和二进制数据的问题。

multipart/form-data 工作原理

multipart/form-data 的核心思想是将一个 HTTP 请求体分割成多个独立的「部分」(parts),每个部分可以有自己的内容类型。

api-file-upload-multipart-form-data-guide 图示

数据结构详解

一个典型的 multipart/form-data 请求包含以下结构:

POST /v1/videos HTTP/1.1
Host: api.apiyi.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk

------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="prompt"

She turns around and smiles
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="model"

sora-2-pro
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="input_reference"; filename="sample.jpeg"
Content-Type: image/jpeg

[二进制图片数据]
------WebKitFormBoundary7MA4YWxk--
组件 作用 示例
Boundary 分隔各个数据部分的唯一标识符 ----WebKitFormBoundary7MA4YWxk
Content-Disposition 描述该部分的元数据 form-data; name="prompt"
Content-Type 该部分的 MIME 类型 image/jpeg
Body 实际数据内容 文本或二进制数据

🎯 技术要点: Boundary 必须是请求体中不会出现的唯一字符串。服务器通过 boundary 来解析和分离各个数据部分。


curl -F 命令详解: API 文件上传实战

curl 是最常用的命令行 HTTP 客户端工具,其 -F 参数专门用于 multipart/form-data 请求。

curl -F 基础语法

curl -F "字段名=值" URL
curl -F "文件字段=@本地文件路径" URL
参数形式 说明 示例
-F "key=value" 发送普通文本字段 -F "prompt=Hello"
-F "key=@file" 上传本地文件 -F "[email protected]"
-F "key=@file;type=mime" 指定文件 MIME 类型 -F "[email protected];type=image/jpeg"
-F "key=@file;filename=new.jpg" 自定义上传文件名 -F "[email protected];filename=upload.jpg"

curl -F 与其他参数的区别

很多开发者容易混淆 -F-d-X POST 的用法:

# ❌ 错误: -d 用于 x-www-form-urlencoded,不适合文件上传
curl -X POST -d "[email protected]" https://api.example.com/upload

# ❌ 错误: 手动指定 Content-Type 但使用 -d
curl -X POST -H "Content-Type: multipart/form-data" -d "..." https://api.example.com/upload

# ✅ 正确: 使用 -F 自动设置正确的 Content-Type 和 boundary
curl -F "[email protected]" https://api.example.com/upload

技术说明: 使用 -F 时,curl 会自动:

  1. 将请求方法设为 POST
  2. 设置 Content-Type: multipart/form-data
  3. 生成唯一的 boundary
  4. 按照 RFC 标准格式化请求体

Sora 2 API 文件上传实战

Sora 2 是 OpenAI 推出的视频生成模型,支持通过 API 上传参考图片来生成视频。这是 multipart/form-data 的典型应用场景。

Sora 2 图生视频 API 参数

参数 类型 必填 说明
prompt string 视频描述文本
model string 模型选择: sora-2sora-2-pro
size string 分辨率: 1280x720, 720x1280, 1024x1792, 1792x1024
seconds integer 时长: 4, 8, 12
input_reference file 参考图片,作为视频首帧

api-file-upload-multipart-form-data-guide 图示

Sora 2 模型对比

特性 sora-2 sora-2-pro
生成质量 良好 卓越
渲染速度 较快 较慢
适用场景 快速原型、概念验证 生产级输出
价格 标准 较高
可用平台 API易 apiyi.com, 官方 API API易 apiyi.com, 官方 API

Sora 2 文件上传完整示例

以下是使用 curl 调用 Sora 2 API 进行图生视频的完整示例:

curl -X POST "https://api.apiyi.com/v1/videos" \
  -H "Authorization: Bearer $APIYI_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F prompt="She turns around and smiles, then slowly walks out of the frame." \
  -F model="sora-2-pro" \
  -F size="1280x720" \
  -F seconds="8" \
  -F input_reference="@sample_720p.jpeg;type=image/jpeg"

命令解析

部分 说明
curl -X POST 指定 POST 请求方法
"https://api.apiyi.com/v1/videos" API易 Sora 2 视频生成端点
-H "Authorization: Bearer $APIYI_KEY" 使用环境变量传递 API 密钥
-H "Content-Type: multipart/form-data" 声明内容类型 (curl -F 会自动添加)
-F prompt="..." 视频描述提示词
-F model="sora-2-pro" 选择高质量模型
-F size="1280x720" 横屏 720p 分辨率
-F seconds="8" 8 秒时长
-F input_reference="@sample_720p.jpeg;type=image/jpeg" 上传参考图片

🚀 快速开始: 推荐使用 API易 apiyi.com 平台快速测试 Sora 2 API。该平台提供开箱即用的 API 接口,无需复杂配置即可完成集成。

图片上传注意事项

使用 Sora 2 API 上传参考图片时需要注意:

要求 说明
分辨率匹配 图片分辨率必须与目标视频 size 参数匹配
支持格式 image/jpeg, image/png, image/webp
文件大小 建议不超过 10MB
图片质量 清晰、构图完整的图片效果更好

Python 实现 multipart/form-data 上传

除了 curl,在实际开发中更常使用编程语言来实现文件上传。以下是 Python 的实现方式。

极简示例

import requests

# 使用 API易 统一接口
url = "https://api.apiyi.com/v1/videos"
headers = {"Authorization": "Bearer YOUR_API_KEY"}

# 准备 multipart 数据
files = {
    "input_reference": ("sample.jpeg", open("sample_720p.jpeg", "rb"), "image/jpeg")
}
data = {
    "prompt": "She turns around and smiles, then slowly walks out of the frame.",
    "model": "sora-2-pro",
    "size": "1280x720",
    "seconds": "8"
}

response = requests.post(url, headers=headers, data=data, files=files)
print(response.json())
查看完整代码 (含错误处理和轮询)
import requests
import time
import os

class Sora2Client:
    """Sora 2 API 客户端 - 支持 multipart/form-data 文件上传"""

    def __init__(self, api_key: str, base_url: str = "https://api.apiyi.com/v1"):
        self.api_key = api_key
        self.base_url = base_url
        self.headers = {"Authorization": f"Bearer {api_key}"}

    def create_video(
        self,
        prompt: str,
        model: str = "sora-2",
        size: str = "1280x720",
        seconds: int = 8,
        input_reference: str = None
    ) -> dict:
        """
        创建视频生成任务

        Args:
            prompt: 视频描述
            model: 模型选择 (sora-2 或 sora-2-pro)
            size: 分辨率
            seconds: 时长 (4, 8, 12)
            input_reference: 参考图片路径 (可选)

        Returns:
            任务信息字典
        """
        url = f"{self.base_url}/videos"

        data = {
            "prompt": prompt,
            "model": model,
            "size": size,
            "seconds": str(seconds)
        }

        files = None
        if input_reference and os.path.exists(input_reference):
            # 根据文件扩展名确定 MIME 类型
            ext = os.path.splitext(input_reference)[1].lower()
            mime_types = {
                ".jpg": "image/jpeg",
                ".jpeg": "image/jpeg",
                ".png": "image/png",
                ".webp": "image/webp"
            }
            mime_type = mime_types.get(ext, "application/octet-stream")

            files = {
                "input_reference": (
                    os.path.basename(input_reference),
                    open(input_reference, "rb"),
                    mime_type
                )
            }

        try:
            response = requests.post(
                url,
                headers=self.headers,
                data=data,
                files=files,
                timeout=30
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            return {"error": str(e)}
        finally:
            if files and "input_reference" in files:
                files["input_reference"][1].close()

    def get_video_status(self, video_id: str) -> dict:
        """查询视频生成状态"""
        url = f"{self.base_url}/videos/{video_id}"
        response = requests.get(url, headers=self.headers, timeout=30)
        return response.json()

    def wait_for_completion(self, video_id: str, poll_interval: int = 10) -> dict:
        """轮询等待视频生成完成"""
        while True:
            status = self.get_video_status(video_id)
            if status.get("status") in ["completed", "failed"]:
                return status
            print(f"Status: {status.get('status')}... waiting {poll_interval}s")
            time.sleep(poll_interval)


# 使用示例
if __name__ == "__main__":
    client = Sora2Client(api_key=os.getenv("APIYI_KEY"))

    # 创建图生视频任务
    result = client.create_video(
        prompt="She turns around and smiles, then slowly walks out of the frame.",
        model="sora-2-pro",
        size="1280x720",
        seconds=8,
        input_reference="sample_720p.jpeg"
    )

    if "id" in result:
        print(f"Task created: {result['id']}")
        final_result = client.wait_for_completion(result["id"])
        print(f"Video URL: {final_result.get('video_url')}")
    else:
        print(f"Error: {result}")

建议: 通过 API易 apiyi.com 获取免费测试额度,快速验证图生视频功能。

requests 库的 multipart 处理

Python requests 库处理 multipart/form-data 的关键点:

参数 用途 说明
data 普通表单字段 字典格式: {"key": "value"}
files 文件字段 元组格式: {"name": (filename, file_obj, content_type)}

⚠️ 注意: 同时使用 datafiles 参数时,requests 会自动设置正确的 Content-Type 和 boundary,无需手动指定。


JavaScript/Node.js 实现方案

浏览器环境 (FormData API)

const formData = new FormData();
formData.append('prompt', 'She turns around and smiles');
formData.append('model', 'sora-2-pro');
formData.append('size', '1280x720');
formData.append('seconds', '8');
formData.append('input_reference', fileInput.files[0]);

fetch('https://api.apiyi.com/v1/videos', {
    method: 'POST',
    headers: {
        'Authorization': 'Bearer YOUR_API_KEY'
        // 注意: 不要手动设置 Content-Type
    },
    body: formData
})
.then(response => response.json())
.then(data => console.log(data));

Node.js 环境

const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');

const form = new FormData();
form.append('prompt', 'She turns around and smiles');
form.append('model', 'sora-2-pro');
form.append('size', '1280x720');
form.append('seconds', '8');
form.append('input_reference', fs.createReadStream('sample_720p.jpeg'), {
    contentType: 'image/jpeg'
});

axios.post('https://api.apiyi.com/v1/videos', form, {
    headers: {
        ...form.getHeaders(),
        'Authorization': 'Bearer YOUR_API_KEY'
    }
})
.then(response => console.log(response.data));

💡 关键提示: 在浏览器中使用 FormData 时,不要手动设置 Content-Type header。浏览器会自动添加正确的 boundary 参数。


multipart/form-data 常见问题排查

上传失败常见原因

问题 症状 解决方案
boundary 缺失 服务器返回 400 不要手动设置 Content-Type,让工具自动生成
MIME 类型错误 文件被拒绝 使用 ;type=image/jpeg 明确指定
文件路径错误 找不到文件 确保 @ 后的路径正确,支持相对/绝对路径
分辨率不匹配 Sora API 报错 图片分辨率必须与 size 参数匹配
文件过大 超时或被拒绝 压缩图片或分片上传

调试技巧

使用 curl 的 -v 参数查看完整请求:

curl -v -F "[email protected]" https://api.example.com/upload

这会显示:

  • 请求头 (包括自动生成的 Content-Type 和 boundary)
  • 请求体结构
  • 服务器响应

常见问题

Q1: multipart/form-data 和 Base64 编码哪个更好?

multipart/form-data 更适合文件上传。Base64 编码会将文件体积增大约 33%,增加网络传输时间和服务器处理负担。multipart/form-data 直接传输二进制数据,效率更高。

不过在某些场景下 (如 WebSocket、单字段 JSON API),Base64 可能是唯一选择。通过 API易 apiyi.com 平台调用 API 时,优先使用 multipart/form-data 方式可获得更好的性能体验。

Q2: 为什么我的 curl -F 上传失败?

常见原因包括:

  1. 文件路径问题: 确保 @ 符号后跟正确的文件路径
  2. 权限问题: 检查文件读取权限
  3. MIME 类型: 某些 API 要求指定正确的 content-type

建议先通过 API易 apiyi.com 获取测试环境验证请求格式,平台提供详细的错误信息帮助快速定位问题。

Q3: Sora 2 API 支持哪些图片格式?

Sora 2 API 支持以下图片格式用于 input_reference:

  • JPEG (.jpg, .jpeg) – 推荐,压缩率好
  • PNG (.png) – 支持透明通道
  • WebP (.webp) – 现代格式,体积小

图片分辨率必须与目标视频的 size 参数匹配。例如使用 1280x720 分辨率,参考图片也需要是 1280×720。

Q4: 如何处理大文件上传?

对于大文件上传,可以考虑:

  1. 分片上传: 将文件分成小块依次上传
  2. 压缩优化: 在保证质量的前提下压缩文件
  3. 断点续传: 支持上传失败后从断点继续

multipart/form-data 支持流式传输,服务器可以边接收边处理,适合大文件场景。


总结

本文详细介绍了 API 文件上传的核心技术 multipart/form-data:

关键知识点回顾:

要点 说明
编码原理 boundary 分隔多部分数据,每部分独立 Content-Type
curl -F 命令 -F "key=value" 发送文本,-F "key=@file" 上传文件
Sora 2 实战 input_reference 参数上传参考图片,分辨率需匹配
多语言实现 Python requests / JavaScript FormData
调试技巧 使用 curl -v 查看完整请求

掌握 multipart/form-data 是进行 AI API 开发的基础能力。无论是 Sora 2 视频生成、GPT-4 Vision 图像理解,还是其他需要文件上传的 API,核心原理都是相通的。

推荐通过 API易 apiyi.com 快速验证文件上传功能,体验统一的 API 接口和详尽的技术支持。


作者: APIYI Team | 专注 AI 大模型 API 技术分享
技术交流: 访问 apiyi.com 获取更多 API 开发资源

参考资料

  1. RFC 2388: multipart/form-data 标准规范

    • 链接: tools.ietf.org/html/rfc2388
  2. curl 官方文档: Multipart Formposts

    • 链接: everything.curl.dev/http/post/multipart
  3. MDN Web Docs: Using FormData Objects

    • 链接: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects
  4. OpenAI Sora API 文档: Video Generation Guide

    • 链接: platform.openai.com/docs/guides/video-generation

类似文章