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

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

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

namespace :api do resources :users end 

我使用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 

除了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" 。 当然,这是由命名空间配置引起的。 因此,在设置节流器时要小心。

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

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

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