Oj 入门:Ruby 高性能 JSON 解析与生成

了解 Oj 的 JSON 解析模式、严格输入处理、键类型和文件操作,并检查替换标准库时的序列化兼容性。

最佳实践
红宝石与应用开发工作台插画

Oj 是 Ruby 的 JSON 处理库。选择前先定位解析或序列化是否为实际瓶颈,再对同一数据集比较耗时与内存;类型映射与安全边界比单次速度数字更重要。

基本用法:明确指定模式

gem install oj
require 'oj'
data = Oj.load('{"name":"demo","users":42}', mode: :strict)
json = Oj.dump({ 'name' => 'demo', 'tags' => ['a', 'b'] }, mode: :strict)

外部输入优先使用普通 JSON 模式,并限制输入大小。不要将支持 Ruby 对象恢复的模式直接用于不可信数据。全局替换 JSON 行为前,应覆盖特殊字符、数字、时间及自定义对象的兼容性测试。

解析模式:按需选择行为

Oj 的 :mode 选项决定输出结构:

  • :object:支持 Ruby 对象序列化与恢复,不能等同普通 JSON,也不应处理不可信输入;
  • :compat:以兼容 JSON gem 为目标,仍需核对选项与自定义序列化行为;
  • :strict:严格 JSON 规范,不允许 NaN/Infinity 等非标值;
  • :custom:自定义映射规则(如把特定键直接实例化为 Ruby 对象);
  • :wab:面向 WAB 对象模型的模式。

应明确指定所需模式,避免依赖全局默认值。

键类型与符号化

Oj.load('{"a":1}', symbol_keys: true)   # => {:a=>1}

symbol_keys: true 让所有键变成 Symbol,省去后续 deep_symbolize_keys。注意:处理外部不可信 JSON 时不要盲目符号化——恶意构造的海量不同键会撑爆 symbol 表(老版本 Ruby 的 symbol 不回收,新版本虽回收但仍是无谓开销)。

格式化输出与文件处理

Oj.to_file('data.json', { 'a' => 1 }, mode: :strict)        # 写文件
Oj.load_file('data.json', mode: :strict)                # 读文件
Oj.dump({ 'a' => 1 }, mode: :strict, indent: 2) # 美化输出

大文件处理配合 Oj::ScHandler 的 SAX 式回调解析,可以在不全量加载的情况下流式提取字段——处理 GB 级 JSON 导出文件的利器。

调试解析问题

Oj 报错信息比标准库更精确(带行列位置),排查坏 JSON 时先开 :strict 模式定位语法错误;遇到类型映射问题(如 BigDecimal、Time),检查 :create_additions 选项与自定义类的序列化约定。与标准库混用时统一入口,避免同一对象在两个库里序列化结果不同。

常见问题(FAQ)

Q:Oj 和标准库 JSON 结果完全一致吗?

绝大多数场景一致,细节有差异:浮点精度处理、非 UTF-8 字符、Time/BigDecimal 等特殊类型的默认序列化。替换前跑一遍测试套,重点覆盖含特殊字符和自定义类型的用例。

Q:Rails 项目怎么全局启用 Oj?

先按所选 Oj 与 Rails 版本确认适配入口,再评估 Oj.optimize_rails 或兼容层;不要同时叠加多个全局替换。替换后跑全量测试,确认序列化输出无回归。

Q:Oj 能处理 JSON 流(JSON Lines)吗?

可以。JSONL 格式按行读取逐行 Oj.load 即可;需要更高性能时用 Oj 的 sc 模式(Simple Callback)边读边处理,内存使用取决于输入缓冲和回调中保留的数据。


参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台