【问题标题】:Invalid JSON string error in RailsRails 中的无效 JSON 字符串错误
【发布时间】:2010-11-08 10:16:45
【问题描述】:

我在 Rails 2.3.5 上。在典型的用户控制器中创建操作

class UsersController
  def create
    @user = User.new(params[:user])
    respond_to do |format]
      if @user.save ...
      else
        format.json ....
      end        
  end
end

当客户端传递一个无效/格式错误的 JSON 字符串作为输入时,Rails 会抛出一个 500 内部服务器错误,提示“无效的 JSON 字符串”。我是否可以捕获错误以便提供自定义消息?

更新这是所要求的堆栈跟踪。我很清楚,我知道这是一个格式错误的 JSON 字符串,我的问题不是如何修复 JSON 字符串,而是如何捕获这个特定错误,以便我可以发回比 HTTP 500 Internal Server Error 更有意义的错误消息.提前感谢您的帮助

Error occurred while parsing request parameters.
Contents:

user: {login: "John", email: "john@yahoo.com", password: "111"}}
/!\ FAILSAFE /!\  Mon Nov 08 02:01:04 -0800 2010

  Status: 500 Internal Server Error
  Invalid JSON string
    c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/json/backends/yaml.rb:14:in `decode'
    c:1:in `__send__'
    c:1:in `decode'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:42:in `parse_formatted_parameters'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:11:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/session/cookie_store.rb:93:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/failsafe.rb:26:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `synchronize'
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:114:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/reloader.rb:34:in `run'
    c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:108:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/rack/static.rb:31:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:46:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `each'
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `call'
    c:/ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/rack/log_tailer.rb:17:in `call'
    ...
    c:/ruby/lib/ruby/gems/1.8/gems/rack-1.0.1/lib/rack/handler/mongrel.rb:34:in `run'
    c:/ruby/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/commands/server.rb:111
    c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
    c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
    script/server:3
re.rb:31:in `require'
    script/server:3

【问题讨论】:

  • 你能放一个完整的回溯吗?

标签: ruby-on-rails json


【解决方案1】:

我发现这个 rails 插件可以在 rails 3.0.5 上运行:https://github.com/kares/request_exception_handler

作为罗布·卡梅隆 建议它加载您的 rails 应用程序并从您的应用程序代码中引发 parseError。我还没有测试它的性能影响,但它似乎运作良好。

【讨论】:

    【解决方案2】:

    查看 /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/json/backends/yaml.rb (诚然,版本略有不同),看起来 ParseError 正在提高。假设错误发生在“format.json”,您可以尝试类似

    begin
      format.json
    rescue ParseError => e
      render :text => "Now there's some ugly JSON! (#{e.message})", :status => 500
    end
    

    如果这不起作用,您可以尝试使用控制器中的 rescue_from 回调更早地捕获它。

    class UsersController < ApplicationController
    ...
      rescue_from ParseError do |e|
        render ...
      end
    ...
    end
    

    【讨论】:

    • 感谢您的建议,不幸的是,format.json 中没有出现错误。我相信它是在调用用户/创建操作之前引发的,因为 Rails 需要解析 JSON 字符串才能访问参数。
    • 啊,我想这是有道理的。在这种情况下,请尝试 rescue_from 回调。我在上面添加了一个示例。
    • 另一个好主意,但唉,没有骰子,错误甚至在它到达控制器之前就被提出了
    【解决方案3】:

    我现在遇到了同样的问题——我有一个 API,有人可以将无效的 JSON 传递给它,我想对我返回的错误保持聪明。我正在运行 Rails 3.0.5。我追踪到lib/active_support/json/backends/yaml.rb第17行的错误:

    def decode(json)
      if json.respond_to?(:read)
        json = json.read
      end
      YAML.load(convert_json_to_yaml(json))
    rescue ArgumentError
      raise ParseError, "Invalid JSON string"
    end
    

    所以,json.read 失败并抛出错误。不幸的是,这在您的控制器被调用之前很久就发生了(它是 Rails 与 Rack 绑定的初始请求参数解析的一部分)。我认为,为了捕捉到这一点,您需要添加一个小猴子补丁来覆盖一些内置的错误抛出,而是冒泡一些您可以使用的东西......也许您可以向请求对象添加一个标头然后你可以在你的控制器中检测到并抛出你自己的错误。

    不幸的是,我认为这对我不起作用,因为我只想覆盖访问 API 时的行为,而不是网站的其余部分。尽管我认为在猴子补丁中,假设我可以访问请求对象,但我可以告诉它仅在请求的路径与 /\/api\// 之类的正则表达式匹配时才使用我的新行为@

    【讨论】:

    • 我已经使用 Rack 中间件解决了这个问题。中间件插入到 ActionDispatch::ParamsParser 之前并捕获@app.call 发出的错误。由于控制器动作也是 rails 应用程序中的机架应用程序,因此我可以使用控制器动作来使用所有 rails 模板呈现漂亮的错误消息。 (为从 Google 到这里的其他人发帖)gist.github.com/4709748
    猜你喜欢
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多