每当针对我的仅API Rails 5.x应用程序发送格式错误的
JSON时,我都会收到异常,并且Rails将整个堆栈跟踪作为JSON返回.显然,我想回答一个很好的,自定义的,格式化的错误.
=> Booting Puma => Rails 5.0.0.1 application starting in development on http://localhost:3000 => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.6.0 (ruby 2.3.0-p0),codename: Sleepy Sunday Serenity * Min threads: 5,max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stop Started POST "/api/v1/identities/" for ::1 at 2016-10-26 18:42:32 +0200 ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations" Error occurred while parsing request parameters. Contents: { "whatever": "ewewgewewtwe" "malformed_json": "; } ActionDispatch::ParamsParser::ParseError (822: unexpected token at '{ "whatever": "ewewgewewtwe" "malformed_json": "; }'): actionpack (5.0.0.1) lib/action_dispatch/http/parameters.rb:71:in `rescue in parse_formatted_parameters' actionpack (5.0.0.1) lib/action_dispatch/http/parameters.rb:65:in `parse_formatted_parameters' actionpack (5.0.0.1) lib/action_dispatch/http/request.rb:366:in `block in POST' rack (2.0.1) lib/rack/request.rb:57:in `fetch' rack (2.0.1) lib/rack/request.rb:57:in `fetch_header' actionpack (5.0.0.1) lib/action_dispatch/http/request.rb:365:in `POST' actionpack (5.0.0.1) lib/action_controller/Metal/params_wrapper.rb:282:in `_wrapper_enabled?' actionpack (5.0.0.1) lib/action_controller/Metal/params_wrapper.rb:231:in `process_action' activerecord (5.0.0.1) lib/active_record/railties/controller_runtime.rb:18:in `process_action' actionpack (5.0.0.1) lib/abstract_controller/base.rb:126:in `process' actionpack (5.0.0.1) lib/action_controller/Metal.rb:190:in `dispatch' actionpack (5.0.0.1) lib/action_controller/Metal.rb:262:in `dispatch' actionpack (5.0.0.1) lib/action_dispatch/routing/route_set.rb:50:in `dispatch' actionpack (5.0.0.1) lib/action_dispatch/routing/route_set.rb:32:in `serve' actionpack (5.0.0.1) lib/action_dispatch/journey/router.rb:39:in `block in serve' actionpack (5.0.0.1) lib/action_dispatch/journey/router.rb:26:in `each' actionpack (5.0.0.1) lib/action_dispatch/journey/router.rb:26:in `serve' actionpack (5.0.0.1) lib/action_dispatch/routing/route_set.rb:725:in `call' rack (2.0.1) lib/rack/etag.rb:25:in `call' rack (2.0.1) lib/rack/conditional_get.rb:38:in `call' rack (2.0.1) lib/rack/head.rb:12:in `call' activerecord (5.0.0.1) lib/active_record/migration.rb:552:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/callbacks.rb:38:in `block in call' activesupport (5.0.0.1) lib/active_support/callbacks.rb:97:in `__run_callbacks__' activesupport (5.0.0.1) lib/active_support/callbacks.rb:750:in `_run_call_callbacks' activesupport (5.0.0.1) lib/active_support/callbacks.rb:90:in `run_callbacks' actionpack (5.0.0.1) lib/action_dispatch/middleware/callbacks.rb:36:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/executor.rb:12:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/remote_ip.rb:79:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/debug_exceptions.rb:49:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call' railties (5.0.0.1) lib/rails/rack/logger.rb:36:in `call_app' railties (5.0.0.1) lib/rails/rack/logger.rb:24:in `block in call' activesupport (5.0.0.1) lib/active_support/tagged_logging.rb:70:in `block in tagged' activesupport (5.0.0.1) lib/active_support/tagged_logging.rb:26:in `tagged' activesupport (5.0.0.1) lib/active_support/tagged_logging.rb:70:in `tagged' railties (5.0.0.1) lib/rails/rack/logger.rb:24:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/request_id.rb:24:in `call' rack (2.0.1) lib/rack/runtime.rb:22:in `call' activesupport (5.0.0.1) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/executor.rb:12:in `call' actionpack (5.0.0.1) lib/action_dispatch/middleware/static.rb:136:in `call' rack (2.0.1) lib/rack/sendfile.rb:111:in `call' railties (5.0.0.1) lib/rails/engine.rb:522:in `call' puma (3.6.0) lib/puma/configuration.rb:225:in `call' puma (3.6.0) lib/puma/server.rb:578:in `handle_request' puma (3.6.0) lib/puma/server.rb:415:in `process_client' puma (3.6.0) lib/puma/server.rb:275:in `block in run' puma (3.6.0) lib/puma/thread_pool.rb:116:in `block in spawn_thread'
以前我认为可以添加中间件并处理异常如下:
# in config/application.rb config.middleware.insert_before(ActionDispatch::ParamsError,'BadRequestError') # middleware class BadRequestError def initialize(app) @app = app end def call(env) begin @app.call(env) rescue ActionDispatch::ParamsParser::ParseError Api::ApiController.action(:raise_bad_request).call(env) end end end
但是,似乎从Rails 5中删除了中间件ActionDispatch :: ParamsError;
我还试过其他中间件(例如ActionDispatch :: ShowExceptions),抢救不同的错误,但我的raise_bad_request动作以某种方式从未调用过.
我错过了什么,做错了什么,或者是否有其他方法可以使用Rails 5?
谢谢!
解决方法
更新了使用Rails 5.1及更高版本的答案. (谢谢@Edwin Meyer)
config.middlware.use现在需要一个类,而不是字符串.
config.middlware.use现在需要一个类,而不是字符串.
我现在还提到,我已将中间件放在app / middleware下.所以没必要.
我遇到了同样的问题,在我的案例中解决起来非常简单.
只需在application.rb中使用:
config.middleware.use CatchJsonParseErrors # Instead of # config.middleware.insert_before ActionDispatch::ParamsParser,"CatchJsonParseErrors" # I used in my Rails 4 app
我的中间件看起来像这样(从Catching Invalid JSON Parse Errors with Rack Middleware开始):
# app/middleware/catch_json_parse_errors.rb class CatchJsonParseErrors def initialize(app) @app = app end def call(env) begin @app.call(env) rescue ActionDispatch::ParamsParser::ParseError => error if env['HTTP_ACCEPT'] =~ /application\/json/ error_output = "There was a problem in the JSON you submitted: #{error}" return [ 400,{ "Content-Type" => "application/json" },[ { status: 400,error: error_output }.to_json ] ] else raise error end end end end
然后当我发送一个无效的json时,响应看起来像这样:
{"status":400,"error":"There was a problem in the JSON you submitted: 743: unexpected token at '{ \"foo\": \"bar\" '"}
您必须提供正确的ACCEPT标头.
希望它也能帮到你.