如何处理基于JSON的RESTful代码中的异常?

时间:2012-08-08 07:12:16

标签: ruby-on-rails json actioncontroller

我有一个“软件即服务”应用程序,它使用通过RESTful API传递的JSON。

简单说明:在使用带有JSON数据交换的RESTful API时捕获和报告异常的最佳做法是什么?

我的第一个想法是通过生成支架看看Rails的作用,但这显然是不对的。这是一段摘录:

class MumblesController < ApplicationController

  # GET /mumbles/1
  # GET /mumbles/1.json
  def show
    @mumble = Mumble.find(params[:id])
    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @mumble }
    end
  end

end

在这种情况下,如果JSON代码发送不存在的ID,例如

http://www.myhost.com/mumbles/99999.json

然后Mumble.find()将引发ActiveRecord :: RecordNotFound。 ActionController将捕获它并在HTML中呈现错误页面。但HTML对于期望JSON的客户端来说是无用的。

我可以通过将Mumble.find()包装在begin ... rescue RuntimeError块中并渲染JSON状态=&gt;来解决这个问题。 :unprocessable_entity或其他东西。

但是,如果客户端的应用程序发送无效路径,例如:

,该怎么办?
http://www.myhost.com/badtypo/1.json

基于JSON的应用程序应该捕获它并在JSON中返回错误吗?如果是这样,我在哪里捕获它而不深入ActionDispatch?

总的来说,如果出现错误,我是否应该让ActionController生成HTML?这感觉不对......

4 个答案:

答案 0 :(得分:75)

(我在点击[发布你的问题]之前找到了答案。但这也可以帮助其他人......)

使用ActionController的rescue_from

答案是使用ActionController的rescue_from,如in this Guide所述并记录here。特别是,您可以在以下行中替换默认的404.html和500.html文件的默认呈现:

class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found

private
  def record_not_found(error)
    render :json => {:error => error.message}, :status => :not_found
  end 
end

答案 1 :(得分:7)

如果它对任何人有帮助,这就是我为纯粹的json api所做的一切:

在每个特定控制器继承的ApplicationController中,添加

# app/controllers/api/v1/application_controller.rb

# ...

rescue_from StandardError do |exception|
    render json: { :error => exception.message }, :status => 500
end

# ...
  • 主要基于fearless_fool的回答

答案 2 :(得分:3)

作为开发人员,您还需要查看跟踪(最好使用有用的行,过滤掉宝石)。并使痕迹无法生产:

  rescue_from StandardError do |exception|
    # Handle only JSON requests
    raise unless request.format.json?

    err = {error: exception.message}

    err[:backtrace] = exception.backtrace.select do |line|
      # filter out non-significant lines:
      %w(/gems/ /rubygems/ /lib/ruby/).all? do |litter|
         not line.include?(litter)
      end
    end if Rails.env.development? and exception.is_a? Exception

    # duplicate exception output to console:
    STDERR.puts ['ERROR:', err[:error], '']
                    .concat(err[:backtrace] || []).join "\n"

    render :json => err, :status => 500
  end

答案 3 :(得分:1)

关于如何为编写JSON API代码保持一致的标准没有明确的共识,但这是我练习的一些内容(比你要求的更多):

  1. 保持简单 - 尽量保持安宁。自定义方法可以使事情变得复杂。
  2. 让服务器返回本机错误代码,并使用'rescue_from'捕获,
  3. 在其他情况下,呈现Rails HTTP响应代码,可以由客户端应用程序专门定位。
  4. 在您的情况下,您可能会发现Rails respond_to和respond_with处理html / json /其他响应。即使在您的解决方案中,它仍然会有效地呈现HTML,但这不是您的客户端应用程序将解释的内容,而是会读取HTTP标头并获取HTTP响应代码,这就是触发“rescue_from”的内容