Code Monkey home page Code Monkey logo

ratelimit's Introduction

koa-ratelimit

NPM version build status node version

Rate limiter middleware for koa.

Installation

# npm
$ npm install koa-ratelimit
# yarn
$ yarn add koa-ratelimit

Example

With a Redis driver

const Koa = require('koa');
const ratelimit = require('koa-ratelimit');
const Redis = require('ioredis');
const app = new Koa();

// apply rate limit
app.use(ratelimit({
  driver: 'redis',
  db: new Redis(),
  duration: 60000,
  errorMessage: 'Sometimes You Just Have to Slow Down.',
  id: (ctx) => ctx.ip,
  headers: {
    remaining: 'Rate-Limit-Remaining',
    reset: 'Rate-Limit-Reset',
    total: 'Rate-Limit-Total'
  },
  max: 100,
  disableHeader: false,
  whitelist: (ctx) => {
    // some logic that returns a boolean
  },
  blacklist: (ctx) => {
    // some logic that returns a boolean
  }
}));

// response middleware
app.use(async (ctx) => {
  ctx.body = 'Stuff!';
});

// run server
app.listen(
  3000,
  () => console.log('listening on port 3000')
);

With a memory driver

const Koa = require('koa');
const ratelimit = require('koa-ratelimit');
const app = new Koa();

// apply rate limit
const db = new Map();

app.use(ratelimit({
  driver: 'memory',
  db: db,
  duration: 60000,
  errorMessage: 'Sometimes You Just Have to Slow Down.',
  id: (ctx) => ctx.ip,
  headers: {
    remaining: 'Rate-Limit-Remaining',
    reset: 'Rate-Limit-Reset',
    total: 'Rate-Limit-Total'
  },
  max: 100,
  disableHeader: false,
  whitelist: (ctx) => {
    // some logic that returns a boolean
  },
  blacklist: (ctx) => {
    // some logic that returns a boolean
  }
}));

// response middleware
app.use(async (ctx) => {
  ctx.body = 'Stuff!';
});

// run server
app.listen(
  3000,
  () => console.log('listening on port 3000')
);

Options

  • driver memory or redis [redis]
  • db redis connection instance or Map instance (memory)
  • duration of limit in milliseconds [3600000]
  • errorMessage custom error message
  • id id to compare requests [ip]
  • namespace prefix for storage driver key name [limit]
  • headers custom header names
  • max max requests within duration [2500]
  • disableHeader set whether send the remaining, reset, total headers [false]
  • remaining remaining number of requests ['X-RateLimit-Remaining']
  • reset reset timestamp ['X-RateLimit-Reset']
  • total total number of requests ['X-RateLimit-Limit']
  • whitelist if function returns true, middleware exits before limiting
  • blacklist if function returns true, 403 error is thrown
  • throw call ctx.throw if true

Responses

Example 200 with header fields:

HTTP/1.1 200 OK
X-Powered-By: koa
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1384377793
Content-Type: text/plain; charset=utf-8
Content-Length: 6
Date: Wed, 13 Nov 2013 21:22:13 GMT
Connection: keep-alive

Stuff!

Example 429 response:

HTTP/1.1 429 Too Many Requests
X-Powered-By: koa
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1384377716
Content-Type: text/plain; charset=utf-8
Content-Length: 39
Retry-After: 7
Date: Wed, 13 Nov 2013 21:21:48 GMT
Connection: keep-alive

Rate limit exceeded, retry in 8 seconds

License

MIT

ratelimit's People

Contributors

3imed-jaberi avatar agorf avatar altruism avatar ciqulover avatar dead-horse avatar fixe avatar haoxins avatar jonathanong avatar mikaelbr avatar niftylettuce avatar ozzieorca avatar promag avatar ramskedlaya avatar ruiquelhas avatar ryan-verys avatar singlebyted avatar snyk-bot avatar titanism avatar tj avatar tuananh avatar whatwewant avatar yelworc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ratelimit's Issues

Custom header names

Hi. As far as I can tell, there is currently no support for setting custom header names (for X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset). Would you consider accepting a PR for it?

Thanks.

async-ratelimiter does not support `redis` library

The old ratelimiter library has an ioredis check:

