Skip to content
Kembali ke Blog
Tutorial

Kode Status HTTP: Panduan Lengkap 1xx-5xx untuk Developer

Referensi lengkap kode status HTTP 1xx hingga 5xx dengan contoh nyata, kesalahan umum (401 vs 403, 301 vs 302), dan dampak SEO. Lihat panduan sekarang.

14 menit membaca

Kode status HTTP: panduan lengkap 1xx-5xx untuk developer

Anda membuka DevTools dan tab Network setengahnya merah. Endpoint Anda menghasilkan 502 di production, 200 di lokal, dan rekan kerja di Slack baru saja bertanya, “Ini seharusnya 401 atau 403?”. Kode status HTTP terlihat sederhana, tiga digit dalam lima kelompok, tapi pilihan yang salah membocorkan informasi, merusak SEO, dan membuat giliran on-call jadi mimpi buruk.

Panduan ini adalah lembar contekan (cheat sheet) lengkap kode status HTTP untuk developer yang bekerja sehari-hari. Anda mendapatkan tiga hal: (1) tabel referensi cepat untuk setiap kode yang benar-benar Anda temui di lapangan, (2) matriks keputusan untuk pasangan yang sering tertukar (301 vs 302, 401 vs 403, 404 vs 410, 502 vs 504), dan (3) bagian tooling yang menunjukkan cara memeriksa kode status dari curl, fetch, dan Python requests. Setiap kode di bawah berlandaskan pada RFC 9110, standar semantik HTTP saat ini, serta Registri Kode Status HTTP IANA.

Referensi cepat: semua kode status HTTP sekilas

Berikut kode-kode yang akan Anda temui di production, dikelompokkan per kelas. Bookmark tabel ini, sisa artikel akan menjelaskan kode-kode yang lebih rumit.

KodeNamaKapan Anda akan melihatnya
100ContinueMengirim body POST besar dengan Expect: 100-continue
101Switching ProtocolsHandshake WebSocket, upgrade HTTP/2
103Early HintsServer mendorong header Link sebelum respons utama
200OKSukses default untuk GET, PUT, PATCH
201CreatedPOST yang membuat resource (mengembalikan Location)
202AcceptedJob asinkron diantrekan, pekerjaan belum selesai
204No ContentDELETE sukses, PUT tanpa body untuk dikembalikan
206Partial ContentRange request, video seek, download yang bisa di-resume
301Moved PermanentlyURL lama dipensiunkan, mesin pencari mentransfer link equity
302FoundRedirect sementara, URL asli tetap kanonikal
303See OtherPola Post/Redirect/Get setelah POST formulir
304Not ModifiedGET kondisional dengan ETag atau If-Modified-Since cocok
307Temporary RedirectSeperti 302, tapi method dan body dipertahankan
308Permanent RedirectSeperti 301, tapi method dan body dipertahankan
400Bad RequestJSON rusak, field wajib hilang, schema gagal
401UnauthorizedTanpa kredensial atau token kedaluwarsa
403ForbiddenSudah terautentikasi tapi tidak diizinkan
404Not FoundResource tidak ada (atau Anda menyembunyikannya)
405Method Not AllowedPOST ke endpoint yang hanya menerima GET (wajib menyertakan Allow)
408Request TimeoutKlien terlalu lama mengirim permintaan
409ConflictOptimistic-lock gagal, kunci ganda
410GoneResource dihapus permanen, tidak akan kembali
415Unsupported Media TypeContent-Type salah, mis. XML ke API JSON
422Unprocessable ContentSintaks valid, semantik invalid (validation error)
425Too EarlyRisiko replay early-data TLS 1.3
428Precondition RequiredServer mewajibkan If-Match untuk mencegah lost update
429Too Many RequestsTerkena rate limit (wajib menyertakan Retry-After)
451Unavailable for Legal ReasonsDMCA, takedown GDPR, geo-block
500Internal Server ErrorEksepsi tak tertangani di kode Anda
501Not ImplementedMethod atau fitur tidak didukung (jarang di REST)
502Bad GatewayUpstream mengembalikan respons tidak valid
503Service UnavailableMode maintenance atau kelebihan beban
504Gateway TimeoutUpstream tidak merespons tepat waktu
507Insufficient StorageWebDAV kehabisan disk
508Loop DetectedRedirect tak terbatas atau rekursi di WebDAV
511Network Authentication RequiredCaptive portal di WiFi hotel/bandara

Sisa artikel ini menjabarkan setiap kelas dengan matriks keputusan, anti-pattern, dan konsekuensi SEO ketika Anda salah memilih.

