Trigger Rack middleware on specific Rails routes

后端 未结 3 1174
温柔的废话
温柔的废话 2020-12-17 16:50

Is it possible to trigger Rack middleware only on specific Rails routes?

For example, let\'s say I wanted to run a rate limiter middleware only on the api namespace.

相关标签:
3条回答
  • 2020-12-17 17:30

    I've had good success with Rack::Throttle for rate limiting. Subclass one of the built-in throttle classes and overload the 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
    
    0 讨论(0)
  • 2020-12-17 17:33

    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.

    See 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)

    0 讨论(0)
  • 2020-12-17 17:53

    Adding to Ian's answer, to setup up the ApiThrottle you have to:

    # 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". Of course, that is due to the namespace configuration. Therefore, take care when setting up the throttler.

    0 讨论(0)
提交回复
热议问题