You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails接收带前导零数字的JSON POST参数解析报错问题

问题:Rails API解析带前导零数字的JSON请求时报错

我开发的Rails API接收JSON格式POST请求,正常请求可正常处理,但当JSON中数字字段(如zip)带前导零时,会触发参数解析错误,错误栈如下:

eval error: Error occurred while parsing request parameters
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/actionpack-7.0.4/lib/action_dispatch/http/parameters.rb:96:in `rescue in parse_formatted_parameters'
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/actionpack-7.0.4/lib/action_dispatch/http/parameters.rb:92:in `parse_formatted_parameters'
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/actionpack-7.0.4/lib/action_dispatch/http/request.rb:390:in `block in POST'
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/rack-2.2.4/lib/rack/request.rb:69:in `fetch'
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/rack-2.2.4/lib/rack/request.rb:69:in `fetch_header'
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/actionpack-7.0.4/lib/action_dispatch/http/request.rb:389:in `POST'
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/actionpack-7.0.4/lib/action_dispatch/http/parameters.rb:55:in `parameters'
  /home/danniel/.rvm/gems/ruby-2.7.5/gems/actionpack-7.0.4/lib/action_controller/metal/strong_parameters.rb:1232:in `params'
  (rdbg)//home/danniel/workspace/check-my-cep/app/controllers/api/customers_controller.rb:1:in `create'

正常请求示例:

curl -d '[{"zip": 1001000,"name": "JOSE"}, {"zip": 1001900,"name": "FRANCISCO"}]' http://localhost:3000/api/customers --header "Accept: application/json" --header "Content-Type: application/json"

触发错误的请求示例(zip带前导零):

curl -d '[{"zip": 01001000,"name": "JOSE"}, {"zip": 01001900,"name": "FRANCISCO"}]' http://localhost:3000/api/customers --header "Accept: application/json" --header "Content-Type: application/json"

控制器代码:

class Api::CustomersController < ApplicationController
  before_action :set_customer, only: %i[ destroy ]

  def create
    ...
  end

  def destroy
    @customer.destroy
  end

  private
    def set_customer
      @customer = Customer.find(params[:id])
    end

    def customer_params
      params.permit(_json: [:cep, :name]).require(:_json)
    end
end

补充:无法控制请求格式,必须处理这类带前导零的数字JSON。


解决方案

原因分析

标准JSON规范(RFC 8259)明确规定:数字不能有前导零(仅0本身例外)。Rails默认使用的JSON解析器会严格遵守该规范,因此遇到带前导零的数字时会抛出解析错误。

方案1:全局替换宽松JSON解析器

通过修改Rails的参数解析逻辑,允许非标准的前导零数字格式。

用json gem的宽松模式

在config/initializers/json_parser.rb中添加:

require 'json'

ActionDispatch::Request.parameter_parsers[:json] = -> (raw_post) {
  data = JSON.parse(raw_post, allow_nan: true, quirks_mode: true)
  data.is_a?(Hash) ? data : { _json: data }
}

quirks_mode: true会允许前导零数字、尾随逗号等非标准JSON语法。

用oj gem的兼容模式

如果项目已使用oj gem,可配置兼容模式:
在config/initializers/oj_parser.rb中添加:

require 'oj'

ActionDispatch::Request.parameter_parsers[:json] = -> (raw_post) {
  data = Oj.load(raw_post, mode: :compat)
  data.is_a?(Hash) ? data : { _json: data }
}

:compat模式兼容多种非标准JSON语法,包括前导零数字。

方案2:单控制器手动处理请求体

如果不想全局修改解析规则,可在目标控制器中手动读取并解析请求体:

修改create方法:

def create
  raw_body = request.raw_post
  # 宽松模式解析JSON
  json_data = JSON.parse(raw_body, quirks_mode: true)
  # 手动筛选合法参数(替换原customer_params逻辑)
  valid_data = json_data.map { |item| item.slice(:zip, :name) }
  
  # 后续业务逻辑,比如创建记录
  Customer.create!(valid_data)
  head :created
rescue JSON::ParserError => e
  render json: { error: "无效JSON格式: #{e.message}" }, status: :bad_request
end

该方式仅影响当前控制器的create动作,不会全局改变Rails解析行为。

注意事项

  • 宽松解析会引入一定安全风险(如允许NaN、Infinity等非标准值),建议解析后对参数做严格校验(比如检查zip字段格式)。
  • 若zip本质是字符串(如邮政编码无需数值运算),优先建议客户端传字符串格式,但因无法控制请求格式,此方案不适用。

内容的提问来源于stack exchange,提问作者Danniel Rodrigues

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:40:37