Cara kerja kode status HTTP (anatomi 3 digit)

Mengapa tiga digit?

Kode status HTTP terdiri dari tiga digit desimal karena HTTP/0.9 membutuhkan sinyal berukuran tetap yang cukup kecil agar parser dapat bercabang dengan cepat dan cukup besar untuk menyisakan ruang bagi kode baru. Tiga digit memberi Anda 900 kemungkinan nilai (100–999), lebih dari cukup. Registri IANA hari ini hanya memakai sekitar 60 di antaranya.

Digit pertama menunjukkan kelas. Digit kedua dan ketiga adalah kode spesifik di dalam kelas tersebut. Klien yang tidak mengenali 418 harus jatuh kembali (fallback) ke penanganan generik 4xx. RFC 9110 §15 menyatakan ini secara eksplisit: klien harus memperlakukan kode yang tidak dikenal sebagai x00 dari kelasnya.

Lima kategori sekilas

KelasArtiBody wajib?Cacheable secara default?
1xxInformational, sementara, masih ada lanjutanTidakTidak
2xxSuccess, permintaan dipahami dan diterimaSeringTergantung method
3xxRedirection, perlu tindakan lanjutanOpsional301, 308 ya; 302, 307 tidak
4xxClient error, kesalahan Anda, perbaiki permintaanYa (jelaskan)Umumnya tidak
5xxServer error, kesalahan kami, retry mungkin membantuYa (jelaskan)Tidak

Kolom “cacheable secara default” itu penting. CDN dan browser meng-cache 301 dan 308 dengan agresif dan selamanya. Memilih kode redirect yang salah di production sulit dibatalkan karena pengguna sudah memiliki redirect tersimpan secara lokal. Kita akan kembali ke poin ini di bagian SEO.

Jika Anda ingin menggali lebih dalam tentang struktur URL (yang menjadi objek operasi kode redirect), URL Encoding & Decoding menjelaskan percent-encoding, query string, dan jalur byte-level yang menentukan apa yang membuat sebuah URL valid sejak awal.

1xx — informational (kapan Anda benar-benar akan melihatnya)

Sebagian besar developer bertahun-tahun tidak pernah melihat 1xx secara langsung. Kode-kode ini adalah respons sementara: server memberi tahu klien, “Saya masih di sini, lanjutkan.” Browser DevTools biasanya menyembunyikannya, dan kebanyakan library HTTP menggabungkannya ke respons akhir.

Untuk setiap kode di bawah, referensi status respons HTTP MDN adalah rujukan silang yang paling ramah jika Anda ingin pendapat kedua tentang sebuah definisi.

100 Continue

Klien mengirim Expect: 100-continue di header dan menunggu sebelum mengirim body permintaan yang besar. Server membalas 100 Continue jika bersedia menerima body tersebut, atau 4xx jika permintaan akan ditolak. Cara ini menghemat bandwidth pada upload besar; percuma mengirim 200 MB jika server akan menolaknya karena header yang hilang.

curl -v -H "Expect: 100-continue" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @big-file.bin \
  https://api.example.com/upload

Jika Anda tidak melihat < HTTP/1.1 100 Continue di output verbose, kemungkinan klien Anda menghapus header tersebut atau server tidak mendukungnya.

101 Switching Protocols

Handshake yang mengubah koneksi HTTP menjadi koneksi WebSocket atau HTTP/2. Klien mengirim Upgrade: websocket, server membalas 101 Switching Protocols, dan sejak titik itu koneksi berbicara dalam protokol berbeda. Anda akan melihat ini di tab Network pada aplikasi chat, dashboard live, atau alat kolaborasi mana pun.

103 Early Hints

Kode yang relatif baru (RFC 8297, 2017) yang memungkinkan server mengirim header Link untuk hint preload sebelum respons utama siap. Browser mulai mengambil CSS dan JS sementara server masih merender. Per 2026, Cloudflare, Fastly, dan Vercel semuanya mendukung 103 di production, dan ini adalah alternatif modern untuk HTTP/2 server push (yang sudah deprecated di Chrome).

HTTP/1.1 103 Early Hints
Link: </styles.css>; rel=preload; as=style
Link: </app.js>; rel=preload; as=script

HTTP/1.1 200 OK
Content-Type: text/html
...

Cek anti-pattern. Jika klien Anda tidak pernah menerima kode 1xx saat Anda mengharapkannya, pelakunya biasanya adalah reverse proxy. Versi nginx yang lebih lama menghapus Expect: 100-continue dan 103 Early Hints. Periksa konfigurasi proxy sebelum berasumsi server bermasalah.

2xx — success (lebih dari sekadar 200)

