Request Rate Limit
server hook
Rate limit, a maximum of N requests can be initiated within a certain period of time, such as the following scenario.
- When node is used as the middle layer to request downstream services, under the API with serious resource consumption, it is restricted by IP to avoid consuming downstream server resources
- To prevent password brute force cracking, when the downstream server throws login errors repeatedly, it is restricted by IP or username
- As a sending limit for sendCaptcha, it prevents users from sending verification codes frequently
Features
- Limit the number of requests within a certain period of time;
- Support clusters, single server multi-threading or multi-server;
- Support request interval time;
- After the reachable rate limit, extend the reset time, such as login lock;
- Reward mechanism, penalty mechanism, reset mechanism;
Usage
Basic usage
Create a reusable rateLimit
function (server hook), and use it to wrap the method instance and return the method instance of the request limit.
const rateLimit = createRateLimiter({
/**
* Point reset time, in ms
* @default 4000
*/
duration: 60 * 1000,
/**
* Maximum number of points that can be consumed within duration
* @default 4
*/
points: 4,
/**
* Namespace, to prevent conflicts when multiple rateLimits use the same storage
*/
keyPrefix: 'user-rate-limit',
/**
* Lock duration, in ms, means that when the rate limit is reached, it will be extended by [blockDuration]ms. For example, if the password is incorrect 5 times within 1 hour, it will be locked for 24 hours. This 24 hours is this parameter
*/
blockDuration: 24 * 60 * 60 * 1000,
/**
* Delayed operations will be executed evenly within the duration
* @default false
*/
execEvenly: true,
/**
* Minimum delay time (in milliseconds)
* @default duration/points
*/
execEvenlyMinDelayMs: 60 * 1000 / 4
});
// Use rateLimit in request
app.get('/api/user', (req, res) => {
const userResult = await rateLimit(alova.Get('/api/user?id=' + req.query.id), {
// Track request limits for different users by key
key: req.query.id
});
// ...
});
When a request is limited, an error will be thrown instead of waiting for the request.
Custom storage
By default, rateLimit
uses the target method.context.l2Cache
as storage, so when the l2Cache
referenced by the target method meets the project requirements, you don't need any additional settings.
If not, you can also customize the storage for rateLimit
, such as @alova/psc or redis adapter when the cluster is shared.
const { createPSCAdapter, NodeSyncAdapter } = require('@alova/psc');
const rateLimit = createRateLimiter({
// ...
store: createPSCAdapter(NodeSyncAdapter())
});
store
requires the alova storage adapter, and you can also customize the storage adapter to meet your personalized needs.
Operation function
Use times
By default, a request will consume one point
, and you can also consume points
manually.
const limitedMethod = rateLimit(alova.Get('/api/user?id=' + req.query.id), {
key: req.query.id
});
// Manually consume 1 `points`
const rateLimitRes = await limitedMethod.consume(1);
rateLimitRes
is the status under the current key, the format is as follows.
interface RateLimitRes {
/**
* The number of milliseconds before the next operation is completed
*/
msBeforeNext: 250;
/**
* The number of points remaining in the current duration
*/
remainingPoints: 0;
/**
* The number of points consumed in the current duration
*/
consumerPoints: 5;
/**
* The operation is the first operation in the current duration
*/
isFirstInDuration: false;
}
Rewards
Rewards refer to operations that increase points
. You can temporarily increase points
within a certain period of time.
const limitedMethod = rateLimit(alova.Get('/api/user?id=' + req.query.id), {
key: req.query.id
});
// Reward 1 `points`
const rateLimitRes = await limitedMethod.reward(1);
Penalty
Penalty refers to the operation of reducing points
. You can temporarily reduce points
for a certain period of time.
const limitedMethod = rateLimit(alova.Get('/api/user?id=' + req.query.id), {
key: req.query.id
});
// Penalty 1 `points`
const rateLimitRes = await limitedMethod.penalty(1);
Reset
Reset means restarting a new round of points
consumption.
const limitedMethod = rateLimit(alova.Get('/api/user?id=' + req.query.id), {
key: req.query.id
});
// Reset `points`
const rateLimitRes = await limitedMethod.delete();
Lock
Manually lock for a period of time.
const limitedMethod = rateLimit(alova.Get('/api/user?id=' + req.query.id), {
key: req.query.id
});
// Manually lock for 10 minutes
const rateLimitRes = await limitedMethod.block(10 * 60 * 1000);
This hook is based on node-rate-limiter-flexible and implements most of its functions.