【问题标题】:How to catch a Rack RangeError in Rails 6如何在 Rails 6 中捕获 Rack RangeError
【发布时间】:2021-09-27 22:15:35
【问题描述】:

我有一个 Rails 6 应用程序,用户可以将 CSV 文件上传到该应用程序。 Rails/Rack 对可以包含在请求中的参数数量施加了限制,我已将其设置为大于可能提交给我的应用程序的大小。但是,如果上传的文件太大,我想返回友好的响应。

看起来我需要添加一些自定义中间件来捕获和挽救错误,但我无法让代码工作 - 基本错误仍然会在没有调用我的救援块的情况下引发。

来自服务器的错误是:

Rack app error handling request { POST /[PATH_TO]/datasets }
#<RangeError: exceeded available parameter key space>

我的app/middleware/catch_errors.rb 文件中的代码基本上取自a previous SO answer,有人在JSON 中捕获ActionDispatch::ParamsParser::ParseError,但在rescue 块中使用我自己的代码(我意识到这可能无法正常工作)上下文,但这不是现在的问题):

class CatchErrors
  def initialize(_app)
    @app = _app
  end

  def call(_env)
    begin
      @app.call(_env)
    rescue RangeError => _error
      _error_output = "There were too many fields in the data you submitted: #{_error}"
      if env['HTTP_ACCEPT'] =~ /application\/html/
        Rails.logger.error("Caught RangeError: #{_error}")
        flash[:error_title] = 'Too many fields in your data'
        flash[:error_detail1] = _error_output
        render 'static_pages/error', status: :bad_request
      elsif env['HTTP_ACCEPT'] =~ /application\/json/
        return [
          :bad_request, { "Content-Type" => "application/json" },
          [ { status: :bad_request, error: _error_output }.to_json ]
        ]
      else
        raise _error
      end
    end
  end
end

我正在将它加载到config.application.rb,如下所示:

require_relative '../app/middleware/catch_errors'
...
config.middleware.use CatchErrors

我正在重置 app/initializers/rack.rb 中测试的大小限制,如下所示:

if Rack::Utils.respond_to?("key_space_limit=")
  Rack::Utils.key_space_limit = 1
end

感谢您的帮助!

【问题讨论】:

  • 您应该可以上传任意大小的文件。是的,查询参数的长度有限制,但文件上传不应该在查询参数内。建议您重新考虑您的文件上传方案。
  • 问题是我将 CSV 解析后上传为(可能很大)JSON 对象。 Rails 对它的大小有限制。用上传单个二进制 blob 替换它不会(IMO)是一种改进。

标签: ruby-on-rails ruby middleware rack


【解决方案1】:

首先,执行命令查看所有中间件:

bin/rails middleware

config.middleware.use 将您的中间件放在中间件堆栈的底部。因此,它无法捕获错误。尝试将其放在顶部:

config.middleware.insert_before 0, CatchErrors

还有一点需要提一下,可能你需要config.middleware.move_after 甚至config.middleware.delete 一些中间件。例如,在修补时,我需要放置:

config.middleware.move_after CatchErrors, Rack::MiniProfiler

【讨论】:

  • 就是这样,谢谢 - 需要在中间件序列中更早地插入处理程序。现在研究如何在这种情况下正确处理错误。 (不能只使用我常用的 Rails 技巧,因为这些都不可用!)
  • 为了将来参考,rescue 子句最终只需要:rescue RangeError =&gt; _error \n return [400, { "Content-Type" =&gt; "application/json" }, [ "There were too many fields in the data you submitted: #{_error}" ] ] \n end
猜你喜欢
  • 2020-09-03
  • 2013-12-19
  • 2011-03-19
  • 1970-01-01
  • 2015-03-21
  • 1970-01-01
  • 2013-10-04
  • 1970-01-01
  • 2010-10-25
相关资源
最近更新 更多