Mengembalikan 200 OK untuk semua hal adalah code-smell paling umum di REST API. Keluarga 2xx membawa informasi semantik yang membuat klien lebih cerdas dan cache lebih efisien.

200 OK

Pilihan default. GET mengembalikan resource, PUT mengembalikan resource yang sudah diperbarui (atau 204), PATCH mengembalikan resource yang sudah dipatch. Jika tidak ada alasan untuk memakai kode yang lebih spesifik, gunakan 200.

201 Created

POST yang membuat resource baru harus mengembalikan 201 plus header Location yang menunjuk ke resource baru tersebut. Begitulah cara klien RESTful menemukan URL kanonikal dari benda yang baru saja mereka buat.

HTTP/1.1 201 Created
Location: /api/users/42
Content-Type: application/json

{"id": 42, "name": "Ada Lovelace"}

202 Accepted

Server menerima permintaan tapi belum selesai memprosesnya. Gunakan ini untuk pekerjaan asinkron, dan klien sebaiknya melakukan polling, berlangganan webhook, atau memeriksa endpoint status. Sertakan ID job di body.

204 No Content

Sukses, tanpa body. Umum untuk DELETE (resource sudah hilang, apa lagi yang mau dikembalikan?) dan untuk operasi PUT di mana klien sudah tahu state baru. Browser tidak akan mengubah halaman saat ini jika submit formulir mengembalikan 204, dan ini berguna untuk aksi fire-and-forget di single-page app.

206 Partial Content

Dikembalikan untuk range request: klien meminta byte 1000-2000 dengan header Range: bytes=1000-2000, dan server merespons hanya dengan potongan tersebut. Streaming video, download yang dapat di-resume, dan sinkronisasi file berbasis HTTP semuanya bergantung pada 206.

Keputusan: 200 vs 201 vs 204 untuk POST

SkenarioKodeBody
POST membuat resource baru201 CreatedResource baru (atau hanya ID) + Location
POST memicu pekerjaan asinkron, hasil belum siap202 AcceptedID job, URL polling
POST adalah aksi tanpa resource (mis. /login)200 OKHasil aksi (token, status)
POST sukses tapi respons kosong204 No Content(tidak ada)

Jika Anda tidak bisa memutuskan antara 200 dan 201, tanyakan: “apakah server membuat sebuah resource yang sekarang punya URL sendiri?” Jika ya, 201. Jika tidak, 200.

3xx — redirection (301 vs 302 vs 307 vs 308)

Redirect adalah kelas yang paling sering disalahgunakan. Perbedaan antara 301, 302, 307, dan 308 bermuara pada tiga pertanyaan ortogonal: apakah perpindahan permanen, apakah method dipertahankan, dan apakah respons cacheable.

301 Moved Permanently

Resource sudah pindah dan tidak akan kembali. Mesin pencari mentransfer link equity ke URL baru. Browser dan CDN meng-cache 301 tanpa batas waktu. Jika Anda mengarahkan ulang /old ke /new dengan 301 lalu berubah pikiran, pengguna dengan redirect yang ter-cache akan terus pergi ke /new selamanya (atau sampai mereka menghapus cache).

Secara historis, browser bisa menulis ulang method permintaan pada 301 (POST → GET), itulah sebabnya HTTP/1.1 memperkenalkan 308 untuk memperbaiki hal tersebut.

302 Found

Redirect sementara. URL asli tetap kanonikal, dan mesin pencari sebaiknya terus mengindeks URL asli. Gunakan ini untuk routing A/B testing, halaman maintenance, atau alur “login untuk melanjutkan”.

Seperti 301, browser secara historis menulis ulang POST menjadi GET pada 302. Jika Anda perlu mengarahkan ulang POST dan mempertahankannya sebagai POST, gunakan 307 saja.

303 See Other

Selalu menulis ulang method menjadi GET. Pola Post/Redirect/Get: formulir dikirim ke /submit, server mengembalikan 303 dengan Location: /thank-you, browser melakukan GET /thank-you. Refresh halaman thank-you tidak mengirim ulang formulir. Untuk inilah 303 dirancang.

304 Not Modified

Respons kondisional. Klien mengirim If-None-Match: "abc123" (atau If-Modified-Since), server memeriksa apakah resource berubah, dan jika tidak, mengembalikan 304 tanpa body. Browser memakai salinan cache-nya. Begitulah setiap CDN dan lapisan caching menjaga situs Anda tetap cepat.

307 Temporary Redirect

Seperti 302, tapi method tidak boleh berubah. POST tetap POST, body dipertahankan. Gunakan ini ketika Anda ingin redirect sementara pada permintaan non-GET.

