14

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

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

namespace :api do
  resources :users
end
4

3 回答 3

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
于 2012-11-30T21:34:40.817 回答
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"。当然,这是由于命名空间配置。因此,在设置节流阀时要小心。

于 2014-01-03T19:32:24.860 回答
1

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

https://stackoverflow.com/a/41515577/79079

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

于 2017-01-09T15:40:51.040 回答