Ruby on rails Rails中的JSON字符串错误无效

Ruby on rails Rails中的JSON字符串错误无效,ruby-on-rails,json,Ruby On Rails,Json,我在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会

我在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字符串”。我是否可以捕获错误,以便提供自定义消息

已更新这是所需的stacktrace。我很清楚,我知道这是一个格式错误的JSON字符串,我的问题不是如何修复JSON字符串,而是如何捕获这个特定错误,这样我就可以发回比HTTP 500内部服务器错误更有意义的错误消息。提前谢谢你的帮助

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

查看/usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/json/backends/yaml.rb(无可否认是一个稍有不同的版本),似乎出现了一个语法错误。假设错误发生在“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
class UsersController
我现在遇到了同样的问题——我有一个API,有人可以将无效的JSON传递给它,我希望对返回的错误保持明智。我正在运行Rails 3.0.5。我将抛出的错误跟踪到
lib/active\u 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连接到机架的初始请求参数解析的一部分)。我认为,为了抓住这一点,你需要添加一个小的猴子补丁来覆盖一些内置的错误抛出,而不是冒泡出一些你可以使用的东西……也许你可以在请求对象中添加一个头,然后在你的控制器中检测并抛出你自己的错误


不幸的是,我认为这对我不起作用,因为我只想在访问API时覆盖行为,而不是站点的其余部分。尽管我假设在monkey补丁中,假设我有权访问请求对象,我可以告诉它只有在请求的路径与正则表达式匹配时才使用我的新行为,比如
/\/api\/
我发现这个rails插件可以在rails 3.0.5上工作:

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

你能做一个完整的回溯吗?谢谢你的建议,不幸的是format.json上没有出现错误。我相信它是在调用user/create操作之前提出的,因为Rails需要解析JSON字符串才能访问params。啊,我想这是有道理的。在这种情况下,请尝试从回调中进行营救。我在上面添加了一个例子。这是另一个好主意,但可惜的是,没有骰子,错误在到达控制器之前就出现了。我已经使用机架中间件解决了这个问题。中间件在ActionDispatch::ParamsParser之前插入,并捕获@app.call发出的错误。由于控制器动作也是rails应用程序中的机架应用程序,所以我可以使用控制器动作来使用所有rails模板呈现一条非常漂亮的错误消息。(为其他从谷歌来到这里的人发帖)