308 Permanent Redirect

Seperti 301, tapi method tidak boleh berubah. Pilihan modern dan lebih aman untuk redirect permanen pada API yang menerima POST/PUT.

Matriks keputusan: kode redirect mana?

Permanen (cache selamanya)Sementara (jangan di-cache)
Method boleh berubah jadi GET301 Moved Permanently302 Found
Method harus tetap sama308 Permanent Redirect307 Temporary Redirect

Kasus khusus: jika Anda secara spesifik menginginkan POST → GET (pola Post/Redirect/Get), gunakan 303 See Other.

Untuk halaman HTML dengan navigasi browser, 301 dan 302 biasanya cukup karena GET tetap GET. Untuk API dan formulir, prioritaskan 308 dan 307 agar terhindar dari penulisan ulang method yang mengejutkan.

4xx — client errors (memilih yang tepat)

4xx berarti klien melakukan sesuatu yang salah. Semakin kaya kosakata 4xx Anda, semakin mudah API Anda dipakai, karena klien dapat bercabang berdasarkan kode alih-alih mem-parse string error.

400 Bad Request

Error sintaks generik. JSON yang rusak, field wajib yang hilang di tingkat struktural, permintaan yang bahkan tidak bisa di-parse server. Jika permintaan ter-parse tapi gagal validasi bisnis, lebih baik 422.

401 Unauthorized vs 403 Forbidden

Pasangan paling membingungkan di HTTP. Pembedanya sederhana begitu Anda melihatnya:

  • 401 Unauthorized berarti permintaan kekurangan autentikasi yang valid. Server tidak tahu siapa Anda. Mengirim ulang kredensial (atau menyegarkan token) mungkin memperbaikinya. Respons harus menyertakan header WWW-Authenticate per RFC 9110 §15.5.2.
  • 403 Forbidden berarti server tahu siapa Anda dan tetap menolak. Mengirim ulang permintaan tidak akan membantu. Anda butuh kredensial berbeda atau izin berbeda.
Anda melihatYang sebenarnya terjadi
401 dengan WWW-Authenticate: BearerTidak ada token, token kedaluwarsa, atau token invalid
403 setelah login berhasilSudah login, tapi user ini tidak boleh mengakses resource ini
401 setelah login berhasilBug, kemungkinan besar Anda butuh 403

Anti-pattern: 403-as-404. Beberapa situs mengembalikan 403 ketika user tanpa autentikasi meminta /admin/dashboard. Cara ini membocorkan keberadaan /admin/dashboard. GitHub menyelesaikannya dengan mengembalikan 404 untuk repository privat yang Anda bukan anggotanya, sehingga resource “tidak ada” dari sudut pandang Anda. Itu pilihan penyembunyian informasi yang disengaja, bukan bug.

404 Not Found vs 410 Gone

Keduanya berkata “resource ini tidak ada di sini.” Bedanya pada permanensi dan SEO.

  • 404 Not Found berarti mungkin ada, mungkin tidak, mungkin akan kembali. Mesin pencari akan terus memeriksanya.
  • 410 Gone berarti pernah ada, dihapus dengan sengaja, tidak akan kembali. Mesin pencari mengeluarkannya dari indeks jauh lebih cepat.

Jika Anda menghapus halaman produk dan ingin keluar dari indeks Google sekarang, 410 adalah pilihan tepat. Jika sebuah URL hanya rusak sementara, 404 sudah cukup.

405 Method Not Allowed

URL ada tapi tidak menerima method ini. Respons harus menyertakan header Allow yang mendaftarkan method yang didukung.

HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, OPTIONS
Content-Type: application/json

{"error": "POST is not allowed on this endpoint"}

Lupa header Allow adalah pelanggaran kontrak nomor 1 di REST API yang dibangun manual.

408 Request Timeout

Klien mulai mengirim permintaan lalu diam. Server menyerah. Berbeda dari 504 Gateway Timeout, yang berkaitan dengan upstream; 408 adalah “Anda, klien, terlalu lama.”

409 Conflict

Permintaan bertentangan dengan state saat ini. Penggunaan paling umum: optimistic locking. Klien mengirim If-Match: "etag-v3" dan ETag server saat ini adalah "etag-v4", jadi pembaruan ditolak dengan 409.

410 Gone

Lihat di atas: penghapusan permanen. Berguna untuk mengeluarkan record yang dihapus secara soft dari indeks pencarian.

415 Unsupported Media Type

Klien mengirim body yang tidak dipahami server. POST XML ke API yang hanya menerima JSON akan menghasilkan 415. Respons sebaiknya memberi petunjuk tipe yang dapat diterima.

