mikochi 1.12.2 API 使用详解
mikochi 1.12.2 全部 11 个 REST 端点实测手册:双令牌认证体系(Bearer 头 JWT 与 auth 参数流式令牌)、browse/upload/move/delete/stream 逐域实测回显、错误码速查表、登录指数退避限流与 1.12.0 端点改名破坏性变更。
mikochi 1.12.2 API 使用详解
目标:本篇完整覆盖 mikochi 1.12.2 的 REST API——全部 11 个端点的认证方式、请求参数与实测响应回显(含错误码、限流与流式令牌机制),命令均经真实环境逐条执行验证,可直接作为脚本化操作 mikochi 的参考手册。
一、环境信息
- 操作系统:Linux x86_64(内核 5.x 系列,Ubuntu 系发行版实测)
- mikochi:1.12.2(官方镜像
zer0tonin/mikochi:1.12.2,Docker Compose 部署,栈mikochi-1.12.2-stack) - API 基地址:
http://127.0.0.1:8148(宿主机端口 8148 映射服务内 8080) - 客户端工具:curl(系统自带即可,全部示例可直接复制执行)
- 登录凭据:
admin/q1w2e3r4(演示账号) - API 契约基准:1.12.2 运行实例逐条实测(查询日期 2026-10-30);注意 1.12.0 起 API 有一处破坏性变更——流式令牌端点由
/api/single-use更名为/api/stream-token,旧脚本升级时需同步改名
二、前置条件
- 一个可用的 mikochi 1.12.2 实例(部署见 《mikochi 1.12.2 Docker Compose 部署指南》);
- curl 命令行工具(或 Postman 等等效客户端);
- 理解两类令牌的分工(下文 4.1 节):普通操作用
Authorization: Bearer头,流式播放用auth查询参数; - 健康自检:
curl -s http://127.0.0.1:8148/ready,预期{"status":"ok"}(实测回显)。
三、API 总览
3.1 协议与端点清单
REST 风格,JSON 报文为主(上传为 multipart 表单,流式下载为原始文件流)。全部端点如下:
| 分域 | 方法 | 端点 | 认证载体 | 作用 |
|---|---|---|---|---|
| 认证 | POST | /api/login | 无 | 登录换取 JWT(730 小时) |
| 认证 | GET | /api/refresh | Bearer 头 | 续签新 JWT |
| 认证 | POST | /api/logout | Bearer 头 | 吊销当前令牌(jti 黑名单) |
| 认证 | GET | /api/stream-token | Bearer 头 | 为单个文件签发 24 小时流式令牌 |
| 浏览 | GET | /api/browse/*path | Bearer 头 | 列目录 / 模糊搜索 |
| 流式 | GET | /api/stream/*path | auth 查询参数 | 拉流播放或下载(目录自动 tar.gz) |
| 写操作 | PUT | /api/upload/*path | Bearer 头 | 上传文件(multipart,字段名 file) |
| 写操作 | PUT | /api/mkdir/*path | Bearer 头 | 创建目录 |
| 写操作 | PUT | /api/move/*path | Bearer 头 | 移动/重命名(JSON body) |
| 写操作 | DELETE | /api/delete/*path | Bearer 头 | 删除文件/目录(递归) |
| 健康检查 | GET | /ready | 无 | k8s 就绪探针端点 |
3.2 认证与限流约定
- 普通令牌:
POST /api/login签发,JWT HS256,payload 含scope: "mikochi-user"与jti(令牌唯一 ID),有效期 730 小时;请求时以Authorization: Bearer <token>头携带; - 登出黑名单:logout 把当前令牌的 jti 拉入黑名单并保留 730 小时(与令牌寿命一致),期间同 jti 的令牌即使签名正确也返回 403;
- 流式令牌:与普通令牌完全独立——scope 即目标文件路径、有效期 24 小时、经
auth查询参数传递(专为 VLC/mpv 这类无法自定义请求头的播放器设计),且不进登出黑名单; - 登录限流:按用户名指数退避,第 n 次失败冷却 2^n 秒(1s → 2s → 4s → …),成功登录即重置;被限流时返回 HTTP 429;
- 路径约定:所有
*path均相对DATA_DIR,以/开头(/docs/report.md即DATA_DIR/docs/report.md)。
四、认证与首次调用
4.1 登录拿令牌
curl -s -X POST http://127.0.0.1:8148/api/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}'
实测回显(token 节选):
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6Im1pa29jaGktdXNlciIsImlzcyI6Ik1pa29jaGkiLCJleHAiOjE3OTU5NzUwNjksImlhdCI6MTc5MzM0NzA2OSwianRpIjoiNDk5OTM5MTEtODY3Yy00NDVlLWJhOGEtMGZiZDk1YjVhMTljIn0.d0tN0jDdvqgDYdWeaq8ePUhwc8Dm-rfQvXsjHLMD52Y"}
解码 payload 可见 scope、iss: "Mikochi"、exp(签发时间 + 730 小时)、jti。下文示例统一以 $TOKEN 表示该令牌:
TOKEN=$(curl -s -X POST http://127.0.0.1:8148/api/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}' | sed -E 's/.*"token":"([^"]+)".*/\1/')
4.2 未认证与错误凭据的对照
未携带令牌访问受保护接口:
$ curl -s http://127.0.0.1:8148/api/browse/
{"err":"Invalid Authorization header format"} # HTTP 400:连 Bearer 头都没有
密码错误:
$ curl -s -X POST http://127.0.0.1:8148/api/login \
-H 'Content-Type: application/json' -d '{"username":"admin","password":"wrong"}' -w ' [HTTP %{http_code}]'
{"err":"Invalid credentials"} [HTTP 401]
连续失败触发限流(实测第 2 次失败起):
{"err":"You are being rate limited"} [HTTP 429]
4.3 首次成功调用
拿到令牌后第一件事——列根目录,验证认证与数据边界同时成立:
curl -s http://127.0.0.1:8148/api/browse/ -H "Authorization: Bearer $TOKEN"
实测回显(数据目录预置两个测试文件):
{"fileInfos":[{"isDir":false,"size":14,"path":"/hello.txt"},{"isDir":false,"size":0,"path":"/sample.bin"}],"isRoot":true}
五、各 API 域详解
5.1 浏览域:/api/browse
GET /api/browse/*path(Bearer 头认证)
- 路径参数
*path:目标目录(/为根); - 查询参数
search(可选):提供时在当前目录子树内做模糊搜索并按匹配度排序,不提供时列出当前目录直接子项。
列子目录:
$ curl -s http://127.0.0.1:8148/api/browse/docs -H "Authorization: Bearer $TOKEN"
{"fileInfos":[{"isDir":false,"size":14,"path":"/docs/report.md"}],"isRoot":false}
模糊搜索(搜索词 sam 命中 /sample.bin):
$ curl -s "http://127.0.0.1:8148/api/browse/?search=sam" -H "Authorization: Bearer $TOKEN"
{"fileInfos":[{"isDir":false,"size":2048,"path":"/sample.bin"}],"isRoot":true}
响应字段说明:fileInfos[].path 为相对根的绝对路径;isDir 区分目录与文件;size 字节数(目录固定 4096);顶层 isRoot 标识是否正在浏览根目录。
5.2 写操作域:upload / mkdir / move / delete
PUT /api/mkdir/*path(Bearer 头)——创建目录:
$ curl -s -X PUT http://127.0.0.1:8148/api/mkdir/docs -H "Authorization: Bearer $TOKEN"
{"status":"ok"}
PUT /api/upload/*path(Bearer 头)——上传文件。路径即上传后的目标路径,请求体必须是 multipart 表单且字段名固定为 file:
$ curl -s -X PUT http://127.0.0.1:8148/api/upload/docs/report.md \
-F "file=@./data/hello.txt" -H "Authorization: Bearer $TOKEN"
{"status":"ok"}
错误姿势实测(直接放二进制体,非 multipart):
$ curl -s -X PUT http://127.0.0.1:8148/api/upload/hello.txt \
--data-binary @data/hello.txt -H "Authorization: Bearer $TOKEN"
{"err":"Couldn't read file from request"} # HTTP 400
PUT /api/move/*path(Bearer 头)——移动或重命名,JSON body 指定新路径:
$ curl -s -X PUT http://127.0.0.1:8148/api/move/hello.txt \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"newPath":"/hello-renamed.txt"}'
{"status":"ok"}
body 字段名是驼峰 newPath(不是 new_path);目标路径同样相对 DATA_DIR。
DELETE /api/delete/*path(Bearer 头)——删除(文件与目录同一端点,目录递归真删、无回收站):
$ curl -s -X DELETE http://127.0.0.1:8148/api/delete/hello-renamed.txt -H "Authorization: Bearer $TOKEN"
{"status":"ok"}
⚠️ 注意:delete 对目录执行的是递归删除且不可撤销,脚本化批量删除前先以 browse 核对路径;写操作成功后服务端会同步刷新内存索引,紧随其后的 browse 不会读到旧数据(实测验证)。
5.3 流式域:stream-token + stream
这是 mikochi API 设计上最有特色的一域,两步协作:
第一步,签发流式令牌——GET /api/stream-token?target=<路径>(Bearer 头):
$ curl -s "http://127.0.0.1:8148/api/stream-token?target=/sample.bin" -H "Authorization: Bearer $TOKEN"
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6Ii9zYW1wbGUuYmluIiwiaXNzIjoiTWlrb2NoaSIsImV4cCI6MTc5MzQzMzczMiwiaWF0IjoxNzkzMzQ3MzMyLCJqdGkiOiI3ZDU3NmM1OS03MzRkLTRmZDQtYmQ1OS03NDZkMmZhMzBmZGYifQ.w8jq_..."}(节选)
解码 payload:scope 字段即绑定的目标路径 /sample.bin,exp - iat = 86400 秒(24 小时)。
第二步,凭 auth 查询参数拉流——GET /api/stream/*path?auth=<流式令牌>:
$ curl -s "http://127.0.0.1:8148/api/stream/sample.bin?auth=$ST" | head -c 48 | xxd | head -2
00000000: b628 505d b6e2 5dac 2f45 cce4 ac40 c7c6 .(P]..]./E...@..
00000010: fbca b806 c9ca cac9 adc9 0584 5edc 8e8d ............^...
($ST 为第一步签发的流式令牌;文件流原样返回,VLC/mpv 直接打开形如 http://<host>:8148/api/stream/sample.bin?auth=<token> 的 URL 即可播放。)
令牌与路径严格绑定——拿 /sample.bin 的令牌去请求别的文件:
$ curl -s "http://127.0.0.1:8148/api/stream/hello.txt?auth=$ST" -w ' [HTTP %{http_code}]'
{"err":"Expired token"} [HTTP 401]
("Expired token" 这个错误文案实际涵盖"scope 不匹配",令牌本身没过期——实测确认。)
目录流式下载:对目录路径发起 stream,服务端自动打包为 tar.gz 并附下载头:
$ curl -s "http://127.0.0.1:8148/api/stream/docs?auth=$SD" -o docs.tar.gz -w '[HTTP %{http_code}] bytes=%{size_download}\n'
[HTTP 200] bytes=124
$ tar -tzf docs.tar.gz
/report.md
令牌传错位置(用 token 参数而非 auth)的实测:
$ curl -s "http://127.0.0.1:8148/api/stream/sample.bin?token=$ST"
{"err":"Failed to parse token"} [HTTP 401]
5.4 会话域:refresh 与 logout
GET /api/refresh(Bearer 头)——用旧令牌换新令牌(续期):
$ curl -s http://127.0.0.1:8148/api/refresh -H "Authorization: Bearer $TOKEN"
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6Im1pa29jaGktdXNlciIsImlzcyI6Ik1pa29jaGkiLCJleHAiOjE3OTU5NzUxN..."}(节选)
POST /api/logout(Bearer 头)——吊销当前令牌:
$ curl -s -X POST http://127.0.0.1:8148/api/logout -H "Authorization: Bearer $TOKEN"
{"message":"Logged out successfully"}
登出后同一令牌立即失效(jti 进黑名单),实测:
$ curl -s http://127.0.0.1:8148/api/browse/ -H "Authorization: Bearer $TOKEN"
{"err":"Invalid token"} # HTTP 403:签名正确但 jti 已被吊销
黑名单语义可再验证一步:拿已登出的令牌去签流式令牌,同样被拒:
$ curl -s "http://127.0.0.1:8148/api/stream-token?target=/sample.bin" -H "Authorization: Bearer $TOKEN"
{"err":"Invalid token"} [HTTP 403]
5.5 健康检查域:/ready
$ curl -s http://127.0.0.1:8148/ready
{"status":"ok"}
无需认证,k8s 就绪/存活探针直接指向它即可。
六、错误码与响应速查
| HTTP 状态 | 实测报文 | 触发场景 |
|---|---|---|
| 200 | {"status":"ok"} / JSON 数据 | 正常 |
| 400 | {"err":"Invalid Authorization header format"} | 缺少或格式错误的 Bearer 头 |
| 400 | {"err":"Couldn't read file from request"} | 上传非 multipart 或字段名不是 file |
| 400 | {"err":"Couldn't deserialize command"} | move 的 JSON body 解析失败 |
| 400 | {"err":"Invalid path"} | 路径逃逸 DATA_DIR 或非法 |
| 401 | {"err":"Invalid credentials"} | 登录凭据错误 |
| 401 | {"err":"Failed to parse token"} | 令牌无法解析(签名密钥不符/传参位置错/重启后旧令牌) |
| 401 | {"err":"Expired token"} | 流式令牌过期或 scope 与请求路径不匹配 |
| 403 | {"err":"Invalid token"} | jti 已被 logout 吊销 |
| 429 | {"err":"You are being rate limited"} | 登录失败触发指数退避限流 |
| 500 | {"err":"Couldn't move file"} 等 | 服务端文件系统操作失败(如目标父目录不存在) |
💡 说明:mikochi 的错误报文统一为
{"err": "<一句话>"}(logout 成功报文为{"message": ...}属例外),脚本解析时按err字段判错即可;Expired token文案具有二义性(过期或不匹配),排障时先核对 scope 与路径是否完全一致(含前导斜杠)。
七、分页、过滤与排序的通用约定
mikochi API 没有分页、排序与字段过滤参数——浏览接口一次性返回目录全部直接子项,搜索接口返回全部匹配项。相关约定替代如下:
- 大目录性能由服务端内存索引兜底(浏览不落盘遍历),实测根目录请求毫秒级返回(Gin 日志显示 browse 类请求耗时约 50–100µs 量级);
- 排序由前端按名称组织,API 层保持原始顺序;
- 需要"分页"效果时用
search参数缩小结果集(模糊匹配当前目录子树)。
脚本化调用时的实用约定:写操作(upload/mkdir/move/delete)成功返回一律是 {"status":"ok"},读操作返回 {"fileInfos": [...], "isRoot": bool},以此区分成败即可,无需依赖 HTTP 状态码细分。
八、常见问题
Q1:脚本里 token 该放哪个位置?
两套体系:普通接口放 Authorization: Bearer 请求头;stream 接口放 auth 查询参数。实测把流式令牌放进 token 查询参数会得到 Failed to parse token。
Q2:升级 1.12.0+ 后旧脚本报 404?
流式令牌端点改名:/api/single-use → /api/stream-token(1.12.0 破坏性变更,官方 Release Note 明示)。语义同时明确为"绑定单文件 + 24 小时有效",并非字面上的"一次性"。
Q3:move 报 500 Couldn't move file?
实测常见原因:目标路径的父目录不存在,或目标与源在同一不可写挂载上。先确认目标父目录存在(可先用 mkdir 创建),JSON body 字段名确认是驼峰 newPath。
Q4:登录一直 429? 指数退避按用户名计数:失败冷却时间按 2 的幂增长,连续失败后冷却可达数分钟。等待冷却自然解除(不要用错误密码反复试探),或重启服务清空内存计数器。
Q5:重启后所有脚本令牌全失效?
JWT_SECRET 未固定时每次重启随机重生(实测重启后旧令牌 401),两类令牌(普通/流式)同时失效。生产实例固定该变量(见 《mikochi 1.12.2 配置参数详解》 5.4 节)。
九、参考链接
- API 契约源码(路由与处理器):https://github.com/zer0tonin/Mikochi/blob/main/backend/main.go (查询日期 2026-10-30)
- 1.12.0 破坏性变更说明:https://github.com/zer0tonin/Mikochi/releases/tag/1.12.0
- 站内相关文档:《mikochi 1.12.2 Docker Compose 部署指南》、《mikochi 1.12.2 配置参数详解》、《mikochi 介绍与选型指南》