2016-12-16 15 views
4

我正在使用Rails 5,並試圖改進對我的API的無效JSON請求的錯誤處理。使用Rack Middleware捕獲無效的JSON分析錯誤

我試着通過解析控制器中的救援來處理無效格式的JSON,但意識到如果用戶將內容類型添加到他們的請求標頭中,Rails中間件在它擊中控制器之前解析我的JSON請求。

我也跟着下面的指南: https://robots.thoughtbot.com/catching-json-parse-errors-with-custom-middleware

然而,在啓動服務器時,我得到了以下錯誤:

.rbenv /版本/ 2.3.1/lib中/紅寶石/寶石/ 2.3 0.0 /寶石/ ActionPack的-5.0.0.1/LIB/action_dispatch /中間件/ stack.rb:108:在`assert_index:沒有這樣的中間件插入之前:ActionDispatch :: ParamsParser(RuntimeError)

現在,這意味着ActionD ispatch :: ParamsParser未運行。我認爲它在Rails 5中已被棄用,因此排除了該選項。

我也試過在我的API控制器使用rescue_from:

rescue_from JSON::ParserError, with: :json_error 

def json_error 
    render status: 400, json: {error: "Invalid JSON format in request body"}, status: :unprocessable_entity 
end 

不過,這也沒有工作。它似乎跳過它。

或者,如果我試試這個:

rescue_from JSON::ParserError, with: json_error 

def json_error 
    render status: 400, json: {error: "Invalid JSON format in request body"}, status: :unprocessable_entity 
end 

我得到:

undefined local variable or method `json_error' for Api::ApiController:Class 
actionpack (5.0.0.1) lib/action_dispatch/routing/route_set.rb, line 46 

``` ruby 
    41   private 
    42 
    43   def controller(req) 
    44    req.controller_class 
    45   rescue NameError => e 
> 46    raise ActionController::RoutingError, e.message, e.backtrace 
    47   end 
    48 
    49   def dispatch(controller, action, req, res) 
    50    controller.dispatch(action, req, res) 
    51   end 

入門很失落,可以使用一些指導

+0

你有沒有加入'應用程序/中間件/ catch_json_parse_errors.rb'的項目?除此之外,'app/middleware'應該位於應用程序的'autoload_paths'上。 – 0xd

+0

是的,我添加了文件。該錯誤與ActionDispatch :: ParamsParser有關,不是我的類 – pronoob

回答

11

似乎導上方是過時和Rails 5.後一些調查顯示,似乎下面的中間件不再叫:

的config/application.rb中

config.middleware.insert_before ActionDispatch::ParamsParser, "CatchJsonParseErrors" 

我修改它是:

require "./lib/middleware/catch_json_parse_errors.rb" 
config.middleware.insert_before Rack::Head, CatchJsonParseErrors 

這是因爲機架::頭是在中間件堆棧,但ActionDispatch :: ParamsParser不是。此外,不推薦使用Class名稱作爲字符串,所以您需要文件,然後傳入該類。

我還修改了以下類檢查ENV [ 'CONTENT_TYPE'],而不是ENV [ 'HTTP_ACCEPT']

class CatchJsonParseErrors 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    begin 
     @app.call(env) 
    rescue ActionDispatch::ParamsParser::ParseError => error 
     if env['CONTENT_TYPE'] =~ /application\/json/ 
     error_output = "There was a problem in the JSON you submitted: #{error.class}" 
     return [ 
      400, { "Content-Type" => "application/json" }, 
      [ { status: 400, error: error_output }.to_json ] 
     ] 
     else 
     raise error 
     end 
    end 
    end 
end 
+0

爲什麼將HTTP_ACCEPT更改爲CONTENT_TYPE? Accept-Header似乎是信息的正確來源,因爲它定義了客戶期望得到的內容 - 而ContentType定義了什麼(與*響應*的格式無關)。 –

+0

@AndreasBaumgart是因爲這個中間件設想檢查無效的json請求,而不是響應。不過,我建議保留接受標題上的現有檢查。 – Andy