我正在使用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:in`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
但是,这也行不通。它似乎跳过了它。
或者如果我试试这个:
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 :(得分:16)
似乎上面的指南已经过时了Rails 5.经过一番调查后,似乎不再调用以下中间件:
<强>配置/ application.rb中强>
config.middleware.insert_before ActionDispatch::ParamsParser, "CatchJsonParseErrors"
我将其修改为:
require "./lib/middleware/catch_json_parse_errors.rb"
config.middleware.insert_before Rack::Head, CatchJsonParseErrors
这是因为Rack :: Head在中间件堆栈中,但ActionDispatch :: ParamsParser不在。此外,不推荐使用类名作为字符串,因此您需要该文件然后传入该类。
我还修改了以下课程,以检查环境[&#39; CONTENT_TYPE&#39;]而不是env [&#39; HTTP_ACCEPT&#39;]
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