Kinto 26.5.0 常用 CLI 命令与 HTTP API 详解
Kinto 26.5.0 CLI 与 HTTP API 实测详解:7 个 kinto 子命令用法回显,资源 CRUD、batch 批量、_since 增量同步、墓碑删除、If-Match 并发控制与组权限 API 全流程取证。
Kinto 26.5.0 常用 CLI 命令与 HTTP API 详解
Kinto 有两条操作通道:CLI(kinto 命令,面向部署与运维)与 HTTP API(面向应用与客户端,是 Kinto 的主要交互方式)。本文全部命令与回显均来自 26.5.0 实测环境(2026-10-30,部署见《Kinto 26.5.0 Docker Compose 部署指南》,服务地址 http://127.0.0.1:8149/v1/,示例账号 admin/q1w2e3r4);配置项含义不展开,见《Kinto 26.5.0 配置参数详解》。
一、两条操作通道总览
1.1 CLI:kinto 命令
CLI 在服务所在机器上执行,读取与常驻服务同一份配置文件(--ini 参数指定,默认 config/kinto.ini,环境变量 KINTO_INI 可覆盖)。26.5.0 的命令总览实测回显:
$ kinto --help
usage: kinto [-h]
{init,start,migrate,flush-cache,version,create-user,purge-deleted}
...
Kinto Command-Line Interface
options:
-h, --help show this help message and exit
subcommands:
Main Kinto CLI commands
{init,start,migrate,flush-cache,version,create-user,purge-deleted}
Choose and run with --help
7 个子命令分两类:init/start/migrate 支撑服务生命周期,create-user/flush-cache/purge-deleted/version 做日常运维。官方 Command Line 文档页(docs.kinto-storage.org/en/stable/commandline.html,查询日期 2026-10-30)只收录了 5 个,create-user 与 flush-cache 是 26.x 新增文档未及的,以 --help 实测为准。
💡 技术拓展:CLI 与 API 的分工边界在"存储即服务"类组件里普遍存在:CLI 操作的是"服务本体"(建库迁移、账号管理、模式升级),API 操作的是"库内数据"(记录读写同步)。Kinto 的 CLI 刻意保持极少——所有数据操作都走 API,因为客户端可能分布于任何设备,而运维动作必然发生在服务主机上。
1.2 HTTP API
REST 风格,资源路径即 26.5.0 的四级模型 /v1/buckets/<b>/collections/<c>/records/<r>(概念见《Kinto 26.5.0 介绍与选型指南》)。API 契约版本 1.23,根视图 GET /v1/ 返回能力自描述(见部署篇 4.1 节回显),心跳 GET /v1/__heartbeat__ 返回三后端状态。
二、CLI 命令详解
2.1 kinto init:生成配置文件
kinto init [--ini INI_FILE] [--backend {memory,postgresql}]
[--cache-backend {memory,postgresql,memcached,redis}] [--host HOST]
按指定后端生成一份开箱可用的 INI。关键参数:
| 参数 | 默认 | 说明 |
|---|---|---|
| --ini | config/kinto.ini(或 $KINTO_INI) | 输出路径,已存在时报错拒绝覆盖 |
| --backend | memory | storage/permission 后端,选 postgresql 时自动装 psycopg2 依赖 |
| --cache-backend | memory | 缓存后端 |
| --host | 127.0.0.1 | 写入 [server:main] 的监听地址,服务化部署必须给 0.0.0.0 |
实测回显(生成 PostgreSQL + Memcached 配置):
$ kinto init --ini /etc/kinto/kinto.ini --host 0.0.0.0 --backend postgresql --cache-backend memcached
INFO Created config /etc/kinto/kinto.ini
注意 --ini 指向已存在的文件时会报 already exists 退出(官方镜像内置配置即因此未被覆盖),重复生成先移走旧文件。
2.2 kinto migrate:数据库模式迁移
kinto migrate [--ini INI_FILE] [--dry-run]
把存储/权限后端的表结构升级到当前版本 schema(PostgreSQL 需要 DDL 权限)。--dry-run 模拟执行并打印判定,对现库实测回显:
$ kinto migrate --ini /etc/kinto/kinto.ini --dry-run
INFO Running kinto 0.0.0.
INFO Detected PostgreSQL storage schema version 26.
INFO PostgreSQL storage schema is up-to-date.
INFO Detected PostgreSQL permission schema version 2.
INFO PostgreSQL permission schema is up-to-date.
解读:存储模式版本 26、权限模式版本 2 即 26.5.0 的当前 schema 版本号;升级 Kinto 版本后 Detected ... version N(旧)与 Running kinto ...(新)不一致时,去掉 --dry-run 执行真实迁移。官方部署栈的启动流程已内置 kinto migrate && kinto start,日常升级无需手工跑。
2.3 kinto start:启动本地服务
kinto start [--ini INI_FILE] [-q] [-v] [--reload] [--port PORT]
以 pserve/waitress 前台启动服务。--port 覆盖配置端口;--reload 监听代码与配置变更自动重启(开发用)。官方文档明确此方式不推荐用于生产——生产应交给 systemd/compose 等进程管理器,并以多进程方式跑 WSGI(waitress 单进程模型吞吐有限)。实测启动横幅:
$ kinto start --ini /etc/kinto/kinto.ini --port 8888
Starting server in PID 9.
Serving on http://0.0.0.0:8888 rid=None
2.4 kinto version:输出版本号
$ kinto version
0.0.0
输出 0.0.0 是官方镜像构建流程不回填版本元数据的已知现象(pip show kinto 同样显示 0.0.0),真实版本以镜像 tag 与 GitHub Releases 为准(26.5.0);pip 源码安装时此命令输出真实版本。
2.5 kinto create-user:创建账号
kinto create-user [--ini INI_FILE] [-u USERNAME] [-p PASSWORD]
依赖 accounts 插件启用,等价于调 API 建 account:<username>(密码 bcrypt 哈希后入库)。实测:
$ kinto create-user --ini /etc/kinto/kinto.ini -u alice -p q1w2e3r4
INFO Running kinto 0.0.0.
Creating user 'alice'
创建后用该账号走 Basic 认证即可访问 API(见 3.2 节)。重复执行同一用户名时命令再次输出 Creating user 'alice' 并以新密码覆盖旧密码——它是"设置密码"语义而非"仅创建",可当重置密码工具用。
2.6 kinto flush-cache:清空缓存后端
$ kinto flush-cache --ini /etc/kinto/kinto.ini
INFO Running kinto 0.0.0.
INFO Cache has been cleared.
对配置的 cache 后端(本文环境为 Memcached)做整体清空。排障时用于清理 OpenID 会话态、认证中间缓存;因记录本体不依赖缓存,清缓存不丢业务数据。
2.7 kinto purge-deleted:清理墓碑记录
kinto purge-deleted [--ini INI_FILE] [-q] [-v] RESOURCES... MAX_RETAINED
删除 tombstone(墓碑),每个父资源与资源类型组合保留最近 MAX_RETAINED 条。实测:
$ kinto purge-deleted --ini /etc/kinto/kinto.ini record 10000
INFO Running kinto 0.0.0.
INFO Keep only 10000 tombstones per parent and resource.
INFO 0 tombstone(s) deleted.
RESOURCES 位置参数取值 bucket/collection/group/record(可多个),MAX_RETAINED 为保留条数。官方文档特别警示:生产环境慎用——墓碑是 _since 增量同步时向客户端报告"哪些对象被删了"的依据,过早清理会让未同步的客户端永远收不到删除事件(同步语义见 5.2 节)。
三、HTTP API 基础约定
3.1 认证:Basic 与 whoami
26.5.0 默认仅启用 account 策略,Basic 认证(用户名:密码)即换得身份:
$ curl -s http://127.0.0.1:8149/v1/ -u admin:q1w2e3r4
回显(节选 user 字段):
{
"user": {
"id": "account:admin",
"principals": ["account:admin", "system.Authenticated", "system.Everyone"],
"bucket": "deaec1ea-8c0a-4584-d5fb-2ad9942e9161"
}
}
user.id 是鉴权主体,principals 是该请求所属的全部主体集合(授权判断都基于它),bucket 是个人默认桶的派生 ID。未携带认证头时请求以 system.Everyone 匿名身份通过。
3.2 响应头约定
列表接口的响应头承载了分页与并发控制语义(curl -I 实测节选):
Etag: "1793347707819"
Total-Records: 3
Cache-Control: no-cache, no-store
Access-Control-Expose-Headers: Cache-Control, Total-Objects, Content-Type, Content-Length, Last-Modified, Backoff, ETag, Total-Records, Pragma, Next-Page, Expires, Alert, Retry-After
| 响应头 | 语义 |
|---|---|
| ETag | 集合当前版本时间戳(等于集合内最大 last_modified),配合 If-Match 做并发控制 |
| Total-Records | 集合记录总数(忽略分页) |
| Next-Page | 分页时下一页绝对 URL |
| Backoff / Retry-After / Alert | 服务端降速/限流/终止预告(配置来源见配置详解篇第八节) |
四、资源 CRUD 与批量操作
4.1 桶与集合(PUT 幂等创建)
$ curl -s -X PUT http://127.0.0.1:8149/v1/buckets/app -u admin:q1w2e3r4 \
-d '{"data": {"name": "应用数据"}}' -H "Content-Type:application/json"
回显:
{
"permissions": {"write": ["account:admin"]},
"data": {"name": "应用数据", "id": "app", "last_modified": 1793347635986}
}
PUT 带自定义 ID(app)幂等可重复;响应三段式:permissions(当前用户对该对象的权限)、data(对象本体,自动补 id 与 last_modified)。集合同理:
$ curl -s -X PUT http://127.0.0.1:8149/v1/buckets/app/collections/notes -u admin:q1w2e3r4 \
-d '{"data": {"schema_note": "个人笔记"}}' -H "Content-Type:application/json"
回显:
{
"permissions": {"write": ["account:admin"]},
"data": {"schema_note": "个人笔记", "id": "notes", "last_modified": 1793347636015}
}
4.2 记录:POST 自动 ID 与 PUT 指定 ID
POST 让服务端生成 UUID:
$ curl -s -X POST http://127.0.0.1:8149/v1/buckets/app/collections/notes/records -u admin:q1w2e3r4 \
-d '{"data": {"title": "第一条笔记", "content": "Kinto 的记录即 JSON 文档"}}' -H "Content-Type:application/json"
回显:
{
"permissions": {"write": ["account:admin"]},
"data": {
"title": "第一条笔记",
"content": "Kinto 的记录即 JSON 文档",
"id": "4b573c78-3546-483d-9328-05d95aa758e5",
"last_modified": 1793347645479
}
}
PUT 用客户端自定义 ID(离线优先客户端可本地先造 ID 后回传,天然幂等):
$ curl -s -X PUT http://127.0.0.1:8149/v1/buckets/app/collections/notes/records/note-002 -u admin:q1w2e3r4 \
-d '{"data": {"title": "第二条笔记", "done": false}}' -H "Content-Type:application/json"
回显:
{
"permissions": {"write": ["account:admin"]},
"data": {"title": "第二条笔记", "done": false, "id": "note-002", "last_modified": 1793347645507}
}
4.3 列表查询:排序、过滤
$ curl -s "http://127.0.0.1:8149/v1/buckets/app/collections/notes/records?_sort=-last_modified" -u admin:q1w2e3r4
回显:
{
"data": [
{"done": false, "title": "第二条笔记", "id": "note-002", "last_modified": 1793347645507},
{"title": "第一条笔记", "content": "Kinto 的记录即 JSON 文档", "id": "4b573c78-3546-483d-9328-05d95aa758e5", "last_modified": 1793347645479}
]
}
_sort 支持 - 前缀倒序;字段过滤用 ?title=笔记 精确匹配、分页用 _limit/_token、页大小上限受 kinto.paginate_by 与 storage_max_fetch_size 控制。列表响应外层固定为 {"data": [...]},错误为 {"code/errno/error/message/details"} 四段结构。
4.4 default 桶:免建桶直用
$ curl -s -X POST http://127.0.0.1:8149/v1/buckets/default/collections/tasks/records -u admin:q1w2e3r4 \
-d '{"data": {"title": "默认桶任务"}}' -H "Content-Type:application/json"
回显:
{
"permissions": {"write": ["account:admin"]},
"data": {"title": "默认桶任务", "id": "4076c572-a946-4231-bb2b-29a87a624a89", "last_modified": 1793347679847}
}
/buckets/default 是当前账号的专属别名桶,路径上的桶/集合不存在时隐式创建,个人应用零配置起步;它同时是 default_bucket_hmac_secret 的派生结果,秘密钥更换后个人桶"整体搬家"。
4.5 batch:单连接批量请求
$ curl -s -X POST http://127.0.0.1:8149/v1/batch -u admin:q1w2e3r4 \
-d '{"requests": [
{"method": "POST", "path": "/buckets/app/collections/notes/records", "body": {"data": {"title": "批量记录 A"}}},
{"method": "POST", "path": "/buckets/app/collections/notes/records", "body": {"data": {"title": "批量记录 B"}}}
]}' -H "Content-Type:application/json"
回显(解析 responses 摘要):
[
{"status": 201, "path": "/v1/buckets/app/collections/notes/records", "id": "b88c6ced-199a-4e7f-ba7e-0fdaba8c2fef"},
{"status": 201, "path": "/v1/buckets/app/collections/notes/records", "id": "0c5a7280-f87a-4c3c-9b4f-865d8b7276ff"}
]
每个子请求是 {method, path, headers?, body?},body 与普通请求体同构(data 包在 body 里)。实测排障点:若把 data 直接写在子请求顶层(不套 body),返回 400:
{"code": 400, "errno": 107, "error": "Invalid parameters",
"message": "requests.0 in body: Unrecognized keys in mapping: \"{'data': ...}\""}
子请求数上限即 kinto.batch_max_requests(默认 25)。batch 是离线客户端回传积压变更的标准通道,一次网络往返提交 N 个操作。
五、同步与并发控制
5.1 _since:增量拉取
$ curl -s "http://127.0.0.1:8149/v1/buckets/app/collections/notes/records?_since=1793347645479" -u admin:q1w2e3r4
回显(只返回该时间戳之后变过的记录):
{
"data": [
{"done": false, "title": "第二条笔记", "id": "note-002", "last_modified": 1793347645507}
]
}
_since 取值就是客户端上次同步时记录的最大 last_modified。客户端同步循环:首次全量拉取并保存水位 → 之后每次带 _since=水位 只取变更 → 处理完推进水位。集合级 ETag 可替代手工记录水位(_since 省略时用 If-None-Match 询问"集合没变过就不给数据")。
5.2 删除与墓碑
$ curl -s -X DELETE http://127.0.0.1:8149/v1/buckets/app/collections/notes/records/note-002 -u admin:q1w2e3r4
回显:
{"data": {"last_modified": 1793347663374, "id": "note-002", "deleted": true}}
删除后的记录并未物理消失,而是留下带 deleted: true 标记的墓碑——此时再查 _since(水位早于删除时刻):
{
"data": [
{"deleted": true, "id": "note-002", "last_modified": 1793347663374}
]
}
同步客户端据此在本地执行删除。墓碑保留量与清理策略见 2.7 节 purge-deleted 的慎用警示。
5.3 If-Match:并发控制与冲突
乐观锁:写请求携带目标对象当前版本,服务端不匹配即拒绝。实测两条路径——If-Match 给到当前版本(记录的 last_modified 原值)时写入成功并推进版本:
$ curl -s -X PUT http://127.0.0.1:8149/v1/buckets/app/collections/notes/records/4b573c78-3546-483d-9328-05d95aa758e5 \
-u admin:q1w2e3r4 -H 'If-Match: "1793347645479"' \
-d '{"data": {"title": "并发写"}}' -H "Content-Type:application/json"
回显(last_modified 从 1793347645479 推进到 1793348474133):
{
"permissions": {"write": ["account:admin"]},
"data": {"title": "并发写", "id": "4b573c78-3546-483d-9328-05d95aa758e5", "last_modified": 1793348474133}
}
If-Match 给过期版本时返回 412,且 details.existing 把服务端最新版本带回:
{
"code": 412,
"errno": 114,
"error": "Precondition Failed",
"message": "Resource was modified meanwhile",
"details": {
"existing": {"title": "并发写", "id": "4b573c78-3546-483d-9328-05d95aa758e5", "last_modified": 1793348474133}
}
}
Kinto 的冲突策略即到此为止:服务端拒绝 + 给出双版本,裁决交给客户端(官方 kinto.js 提供 SERVER_WINS/CLIENT_WINS/MANUAL 三种封装)。
六、权限 API
6.1 组:创建与成员
$ curl -s -X PUT http://127.0.0.1:8149/v1/buckets/app/groups/readers -u admin:q1w2e3r4 \
-d '{"data": {"members": ["account:alice"]}}' -H "Content-Type:application/json"
回显:
{
"permissions": {"write": ["account:admin"]},
"data": {"members": ["account:alice"], "id": "readers", "last_modified": 1793347719297}
}
6.2 对象 ACL:把读权限授予组
$ curl -s -X PUT http://127.0.0.1:8149/v1/buckets/app/collections/notes -u admin:q1w2e3r4 \
-d '{"permissions": {"read": ["/buckets/app/groups/readers"]}}' -H "Content-Type:application/json"
回显:
{
"permissions": {
"read": ["/buckets/app/groups/readers"],
"write": ["account:admin"]
},
"data": {"schema_note": "个人笔记", "id": "notes", "last_modified": 1793347719324}
}
请求体带 permissions 字段即改 ACL;write 主体自动保留。写 ACL 时引用组的规范形式是组资源路径 /buckets/<b>/groups/<g>,引用用户是 account:<name>,系统主体 system.Everyone/system.Authenticated 对应匿名与任一登录态。
6.3 权限生效验证:成员身份展开
以成员 alice 登录,观察 principals 展开:
$ curl -s http://127.0.0.1:8149/v1/ -u alice:q1w2e3r4
回显:
{
"id": "account:alice",
"principals": [
"account:alice",
"system.Authenticated",
"/buckets/app/groups/readers",
"system.Everyone"
]
}
/buckets/app/groups/readers 出现在 alice 的主体集合中,即组成员资格已注入授权上下文——此后 alice 对 notes 集合的读请求放行。组授权的优势在此显现:调整 members 列表即可批量增减权限,无需逐对象改 ACL。
七、小结
操作 Kinto 的口诀:运维七条 CLI,数据全走 API。CLI 覆盖 init 生成配置、migrate 迁移、start 开发启动、version/create-user/flush-cache/purge-deleted 四个运维动作;API 按"根视图自描述 → Basic 鉴权 → PUT/POST 幂等建资源 → _sort/_limit 查询 → batch 批量 → _since 增量同步 → If-Match 并发控制 → 组与对象 ACL 授权"一条线展开,全部语义都浓缩在响应头(ETag/Total-Records/Backoff)与固定 JSON 结构(data/permissions/errors)里。把 batch 子请求的 body 包装、墓碑与 _since 的联动、If-Match 412 的双版本回显这三个实测细节记住,Kinto 的日常使用与排障就顺了。