Express 中文文档 Express 中文文档
指南
GitHub (opens new window)
指南
GitHub (opens new window)
  • 快速入门

    • 安装
    • 你好世界
    • Express 生成器
    • 基本路由
    • 静态文件
    • 更多示例
    • 常见问题
  • 使用指南

  • express()
  • 应用
  • 请求
  • 响应
  • 路由

Express Rate Limit


Sponsored by Zuplo a fully-managed API Gateway for developers. Add dynamic rate-limiting, authentication and more to any API in minutes. Learn more at zuplo.com

Tests

Basic rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset. Plays nice with express-slow-down.

Alternate Rate Limiters


This module does not share state with other processes/servers by default. If you need a more robust solution, I recommend using an external store. See the stores section below for a list of external stores.


This module was designed to only handle the basics and didn't even support external stores initially. These other options all are excellent pieces of software and may be more appropriate for some situations:

rate-limiter-flexible
express-brute
rate-limiter

Installation


From the npm registry:

  1. ``` shell
  2. # Using npm
  3. > npm install express-rate-limit
  4. # Using yarn or pnpm
  5. > yarn/pnpm add express-rate-limit
  6. ```

From Github Releases:

  1. ``` shell
  2. # Using npm
  3. > npm install https://github.com/express-rate-limit/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
  4. # Using yarn or pnpm
  5. > yarn/pnpm add https://github.com/express-rate-limit/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
  6. ```

Replace {version} with the version of the package that you want to your, e.g.: 6.0.0.

Usage


Importing


This library is provided in ESM as well as CJS forms, and works with both Javascript and Typescript projects.

This package requires you to use Node 14 or above.

Import it in a CommonJS project (type: commonjs or no type field in package.json ) as follows:

  1. ``` ts
  2. const rateLimit = require('express-rate-limit')
  3. ```

Import it in a ESM project (type: module in package.json ) as follows:

  1. ``` ts
  2. import rateLimit from 'express-rate-limit'
  3. ```

Examples


To use it in an API-only server where the rate-limiter should be applied to all requests:

  1. ``` ts
  2. import rateLimit from 'express-rate-limit'

  3. const limiter = rateLimit({
  4. windowMs: 15 * 60 * 1000, // 15 minutes
  5. max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
  6. standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  7. legacyHeaders: false, // Disable the `X-RateLimit-*` headers
  8. })

  9. // Apply the rate limiting middleware to all requests
  10. app.use(limiter)
  11. ```

To use it in a 'regular' web server (e.g. anything that uses express.static() ), where the rate-limiter should only apply to certain requests:

  1. ``` ts
  2. import rateLimit from 'express-rate-limit'

  3. const apiLimiter = rateLimit({
  4. windowMs: 15 * 60 * 1000, // 15 minutes
  5. max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
  6. standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  7. legacyHeaders: false, // Disable the `X-RateLimit-*` headers
  8. })

  9. // Apply the rate limiting middleware to API calls only
  10. app.use('/api', apiLimiter)
  11. ```

To create multiple instances to apply different rules to different endpoints:

  1. ``` ts
  2. import rateLimit from 'express-rate-limit'

  3. const apiLimiter = rateLimit({
  4. windowMs: 15 * 60 * 1000, // 15 minutes
  5. max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
  6. standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  7. legacyHeaders: false, // Disable the `X-RateLimit-*` headers
  8. })

  9. app.use('/api/', apiLimiter)

  10. const createAccountLimiter = rateLimit({
  11. windowMs: 60 * 60 * 1000, // 1 hour
  12. max: 5, // Limit each IP to 5 create account requests per `window` (here, per hour)
  13. message:
  14.   'Too many accounts created from this IP, please try again after an hour',
  15. standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  16. legacyHeaders: false, // Disable the `X-RateLimit-*` headers
  17. })

  18. app.post('/create-account', createAccountLimiter, (request, response) => {
  19. //...
  20. })
  21. ```

To use a custom store:

  1. ``` ts
  2. import rateLimit, { MemoryStore } from 'express-rate-limit'

  3. const apiLimiter = rateLimit({
  4. windowMs: 15 * 60 * 1000, // 15 minutes
  5. max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
  6. standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  7. store: new MemoryStore(),
  8. })

  9. // Apply the rate limiting middleware to API calls only
  10. app.use('/api', apiLimiter)
  11. ```

Note:most stores will require additional configuration, such as custom prefixes, when using multiple instances. The default built-in memory store is an exception to this rule.


Troubleshooting Proxy Issues


If you are behind a proxy/load balancer (usually the case with most hosting services, e.g. Heroku, Bluemix, AWS ELB, Nginx, Cloudflare, Akamai, Fastly, Firebase Hosting, Rackspace LB, Riverbed Stingray, etc.), the IP address of the request might be the IP of the load balancer/reverse proxy (making the rate limiter effectively a global one and blocking all requests once the limit is reached) or undefined. To solve this issue, add the following line to your code (right after you create the express application):

  1. ``` ts
  2. app.set('trust proxy', numberOfProxies)
  3. ```

Where numberOfProxies is the number of proxies between the user and the server. To find the correct number, create a test endpoint that returns the client IP:

  1. ``` ts
  2. app.set('trust proxy', 1)
  3. app.get('/ip', (request, response) => response.send(request.ip))
  4. ```

Go to /ip and see the IP address returned in the response. If it matches your public IP address, then the number of proxies is correct and the rate limiter should now work correctly. If not, then keep increasing the number until it does.

For more information about the trust proxy setting, take a look at the official Express documentation.

Configuration


windowMs


number


Time frame for which requests are checked/remembered. Also used in the Retry-After header when the limit is reached.

Note: with stores that do not implement the init function (see the table in the stores section below ), you may need to configure this value twice, once here and once on the store. In some cases the units also differ (e.g. seconds vs miliseconds).

Defaults to 60000 ms (= 1 minute).

max


number | function


The maximum number of connections to allow during the window before rate limiting the client.

Can be the limit itself as a number or a (sync/async) function that accepts the Express request and response objects and then returns a number.

Defaults to 5. Set it to 0 to disable the rate limiter.

An example of using a function:

  1. ``` ts
  2. const isPremium = async (user) => {
  3. // ...
  4. }

  5. const limiter = rateLimit({
  6. // ...
  7. max: async (request, response) => {
  8.   if (await isPremium(request.user)) return 10
  9.   else return 5
  10. },
  11. })
  12. ```

message


any


The response body to send back when a client is rate limited.

May be a string, JSON object, or any other value that Express's response.send method supports. It can also be a (sync/async) function that accepts the Express request and response objects and then returns a string, JSON object or any other value the Express response.send function accepts.

Defaults to 'Too many requests, please try again later.'

An example of using a function:

  1. ``` ts
  2. const isPremium = async (user) => {
  3. // ...
  4. }

  5. const limiter = rateLimit({
  6. // ...
  7. message: async (request, response) => {
  8.   if (await isPremium(request.user))
  9.    return 'You can only make 10 requests every hour.'
  10.   else return 'You can only make 5 requests every hour.'
  11. },
  12. })
  13. ```

statusCode


number


The HTTP status code to send back when a client is rate limited.

Defaults to 429 (HTTP 429 Too Many Requests - RFC 6585).

legacyHeaders


boolean


Whether to send the legacy rate limit headers for the limit (X-RateLimit-Limit ), current usage (X-RateLimit-Remaining ) and reset time (if the store provides it) (X-RateLimit-Reset ) on all responses. If set to true, the middleware also sends the Retry-After header on all blocked requests.

Defaults to true (for backward compatibility).

Renamed in 6.x from headers to legacyHeaders.


standardHeaders


boolean


Whether to enable support for headers conforming to the ratelimit standardization draft adopted by the IETF (RateLimit-Limit, RateLimit-Remaining, and, if the store supports it, RateLimit-Reset ). If set to true, the middleware also sends the Retry-After header on all blocked requests. May be used in conjunction with, or instead of the legacyHeaders option.

Defaults to false (for backward compatibility, but its use is recommended).

Renamed in 6.x from draft_polli_ratelimit_headers to standardHeaders.


requestPropertyName


string


The name of the property on the Express request object to store the rate limit info.

Defaults to 'rateLimit'.

skipFailedRequests


boolean


When set to true, failed requests won't be counted. Request considered failed when the requestWasSuccessful option returns false. By default, this means requests fail when:

