【问题标题】:Prevent ruby on rails 3 from parsing JSON post防止 ruby​​ on rails 3 解析 JSON 帖子
【发布时间】:2012-04-30 01:03:41
【问题描述】:

我在 Ruby on Rails 3 中有一个控制器方法,它接受应用程序/JSON 作为内容类型。这一切都按预期工作,但我实际上不希望 rails 自动解析 POST 请求正文中的 JSON。此方法充当网关,只是将信息传送到队列中,并且可能非常大。我不想浪费时间处理 @_params 中的数据,因为这是不必要的。

我相信我可以通过将请求标头中的内容类型设置为其他内容来解决此问题,但我希望 HTTP 请求在语义上是正确的。

如何禁用此功能?

编辑: 更具体地说,我如何才能为这一条路线编辑此功能?

【问题讨论】:

  • 您知道,如果您将其发布为 JSON 并告诉 rails 期望它以 JSON 发布,我认为 Rails 将始终解析。要执行您所描述的操作,我认为您几乎想在该路线上安装一个机架端点并使用 rack_raw_upload 之类的实用程序处理 POST ... 好问题,对不起,我真的不知道答案。
  • 有趣的想法...我可以试一试,看看结果如何。

标签: ruby-on-rails ruby-on-rails-3 json http post


【解决方案1】:

参数解析在 actionpack 的 lib/action_dispatch/middleware/params_parser.rb 中非常深入。

我想说你最好的办法就是用 Rack 拦截请求,像这样。

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

config.ru 中,在调用run <your app name>::Application 之前插入这个

require 'raw_json'
use Rack::RawJSON

【讨论】:

  • 似乎您需要添加到此解决方案中的只是检测某个路线 - 例如if request.path == '/foo' and request.content_type =~ /application\/json/i
  • 是的,这就是为什么我在代码中添加注释以测试 request.path。
  • 我还没有尝试过,但这似乎是一个足够合理的解决方案,我会试一试。
  • 谢谢迈克。希望它对你有帮助。我很想知道你的负载测试告诉你什么。
【解决方案2】:

从单个请求中解析 JSON 的开销相对较低。您是否有特定的理由相信处理 JSON 会导致整体处理速度变慢?

如果不是,那么我建议您保持原样,直到可以将其确定为问题为止。

将 rails 配置为不解析 JSON(通过某种机架配置或其他方法)将在您的应用程序中创建至少一个未在标准 Rails 方式中处理的路由。

最终,您可能会发现自己必须对这些数据进行某种处理。或者,您可能需要在它前面设置某种安全措施。或者您可能想要记录它并将其与发送它的用户相关联。当那一天到来时,您(或您团队中的其他人)将需要进入并更改此非标准实施。

在 Rails 实现中以非标准方式做事会增加维护软件的复杂性和时间。这也是常见的缺陷来源,因为人们对非标准加工不太熟悉。

因此,除非它是一个真正的问题,否则我建议让 rails 处理 JSON,然后简单地通过普通 Rails 方式传递它。

【讨论】:

  • 这不能回答问题。我希望不解析传入的 json 响应,主要是为了优化。 json 主体可能是一个包含数万个项目的数组,当它可以/应该做其他事情时,必须解析和迭代它会占用应用程序的时间和内存。此操作只是数据的传递。
  • 它一点也不低,Rails 解析整个输入,过滤并记录所有参数,处理许多 100k 大小的请求时成本是巨大的。
【解决方案3】:

可能是烤进去的,但是看代码:

 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]

因此,如果您可以安排向此初始化程序发送哈希,则可以添加或覆盖默认值。不确定是否允许删除,但可以使用空的解析器方法。

解析器在这里回答:How do I initialize ActionDispatch::ParamsParser in Rails 3.1?

代码来自 actionpack-3.2.8/lib/action_dispatch/middleware/params_parser.rb

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多