- 优化navbar滚动隐藏逻辑,更敏感响应 - 添加返回顶部按钮,固定在右下角 - 实现profile页面侧边栏真正冻结效果 - 修复首页滑动指示器位置 - 优化整体布局确保首屏内容完整显示
20 KiB
20 KiB
CarrotSkin 后端 API 文档
概述
本文档总结了 CarrotSkin 后端 API,主要关注前端需要的接口,不包括 Yggdrasil 相关接口(除了更换 Yggdrasil 密码)。
基础信息
- 基础URL:
/api/v1 - 认证方式: JWT Bearer Token
- 数据格式: JSON
- 字符编码: UTF-8
通用响应格式
所有API响应都遵循以下格式:
{
"code": 200,
"message": "操作成功",
"data": {
// 具体数据内容
}
}
分页响应格式:
{
"code": 200,
"message": "操作成功",
"data": {
"list": [],
"total": 100,
"page": 1,
"page_size": 20,
"total_pages": 5
}
}
认证相关 API
1. 用户注册
- URL:
POST /api/v1/auth/register - 认证: 无需认证
- 请求参数:
{
"username": "newuser", // 用户名,3-50字符
"email": "user@example.com", // 邮箱地址
"password": "password123", // 密码,6-128字符
"verification_code": "123456", // 邮箱验证码,6位数字
"avatar": "https://example.com/avatar.png" // 可选,头像URL
}
- 响应数据:
{
"code": 200,
"message": "注册成功",
"data": {
"token": "jwt_token_here",
"user_info": {
"id": 1,
"username": "newuser",
"email": "user@example.com",
"avatar": "https://example.com/avatar.png",
"points": 0,
"role": "user",
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
}
2. 用户登录
- URL:
POST /api/v1/auth/login - 认证: 无需认证
- 请求参数:
{
"username": "testuser", // 用户名或邮箱
"password": "password123" // 密码
}
- 响应数据:
{
"code": 200,
"message": "登录成功",
"data": {
"token": "jwt_token_here",
"user_info": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"avatar": "https://example.com/avatar.png",
"points": 100,
"role": "user",
"status": 1,
"last_login_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
}
3. 发送验证码
- URL:
POST /api/v1/auth/send-code - 认证: 无需认证
- 请求参数:
{
"email": "user@example.com", // 邮箱地址
"type": "register" // 类型: register/reset_password/change_email
}
- 响应数据:
{
"code": 200,
"message": "验证码已发送,请查收邮件",
"data": {
"message": "验证码已发送,请查收邮件"
}
}
4. 重置密码
- URL:
POST /api/v1/auth/reset-password - 认证: 无需认证
- 请求参数:
{
"email": "user@example.com", // 邮箱地址
"verification_code": "123456", // 邮箱验证码
"new_password": "newpassword123" // 新密码
}
- 响应数据:
{
"code": 200,
"message": "密码重置成功",
"data": {
"message": "密码重置成功"
}
}
用户相关 API
1. 获取用户信息
- URL:
GET /api/v1/user/profile - 认证: 需要JWT认证
- 请求参数: 无
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"avatar": "https://example.com/avatar.png",
"points": 100,
"role": "user",
"status": 1,
"last_login_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
2. 更新用户信息
- URL:
PUT /api/v1/user/profile - 认证: 需要JWT认证
- 请求参数:
{
"avatar": "https://example.com/new-avatar.png", // 可选,新头像URL
"old_password": "oldpassword123", // 可选,修改密码时需要
"new_password": "newpassword123" // 可选,新密码
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"avatar": "https://example.com/new-avatar.png",
"points": 100,
"role": "user",
"status": 1,
"last_login_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
3. 生成头像上传URL
- URL:
POST /api/v1/user/avatar/upload-url - 认证: 需要JWT认证
- 请求参数:
{
"file_name": "avatar.png" // 文件名
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"post_url": "https://rustfs.example.com/avatars",
"form_data": {
"key": "user_1/xxx.png",
"policy": "base64_policy",
"x-amz-signature": "signature"
},
"avatar_url": "https://rustfs.example.com/avatars/user_1/xxx.png",
"expires_in": 900
}
}
4. 更新头像URL
- URL:
PUT /api/v1/user/avatar - 认证: 需要JWT认证
- 请求参数:
- Query参数:
avatar_url- 头像URL
- Query参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"avatar": "https://example.com/new-avatar.png",
"points": 100,
"role": "user",
"status": 1,
"last_login_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
5. 更换邮箱
- URL:
POST /api/v1/user/change-email - 认证: 需要JWT认证
- 请求参数:
{
"new_email": "newemail@example.com", // 新邮箱地址
"verification_code": "123456" // 邮箱验证码
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"username": "testuser",
"email": "newemail@example.com",
"avatar": "https://example.com/avatar.png",
"points": 100,
"role": "user",
"status": 1,
"last_login_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
6. 重置Yggdrasil密码
- URL:
POST /api/v1/user/yggdrasil-password/reset - 认证: 需要JWT认证
- 请求参数: 无
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"password": "new_yggdrasil_password"
}
}
材质相关 API
1. 搜索材质
- URL:
GET /api/v1/texture - 认证: 无需认证
- 请求参数:
- Query参数:
keyword: 搜索关键词type: 材质类型 (SKIN/CAPE)public_only: 是否只搜索公开材质 (true/false)page: 页码,默认1page_size: 每页数量,默认20
- Query参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"list": [
{
"id": 1,
"uploader_id": 1,
"name": "My Skin",
"description": "A cool skin",
"type": "SKIN",
"url": "https://rustfs.example.com/textures/xxx.png",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 2048,
"is_public": true,
"download_count": 100,
"favorite_count": 50,
"is_slim": false,
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
],
"total": 100,
"page": 1,
"page_size": 20,
"total_pages": 5
}
}
2. 获取材质详情
- URL:
GET /api/v1/texture/{id} - 认证: 无需认证
- 请求参数:
- 路径参数:
id- 材质ID
- 路径参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"uploader_id": 1,
"name": "My Skin",
"description": "A cool skin",
"type": "SKIN",
"url": "https://rustfs.example.com/textures/xxx.png",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 2048,
"is_public": true,
"download_count": 100,
"favorite_count": 50,
"is_slim": false,
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
3. 直接上传材质文件(推荐)
- URL:
POST /api/v1/texture/upload - 认证: 需要JWT认证
- Content-Type:
multipart/form-data - 请求参数:
file: 材质文件(PNG格式,1KB-10MB)name: 材质名称(必填,1-100字符)description: 材质描述(可选,最多500字符)type: 材质类型(可选,默认SKIN,可选值:SKIN/CAPE)is_public: 是否公开(可选,默认false,true/false)is_slim: 是否为细臂模型(可选,默认false,true/false)
- 说明:
- 后端会自动计算文件的SHA256哈希值
- 如果已存在相同哈希的材质,会复用已存在的文件URL,不重复上传
- 允许多次上传相同哈希的材质(包括同一用户),每次都会创建新的数据库记录
- 文件存储路径格式:
{type}/{hash[:2]}/{hash[2:4]}/{hash}.png
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"uploader_id": 1,
"name": "My Cool Skin",
"description": "A very cool skin",
"type": "SKIN",
"url": "https://rustfs.example.com/textures/skin/e3/b0/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.png",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 2048,
"is_public": true,
"download_count": 0,
"favorite_count": 0,
"is_slim": false,
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
4. 生成材质上传URL(兼容接口)
- URL:
POST /api/v1/texture/upload-url - 认证: 需要JWT认证
- 请求参数:
{
"file_name": "skin.png", // 文件名
"texture_type": "SKIN" // 材质类型: SKIN/CAPE
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"post_url": "https://rustfs.example.com/textures",
"form_data": {
"key": "user_1/skin/xxx.png",
"policy": "base64_policy",
"x-amz-signature": "signature"
},
"texture_url": "https://rustfs.example.com/textures/user_1/skin/xxx.png",
"expires_in": 900
}
}
5. 创建材质记录(配合预签名URL使用)
- URL:
POST /api/v1/texture - 认证: 需要JWT认证
- 请求参数:
{
"name": "My Cool Skin", // 材质名称,1-100字符
"description": "A very cool skin", // 描述,最多500字符
"type": "SKIN", // 材质类型: SKIN/CAPE
"url": "https://rustfs.example.com/textures/user_1/skin/xxx.png", // 材质URL
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // SHA256哈希
"size": 2048, // 文件大小(字节)
"is_public": true, // 是否公开
"is_slim": false // 是否为细臂模型(Alex)
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"uploader_id": 1,
"name": "My Cool Skin",
"description": "A very cool skin",
"type": "SKIN",
"url": "https://rustfs.example.com/textures/user_1/skin/xxx.png",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 2048,
"is_public": true,
"download_count": 0,
"favorite_count": 0,
"is_slim": false,
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
6. 更新材质
- URL:
PUT /api/v1/texture/{id} - 认证: 需要JWT认证
- 请求参数:
- 路径参数:
id- 材质ID - 请求体:
- 路径参数:
{
"name": "Updated Skin Name", // 可选,新名称
"description": "Updated description", // 可选,新描述
"is_public": false // 可选,是否公开
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"uploader_id": 1,
"name": "Updated Skin Name",
"description": "Updated description",
"type": "SKIN",
"url": "https://rustfs.example.com/textures/user_1/skin/xxx.png",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 2048,
"is_public": false,
"download_count": 100,
"favorite_count": 50,
"is_slim": false,
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
7. 删除材质
- URL:
DELETE /api/v1/texture/{id} - 认证: 需要JWT认证
- 请求参数:
- 路径参数:
id- 材质ID
- 路径参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": null
}
8. 切换收藏状态
- URL:
POST /api/v1/texture/{id}/favorite - 认证: 需要JWT认证
- 请求参数:
- 路径参数:
id- 材质ID
- 路径参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"is_favorited": true
}
}
9. 获取用户上传的材质列表
- URL:
GET /api/v1/texture/my - 认证: 需要JWT认证
- 请求参数:
- Query参数:
page: 页码,默认1page_size: 每页数量,默认20
- Query参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"list": [
{
"id": 1,
"uploader_id": 1,
"name": "My Skin",
"description": "A cool skin",
"type": "SKIN",
"url": "https://rustfs.example.com/textures/xxx.png",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 2048,
"is_public": true,
"download_count": 100,
"favorite_count": 50,
"is_slim": false,
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
],
"total": 50,
"page": 1,
"page_size": 20,
"total_pages": 3
}
}
10. 获取用户收藏的材质列表
- URL:
GET /api/v1/texture/favorites - 认证: 需要JWT认证
- 请求参数:
- Query参数:
page: 页码,默认1page_size: 每页数量,默认20
- Query参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"list": [
{
"id": 1,
"uploader_id": 2,
"name": "Cool Skin",
"description": "A very cool skin",
"type": "SKIN",
"url": "https://rustfs.example.com/textures/xxx.png",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"size": 2048,
"is_public": true,
"download_count": 100,
"favorite_count": 50,
"is_slim": false,
"status": 1,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
],
"total": 30,
"page": 1,
"page_size": 20,
"total_pages": 2
}
}
档案相关 API
1. 创建档案
- URL:
POST /api/v1/profile - 认证: 需要JWT认证
- 请求参数:
{
"name": "PlayerName" // 角色名,1-16字符
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"user_id": 1,
"name": "PlayerName",
"skin_id": null,
"cape_id": null,
"is_active": false,
"last_used_at": null,
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
2. 获取档案列表
- URL:
GET /api/v1/profile - 认证: 需要JWT认证
- 请求参数: 无
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": [
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"user_id": 1,
"name": "PlayerName",
"skin_id": 1,
"cape_id": 2,
"is_active": true,
"last_used_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
]
}
3. 获取档案详情
- URL:
GET /api/v1/profile/{uuid} - 认证: 无需认证
- 请求参数:
- 路径参数:
uuid- 档案UUID
- 路径参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"user_id": 1,
"name": "PlayerName",
"skin_id": 1,
"cape_id": 2,
"is_active": true,
"last_used_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
4. 更新档案
- URL:
PUT /api/v1/profile/{uuid} - 认证: 需要JWT认证
- 请求参数:
- 路径参数:
uuid- 档案UUID - 请求体:
- 路径参数:
{
"name": "NewPlayerName", // 可选,新角色名
"skin_id": 1, // 可选,皮肤ID
"cape_id": 2 // 可选,披风ID
}
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"user_id": 1,
"name": "NewPlayerName",
"skin_id": 1,
"cape_id": 2,
"is_active": true,
"last_used_at": "2025-10-01T12:00:00Z",
"created_at": "2025-10-01T10:00:00Z",
"updated_at": "2025-10-01T10:00:00Z"
}
}
5. 删除档案
- URL:
DELETE /api/v1/profile/{uuid} - 认证: 需要JWT认证
- 请求参数:
- 路径参数:
uuid- 档案UUID
- 路径参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"message": "删除成功"
}
}
6. 设置活跃档案
- URL:
POST /api/v1/profile/{uuid}/activate - 认证: 需要JWT认证
- 请求参数:
- 路径参数:
uuid- 档案UUID
- 路径参数:
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"message": "设置成功"
}
}
验证码相关 API
1. 生成验证码
- URL:
GET /api/v1/captcha/generate - 认证: 无需认证
- 请求参数: 无
- 响应数据:
{
"code": 200,
"data": {
"masterImage": "base64_encoded_master_image",
"tileImage": "base64_encoded_tile_image",
"captchaId": "captcha_id_here",
"y": 100
}
}
2. 验证验证码
- URL:
POST /api/v1/captcha/verify - 认证: 无需认证
- 请求参数:
{
"captchaId": "captcha_id_here",
"dx": 150 // 滑动距离
}
- 响应数据:
{
"code": 200,
"msg": "验证成功"
}
系统相关 API
1. 获取系统配置
- URL:
GET /api/v1/system/config - 认证: 无需认证
- 请求参数: 无
- 响应数据:
{
"code": 200,
"message": "操作成功",
"data": {
"site_name": "CarrotSkin",
"site_description": "A Minecraft Skin Station",
"registration_enabled": true,
"max_textures_per_user": 100,
"max_profiles_per_user": 5
}
}
CustomSkin API
1. 获取玩家信息
- URL:
GET /api/v1/csl/{username} - 认证: 无需认证
- 请求参数:
- 路径参数:
username- 玩家用户名
- 路径参数:
- 响应数据:
{
"username": "PlayerName",
"textures": {
"default": "skin_hash_here",
"slim": "skin_hash_here",
"cape": "cape_hash_here",
"elytra": "cape_hash_here"
}
}
或简化格式:
{
"username": "PlayerName",
"skin": "skin_hash_here"
}
2. 获取资源文件
- URL:
GET /api/v1/csl/textures/{hash} - 认证: 无需认证
- 请求参数:
- 路径参数:
hash- 资源哈希值
- 路径参数:
- 响应数据: 二进制文件内容
健康检查
1. 健康检查
- URL:
GET /health - 认证: 无需认证
- 请求参数: 无
- 响应数据:
{
"status": "ok"
}
错误码说明
| 错误码 | 说明 |
|---|---|
| 200 | 操作成功 |
| 400 | 请求参数错误 |
| 401 | 未认证或认证失败 |
| 403 | 无权限操作 |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
认证说明
需要JWT认证的API需要在请求头中添加:
Authorization: Bearer {jwt_token}
JWT Token在用户登录或注册成功后返回,有效期内可用于访问需要认证的API。