Rate Limit
Phạm vi hệ thống
rate limitinglà yêu cầu hệ thống, không phải feature.- Áp dụng cho toàn bộ backend HTTP API.
- Cơ chế chuẩn:
bucket4j + Redis.
Quy tắc runtime
- Key theo caller:
- Đã đăng nhập:
userId - Ẩn danh:
IP
- Đã đăng nhập:
- Client IP ưu tiên header
CF-Connecting-IP, fallbackremoteAddr. - Khi Redis/layer limit lỗi:
fail-open(cho request đi tiếp). - Trả lỗi quá hạn: HTTP
429+ headerRetry-After.
Môi trường
| Môi trường | Trạng thái |
|---|---|
prod | bật theo cấu hình bucket |
dev | bật, ngưỡng cao hơn |
test | tắt (app.ratelimit.enabled=false) |
Cấu hình bucket theo phút
| Bucket | Key theo | prod /phút | dev /phút | test | Nhóm endpoint |
|---|---|---|---|---|---|
auth-otp | IP | 5 | 30 | off | OTP request/resend |
auth-login | IP | 15 | 60 | off | Login/verify/reset/refresh/logout |
payment | userId | 30 | 120 | off | /wallet/**, /payments/**, purchase/renewal, unlock-credits |
ai | userId | 15 | 100 | off | /ai/** |
upload | userId | 20 | 100 | off | POST /uploads/presigned-url |
admin | userId | 60 | 300 | off | /admin/** |
authenticated | userId | 120 | 600 | off | Mặc định cho request đã đăng nhập còn lại |
address | IP hoặc userId | 300 | 600 | off | GET /provinces/**, GET /wards/** (master data địa chỉ) |
public-read | IP | 100 | 600 | off | GET public listing/property/user/subscription plans |
Endpoint bỏ qua rate limit
OPTIONS /**GET /health/actuator/**/v3/api-docs/**/swagger-ui/**,/swagger-ui.htmlPOST /payments/sepay/ipnPOST /v1/payments/sepay/ipn
Mapping rule (ưu tiên từ trên xuống)
| Thứ tự | Match | Bucket |
|---|---|---|
| 1 | Skip list | skip |
| 2 | OTP routes | auth-otp |
| 3 | Auth login/reset/refresh/logout routes | auth-login |
| 4 | /ai/** | ai |
| 5 | POST /uploads/presigned-url | upload |
| 6 | POST /listings/*/unlock-credits | payment |
| 7 | /wallet/**, /payments/**, purchase/renewal | payment |
| 8 | /admin/** | admin |
| 9 | GET /provinces/**, GET /wards/** | address |
| 10 | GET public routes khi anonymous | public-read |
| 11 | Còn lại | authenticated |
Quy tắc public route khi có đăng nhập
- Nếu request có
UserPrincipal: dùng bucketauthenticated+ keyuserId. - Nếu anonymous: dùng bucket
public-read+ keyIP.