feat: 开发采集、采集箱和商品编辑功能

This commit is contained in:
Joey
2026-08-15 22:17:26 +08:00
parent c61d1a3154
commit 36357843d0
130 changed files with 18005 additions and 12 deletions
+234
View File
@@ -0,0 +1,234 @@
# Ozon Seller API 鉴权与基础
> 官方文档:https://docs.ozon.ru/api/seller/zh/#tag/Introduction
---
## 1. 鉴权方式
Ozon Seller API 使用 **API Key 鉴权**(非 OAuth),每个请求需在请求头携带:
```http
Client-Id: < Client ID>
Api-Key: < API Key>
Content-Type: application/json
```
### 获取凭证
1. 登录 Ozon 卖家后台
2. 进入「设置」→「Seller API」
3. 点击「生成 API Key」
4. 选择权限级别:
- **只读**Read):仅查询
- **读写**Read & Write):查询 + 创建/更新商品
- **管理员**(Admin):所有权限
5. 保存 `Client-Id``Api-Key`**Api-Key 仅显示一次**
### 安全约束
- ⚠️ **Api-Key 等同密码**:泄露后任何人可操作你的店铺
- 🔒 **服务端存储**:加密落库(AES-GCM),前端永不传输/回显明文
- 🔄 **定期轮换**:建议每 90 天更换一次
- 🚫 **前端禁用**:插件/studio 不得持有店铺凭证,只能持有用户 token
---
## 2. Base URL
```
https://api-seller.ozon.ru
```
所有接口路径都基于此 URL,例如:
```
POST https://api-seller.ozon.ru/v3/product/import
```
---
## 3. 请求示例
### cURL
```bash
curl -X POST "https://api-seller.ozon.ru/v1/description-category/tree" \
-H "Client-Id: 123456" \
-H "Api-Key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"language":"RU"}'
```
### Python (httpx)
```python
import httpx
headers = {
"Client-Id": "123456",
"Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"Content-Type": "application/json"
}
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.post(
"https://api-seller.ozon.ru/v1/description-category/tree",
headers=headers,
json={"language": "RU"}
)
data = resp.json()
```
---
## 4. 通用响应结构
### 成功响应(200/201
```json
{
"result": { /* */ }
}
```
部分接口直接返回数组或对象,不包裹 `result`
### 错误响应(4xx/5xx
```json
{
"code": 400,
"message": "INVALID_ARGUMENT",
"details": [
{
"typeUrl": "type.googleapis.com/ozon.ValidationError",
"value": "..."
}
]
}
```
或简化版:
```json
{
"error": {
"code": "INVALID_PARAMETER",
"message": "offer_id is required"
}
}
```
---
## 5. 错误码
| HTTP 状态码 | 含义 | 常见原因 | 处理建议 |
|---|---|---|---|
| **400** | 参数错误 | 必填字段缺失 / 格式错误 / 枚举值非法 | 检查请求体字段,读 `details` 定位 |
| **401** | 未鉴权 | 请求头缺 `Client-Id``Api-Key` | 检查请求头 |
| **403** | 权限不足 | Api-Key 权限级别不够(如只读 key 调创建接口) | 重新生成读写权限 key |
| **404** | 资源不存在 | `product_id` / `category_id` 不存在 | 检查 ID 是否正确 |
| **409** | 资源冲突 | `offer_id` 重复 / 商品已存在 | 改用唯一 offer_id 或走更新接口 |
| **429** | 限流 | 请求频率超限 | 指数退避重试(1s → 2s → 4s) |
| **500** | 服务端错误 | Ozon 内部错误 | 重试 1-2 次,仍失败则联系支持 |
| **503** | 服务不可用 | 维护中 | 稍后重试 |
---
## 6. 限流规则
官方未公开明确的限流阈值,根据社区经验:
- **常规接口**~10 req/s
- **批量接口**(如 `/v3/product/list`):~5 req/s
- **同一 task_id 轮询**:建议间隔 ≥5s
触发 429 后:
1. 解析响应头 `Retry-After`(秒数)
2. 若无此头,使用指数退避:1s → 2s → 4s → 8s
3. 最多重试 3 次
---
## 7. 超时建议
| 接口类型 | 超时时间 | 理由 |
|---|---|---|
| 查询类(类目/属性/商品列表) | 30s | 轻量请求 |
| 导入类(`/v3/product/import` | 60-90s | 后端需校验 + 入库 |
| 轮询状态(`/v1/product/import/info`) | 30s | 单次轮询快,但需多次 |
| 图片上传 | 90s | 网络传输耗时 |
---
## 8. 测试凭证有效性
### `/v1/roles` —— 获取当前 Key 的角色与权限
```http
POST https://api-seller.ozon.ru/v1/roles
```
**请求体**:空 `{}`
**响应**
```json
{
"result": [
{
"role_name": "Seller",
"permissions": [
"read:products",
"write:products",
"read:categories",
...
]
}
]
}
```
**用途**
- ✅ 验证凭证有效性(200 = 有效,401/403 = 无效)
- ✅ 查看权限范围(判断是否有 `write:products`
- ✅ 零业务副作用(不消耗额度,不修改数据)
**V2 集成点**`POST /api/shops/:id/test` 调此接口作连通性校验。
---
## 9. 请求 ID 追踪
部分接口响应包含 `request_id`(如图生图、导入任务),用于:
- 问题排查:联系 Ozon 支持时提供此 ID
- 幂等重试:某些接口可根据 `request_id` 避免重复创建
建议:每次请求在日志里记录 `request_id`(若有)与请求体摘要,便于回溯。
---
## 10. 环境
Ozon Seller API **仅生产环境**,无测试沙箱。调试时需注意:
- ⚠️ 所有操作都在真实店铺
- 💡 建议用「测试商品」标识(如 offer_id 前缀 `TEST-`
- 🗑️ 测试后及时删除/归档测试商品
---
## 11. SDK 与工具
官方未提供 Python SDK,社区方案:
- 自封装 `httpx` 客户端(V2 采用,见 `server/services/ozon_client.py`
- 第三方库:`ozon-api`PyPI,非官方,更新滞后)
---
## 12. 相关链接
- [官方文档(中文)](https://docs.ozon.ru/api/seller/zh/)
- [官方文档(俄文)](https://docs.ozon.ru/api/seller/)
- [卖家后台](https://seller.ozon.ru/)
- [API 状态页](https://status.ozon.ru/)(维护公告)