2011-07-22 32 views

Trả lời

8

Nó có thể được xử lý bởi: 1) máy chủ web 2) rack-application. Tất cả phụ thuộc vào những gì bạn cần. Chúng tôi use built-in chức năng nginx để hạn chế yêu cầu API:

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

Các giải pháp khác là rack-throttle.

Đây là phần mềm trung gian giá cung cấp logic cho việc giới hạn tốc độ các yêu cầu HTTP đến các ứng dụng Rack. Bạn có thể sử dụng Rack :: Throttle với bất kỳ khung công tác web Ruby nào dựa trên Rack, bao gồm cả Ruby on Rails 3.0 và với Sinatra.

+0

Là phần yêu cầu của địa chỉ ip? Đã tự hỏi nếu điều này là cho mỗi người dùng. –

2

Dưới đây là ví dụ về cách nó có thể được triển khai bằng Redis và dấu thời gian. Bạn sẽ bao gồm mô-đun này trong user.rb và sau đó bạn có thể gọi 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 * 7 * 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 
+0

Chỉ cần thông báo: tính toán của bạn cho 'tháng' không chính xác; bạn không cần hệ số "* 7". Hơn nữa, bạn chỉ có thể sử dụng '1.month.to_i' để lấy số giây trong vòng một tháng (và tương tự cho các đơn vị khác). –

+0

Cảm ơn bạn! Nhiều đánh giá cao. –

Các vấn đề liên quan