⚠️ Jebakan Terbesar: policy local
plugins:
- name: rate-limiting
config:
minute: 100
policy: local # ← bawaan
Dengan policy: local, setiap simpul Kong menyimpan hitungannya sendiri di memori. Load balancer menyebar permintaan ke tiga simpul, masing-masing menghitung sampai 100, sehingga total yang lolos adalah 300. Kuota yang Anda janjikan ke pelanggan menjadi tidak akurat, dan proteksi terhadap penyalahgunaan jauh lebih lemah dari yang dikira.
Ini hanya tidak bermasalah bila Anda benar-benar menjalankan satu simpul, atau bila batasnya memang sekadar pengaman kasar.
plugins:
- name: rate-limiting
config:
minute: 100
hour: 2000
policy: redis
redis:
host: redis
port: 6379
password: "${REDIS_PASSWORD}"
database: 0
timeout: 2000
fault_tolerant: true # bila Redis mati, JANGAN tolak permintaan
hide_client_headers: false
fault_tolerant
Bila bernilai true dan Redis tidak terjangkau, Kong meloloskan permintaan alih-alih menolaknya. Ini menjaga layanan tetap hidup ketika Redis bermasalah, tetapi berarti pembatasan laju hilang sementara. Bila rate limiting Anda merupakan kendali keamanan (bukan sekadar kuota komersial), pertimbangkan false — dan pastikan Redis Anda punya ketersediaan tinggi.
📊 Header yang Dikirim ke Klien
RateLimit-Limit: 100
RateLimit-Remaining: 87
RateLimit-Reset: 34
# Saat kuota habis:
HTTP/1.1 429 Too Many Requests
Retry-After: 34
Klien yang bisa melihat sisa kuotanya dapat mengatur ritme sendiri dan menghormati Retry-After. Menyembunyikannya membuat klien menabrak batas berulang kali tanpa tahu kapan harus berhenti — yang justru menambah beban gateway Anda.
💾 proxy-cache
plugins:
- name: proxy-cache
service: layanan-katalog
config:
response_code: [200, 301]
request_method: ["GET", "HEAD"]
content_type: ["application/json"]
cache_ttl: 300 # detik
strategy: memory
cache_control: false # abaikan header Cache-Control upstream
vary_headers: ["Accept-Language"]
Bila endpoint mengembalikan data berbeda per pengguna berdasarkan token, dan Anda men-cache-nya tanpa memasukkan identitas ke dalam kunci cache, pengguna A akan menerima respons milik pengguna B. Ini bukan kemungkinan teoretis — ini insiden yang berulang kali terjadi.
Aturannya: hanya cache data yang benar-benar identik untuk semua orang. Katalog produk publik, daftar kategori, konfigurasi statis. Jangan pernah cache respons yang bergantung pada identitas kecuali Anda memasukkan pengenal pengguna ke vary_headers secara eksplisit dan memahami konsekuensinya.
Respons dari cache membawa header:
X-Cache-Status: Hit | Miss | Bypass | Refresh
# Membersihkan seluruh cache
curl -X DELETE http://localhost:8001/proxy-cache
🛡️ Perlindungan Lain
# Membatasi ukuran permintaan
plugins:
- name: request-size-limiting
config:
allowed_payload_size: 10 # megabyte
size_unit: megabytes
# Membatasi berdasarkan alamat IP
- name: ip-restriction
route: rute-admin
config:
allow: ["10.0.0.0/8", "192.168.1.0/24"]
# Menolak permintaan tanpa meneruskan ke upstream
- name: request-termination
route: rute-usang
config:
status_code: 410
message: "Endpoint ini sudah dihentikan. Gunakan /v2/pesanan."
Ketika sebuah versi API dihentikan, mematikannya begitu saja membuat klien menerima error jaringan yang membingungkan. Plugin ini membalas kode status yang jelas beserta pesan yang memberi tahu ke mana harus pindah — tanpa perlu menyentuh kode layanan sama sekali. Ia juga berguna sebagai sakelar darurat untuk mematikan endpoint bermasalah dengan cepat.