简体   繁体   English

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

[英]Trigger Rack middleware on specific Rails routes

Is it possible to trigger Rack middleware only on specific Rails routes? 是否可以仅在特定的Rails路由上触发Rack中间件?

For example, let's say I wanted to run a rate limiter middleware only on the api namespace. 例如,假设我只想在api名称空间上运行限速器中间件。

namespace :api do
  resources :users
end

I've had good success with Rack::Throttle for rate limiting. 我使用Rack :: Throttle进行了成功的速率限制。 Subclass one of the built-in throttle classes and overload the allowed? 子类化内置节气门类之一,并allowed?重载allowed? method. 方法。 Your custom logic can check which controller is being accessed and apply the rate limit as needed. 您的自定义逻辑可以检查正在访问哪个控制器,并根据需要应用速率限制。

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

Adding to Ian's answer, to setup up the ApiThrottle you have to: 添加到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

One important thing to add is that, for me, the path_info[:controller] came as "api/v1/cities" and not only as "api" . 要补充的一件事是,对我而言, path_info[:controller]"api/v1/cities" ,而不仅仅是以"api" Of course, that is due to the namespace configuration. 当然,这是由于名称空间配置所致。 Therefore, take care when setting up the throttler. 因此,在安装节流阀时要小心。

You can also (now) use a Rails Engine to create an isolated set of routes that adds additional middleware to the stack for its mounted routes. 您还可以(现在)使用Rails Engine创建一组隔离的路由,从而为堆栈中已安装的路由添加其他中间件。

See https://stackoverflow.com/a/41515577/79079 参见https://stackoverflow.com/a/41515577/79079

(Unfortunately I found this question while looking to see if there was any simpler way to do it. Writing a custom middleware for every middleware that I wanted to add seems even more round-about than using a Rails::Engine) (不幸的是,我在寻找是否有更简单的方法时发现了这个问题。为我想添加的每个中间件编写一个定制的中间件似乎比使用Rails :: Engine更复杂。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM