req-guard-lite: Мінімалістычны лімітэр частоты запыткаў для Express, створаны на базе TypeScript
Дазнайце, як працюе лёгкі рэгулярны лімітар Express без жадных залежнасцей, ад стандартных настройкаў у памяці да масштабавання за дапамою Redis і спецыяльных генератораў ключоў.
Кожны аплікэнт Express раней чым пазнае момент, калі яму стае неабходныя правілы лімітавання частоты запытоў.
Незалежна ад таго, чым являецца мета — захаванне маршрутаў для запуску пры входзе, зменшэнне спаму чы проста запобежанне неняхучам перасвайгоўванню, лімітаванне прыходзячага трафіку быстра ператвараецца з прыемнай функцыі на неабходнасць, калі API стае доступным для публічнага вжытку.
Пад час пошуку раўняння для лімітавання частоты, якое падходзіла б для стандартных задач, стало ясна, што хоча і існуе множыцтва супэрнасых бібліятак, багатыя проекты на самай працоўцы жадаюць чагось малог, простаг у розумеенні і лёгкаг у налаштаванні.
Самэй гэтыя прасоцінкі сталі падставай для стварэння req-guard-lite.
Чаму ўсё жа іншы лімітэр частоты?
Большасць API не патрабуе цэлага комплекту адпраўнай безпекі з самага пачатку.
Часта ўсё, чаго хочацца, — гэта можласць напісаць кашто-наступны код:
app.use(rateLimit({
max: 100,
windowMs: 15 * 60 * 1000
}));
...і вярніцеся да продажоўка рэшты прыкладнення.
Цялі дизайна для гэтага пакета былі такімі:
- Залічвацца лёгкім
- Быць простым у налаштаванні
- Быць створаным з урахоўваннем TypeScript з самага пачатку
- Дазволяць простую розшырэннае
- Функціонаваць як для малых проектаў, так і для систем вялікага масштабу
Представляем req-guard-lite
req-guard-lite — это компактны элемент мідлвэра Express, створаны для захавання вашага API ад вялікай колькасці запытанняў.
По значэнню ён працуе выключна ў памяці, але таксама можа масштабавацца да распадзеленых сэтапаў праз ад’ёднанне з Redis.
Його функцыя ўмышлена вузкая — ён добра выканае адна задача:
Фіксуе прыходзячыя запытанні і адхоўляе кліентаў, калі яны перакроюць заданы вам ліміт.
Функцыяў
Легкая рэалізацыя Няма жаданняў да выконвальнага часу ў основным пакете Функцыонавае як мідлвэр Express Падтрымка TypeScript ужо з самага пачатку Можліва інтеграцыя з Redis Падтрымка спецыяльных бэкендоў для зберагчыка Падтрымка спецыяльных генератараў ключоў
Пачатак работы
Установіце яго як дадатковы компаньон для Express.
npm install req-guard-lite express
Далей падключыце яго да вашага прыемніка.
import express from 'express';
import { rateLimit } from 'req-guard-lite';
const app = express();
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: 'Too many requests, please try again later.'
});
app.use(limiter);
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000);
Гэта ўсё, што трэба зробіць для налаштавання.
Ваш API тепер блакуе будь-якому кліенту, який надае больш чым 100 запитоў за період у 15 хвілін.
Стандартны внутрашній зберагчык
З самага пачатку лічыльнікі запитоў знаходзяцца ў памяці.
Практычна гэта значыць:
- Не трэба Redis
- Не трэба базы дадзенаў
- Няма патрэбы ў дадатковай налаштаванні
- Ідеальна для локальнай розробкі
- Хорашы выбар для працы ў прыемніку на аднам сервере
Для большайшай часткі правілаў прыемлівання запитоў, гэтага ўсё, што вам патрэбна.
Масштабаванне з Redis
Калі прыемлівач запитоў пачынае працаваць на калькі сервероў або контейнероў, гэтым экземплярам неабходна спяльная інформацыя пра колькість запитоў.
Самэ гэтаю роллю тут выступае Redis.
import Redis from "ioredis";
import { createRedisStore } from "req-guard-lite/redis";
const redis = new Redis();
const limiter = rateLimit({
max: 100,
windowMs: 15 * 60 * 1000,
store: createRedisStore(redis, {
max: 100,
windowMs: 15 * 60 * 1000
})
});
Калі гэта налажана, кожны экземпляр сервера чытае і запісвае тыя ж самыя лічыльнікі, таму правілы залишаюцца аднаковымі, незалежна ад таго, який вузел обробляе запит.
Спецыяльныя генераторы ключоў
Обмежэнне швайнасці за адрасам IP не завжды є правильным падходам.
У дзеякіх случаях кращэ ставіць правілы на адной з следуючых вясей:
- ID пользователя
- Ключ API
- Ідэнтыфікатор аб’екта
- Арганізацыя
- Змест клэйма JWT
- Або будзь-які іншы ідэнтыфікатор, який падходзіць вашай модэлі
Ёнколі, req-guard-lite дазвае выкарыстоўваць савой функцыю для гэнеравання ключа.
const limiter = rateLimit({
max: 100,
keyGenerator: (req) =>
req.headers["x-api-key"] as string
});
Альбо, замест таго, ключ можа быць прыязначаны запісанаму пользователя:
const limiter = rateLimit({
max: 50,
keyGenerator: (req) =>
(req as any).user.id
});
Сам мідлвэр не залежыць ад таго, што представляе ключ — ён проста ведае колькісць вызывоў на адпаведны ідэнтыфікатор, які вяртае ваша функцыя.
Выкарыстоўваеце савой хранальнік
Можлівасць расшырэння была адной з ключоўых вясковах з самага пачатку.
Уместо таго, каб прыкрепіць вас да Redis, req-guard-lite адкрывае просты інтэфейс RateLimitStore. Якщо ваша інфраструктура вяліка часткаю выкарыстоўвае:
- PostgreSQL
- DynamoDB
- Memcached
- MongoDB
- SQLite
- Іншыя спецыяльныя слоі кэшавання
вы можете яго падключыць, рэалізаваўшы гэты інтэфейс.
class MyStore implements RateLimitStore {
consume(key: string) {
// your implementation
}
}
Такій структуре пакета ўмоžнівае адаптацыю да практычна будзь-яго бэкенду, які вы вже выкарыстоўвайце.
Адны важлівы совет для працы ў продакшэне
Якщо ваша аплікацыя знаходзіцца за:
- Nginx
- AWS Load Balancer
- Heroku
- Cloudflare
- Будзь-якім рыверсным проксі
обавяжыцеся правільна настроіць Express:
app.set("trust proxy", 1);
Якшо праігнораваць гэты крок, Express часта будзе спрыяваць кожнаму запыту, як даходзіць з самага проксі, што значыць, ўсе вашы корыстувальнікі будуць дзеліцца адным лімітом частоты запытоў. Гэта можна выправіць за адну лінію коду, але таким чынам ухільваецца ад проблем у продакшэне, якія часта застаюцца неспадзеванымі для большасці команд.
Як гэта працуе
Внутршній трыкць спецыяльна зроблена мінімальным:
- Прыходзіць запыт.
- Мідлвэр генеруе для яго ключ (за замовчаннем — IP-адрэс кліента).
- Актыўны хранальнік збільшае лічылак, прыязначаны да гэтага ключа.
Пакалькі, што хранэнне ўможліва падключыць, гэты той самы прыем пераводзіцца незалежна ад таго, чы робіцца це за дапамой памяці, Redis чы спецыяльнай рэалізацыі.
Чаму TypeScript?
Усю бібліятэку напісана на TypeScript, што дае:
- Строгую типаванасць у всім
- Больш разнаўажаную автодополненасць у рэдагары
- Прыемнейшую дагляд за часам
- API, якія важкае злослужыць
Пользоватэры TypeScript атрымліваюць полныя апісанні типаў з самага пачатку, без неабходнасці інсталлявання дадатковых пакетаў @types.
План развіцця
Развіцце продовжваецца, і вялікія функцыі вже запланаваны.
v0.4.0
- Падтрымка стандартных заголовакоў адказу пра ліміт частоты
X-RateLimit-Limit
X-RateLimit-Remaining
X-RateLimit-Reset
Этыя заголовкі з’являюцца ў кліентскіх прыладах і паказваюць, сколькі запитоў засталося да выплнення перад досягненням максімальнага ліміту.
v0.5.0
Настроюемыя функціі, якія запускаюцца, калі перакрыты ліміт, і ўжыткаваныя для такіх цэлей, як:
- Логаванне
- Збір метрык
- Спавешчэння
- Аналітыка
- Адправка дадзейнняў у зовнішнія інструменты манітарынгу
Чаму гэты проект ў відкрытай ліцензыі
Гэты проект не ўзнік як рэакцыя на недастаткі існуючых бібліятэкаў — у экосыстэме Node вялікі выбар адлічвальных рашэнняў. req-guard-lite створаны таму, што метай быў пакет, які:
- Дастатнька компактны, ўжо пасля адзінаго прачытання можна яго зрозумець
- Просты ў расшырэнні
- Разрабатаваны з урахоўваннем TypeScript
- Без непатрэбной складнасці
- Дастатнька гнучкі, каб адпавядаў рэальным патрэбам працы
Стварэнне яго таксама стало цінным апрактыкаваннем у публікацыі пакетаў, проектаванні API, напісанні тэстаў, інтеграцыі з Redis і стварэнні абстракцый, якія будуць зручнымі для викорыстання іншымі разработчыкамі.
Заключныя заўважэнні
Размешчэнне проекта у формате адкрытага кода — адна з найэфектывнейшых способаў падтрымкі вашых інжынерных навыкаў. Калі іншы разработчыкі можуць запускаць, викорыстоўваць і дапамагаць у розвіцыі вашага коду, вас прыводзяць да неабходнасці думаць не толькі пра свою безпосереднюя мету — дакументацыя, проектаванне API, тэставанне, версійнаўка і адваротная сумеснае працаванне стаюць рэальнымі обмежэннямі, якія трэба врачыць.
req-guard-lite пачаўся як маленькі мідлвэр, створаны для рашэння персональной проблемы, але спадзяюцца, што ён стане корыстным, лёгкім і расширюемым апаратам для обмежэння частоты запытоў для іншых разработчыкаў Express. Будзем рады будь-якім адгукам, працэсам і дапамозе.
Спадневана літэратура
- Адзін шымат Zod для верыфікацыі форм у React, адказоў API, тэла запытак Express і змянных сяродовішча — Дазвольце дазнацца, як адзін шымат Zod можа верыфікацыяваць формы у React, адказы API, тэла запытак Express і змянныя сяродовішча, адночасна ствараючы адпаведныя типы TypeScript.
- Zod проты express-validator: два падходы да верыфікацыі запытак у Express — Поручае верыфікацыю запытака на адной ступені з викорыстаннем Zod і верыфікацыю на каскадных мідлвэрах express-validator, рассматраючы настройкі, форматаванне адзяўок і распашчытныя проблемы.