2012-08-08 38 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