422 Unprocessable Content

Permintaan ter-parse dengan baik, tapi gagal validasi semantik. RFC 9110 akhirnya mempromosikan kode ini dari WebDAV ke spesifikasi inti pada 2022. Gunakan 422 untuk error validasi:

{
  "error": "validation_failed",
  "details": [
    {"field": "email", "message": "must be a valid email"},
    {"field": "age", "message": "must be at least 13"}
  ]
}

Jika API Anda tidak bisa memutuskan antara 400 dan 422, aturan praktisnya: 400 untuk “saya bahkan tidak bisa mem-parse ini,” 422 untuk “saya sudah parse dan isinya tidak masuk akal.”

425 Too Early

Dikirim saat server tidak ingin mengambil risiko memproses permintaan yang mungkin merupakan replay early-data TLS 1.3. Sebagian besar relevan untuk CDN dan reverse proxy.

428 Precondition Required

Server bersikeras Anda mengirim If-Match atau If-Unmodified-Since untuk menghindari masalah lost-update. Dipakai pada API editing kolaboratif.

429 Too Many Requests

Terkena rate limit. Respons harus menyertakan Retry-After (dalam detik, atau sebagai HTTP date) agar klien yang sopan dapat mundur sejenak.

HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json

{"error": "rate_limited", "limit": 100, "window": "1m"}

Angkanya adalah referensi ke karya Bradbury (Fahrenheit 451). Kasus penggunaannya bukan fiksi: takedown DMCA, penghapusan right-to-be-forgotten GDPR, dan geo-block tingkat negara semuanya membenarkan 451. Respons sebaiknya menyertakan header Link yang menunjuk ke otoritas hukum yang mewajibkan blokir, sesuai RFC 7725.

418 I’m a Teapot (easter egg)

Ya, ini nyata. RFC 2324 (April Mop 1998) dan IETF mempertahankannya karena terlalu banyak produk yang ikut-ikutan mengimplementasikannya sebagai lelucon. Jangan rilis 418 di API sungguhan, karena kebanyakan reverse proxy dan load balancer akan salah menanganinya.

Matriks keputusan: 4xx mana?

SituasiKode
Body rusak atau tidak bisa di-parse400
Tanpa autentikasi / token kedaluwarsa401
Sudah terautentikasi tapi tidak diizinkan403
URL tidak ada (atau Anda menyembunyikannya)404
URL pernah ada, dihapus dengan sengaja410
Method HTTP salah405 (dengan Allow)
Content-Type salah415
Konflik optimistic-lock409
Error validasi (parse oke, validasi gagal)422
Terkena rate limit429 (dengan Retry-After)
Diblokir karena alasan hukum451

5xx — server errors (apa yang sebenarnya rusak)

5xx adalah “kesalahan kami.” Engineer yang on-call paling peduli pada 5xx mana yang membangunkan mereka pukul 3 pagi, karena kodenya memberi tahu lapisan mana yang harus diselidiki lebih dulu.

500 Internal Server Error

Penampung serbaguna. Hampir selalu berarti eksepsi tak tertangani naik ke handler default framework. Kode ini tidak memberi tahu apa-apa tentang penyebabnya, dan itulah sebabnya structured logging lebih penting daripada kode statusnya di sini.

501 Not Implemented

Server sama sekali tidak mendukung method tersebut. Berbeda dari 405 (method ini tidak diizinkan untuk URL ini); 501 berkata “server ini tidak tahu apa itu PROPFIND.” Jarang di REST API.

502 Bad Gateway

Sebuah reverse proxy atau load balancer menerima respons tidak valid dari upstream. Upstream membalas, tapi dengan sampah: protokol salah, header rusak, koneksi terputus di tengah respons. Jika Anda melihat 502 dari CDN, kemungkinan origin sedang crash atau mengembalikan body yang terpotong.

503 Service Unavailable

Server sengaja tidak melayani permintaan saat ini. Gunakan ini untuk jendela maintenance atau respons graceful overload. Sebaiknya menyertakan Retry-After.

504 Gateway Timeout

Reverse proxy menunggu upstream dan upstream tidak pernah membalas tepat waktu. Upstream lambat atau macet, berbeda dari 502, di mana upstream membalas dengan sampah.

502 vs 504: diagnosis on-call

Anda melihatHal pertama yang perlu diperiksa
502 Bad GatewayUpstream membalas dengan data tidak valid; periksa log origin untuk crash, respons rusak, ketidakcocokan protokol
504 Gateway TimeoutUpstream menggantung; periksa CPU origin, query DB, panggilan API downstream, dan proxy_read_timeout proxy

