Prevent ruby on rails 3 from parsing JSON post

2019-04-03 15:29发布

问题:

I have a controller method in Ruby on Rails 3 that accepts application/JSON as the content type. This all works as expected, but I actually do not want rails to automatically parse the JSON in the body of the POST request. This method is acting as a gateway and just shuttles the information in to a queue and could be quite large. I do not want to waste the time processing the data in to the @_params since it's unnecessary.

I believe I could get around this by setting the content-type in the header of the request to something else, but I would like to be semantically correct for the HTTP requests.

How can I disable this functionality?

EDIT: more specifically how can I edit this functionality for just this one route?

回答1:

Parameter parsing is baked pretty deeply inside actionpack's lib/action_dispatch/middleware/params_parser.rb.

I'd say the best you're going to get away with is intercepting the request with Rack, something like this.

In lib/raw_json.rb

module Rack
  class RawJSON
    def initialize(app)
      @app = app
    end

    def call(env)
      request = Request.new(env)
      if request.content_type =~ /application\/json/i
        # test request.path here to limit your processing to particular actions
        raw_json = env['rack.input'].read
        env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
        env['rack.input'] = StringIO.new("raw_json=#{raw_json}")
      end
      return @app.call(env)
    end
  end
end

In config.ru, insert this before the call to run <your app name>::Application

require 'raw_json'
use Rack::RawJSON


回答2:

The overhead for parsing the JSON from a single request is relatively low. Do you have a specific reason to believe that processing the JSON is contributing to any kind of slowness in overall processing?

If not, then I'd recommend that you leave this as it is until such time is it can be identified as a problem.

Configuring rails to not parse that JSON (either via some sort of rack configuration or in some other method) will create at lest one route in your application that is not handled in a standard Rails Way.

Eventually, you may find yourself having to do some sort of processing of this data. Or maybe you'll need to put some sort of security in front of it. Or maybe you'll want to log it and related it to the user that sent it. And when that day comes you (or someone else on your team) will need to go in and make changes to this non-standard implementation.

Doing things in a non-standard way in a Rails implementation can add to the complexity and time to maintain the software. It is also a common source of defects since people are less familiar with non-standard processing.

So unless it is a real issue, I'd recommend just letting rails process the JSON and then simply pass it through the normal Rails Way.



回答3:

It may be baked in, but looking at the code:

 module ActionDispatch
  class ParamsParser
    DEFAULT_PARSERS = {
      Mime::XML => :xml_simple,
      Mime::JSON => :json
    }

    def initialize(app, parsers = {})
      @app, @parsers = app, DEFAULT_PARSERS.merge(parsers)
    end

     [ ... ]

        strategy = @parsers[mime_type]

So, if you can arrange to send a hash to this initializer, you can add or override the default. Not sure the allow for removing, but an empty parser method could work.

Parsers answer here: How do I initialize ActionDispatch::ParamsParser in Rails 3.1?

Code is from actionpack-3.2.8/lib/action_dispatch/middleware/params_parser.rb