2012-08-08 95 views
32

我有一个“软件即服务”应用程序,它使用JSON通过RESTful API进行通信。如何在基于JSON的RESTful代码中处理异常?

简单地说:在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中呈现错误页面。但对于期待JSON的客户端而言,HTML是无用的。

我可以通过将Mumble.find()包装在begin ... rescue RuntimeError块中并呈现JSON状态=>:unprocessable_entity或其他东西来解决该问题。

那么是什么,如果客户端的应用程序发送一个无效的路径,例如:

http://www.myhost.com/badtypo/1.json 

是一个JSON基于应用程序应该赶上和JSON返回一个错误?如果是这样,我可以在没有深入研究ActionDispatch的情况下将其捕获到哪里?

因此,总体而言,如果出现错误,我是否会放下并让ActionController生成HTML?这感觉不对......

回答

71

(我找到了答案之前我打[发布你的问题。但是,这可能会帮助别人,以及...)

的答案是使用的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

小心:至少在导轨4,在'rescue_from'匹配的顺序是颠倒*从*'定期rescue':如果你想为一个子类对不同的行为它的父类,把子类*放在父类后面: - /' – AlexChaffee 2016-07-12 15:38:04

1

有关于如何保持一致的标准编写JSON API代码没有明确的共识,但这是我练习的一些东西(超过你所要求的):

  1. 保持简单 - 尽量保持安宁。自定义方法可以让事情变得更快速。
  2. 让服务器返回本地错误代码,并使用'rescue_from'进行捕获,并在其他情况下渲染Rails HTTP响应代码,该代码可以由客户端应用专门定位。

在你的情况下,你可能会发现Rails的respond_to和respond_with处理html/json /其他响应与宽限期。即使在你的解决方案中,它仍然会有效地呈现HTML,但这不是你的客户端应用程序将会解释的内容,它将读取HTTP标头并获取HTTP响应代码,这就是触发你的'rescue_from' 。

5

如果有帮助的人,这是我做的是一个包罗万象的我纯粹是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的回答
+0

对于任何被救出的错误,这看起来像是矫枉过正500。 – 2016-11-15 01:01:19

2

作为一名开发人员,您还需要查看痕迹(最好使用有用的线条,过滤掉ge女士)。并跟踪生产隐形:

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