var isIoRedis = Array.isArray(res[0]);
var count = parseInt(isIoRedis ? res[1][1] : res[1]);
var oldest = parseInt(isIoRedis ? res[3][1] : res[3]);
var oldestInRange = parseInt(isIoRedis ? res[4][1] : res[4]);

but async-ratelimiter does not.

This will cause erroneous 429s to occur with the latest version of koa-ratelimit for people using the regular redis library. Please list this as a breaking change.

microlinkhq/async-ratelimiter#22

I'm not interested into support node-redis since ioredis have all the features necessaries and the project is well maintained 🙂

TypeError: Cannot read properties of undefined (reading 'remoteAddress')

$ deno run -A index.js
http://localhost:3000

  TypeError: Cannot read properties of undefined (reading 'remoteAddress')
      at Object.get ip (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa/2.14.1/lib/request.js:456:45)
      at Object.ip (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/delegates/1.0.0/index.js:72:24)
      at Object.id (file:///E:/test/deno/deno01/index.js:168:20)
      at ratelimit (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa-ratelimit/5.0.1/index.js:57:21)
      at dispatch (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa-compose/4.2.0/index.js:47:32)
      at file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa-compose/4.2.0/index.js:39:12
      at Application.handleRequest (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa/2.14.1/lib/application.js:182:12)
      at ServerImpl.handleRequest (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa/2.14.1/lib/application.js:157:19)
      at ServerImpl.emit (https://deno.land/[email protected]/node/_events.mjs:379:28)
      at https://deno.land/[email protected]/node/http.ts:634:16


  TypeError: Cannot read properties of undefined (reading 'remoteAddress')
      at Object.get ip (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa/2.14.1/lib/request.js:456:45)
      at Object.ip (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/delegates/1.0.0/index.js:72:24)
      at Object.id (file:///E:/test/deno/deno01/index.js:168:20)
      at ratelimit (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa-ratelimit/5.0.1/index.js:57:21)
      at dispatch (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa-compose/4.2.0/index.js:47:32)
      at file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa-compose/4.2.0/index.js:39:12
      at Application.handleRequest (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa/2.14.1/lib/application.js:182:12)
      at ServerImpl.handleRequest (file:///C:/Users/13697/AppData/Local/deno/npm/registry.npmjs.org/koa/2.14.1/lib/application.js:157:19)
      at ServerImpl.emit (https://deno.land/[email protected]/node/_events.mjs:379:28)
      at https://deno.land/[email protected]/node/http.ts:634:16

Help me understand this middleware

app.use(ratelimit({
  db: redis.createClient(),
  duration: 60000,
  max: 100
}));

Does this mean that each ip can send 100 requests per minute and if it tries to send more, it is blocked for 1 minute?

does it support redis (not ioredis)

does it support redis (not ioredis) ?

Error
TypeError: Cannot read properties of undefined (reading '1')

Code which does not work

import { createClient } from 'redis';
app.use(
    rateLimit({
      driver: 'redis',
      db: createClient,
      duration: 1000,
      errorMessage: 'You Just Have to Slow Down',
      id: (c) => c.ip,
      headers: {
        remaining: 'Rate-Limit-Remaining',
        reset: 'Rate-Limit-Reset',
        total: 'Rate-Limit-Total',
      },
      max: 99,
      disableHeader: false,
    }),
  );

Property "max" expected behaviour

Node version: 13.0.1
koa-ratelimit version: 4.3.0
koa version: 2.11.0

Tested from localhost with alias => example.com => 127.0.0.1

For me the expected behavior would be that every 60 seconds I can only send two requests.
However, only the third request is blocking me every 60 seconds, (max + 1 request).
The same thing happens with 10, 100 ...

If i console.log db for my ip it has negative remaining values for > max

const db = new Map(); app.use( rateLimit({ driver: 'memory', db: db, duration: 60000, errorMessage: 'rate limit exceded', id: (ctx) => ctx.ip, headers: { remaining: 'Rate-Limit-Remaining', reset: 'Rate-Limit-Reset', total: 'Rate-Limit-Total' }, max: 2, disableHeader: true, whitelist: (ctx) => { }, blacklist: (ctx) => { } }) );

Use session instead of redis

Maybe session is a better choice, because not every app uses redis. And it is more server-friendly to use session, which will reduce the server load.

Whitelist/Blacklist methods not listed in ReadMe options

I'm looking to add some whitelist options, I see the whitelist/blacklist properties in the source code from the PR but because there's not a definitive indication that it can be/should be used, that suggests to me that it could change in any patch version without notice.

More specifically I'm trying to use the whitelist to NOT rate limit requests that return true from the whitelist method.

Is it just a matter of adding it to the ReadMe? If so, I'm happy to open a PR.
Example trying to use:

app.use(ratelimit({
  db: new Redis(),
  duration: 60000,
  errorMessage: 'Sometimes You Just Have to Slow Down.',
  id: (ctx) => ctx.ip,
  max: 100,
  disableHeader: false,
  whitelist: (ctx) => {
    // some logic that returns a boolean
  }
}));

Some enhancements - koa-better-ratelimit

Hi folks.

What think for this memory-only-for-now store implementation - koa-better-ratelimit with only 4 dependencies?
I know it's near between koa-limit and koa-ratelimit, but I think it's smaller and rationally better than koa-limit that is totally broken for me.

There's no db option, cuz I don't need other than in-memory.

Diferences

Between koa-better-ratelimit and koa-ratelimit

  • Support blackList and whiteList options
  • Pure in-memory store, no other adapters
  • duration option in seconds, not in milliseconds
  • 7 working tests with Mocha, Supertest and Should
  • removed db option
  • added Retry-After header
  • added separate 403 and 429 option messages

Between koa-better-ratelimit and koa-limit

  • koa-limit is totally broken (to v1.0.1)
  • removed redis and test dependencies
  • smaller, better, working, simple
  • added separate 403 and 429 option messages

If you want you can add to wiki page :)

It does not work

it is just does not work for this simple koa app:
`const Koa = require('koa');
const ratelimit = require('koa-ratelimit');
const Promise = require('bluebird');
const redis = require('redis');

const redisOption = {};
const redisClient = redis.createClient(redisOption);
Promise.promisifyAll(redis.RedisClient.prototype);
Promise.promisifyAll(redis.Multi.prototype);
redisClient.once('ready', () => {
console.log('redis connnection ready');
});
redisClient.on('error', (err) => {
console.log('can't connect to redis', err);
process.exit(1);
});

const app = new Koa();

// apply rate limit

app.use(ratelimit({
db: redisClient,
duration: 10000,
max: 10
}));

// response middleware

app.use(async (ctx) => {
ctx.body = 'Stuff!';
});

app.listen(4000);
console.log('listening on port 4000');
`
then keep trying send request use postman, right after the duration pass the remaining time will jump to a random num, even with a negative value, e.g.

Rate limit exceeded, retry in -412 ms.

I am using NodeJs v8.11.1, Redis 3.0.0, "koa": "^2.5.1", "koa-ratelimit": "^4.1.2", "redis": "^2.8.0",

Error in koa-ratelimit/limiter/memory.js:34:3: ".id required"

I see this error multiple times in the logs of my server. Can you tell me what could be the problem? I'm not calling the Limiter class or constructor in my code (at least not directly).
I'm using 4.2.0 version.
The rate limiter is working but sometimes I get this error on the logs.

AssertionError [ERR_ASSERTION]: .id required
      at new Limiter (/home/fer/polyamory-dates-server/node_modules/koa-ratelimit/limiter/memory.js:34:3)
      at ratelimit (/home/fer/polyamory-dates-server/node_modules/koa-ratelimit/index.js:74:17)
      at dispatch (/home/fer/polyamory-dates-server/node_modules/koa-compose/index.js:42:32)
      at cors (/home/fer/polyamory-dates-server/node_modules/@koa/cors/index.js:56:38)
      at dispatch (/home/fer/polyamory-dates-server/node_modules/koa-compose/index.js:42:32)
      at /home/fer/polyamory-dates-server/node_modules/koa-compose/index.js:34:12
      at Application.handleRequest (/home/fer/polyamory-dates-server/node_modules/koa/lib/application.js:168:12)
      at Server.handleRequest (/home/fer/polyamory-dates-server/node_modules/koa/lib/application.js:150:19)
      at Server.emit (events.js:315:20)
      at Server.<anonymous> (/home/fer/.nvm/versions/node/v14.16.1/lib/node_modules/pm2/node_modules/@pm2/io/src/metrics/httpMetrics.ts:181:25)

I suspect the problem is in the index.js line 40. Maybe you should replace the line with this one: id: ctx => ctx.request.ip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.