4

APIのみのRails 5.xアプリケーションに対して不正な形式のJSONを送信すると例外が発生し、Railsはスタックトレース全体をJSONとして返します。明らかに、私はきれいな、カスタムのフォーマットされたエラーで応答したいと思います。ActionDispatch :: ParamsParser :: ParseErrorを救い、レール5でカスタムAPIエラーを返すには?

=> 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 

それはミドルウェアActionDispatch::ParamsErrorはRailsの5から削除されたようですが。

他のミドルウェア(ActionDispatch :: ShowExceptionsなど)でも試してみましたが、別のエラーを救済しましたが、私のraise_bad_requestアクションは何とか呼び出されません。

何か不足している、何か間違っている、またはRails 5でこれを行う別の方法がありますか?

ありがとうございます!

答えて

8

答えがRails 5.1以降で動作するように更新されました。 (Thanks @Edwin Meyer) config.middlware.useには、文字列ではなくクラスが必要になります。

また、ミドルウェアをapp/middlewareの下に置いていることにも言及します。したがって、必要はありません。


私は同じ問題を抱えていて、私の場合は解決するのが非常に簡単でした。

ただapplication.rbに使用します。次に

# 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を送信するとき、応答は次のようになります:

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から)次のようになります

{"status":400,"error":"There was a problem in the JSON you submitted: 743: unexpected token at '{ \"foo\": \"bar\" '"} 

正しい012を入力する必要がありますヘッダー。

あなたも役に立ちます。

2

私はRailsの5.1.4を実行している、と私は私のために動作するようにスパの解決策を得るために必要な以下の修正が見つかりました:application.rbで

-

1)config.middlewareの引数をconfig.middleware.use CatchJsonParseErrors
2)catch_json_parse_errors.rbが必要とされなければならない:catch_json_parse_errorsで
require './app/middleware/catch_json_parse_errors'

.USEはクラスではなく、文字列のようです。RB - CONTENT_TYPEなくHTTP_ACCEPTが指定されている
変更ライン
if env['HTTP_ACCEPT'] =~ /application\/json/
if env['HTTP_ACCEPT'] =~ /application\/json/ || env['CONTENT_TYPE'] =~ /application\/json/

に非常に悪いコンテンツのHTTP要求も処理されます。

関連する問題