# CarrotSkin API 文档(基于后端代码,2026-07 修订) > 本文档由后端 `internal/handler/*.go` + `internal/types/common.go` 直接整理而来, > 是前后端契约的唯一事实来源。所有路径以 `/api/v1` 为前缀(Yggdrasil / CSL 除外)。 ## 通用约定 ### 统一响应格式 成功: ```json { "code": 200, "message": "操作成功", "data": <任意> } ``` 错误: ```json { "code": <非200>, "message": "<错误描述>", "error": "<仅非生产环境返回>" } ``` 常用状态码:`200 成功` / `201 创建成功` / `400 参数错误` / `401 未授权` / `403 禁止` / `404 不存在` / `500 服务器错误`。 ### 认证 - 除"无需认证"标注的接口外,所有 `/user/*`、`/profile` 写操作、`/texture` 写操作均需在请求头携带: `Authorization: Bearer ` - JWT 通过登录或注册接口获取。 ### 分页 - 请求参数:`page`(页码,默认 1)、`page_size`(每页数量,默认 20)。 - 响应数据形态(注意:后端返回的字段名是 **`per_page`**,且 **不含 `total_pages`**): ```json { "code": 200, "message": "操作成功", "data": { "list": [ ... ], "total": 100, "page": 1, "per_page": 20 } } ``` --- ## 一、认证 `/auth`(无需 JWT) ### 1. 用户注册 - `POST /api/v1/auth/register` - Body: ```json { "username": "newuser", "email": "user@example.com", "password": "password123", "verification_code": "123456", "captcha_id": "uuid-xxxx", "avatar": "https://example.com/a.png" } ``` - `username` 3–50 字符;`password` 6–128;`verification_code` 必填 6 位; - `captcha_id` 必填(来自 `POST /captcha/verify` 后透传的 `captchaId`); - `avatar` 可选,必须是合法 URL。 - 响应 `data`: ```json { "token": "", "user_info": { "id": 1, "username": "newuser", "email": "user@example.com", "avatar": "", "points": 0, "role": "user", "status": 1, "last_login_at": null, "created_at": "2026-07-08T10:00:00Z", "updated_at": "2026-07-08T10:00:00Z" } } ``` ### 2. 用户登录 - `POST /api/v1/auth/login` - Body: ```json { "username": "newuser 或 user@example.com", "password": "password123" } ``` - 响应 `data`:同注册(`{ token, user_info }`)。 ### 3. 发送邮箱验证码 - `POST /api/v1/auth/send-code` - Body: ```json { "email": "user@example.com", "type": "register | reset_password | change_email" } ``` - 响应 `data`:`{ "message": "验证码已发送,请查收邮件" }`。 ### 4. 重置密码 - `POST /api/v1/auth/reset-password` - Body: ```json { "email": "user@example.com", "verification_code": "123456", "new_password": "newpassword123" } ``` - 响应 `data`:`{ "message": "密码重置成功" }`。 --- ## 二、用户 `/user`(需 JWT) ### 5. 获取当前用户信息 - `GET /api/v1/user/profile` - 响应 `data`:`UserInfo`(同注册返回的 `user_info`)。 ### 6. 更新用户信息(密码 / 头像 URL) - `PUT /api/v1/user/profile` - Body: ```json { "avatar": "https://example.com/a.png", // 可选,更新头像 URL "old_password": "oldpassword123", // 修改密码时必填 "new_password": "newpassword123" // 6–128 } ``` - 响应 `data`:更新后的 `UserInfo`。 ### 7. 上传头像文件 - `POST /api/v1/user/avatar/upload`(multipart/form-data) - 字段:`file`(图片文件,≤10MB) - 响应 `data`: ```json { "avatar_url": "https://.../avatar.png", "user": { ...UserInfo } } ``` ### 8. 更新头像 URL(外部 URL) - `PUT /api/v1/user/avatar?avatar_url=` - 响应 `data`:`UserInfo`。 ### 9. 更换邮箱 - `POST /api/v1/user/change-email` - Body: ```json { "new_email": "new@example.com", "verification_code": "123456" } ``` - 响应 `data`:更换后的 `UserInfo`(新邮箱已生效)。 ### 10. 重置 Yggdrasil 密码 - `POST /api/v1/user/yggdrasil-password/reset` - 响应 `data`:`{ "password": "<新的Yggdrasil密码>" }`。 ### 11. 获取用户公开信息 - `GET /api/v1/users/public?username=` 或 `?id=`(无需 JWT) - 响应 `data`: ```json { "id": 1, "username": "testuser", "avatar": "", "points": 100, "role": "user", "status": 1, "created_at": "2026-07-01T10:00:00Z" } ``` --- ## 三、材质 `/texture` ### 12. 搜索材质(公开,无需 JWT) - `GET /api/v1/texture` - Query:`keyword` / `type=SKIN|CAPE` / `public_only=true` / `page` / `page_size` - 响应 `data`:分页结构 `{ list: TextureInfo[], total, page, per_page }`。 ### 13. 获取材质详情(公开) - `GET /api/v1/texture/:id` - 响应 `data`:`TextureInfo`。 ### 14. 上传材质(需 JWT,multipart) - `POST /api/v1/texture/upload` - formData:`file`(PNG, ≤32MB)、`name`(必填)、`description`、`type=SKIN|CAPE`、`is_public`、`is_slim` - 响应 `data`:`TextureInfo`。 ### 15. 更新材质(需 JWT) - `PUT /api/v1/texture/:id` - Body: ```json { "name": "新名称", "description": "新描述", "is_public": true } ``` - `is_public` 后端为 `*bool`,传 `true/false` 会更新;不传保持不变。 - 响应 `data`:`TextureInfo`。 ### 16. 删除材质(需 JWT) - `DELETE /api/v1/texture/:id` - 响应 `data`:`null`。 ### 17. 切换收藏(需 JWT) - `POST /api/v1/texture/:id/favorite` - 响应 `data`:`{ "is_favorited": true }`。 ### 18. 我的上传(需 JWT) - `GET /api/v1/texture/my?page=1&page_size=20` - 响应 `data`:分页结构。 ### 19. 我的收藏(需 JWT) - `GET /api/v1/texture/favorites?page=1&page_size=20` - 响应 `data`:分页结构。 #### TextureInfo 字段 `id, uploader_id, uploader_username, name, description(omitempty), type(SKIN|CAPE), url, hash, size, is_public, download_count, favorite_count, is_slim, status, created_at, updated_at` --- ## 四、档案 `/profile` > ⚠️ **后端当前 `PUT /profile/:uuid` 不支持解除皮肤/披风绑定**: > `UpdateProfileRequest.SkinID / CapeID` 为 `*int64`,仅当非 nil 时才更新; > 传 `null` 与字段缺失都会被 Go 反序列化为 `nil`,二者无法区分,均被忽略。 > 因此前端要"移除角色皮肤",需要后端先支持(详见下方《待补齐》)。 ### 20. 获取档案列表(需 JWT) - `GET /api/v1/profile` 或 `GET /api/v1/profile/` - 响应 `data`:`ProfileInfo[]`。 ### 21. 创建档案(需 JWT) - `POST /api/v1/profile` 或 `POST /api/v1/profile/` - Body:`{ "name": "PlayerName" }`(1–16 字符) - 响应 `data`:`ProfileInfo`。 ### 22. 获取档案详情(公开) - `GET /api/v1/profile/:uuid` - 响应 `data`:`ProfileInfo`。 ### 23. 更新档案(需 JWT) - `PUT /api/v1/profile/:uuid` - Body: ```json { "name": "NewName", "skin_id": 1, "cape_id": 2 } ``` - 当前实现:`skin_id/cape_id` 传数字会设置;传 null / 缺失均被忽略(无法清空)。 - 响应 `data`:`ProfileInfo`。 ### 24. 删除档案(需 JWT) - `DELETE /api/v1/profile/:uuid` - 响应 `data`:`{ "message": "删除成功" }`。 #### ProfileInfo 字段 `uuid, user_id, name, skin_id(omitempty,可空), cape_id(omitempty,可空), last_used_at(omitempty), created_at, updated_at` --- ## 五、滑动验证码 `/captcha`(无需 JWT) ### 25. 生成滑动验证码 - `GET /api/v1/captcha/generate` - 响应(注意:此接口的响应是直接对象,未包裹 `data`): ```json { "code": 200, "data": { "masterImage": "", "tileImage": "", "captchaId": "<进程ID,注册时需要>", "y": <缺口纵坐标> } } ``` ### 26. 校验滑动验证码 - `POST /api/v1/captcha/verify` - Body:`{ "captchaId": "", "dx": <横坐标> }` - 响应:`{ "code": 200, "msg": "验证成功" }` 或 `{ "code": 400, "msg": "验证失败,请重试" }` --- ## 六、Yggdrasil API `/api/yggdrasil`(独立前缀,供 MC 客户端使用) - `GET /api/yggdrasil` —— 元数据 - `POST /api/yggdrasil/minecraftservices/player/certificates` - `POST /api/yggdrasil/authserver/authenticate` - `POST /api/yggdrasil/authserver/validate` - `POST /api/yggdrasil/authserver/refresh` - `POST /api/yggdrasil/authserver/invalidate` - `POST /api/yggdrasil/authserver/signout` - `GET /api/yggdrasil/sessionserver/session/minecraft/profile/:uuid` - `POST /api/yggdrasil/sessionserver/session/minecraft/join` - `GET /api/yggdrasil/sessionserver/session/minecraft/hasJoined` - `POST /api/yggdrasil/api/profiles/minecraft` ## 七、CustomSkinAPI `/api/v1/csl`(公开) - `GET /api/v1/csl/:username` —— 获取玩家信息 JSON - `GET /api/v1/csl/textures/:hash` —— 获取资源文件 ## 八、管理员 `/api/v1/admin`(需 JWT + 管理员) - `GET /admin/users`、`GET /admin/users/:id` - `PUT /admin/users/role`、`PUT /admin/users/status` - `GET /admin/textures`、`DELETE /admin/textures/:id` - `GET /admin/permissions` --- ## 待补齐(后端缺陷,影响前端可用性) 1. **`PUT /profile/:uuid` 不支持清空 skin/cape** 现状:`SkinID/CapeID *int64` 无法区分"未传"与"显式 null"。 建议:改用 `json.RawMessage` 区分三种语义(缺失=不修改 / null=清空 / 数字=设置), 或新增 `remove_skin` / `remove_cape` 布尔字段。前端"移除角色皮肤"依赖此能力。