the response status >= 400
the request was cancelled before last chunk of data was sent (response close event triggered)
the response error event was triggered by response

(Technically they are counted and then un-counted, so a large number of slow requests all at once could still trigger a rate-limit. This may be fixed in a future release. PRs welcome!)

Defaults to false.

skipSuccessfulRequests


boolean


If true, the library will (by default) skip all requests that are considered 'failed' by the requestWasSuccessful function. By default, this means requests succeed when the response status code < 400.

(Technically they are counted and then un-counted, so a large number of slow requests all at once could still trigger a rate-limit. This may be fixed in a future release. PRs welcome!)

Defaults to false.

keyGenerator


function


Method to retrieve custom identifiers for clients, such as their IP address, username, or API Key.

Should be a (sync/async) function that accepts the Express request and response objects and then returns a string.

By default, the client's IP address is used:

  1. ``` ts
  2. const limiter = rateLimit({
  3. // ...
  4. keyGenerator: (request, response) => request.ip,
  5. })
  6. ```

NoteIf a keyGenerator returns the same value for every user, it becomes a global rate limiter. This could be combined with a second instance of express-rate-limit to have both global and per-user limits.


handler


function


Express request handler that sends back a response when a client is rate-limited.

By default, sends back the statusCode and message set via the options, similar to this:

  1. ``` ts
  2. const limiter = rateLimit({
  3. // ...
  4. handler: (request, response, next, options) =>
  5.   response.status(options.statusCode).send(options.message),
  6. })
  7. ```

onLimitReached


function


A (sync/async) function that accepts the Express request and response objects that is called when a client has reached their rate limit, and will be rate limited on their next request.

This method was deprecated in v6 - Please use a custom handler that checks the number of hits instead.

skip


function


Function to determine whether or not this request counts towards a client's quota. Should be a (sync/async) function that accepts the Express request and response objects and then returns true or false.

Could also act as an allowlist for certain keys:

  1. ``` ts
  2. const allowlist = ['192.168.0.56', '192.168.0.21']

  3. const limiter = rateLimit({
  4. // ...
  5. skip: (request, response) => allowlist.includes(request.ip),
  6. })
  7. ```

By default, it skips no requests:

  1. ``` ts
  2. const limiter = rateLimit({
  3. // ...
  4. skip: (request, response) => false,
  5. })
  6. ```

requestWasSuccessful


function


Method to determine whether or not the request counts as 'succesful'. Used when either skipSuccessfulRequests or skipFailedRequests is set to true. Should be a (sync/async) function that accepts the Express request and response objects and then returns true or false.

By default, requests with a response status code less than 400 are considered successful:

  1. ``` ts
  2. const limiter = rateLimit({
  3. // ...
  4. requestWasSuccessful: (request, response) => response.statusCode < 400,
  5. })
  6. ```

store


Store


The Store to use to store the hit count for each client.

By default, the memory-store is used.

Here is a list of external stores:

Name Description Legacy/Modern
:--- :--- :---
memory-store (default) Simple in-memory option. Does not share state when app has multiple processes or servers. Modern as of v6.0.0
rate-limit-redis A Redis-backed store, more suitable for large or demanding deployments. Modern as of v3.0.0
rate-limit-memcached A Memcached-backed store. Legacy
rate-limit-mongo A MongoDB-backed store. Legacy
precise-memory-rate-limit A memory store similar to the built-in one, except that it stores a distinct timestamp for each key. Legacy

Take a look at this guide if you wish to create your own store.

Request API


A request.rateLimit property is added to all requests with the limit, current, and remaining number of requests and, if the store provides it, a resetTime Date object. These may be used in your application code to take additional actions or inform the user of their status.

The property name can be configured with the configuration option requestPropertyName.

Instance API


resetKey(key)


Resets the rate limiting for a given key. An example use case is to allow users to complete a captcha or whatever to reset their rate limit, then call this method.

Issues and Contributing


If you encounter a bug or want to see something added/changed, please go ahead and open an issue ! If you need help with something, feel free to start a discussion !

If you wish to contribute to the library, thanks! First, please read the contributing guide. Then you can pick up any issue and fix/implement it!

License


MIT © Nathan Friedly
Last Updated: 2023-05-23 11:11:51