Kebingungan umum: query database yang memakan waktu 60 detik akan muncul sebagai 504 jika proxy Anda time out di 30 detik, tapi sebagai 500 jika app server time out di 90 detik dan melempar eksepsi. Akar masalah sama, kode beda, baris log beda; latih dashboard Anda untuk menampilkan keduanya.

507 Insufficient Storage

Spesifik WebDAV. Disk di server penuh. Jika Anda melihat ini dari API non-WebDAV, ada yang memaksakan makna kode tersebut.

508 Loop Detected

Rekursi tak terbatas pada operasi PROPFIND WebDAV. Sangat jarang.

511 Network Authentication Required

Kode captive portal: WiFi di hotel atau bandara mengirim 511 untuk memberi tahu browser Anda “Anda perlu login ke portal dulu.” Respons mencakup Location ke halaman portal.

Matriks troubleshooting: lapisan mana yang diperiksa lebih dulu

KodeAppProxyDBNetwork
500YaMungkin (error DB tak tertangani)
502Ya (upstream rusak)Mungkin (TCP reset)
503Ya (flag maintenance)Ya (rate-limit reject)
504Ya (handler lambat)Ya (konfig timeout)Ya (query lambat)Ya (DNS, packet loss)

Anti-pattern kode status HTTP yang umum

Lima kesalahan ini menyumbang sebagian besar kode buruk yang saya tinjau.

1. Membungkus error di dalam 200 OK

HTTP/1.1 200 OK
{"success": false, "error": "user_not_found"}

Setiap alat monitoring, CDN, dan cache sekarang mengira permintaan sukses. Logika retry gagal. Load balancer yang status-code-aware merutekan trafik buruk ke backend “sehat”. Pola ini berasal dari JSON-RPC dan diwarisi GraphQL. GraphQL melakukannya karena partial success butuh pelaporan error per field, dan itu wajar. REST tidak punya alasan: pakai 4xx untuk client error, 5xx untuk server error, dan letakkan detail terstruktur di body.

2. Mencampur 401 dan 403

Jika 401 dan 403 Anda tidak konsisten, penyerang dapat menyelidiki API Anda untuk menemukan resource mana yang ada. Pilih satu kebijakan: kembalikan 404 untuk “Anda tidak boleh melihat ini” (pendekatan GitHub untuk repo privat), atau kembalikan 403 secara konsisten. Inkonsistensi membocorkan informasi.

3. Menyembunyikan 403 di balik 404

Kadang benar, sering jadi bug. GitHub mengembalikan 404 untuk repo privat itu disengaja, karena keberadaan repo itu sendiri sensitif. Tapi jika API Anda mengembalikan 404 untuk “akun user ini ditangguhkan,” sekarang user yang sah tidak bisa membedakan apakah mereka salah ketik username atau ditangguhkan. Dokumentasikan kebijakan Anda secara eksplisit dan terapkan secara konsisten.

4. Memakai 500 sebagai catch default

Framework membuat ini mudah, dan itulah masalahnya. Setiap eksepsi tak tertangani jadi 500 dan alerting Anda tidak bisa membedakan “database mati” dari “user mengirim UUID rusak.” Tangkap error validasi dan lemparkan 400 atau 422. Tangkap NotFound dari ORM Anda dan lemparkan 404. Cadangkan 500 untuk kegagalan yang benar-benar tak terduga, dan saat Anda melemparnya, log request ID agar Anda dapat mengkorelasikan.

5. Rantai redirect yang panjang

Setiap hop memakan satu round trip. Jika /old/intermediate/canonical, itu dua DNS lookup tambahan dan dua TCP handshake tambahan (skenario terburuk). Google secara khusus menurunkan prioritas crawl untuk rantai yang lebih panjang dari 3 hop, dan browser membatasi rantai redirect sekitar 20 untuk mencegah loop. Ringkas rantai di sumbernya, baik di konfigurasi CDN maupun di redirect map aplikasi Anda.

Kode status HTTP dan SEO

Mesin pencari memperlakukan kode status sebagai sinyal otoritatif tentang apakah harus mempertahankan, melepas, atau mentransfer URL. Salah memilihnya, peringkat Anda bergeser.

301 Moved Permanently mentransfer PageRank: Google memperlakukan URL baru sebagai tujuan kanonikal dari semua sinyal yang menunjuk ke URL lama. 302 Found tidak mentransfer link equity (atau mentransfernya dengan lambat, tergantung heuristik Google). Jika Anda mengganti nama URL secara permanen, gunakan 301. Jika Anda mengarahkan tamu ke /login, gunakan 302.

