Upload File
上传图片/视频资源,获得可用于创建项目的 URL
Overview
上传流程:
1. 调用 Prepare Upload Token 获得 ousToken + globalDomain
2. 判断文件大小:
- 小于 blockSize: 单文件上传
- 大于 blockSize: 分片上传
3. 轮询 Upload Status 直到 status=5(成功)
4. 获得 url 用于创建项目
Base URL
https://{globalDomain}/ous/api/v2/...
Header: ous-token-v2: {ousToken}
globalDomain 和 ousToken 来自 Prepare Upload Token。
Single File Upload
适用于文件大小 < blockSize 的情况。
Endpoint
POST https://{globalDomain}/ous/api/v2/single/upload
Content-Type: multipart/form-data;charset=utf-8
Header: ous-token-v2: {ousToken}
Request
Form Data
| Parameter | Required | Type | Description |
|---|---|---|---|
| file | Yes | File | 文件内容 |
| md5 | Yes | String | 文件 MD5 值 |
| metadata | No | String | 元数据 |
| customPrefix | No | String | 自定义存储前缀 |
| customFilename | No | String | 自定义文件名 |
Response
json
{
"c": "0",
"d": {
"taskId": "3FO4K029K4A3"
}
}
Code Example
python
import hashlib
import requests
def upload_single_file(file_path, upload_info):
"""单文件上传"""
# 计算 MD5
with open(file_path, "rb") as f:
file_data = f.read()
md5 = hashlib.md5(file_data).hexdigest()
# 上传
with open(file_path, "rb") as f:
response = requests.post(
f"https://{upload_info['global_domain']}/ous/api/v2/single/upload",
headers={"ous-token-v2": upload_info["ous_token"]},
files={"file": f},
data={"md5": md5}
)
if response.json()["c"] != "0":
raise Exception("上传失败")
return response.json()["d"]["taskId"]
Block Upload (分片上传)
适用于文件大小 > blockSize 的情况。
Step 1: 初始化分片上传
POST https://{globalDomain}/ous/api/v2/block/upload/init
Header: ous-token-v2: {ousToken}
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| md5 | Yes | String | 文件 MD5 值 |
| blocks | Yes | Long | 总分片数 |
| size | Yes | Long | 文件总大小(字节) |
| name | Yes | String | 文件名 |
| metadata | No | String | 元数据 |
| customPrefix | No | String | 自定义存储前缀 |
| customFilename | No | String | 自定义文件名 |
Response
json
{
"c": "0",
"d": {
"taskId": "encrypted_task_id"
}
}
Step 2: 上传分片
POST https://{globalDomain}/ous/api/v2/block/upload/part
Content-Type: multipart/form-data;charset=utf-8
Header: ous-token-v2: {ousToken}
Concurrency Limit
同一文件的分片并发数量不超过 2,超过返回错误码 6。
Request
| Parameter | Required | Type | Description |
|---|---|---|---|
| file | Yes | File | 分片文件内容 |
| block | Yes | Integer | 分片序号(从 1 开始) |
Response
json
{
"c": "0",
"d": null
}
Code Example
python
def upload_large_file(file_path, upload_info):
"""分片上传大文件"""
file_size = os.path.getsize(file_path)
block_size = upload_info["block_size"]
blocks = math.ceil(file_size / block_size)
# 计算 MD5
with open(file_path, "rb") as f:
md5 = hashlib.md5(f.read()).hexdigest()
# 初始化
init_response = requests.post(
f"https://{upload_info['global_domain']}/ous/api/v2/block/upload/init",
headers={"ous-token-v2": upload_info["ous_token"]},
data={
"md5": md5,
"blocks": blocks,
"size": file_size,
"name": os.path.basename(file_path)
}
)
task_id = init_response.json()["d"]["taskId"]
# 上传各分片(并发控制在2以内)
with open(file_path, "rb") as f:
for block_num in range(1, blocks + 1):
chunk = f.read(block_size)
response = requests.post(
f"https://{upload_info['global_domain']}/ous/api/v2/block/upload/part",
headers={"ous-token-v2": upload_info["ous_token"]},
files={"file": chunk},
data={"block": block_num}
)
print(f"分片 {block_num}/{blocks} 上传完成")
return task_id
Abort Upload (中止上传)
POST https://{globalDomain}/ous/api/v2/block/upload/abort
Header: ous-token-v2: {ousToken}
无需参数,ousToken 已绑定 taskId。
Query Upload Status
轮询此接口直到上传完成。
GET https://{globalDomain}/ous/api/v2/upload/status
Header: ous-token-v2: {ousToken}
Response (Single File)
json
{
"c": "0",
"d": {
"status": 5,
"uploadKey": "path/2026/02/03/NGA5S6IKBIDN3RSQAAAAAAA8.jpg",
"url": "https://cdn.kujiale.com/path/2026/02/03/NGA5S6IKBIDN3RSQAAAAAAA8.jpg",
"md5": "c2ce57814593ae4e9fa8f1f473a3ed47",
"obsTaskId": "3FO4K029K4A3"
}
}
Response (Block Upload)
json
{
"c": "0",
"d": {
"taskId": "3FO4K029K4A3",
"status": 5,
"uploadKey": "path/to/file.jpg",
"url": "https://cdn.kujiale.com/path/to/file.jpg",
"md5": "d41d8cd98f00b204e9800998ecf8427e",
"blockUpload": {
"id": "encrypted_block_task_id",
"status": 5,
"progressPercent": 100
}
}
}
Status Codes
| Status | Meaning | Is Final |
|---|---|---|
| 0 | 草稿 | 否 |
| 1 | 基础检测完成 | 否 |
| 2 | 内容检测完成 | 否 |
| 3 | 排队上传 | 否 |
| 4 | 上传中 | 否 |
| 5 | 上传成功 | ✓ 是 |
| 6 | 上传失败 | ✓ 是 |
| 7 | 审核中 | 否 |
| 8 | 手动中止 | ✓ 是 |
Polling Strategy
python
def wait_for_upload(upload_info, timeout=30):
"""等待上传完成"""
start_time = time.time()
while time.time() - start_time < timeout:
response = requests.get(
f"https://{upload_info['global_domain']}/ous/api/v2/upload/status",
headers={"ous-token-v2": upload_info["ous_token"]}
)
data = response.json()["d"]
status = data["status"]
if status == 5: # 成功
return data["url"]
elif status in [6, 8]: # 失败或中止
raise Exception(f"上传失败: status={status}")
progress = data.get("blockUpload", {}).get("progressPercent", 0)
print(f"状态: {status}, 进度: {progress}%")
time.sleep(0.5) # 轮询间隔建议 200ms 以上
raise Exception("上传超时")
# 使用示例
file_url = wait_for_upload(upload_info)
print(f"✓ 文件上传成功: {file_url}")
Error Codes
| Code | Meaning | Description |
|---|---|---|
| 1 | 配置错误 | 配置不存在/未开启 |
| 2 | 文件大小异常 | 文件大小异常 |
| 3 | 文件格式异常 | 文件格式异常 |
| 4 | 文件内容异常 | 文件内容异常 |
| 5 | 内容安全检测异常 | 图片/音频安全校验失败 |
| 6 | 上传限制 | 同时上传任务超限/并发过高 |
| 7 | 文件上传中 | 文件正在上传中 |
| 8 | 分片操作失败 | 文件初始化失败 |
| 9 | 服务器上传限制 | 服务器上传任务较多 |
| 10 | 线程池满 | 上传线程已满 |
| 11 | 元数据超限 | 文件元信息大小超过限制 |
| 12 | Token 异常 | Token 已被使用/未绑定任务 |
| 13 | 任务异常 | 上传任务不存在/已结束 |
Complete Upload Function
python
import os
import hashlib
import requests
import time
import math
def upload_file(file_path, upload_info):
"""
完整上传流程:自动判断单文件/分片上传,并等待完成
Args:
file_path: 本地文件路径
upload_info: 包含 ous_token, global_domain, block_size
Returns:
url: 上传成功后的文件 URL
"""
file_size = os.path.getsize(file_path)
block_size = upload_info["block_size"]
# 计算 MD5
with open(file_path, "rb") as f:
md5 = hashlib.md5(f.read()).hexdigest()
print(f"📤 上传文件: {os.path.basename(file_path)} ({file_size/1024/1024:.2f}MB)")
# 判断上传方式
if file_size < block_size:
# 单文件上传
print(" 使用单文件上传")
task_id = upload_single_file(file_path, upload_info)
else:
# 分片上传
print(f" 使用分片上传 ({math.ceil(file_size/block_size)} 个分片)")
task_id = upload_large_file(file_path, upload_info)
# 等待上传完成
url = wait_for_upload(upload_info)
print(f" ✓ 上传成功: {url}")
return url