39

我有一个“软件即服务”应用程序,它使用通过 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 状态 => :unprocessable_entity 或其他东西来解决这个问题。

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

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

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

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

4

4 回答 4

77

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

使用 ActionController 的rescue_from

答案是使用 ActionController 的rescue_from,如本指南中所述并在此处记录。特别是,您可以按照以下几行替换默认 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
于 2012-08-08T07:21:00.667 回答
7

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

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

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

# ...

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

# ...
  • 主要基于无畏_傻瓜的回答
于 2016-03-24T08:48:57.367 回答
4

作为开发人员,您还希望看到跟踪(最好是有用的行,过滤掉 gem)。并使生产中的痕迹不可见:

  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
于 2016-10-14T13:20:04.727 回答
1

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

  1. 保持简单 - 尽量保持安静。自定义方法可以使事情变得快速复杂。
  2. 让服务器返回本机错误代码,并使用“rescue_from”进行捕获,然后
  3. 在其他情况下,渲染 Rails HTTP 响应代码,客户端应用程序可以专门针对这些代码。

在您的情况下,您可能会发现 Rails respond_to 和 respond_with 可以优雅地处理 html/json/other 响应。即使在您的解决方案中,它仍然会有效地呈现 HTML,但这不是您的客户端应用程序将解释的内容,而是读取 HTTP 标头并获取 HTTP 响应代码,这就是触发您的“rescue_from”的原因.

于 2012-08-08T07:41:39.287 回答