限制每个用户在 Rails 中的函数调用速率

发布于 2024-11-25 13:04:05 字数 74 浏览 4 评论 0原文

有人知道我该怎么做吗?在网上查找信息非常困难。我发现的最好的是 curbit it gem,但我只能想到如何在应用程序方面实现该功能。

Anyone have any idea how I might go about this? Having a pretty hard time finding information online. Best I found is the curbit it gem but I can only think of how to implement that application-wise.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鹤舞 2024-12-02 13:04:05

它可以通过以下方式处理:1) 网络服务器 2) 机架应用程序。一切都取决于你需要什么。我们使用内置的nginx功能来限制API请求:

     limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
     limit_req zone=one burst=2;

另一个解决方案是rack-throttle

这是 Rack 中间件,为 Rack 应用程序的传入 HTTP 请求提供速率限制逻辑。您可以将 Rack::Throttle 与任何基于 Rack 的 Ruby Web 框架一起使用,包括 Ruby on Rails 3.0 和 Sinatra。

It can be handled by: 1) webserver 2) rack-application. All depend on what you need. We use built-in nginx functionality to limit API requests:

     limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
     limit_req zone=one burst=2;

The another solution is rack-throttle.

This is Rack middleware that provides logic for rate-limiting incoming HTTP requests to Rack applications. You can use Rack::Throttle with any Ruby web framework based on Rack, including with Ruby on Rails 3.0 and with Sinatra.

冷夜 2024-12-02 13:04:05

以下是如何使用 Redis 和时间戳来实现它的示例。您可以将此模块包含在 user.rb 中,然后可以调用 user.allowed_to?(:reveal_email)

# Lets you limit the number of actions a user can take per time period
# Keeps an integer timestamp with some buffer in the past and each action increments the timestamp
# If the counter exceeds Time.now the action is disallowed and the user must wait for some time to pass.

module UserRateLimiting

  class RateLimit < Struct.new(:max, :per)
    def minimum
      Time.now.to_i - (step_size * max)
    end

    def step_size
      seconds = case per
                when :month  then 18144000 # 60 * 60 * 24 * 30
                when :week   then 604800   # 60 * 60 * 24 * 7
                when :day    then 86400    # 60 * 60 * 24
                when :hour   then 3600     # 60 * 60
                when :minute then 60
                else raise 'invalid per param (day, hour, etc)'
                end
                seconds / max
    end
  end

  LIMITS = {
    :reveal_email => RateLimit.new(200, :day)
    # add new rate limits here...
  }

  def allowed_to? action
    inc_counter(action) < Time.now.to_i
  end

  private

  def inc_counter action
    rl = LIMITS[action]
    raise "couldn't find that action" if rl.nil?
    val = REDIS_COUNTERS.incrby redis_key(action), rl.step_size
    if val < rl.minimum
      val = REDIS_COUNTERS.set redis_key(action), rl.minimum
    end
    val.to_i
  end

  def redis_key action
    "rate_limit_#{action}_for_user_#{self.id}"
  end
end

Here is an example of how it can be implemented using Redis and timestamps. You'd include this module in user.rb and then you can call user.allowed_to?(:reveal_email)

# Lets you limit the number of actions a user can take per time period
# Keeps an integer timestamp with some buffer in the past and each action increments the timestamp
# If the counter exceeds Time.now the action is disallowed and the user must wait for some time to pass.

module UserRateLimiting

  class RateLimit < Struct.new(:max, :per)
    def minimum
      Time.now.to_i - (step_size * max)
    end

    def step_size
      seconds = case per
                when :month  then 18144000 # 60 * 60 * 24 * 30
                when :week   then 604800   # 60 * 60 * 24 * 7
                when :day    then 86400    # 60 * 60 * 24
                when :hour   then 3600     # 60 * 60
                when :minute then 60
                else raise 'invalid per param (day, hour, etc)'
                end
                seconds / max
    end
  end

  LIMITS = {
    :reveal_email => RateLimit.new(200, :day)
    # add new rate limits here...
  }

  def allowed_to? action
    inc_counter(action) < Time.now.to_i
  end

  private

  def inc_counter action
    rl = LIMITS[action]
    raise "couldn't find that action" if rl.nil?
    val = REDIS_COUNTERS.incrby redis_key(action), rl.step_size
    if val < rl.minimum
      val = REDIS_COUNTERS.set redis_key(action), rl.minimum
    end
    val.to_i
  end

  def redis_key action
    "rate_limit_#{action}_for_user_#{self.id}"
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文