Rate Limiter

RateLimiter provides a Rate Limiter middleware for limiting the amount of requests to the server from a particular IP or id within a time period.

By default an in-memory store is used for keeping track of requests. The default in-memory implementation is focused on correctness and may not be the best option for a high number of concurrent requests or a large number of different identifiers (>16k).

Usage

To add a rate limit to your application simply add the RateLimiter middleware. The example below will limit the application to 20 requests/sec using the default in-memory store:

  1. e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20)))

Rate Limiter - 图1info

If the provided rate is a float number, Burst will be treated as the rounded down value of the rate.

Custom Configuration

  1. config := middleware.RateLimiterConfig{
  2. Skipper: middleware.DefaultSkipper,
  3. Store: middleware.NewRateLimiterMemoryStoreWithConfig(
  4. middleware.RateLimiterMemoryStoreConfig{Rate: 10, Burst: 30, ExpiresIn: 3 * time.Minute},
  5. ),
  6. IdentifierExtractor: func(ctx echo.Context) (string, error) {
  7. id := ctx.RealIP()
  8. return id, nil
  9. },
  10. ErrorHandler: func(context echo.Context, err error) error {
  11. return context.JSON(http.StatusForbidden, nil)
  12. },
  13. DenyHandler: func(context echo.Context, identifier string,err error) error {
  14. return context.JSON(http.StatusTooManyRequests, nil)
  15. },
  16. }
  17. e.Use(middleware.RateLimiterWithConfig(config))

Errors

  1. var (
  2. // ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
  3. ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded")
  4. // ErrExtractorError denotes an error raised when extractor function is unsuccessful
  5. ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
  6. )

Rate Limiter - 图2tip

If you need to implement your own store, be sure to implement the RateLimiterStore interface and pass it to RateLimiterConfig and you’re good to go!

Configuration

  1. type RateLimiterConfig struct {
  2. Skipper Skipper
  3. BeforeFunc BeforeFunc
  4. // IdentifierExtractor uses echo.Context to extract the identifier for a visitor
  5. IdentifierExtractor Extractor
  6. // Store defines a store for the rate limiter
  7. Store RateLimiterStore
  8. // ErrorHandler provides a handler to be called when IdentifierExtractor returns a non-nil error
  9. ErrorHandler func(context echo.Context, err error) error
  10. // DenyHandler provides a handler to be called when RateLimiter denies access
  11. DenyHandler func(context echo.Context, identifier string, err error) error
  12. }

Default Configuration

  1. // DefaultRateLimiterConfig defines default values for RateLimiterConfig
  2. var DefaultRateLimiterConfig = RateLimiterConfig{
  3. Skipper: DefaultSkipper,
  4. IdentifierExtractor: func(ctx echo.Context) (string, error) {
  5. id := ctx.RealIP()
  6. return id, nil
  7. },
  8. ErrorHandler: func(context echo.Context, err error) error {
  9. return &echo.HTTPError{
  10. Code: ErrExtractorError.Code,
  11. Message: ErrExtractorError.Message,
  12. Internal: err,
  13. }
  14. },
  15. DenyHandler: func(context echo.Context, identifier string, err error) error {
  16. return &echo.HTTPError{
  17. Code: ErrRateLimitExceeded.Code,
  18. Message: ErrRateLimitExceeded.Message,
  19. Internal: err,
  20. }
  21. },
  22. }