404 vs 410 vs Soft 404

Google membedakan tiga state “missing”:

  • 404 Not Found berarti Google memeriksa ulang secara berkala dan tetap menyimpan URL di indeks untuk sementara.
  • 410 Gone berarti Google melepasnya lebih cepat, sering hanya dalam satu siklus crawl.
  • Soft 404 adalah istilah Google untuk halaman yang mengembalikan 200 OK tapi merender pesan “not found”. Google mendeteksi ini dari pola konten dan tetap memperlakukannya sebagai 404, tapi Anda sudah menyia-nyiakan satu permintaan crawl dan mungkin mengencerkan konten asli Anda.

Jika Anda sedang membersihkan indeks usang, kembalikan 410 sungguhan untuk URL yang dihapus permanen.

5xx dan crawl budget

Crawler Google menurunkan rate-nya saat sebuah situs terus-menerus mengembalikan 5xx. Laporan Crawl Stats di Search Console menunjukkan ini, dan lonjakan error 5xx yang berkelanjutan dapat memangkas crawl budget Anda berhari-hari, yang berarti halaman baru lebih lama untuk diindeks. Perlakukan rasio 5xx sebagai metrik SEO, bukan hanya metrik reliabilitas.

200 OK yang sebenarnya rusak

Mengembalikan 200 OK dengan halaman error (anti-pattern soft-404) adalah skenario terburuk untuk SEO. Google mengindeks pesan errornya, memberikan peringkat untuk hal yang tidak berarti, dan perlahan mencari tahu bahwa halamannya rusak. Selalu kembalikan kode status yang tepat dari server, bahkan saat single-page app Anda merender UI error yang ramah.

Cara memeriksa kode status HTTP (tooling)

Anda tidak bisa memperbaiki yang tidak bisa Anda lihat. Setiap developer yang aktif sebaiknya fasih setidaknya pada tiga di antara berikut.

Panel Network browser DevTools

Chrome, Firefox, dan Safari semuanya menampilkan kolom Status di tab Network. Klik kanan header kolom untuk menambahkan Status Text jika belum tampak. Trik berguna:

  • Preserve log menjaga entri lintas navigasi agar Anda dapat melihat seluruh rantai redirect.
  • Filter berdasarkan status, ketik status-code:5xx (Chrome) untuk melihat hanya server error.
  • Replay XHR, klik kanan permintaan apa pun lalu pilih Replay XHR untuk menjalankannya ulang tanpa me-reload halaman.

Untuk redirect, perluas permintaan untuk melihat setiap hop dan kode status di tiap langkah.

curl (jawaban universal)

curl menampilkan segalanya. Tiga pola yang menyelesaikan 90% kebutuhan debugging:

# Hanya kode status
curl -o /dev/null -s -w "%{http_code}\n" https://api.example.com/users/1

# Hanya header (HEAD request, ikuti redirect)
curl -I -L https://example.com

# Verbose lengkap dengan header request dan response
curl -v https://api.example.com/users/1

Saat Anda menyusun URL uji dengan karakter spesial di query string, gunakan --data-urlencode agar curl yang menangani encoding-nya, atau tempelkan URL ke URL Decoder & Encoder milik kami untuk memverifikasi byte mana yang sebenarnya akan dikirim.

# curl meng-encode nilai query untuk Anda
curl -G "https://api.example.com/search" \
  --data-urlencode "q=hello world & friends"

# Sends: GET /search?q=hello%20world%20%26%20friends

JavaScript fetch

Properti Response.status berisi kode integer-nya. Response.ok bernilai true untuk 2xx apa pun.

const res = await fetch('https://api.example.com/users/1');

console.log(res.status);      // 200
console.log(res.statusText);  // "OK"
console.log(res.ok);          // true

if (!res.ok) {
  if (res.status === 401) {
    // refresh token and retry
  } else if (res.status === 429) {
    const retryAfter = Number(res.headers.get('Retry-After')) || 1;
    await new Promise(r => setTimeout(r, retryAfter * 1000));
  } else if (res.status >= 500) {
    throw new Error(`Server error: ${res.status}`);
  }
}

Di axios, logika yang sama berada di interceptor:

import axios from 'axios';

axios.interceptors.response.use(
  response => response,
  error => {
    const status = error.response?.status;
    if (status === 401) {
      // redirect to login
    }
    return Promise.reject(error);
  }
);

Python requests

import requests

r = requests.get('https://api.example.com/users/1')

print(r.status_code)  # 200
print(r.reason)       # 'OK'

# Raises requests.exceptions.HTTPError for 4xx/5xx
r.raise_for_status()

