使用机架中间件捕获无效的JSON解析错误

pro*_*oob 6 ruby json ruby-on-rails ruby-on-rails-5

我正在使用Rails 5,我正在尝试改进对我的API的无效JSON请求的错误处理.

我尝试通过在控制器中进行解析来处理无效格式JSON,但是如果用户将内容类型添加到其请求头中,则意识到Rails中间件在它到达控制器之前解析我的JSON请求.

我按照以下指南:https: //robots.thoughtbot.com/catching-json-parse-errors-with-custom-middleware

但是,启动服务器时出现以下错误:

.rbenv/versions/2.3.1/lib/ruby​​/gems/2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/middleware/stack.rb:108:在`assert_index'中:没有这样的中间件要插入之前:ActionDispatch :: ParamsParser(RuntimeError)

现在,这意味着ActionDispatch :: 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
Run Code Online (Sandbox Code Playgroud)

但是,这也没有用.它似乎跳过了它.

或者如果我试试这个:

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
Run Code Online (Sandbox Code Playgroud)

我明白了:

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
Run Code Online (Sandbox Code Playgroud)

迷路了,可以使用一些指导

pro*_*oob 17

似乎上面的指南已经过时了Rails 5.经过一些调查,似乎不再调用以下中间件:

配置/ application.rb中

config.middleware.insert_before ActionDispatch::ParamsParser, "CatchJsonParseErrors"
Run Code Online (Sandbox Code Playgroud)

我把它修改为:

require "./lib/middleware/catch_json_parse_errors.rb"
config.middleware.insert_before Rack::Head, CatchJsonParseErrors
Run Code Online (Sandbox Code Playgroud)

这是因为Rack :: Head是中间件堆栈,但ActionDispatch :: ParamsParser不是.此外,不推荐使用类名作为字符串,因此您需要该文件然后传入该类.

我还修改了下面的类来检查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
Run Code Online (Sandbox Code Playgroud)

  • 截至今天,看起来它引发了`ActionDispatch::Http::Parameters::ParseError` (2认同)