在特定的Rails路由上触发Rack中间件

时间:2012-10-01 19:22:40

标签: ruby-on-rails rack

是否可以仅在特定的Rails路由上触发Rack中间件?

例如,假设我想仅在api命名空间上运行速率限制器中间件。

namespace :api do
  resources :users
end

3 个答案:

答案 0 :(得分:14)

我对Rack::Throttle的速率限制取得了很大的成功。子类化其中一个内置的油门类并重载allowed?方法。您的自定义逻辑可以检查正在访问哪个控制器并根据需要应用速率限制。

class ApiThrottle < Rack::Throttle::Hourly
  ##
  # Returns `false` if the rate limit has been exceeded for the given
  # `request`, or `true` otherwise.
  #
  # Rate limits are only imposed on the "api" controller
  #
  # @param  [Rack::Request] request
  # @return [Boolean]
  def allowed?(request)
    path_info = (Rails.application.routes.recognize_path request.url rescue {}) || {} 

    # Check if this route should be rate-limited
    if path_info[:controller] == "api"
      super
    else
      # other routes are not throttled, so we allow them
      true
    end
  end
end

答案 1 :(得分:5)

添加到Ian的答案,设置ApiThrottle你必须:

# application.rb
require 'rack/throttle'
class Application < Rails::Application
  ...
  config.require "api_throttle"
  # max 100 requests per hour per ip
  config.middleware.use ApiThrottle, :max => 100
  ...
end

# /lib/api_throttle.rb
# Ian's code here

要添加的一件重要事情是,对我来说,path_info[:controller]来自"api/v1/cities"而不仅仅是"api"。当然,这是由命名空间配置引起的。因此,在设置节流器时要小心。

答案 2 :(得分:1)

您还可以(现在)使用Rails引擎创建一组隔离的路由,为堆栈的已安装路由添加额外的中间件。

请参阅https://stackoverflow.com/a/41515577/79079

(不幸的是,我在查看是否有更简单的方法时发现了这个问题。为我想要添加的每个中间件编写自定义中间件似乎比使用Rails :: Engine更加圆润了< / p>