# Manual handling
if r.status_code == 429:
    retry_after = int(r.headers.get('Retry-After', '1'))
    time.sleep(retry_after)
elif 500 <= r.status_code < 600:
    raise RuntimeError(f'Server error: {r.status_code}')

raise_for_status() adalah idiom Python untuk “gagal dengan keras pada 4xx/5xx.” Pakai di skrip yang ingin eksepsi pada error alih-alih bercabang berdasarkan status_code.

Postman dan Bruno

Keduanya memungkinkan Anda mengasersi kode status di dalam test script:

// Postman/Bruno test script
pm.test("Status is 201", () => {
  pm.response.to.have.status(201);
});

pm.test("Has Location header", () => {
  pm.expect(pm.response.headers.get('Location')).to.match(/^\/users\/\d+$/);
});

Jalankan ini terhadap staging di CI untuk menangkap pelanggaran kontrak sebelum production.

FAQ

Apa perbedaan antara 401 dan 403?

401 Unauthorized berarti server tidak tahu siapa Anda, sehingga kredensial Anda hilang, kedaluwarsa, atau invalid. 403 Forbidden berarti server tahu siapa Anda dan tetap menolak. Jika mengirim kredensial berbeda mungkin memperbaikinya, gunakan 401. Jika tidak, gunakan 403.

Kapan saya sebaiknya pakai 301 vs 302?

Gunakan 301 saat perpindahan permanen, ketika URL lama tidak akan kembali, dan Anda ingin mesin pencari mentransfer link equity ke URL baru. Gunakan 302 untuk redirect sementara di mana URL asli tetap kanonikal (alur login, A/B testing, halaman maintenance). Untuk API, prioritaskan 308 dan 307 karena keduanya mempertahankan method permintaan.

Apa arti error 502 Bad Gateway?

502 berarti reverse proxy atau load balancer menerima respons tidak valid dari server upstream. Upstream membalas, tapi dengan sampah: protokol salah, header rusak, atau koneksi terputus. Berbeda dari 504 Gateway Timeout, di mana upstream sama sekali tidak membalas. Tempat pertama untuk diperiksa: log origin server untuk crash atau respons yang terpotong.

Apa itu “soft 404”?

“Soft 404” adalah halaman yang mengembalikan 200 OK tapi sebenarnya menampilkan pesan “not found”. Google mendeteksinya secara heuristik dan tetap memperlakukannya sebagai 404. Halaman seperti ini memboroskan crawl budget dan dapat mengencerkan konten asli Anda. Selalu kembalikan kode status 404 atau 410 sungguhan dari server, bahkan jika single-page app Anda merender UI error yang ramah.

Kapan saya sebaiknya pakai 422 alih-alih 400?

Gunakan 400 Bad Request saat server bahkan tidak bisa mem-parse permintaan, mis. JSON rusak, field struktural hilang, error sintaks. Gunakan 422 Unprocessable Content saat permintaan ter-parse dengan baik tapi gagal validasi bisnis, mis. format email invalid, nilai di luar rentang, field yang tidak konsisten secara semantik. Singkatnya: 400 untuk sintaks, 422 untuk semantik.

Bagaimana cara merespons 429 Too Many Requests?

Baca header Retry-After (jumlah detik atau HTTP date) dan mundur setidaknya selama itu sebelum mencoba lagi. Jika Retry-After tidak ada, gunakan exponential backoff dengan jitter mulai sekitar 1 detik. Jangan pernah retry segera, karena itu cara cepat untuk diblokir.

Apakah kode informational 1xx masih dipakai di 2026?

Ya, tapi sebagian besar tidak terlihat oleh kode aplikasi. 100 Continue dan 101 Switching Protocols adalah fitur dasar HTTP/1.1. 103 Early Hints semakin sering dipakai oleh Cloudflare, Fastly, dan Vercel untuk mendorong hint preload sebelum respons utama, dan dampaknya pada Largest Contentful Paint terasa nyata. Kebanyakan library HTTP menggabungkan 1xx ke respons akhir, jadi Anda biasanya hanya melihatnya di DevTools atau curl -v.

Apakah 418 “I’m a teapot” itu kode status sungguhan?

Ya, mengejutkan tapi benar. RFC 2324 adalah lelucon April Mop tahun 1998, tapi cukup banyak produk yang mengimplementasikannya hingga IETF tetap mempertahankannya di RFC 7168. Jangan rilis 418 di production, karena banyak reverse proxy dan load balancer tidak menanganinya dengan benar, dan kode ini tidak punya tujuan nyata di luar lelucon.

Artikel Terkait

Lihat semua artikel