Litefs JSON 序列化规范
文档版本: 1.0 最后更新: 2026-10-22
概述
Litefs 框架内部统一使用 orjson 做 JSON 序列化,
不再直接依赖标准库 json。
选择 orjson 的原因:
维度 |
标准库 |
orjson |
|---|---|---|
实现语言 |
纯 Python(C 加速可选) |
Rust |
典型序列化吞吐 |
基准 |
约为标准库的 3~5 倍 |
反序列化吞吐 |
基准 |
约为标准库的 2~4 倍 |
非 ASCII 输出 |
默认 |
直接输出原始 UTF-8 |
内存占用 |
较高(构建中间对象) |
低(零拷贝路径) |
对 Web 框架而言,JSON 编解码位于请求热路径上(请求体解析、响应体序列化、 WebSocket 帧编解码、JWT 签发与校验),吞吐提升直接转化为 P99 延迟收益。
唯一出口:litefs._json
框架内所有 JSON 读写必须经由 src/litefs/_json.py 提供的抽象层,
业务代码与扩展代码不得直接 import json 或 import orjson。
from litefs._json import dumps, dumps_str, dumps_ascii, loads
API 一览
函数 |
输入 |
输出 |
用途 |
|---|---|---|---|
|
任意对象 |
|
网络响应、WebSocket 帧、加密前字节流 |
|
任意对象 |
|
必须保持字符串类型的调用点 |
|
任意对象 |
|
写入要求 ASCII 编码的通道(Memcache) |
|
|
任意对象 |
反序列化 |
|
任意对象 |
写入二进制文件 |
文件持久化 |
|
二进制文件 |
任意对象 |
文件读取 |
异常类型
抽象层直接复用 orjson 的异常类,捕获链与标准库完全兼容:
JSONDecodeError—— 继承自标准库json.JSONDecodeError(即ValueError子类);JSONEncodeError—— 继承自TypeError。
因此既有代码中的 except (TypeError, ValueError)、except json.JSONDecodeError
无需修改即可继续工作。
语义对齐策略
orjson 与标准库在若干细节上行为不同,抽象层通过序列化选项逐项对齐:
场景 |
选项 |
对齐效果 |
|---|---|---|
非字符串字典键 |
|
|
|
|
交由 |
|
|
交由 |
为什么 datetime / dataclass 必须 PASSTHROUGH orjson 原生会把
datetime序列化为 ISO 8601("2026-10-22T12:30:00")、 把dataclass序列化为对象字典,这与标准库json.dumps(..., default=str)的输出不同。启用 PASSTHROUGH 后交由default回调处理, 才能与迁移前逐字节一致。
与标准库的固有差异
以下差异为 orjson 的固有行为,无法通过选项关闭,使用时需注意:
差异点 |
标准库 |
orjson |
影响面 |
|---|---|---|---|
|
序列化为 |
序列化为 |
上游若可能产出非有限浮点,行为改变 |
超过 64 位范围的整数 |
任意精度 |
抛出 |
极少数超大整数 ID |
|
标准模式下抛 |
原生序列化为字符串 |
更宽松,属能力增强 |
分隔符 |
|
|
响应体字节数减少;断言字面量的测试需改为语义断言 |
测试断言规范
由于分隔符差异,测试禁止断言 JSON 字面量,必须断言 JSON 语义:
# ❌ 错误:绑定到具体序列化器的分隔符风格
assert response.content == '{"path": "/a", "status_code": 200}'
# ✅ 正确:断言语义
import json
assert json.loads(response.content) == {"path": "/a", "status_code": 200}
ASCII 安全出口:dumps_ascii
标准库 json.dumps 默认 ensure_ascii=True,输出纯 ASCII;而 orjson 始终输出原始 UTF-8。
pymemcache 的 Client.encoding 默认值为 "ascii",写入时执行
str(data).encode("ascii"),非 ASCII 内容会直接抛出
MemcacheIllegalInputError: Data values must be binary-safe。
因此,写入 Memcache 的值必须使用 dumps_ascii:
from litefs._json import dumps_ascii
dumps_ascii({"chinese": "中文", "emoji": "😀"})
# '{"chinese":"\\u4e2d\\u6587","emoji":"\\ud83d\\ude00"}'
该出口与标准库 json.dumps(..., ensure_ascii=True) 逐字节一致,
因此:
迁移前写入的旧缓存数据可被新代码正确读取(双向兼容);
缓存值的体积与迁移前相同,不会因编码方式变化而膨胀或失效。
框架内使用 dumps_ascii 的位置:
src/litefs/cache/memcache.py——put()/set_many()src/litefs/session/memcache.py——put()
其余后端(Redis / Database / Memory / Tree)使用 UTF-8 存储,使用 dumps_str 即可。
编码规范
框架源码
✅ 只允许
from .._json import dumps, dumps_str, dumps_ascii, loads❌ 禁止
import json❌ 禁止
import orjson(绕过抽象层会丢失选项配置,导致行为分叉)
用户代码
用户应用不受此约束,仍可自由使用标准库 json 或直接使用 orjson。
框架不修改用户进程的全局序列化行为,仅约束框架自身实现。
迁移检查清单
引入 orjson 时必须逐项确认:
[ ] 源码中已无
import json残留(grep -rn "import json" src/)[ ]
pyproject.toml/requirements.txt已声明orjson>=3.10[ ] 依赖版本兼容目标 Python 基线(orjson 3.10.15 是支持 Python 3.8 的最高版本)
[ ] 断言 JSON 字面量的测试已改为语义断言
[ ] 写入 Memcache 的值改用
dumps_ascii[ ]
Response.content等公开属性保持str类型[ ]
make lint(flake8 + ruff + mypy)通过[ ] 全量
pytest通过
相关文档
:doc:
dependency-audit—— 依赖安全审计(orjson纳入requirements.txt审计面):doc:
static-checks—— 静态检查规范:doc:
release-roadmap—— 版本演进路线