401, 403 va 500 statuslar
Himoyalangan API’da so‘rov turli sabablarga ko‘ra rad etilishi mumkin: token yo‘q, token eskirgan, ruxsat yetarli emas, resurs boshqa odamniki yoki serverda xato yuz bergan. Har bir holat uchun to‘g‘ri status kod tanlash muhim.
To‘g‘ri status kod klientga keyin nima qilish kerakligini aytadi:
401→ "qayta login qiling yoki tokenni yangilang";403→ "qayta urinishning foydasi yo‘q, sizda ruxsat yo‘q";500→ "sizda xato yo‘q, muammo serverda, keyinroq urinib ko‘ring".
Noto‘g‘ri kod esa klientni adashtiradi. Masalan, ruxsat yo‘qligi uchun 401 qaytarilsa, mobil ilova foydalanuvchini qayta-qayta login sahifasiga yuboradi. Foydalanuvchi to‘g‘ri parol kiritadi, lekin baribir ichkariga kira olmaydi.
401 Unauthorized — "sizni tanimadim"
Nomiga qaramay, 401 avtorizatsiya haqida emas, autentifikatsiya haqida. Server so‘rov yuboruvchini aniqlay olmadi.
Qachon qaytariladi:
Authorizationsarlavhasi yo‘q;- token formati noto‘g‘ri yoki imzosi buzilgan;
- token muddati tugagan;
- login paytida email yoki parol noto‘g‘ri;
- token egasi bazadan o‘chirilgan yoki bloklangan.
HTTP standarti (RFC 9110) bo‘yicha 401 javobida WWW-Authenticate sarlavhasi bo‘lishi shart. U qanday autentifikatsiya kutilayotganini bildiradi:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token", error_description="token muddati tugagan"
Content-Type: application/json
{"error":{"code":"token_expired","message":"token muddati tugagan"}}
Klient uchun muhim jihat: muddati tugagan token qayta tiklanadigan holat. Klient refresh token bilan yangi access token oladi va so‘rovni takrorlaydi. Shu sababli token_expired holatini boshqa 401 sabablaridan alohida kod bilan ajratish foydali.
403 Forbidden — "tanidim, lekin ruxsat yo‘q"
Server foydalanuvchini aniq biladi, lekin unga bu amalni bajarishga ruxsat bermaydi.
Qachon qaytariladi:
- rolida kerakli ruxsat yo‘q:
readerkitob o‘chirmoqchi; - resurs boshqa odamniki, lekin foydalanuvchi uni ko‘ra oladi: nashr qilingan begona kitobni tahrirlash;
- biznes qoidasi taqiqlaydi: nashr qilingan kitobni o‘chirib bo‘lmaydi;
- akkaunt tasdiqlanmagan: email hali tasdiqlanmagan.
403 olgan klient qayta login qilmasligi kerak. Boshqa token bilan ham natija o‘zgarmaydi. Foydalanuvchiga tushunarli xabar ko‘rsatish kifoya: "Bu amal uchun ruxsatingiz yo‘q".
404 Not Found — resursni yashirish
Resource-based permission darsida aytilganidek, ba’zan 403 o‘rniga 404 qaytarish xavfsizroq:
GET /orders/1002 (Boburning buyurtmasi, so‘rovni Aziza yubordi)
403 → "Bu buyurtma bor, lekin sizniki emas" ← mavjudlik oshkor bo‘ldi
404 → "Bunday buyurtma yo‘q" ← hech narsa oshkor bo‘lmadi
403 javobidan hujumchi qaysi ID’lar mavjudligini bilib oladi. Bu ma’lumot keyingi hujumlar uchun foydali bo‘lishi mumkin: buyurtmalar soni, yangi foydalanuvchilar, maxfiy loyihalar nomlari.
Qoida: foydalanuvchi resursni ko‘rish huquqiga ega bo‘lmasa, 404 qaytariladi. Ko‘ra oladigan, lekin o‘zgartira olmaydigan bo‘lsa, 403 qaytariladi.
500 Internal Server Error — "muammo bizda"
500 klient xatosi emas. U server kutilmagan holatga duch kelganini bildiradi: baza ishlamayapti, kodda panic yuz berdi yoki tashqi servis javob bermadi.
Auth kodidagi 500 xavfi
Avtorizatsiya kodidagi xato ikki xil yakun topishi mumkin: ochiq qolish (fail open) yoki yopiq qolish (fail closed).
// ❌ Fail open: baza xatosida ruxsat berib yuboriladi
func canEdit(ctx context.Context, userID, bookID int64) bool {
owner, err := repo.OwnerOf(ctx, bookID)
if err != nil {
log.Println(err)
return true // "baza ishlamayapti, mayli, o‘tkazib yuboramiz"
}
return owner == userID
}
// ✅ Fail closed: xato — ruxsat yo‘q, lekin xato yashirilmaydi
func canEdit(ctx context.Context, userID, bookID int64) (bool, error) {
owner, err := repo.OwnerOf(ctx, bookID)
if err != nil {
return false, fmt.Errorf("kitob egasini aniqlash: %w", err)
}
return owner == userID, nil
}
Birinchi variantda bazadagi vaqtinchalik uzilish hamma uchun eshikni ochib qo‘yadi. Ikkinchisida esa xato yuqoriga qaytariladi, handler 500 beradi va hech kim ruxsatsiz o‘tib ketmaydi.
Xatoni 403 sifatida qaytarish ham noto‘g‘ri. Foydalanuvchida ruxsat bor, lekin server buni tekshira olmadi. 403 uni chalg‘itadi, loglarda esa haqiqiy muammo "ruxsat yo‘q" holatlari orasida yo‘qolib ketadi.
Ichki tafsilotlarni yashirish
500 javobida xato matni klientga yuborilmaydi:
❌ {"error": "pq: relation \"user_permissions\" does not exist"}
✅ {"error": {"code": "internal", "message": "Ichki server xatosi", "request_id": "5c1e0a9b"}}
Birinchi javob jadval nomini va database turini oshkor qiladi. To‘liq xato faqat logga yoziladi. Klient esa loglardan kerakli yozuvni topish uchun request_id oladi. Bu yondashuv Xatoliklarni standart formatda qaytarish darsida amalga oshirilgan.
Boshqa tegishli status kodlar
| Kod | Qachon |
|---|---|
400 Bad Request |
So‘rov formati noto‘g‘ri, masalan JSON buzilgan |
409 Conflict |
Holat ziddiyati, masalan email band |
422 Unprocessable Entity |
Validatsiya xatosi |
429 Too Many Requests |
So‘rovlar chegarasidan oshildi. Login’ga urinishlar ham shunga kiradi |
503 Service Unavailable |
Server vaqtincha ishlamayapti yoki haddan tashqari band |
Qaror daraxti
So‘rov keldi
│
├─ Serverda kutilmagan xato bo‘ldimi? ─────────────────── ha → 500
│
├─ Foydalanuvchi aniqlandimi (token to‘g‘ri)? ─────────── yo‘q → 401
│
├─ Foydalanuvchi bu resursni ko‘ra oladimi? ───────────── yo‘q → 404
│
├─ Foydalanuvchi bu amalni bajara oladimi? ────────────── yo‘q → 403
│
└─ Hammasi joyida ─────────────────────────────────────────────→ 2xx
Go’da: xatolarni status kodga moslash
Service qatlami HTTP’ni bilmaydi. U faqat domen xatolarini qaytaradi. Ularni status kodga aylantirish HTTP qatlamida, bitta joyda bajariladi:
"unauthenticated" → 401 {"error":{"code":"unauthorized","message":"tizimga kiring"}}
"token tekshiruvi: token expired" → 401 {"error":{"code":"token_expired","message":"token muddati tugagan"}}
level=WARN msg="ruxsat rad etildi" path=/books/42 method=DELETE
"forbidden" → 403 {"error":{"code":"forbidden","message":"bu amal uchun ruxsat yo‘q"}}
"not found" → 404 {"error":{"code":"not_found","message":"resurs topilmadi"}}
level=ERROR msg="server xatosi" err="pq: connection refused" path=/books/42
"pq: connection refused" → 500 {"error":{"code":"internal","message":"ichki server xatosi"}}
E’tibor bering:
- O‘ralgan xato (
token tekshiruvi: ...) hamerrors.Isorqali to‘g‘ri tanildi. 403holatlariWARNdarajasida logga yozildi. Bitta foydalanuvchidan qisqa vaqt ichida kelgan ko‘plab403javoblari kimdir tizimni "paypaslab" ko‘rayotganidan dalolat berishi mumkin.- Noma’lum xato klientga faqat umumiy xabar bilan qaytdi. To‘liq matn esa logda qoldi.
499rasmiy HTTP status kodi emas. Uni nginx klient ulanishni uzgan holatlar uchun ishlatadi. Bu holatda javob yozilmaydi, chunki uni o‘qiydigan hech kim yo‘q.
Xulosa
| Status | Ma’nosi | Klient nima qiladi |
|---|---|---|
401 |
Sizni tanimadim | Login qiladi yoki tokenni yangilaydi |
403 |
Tanidim, ruxsat yo‘q | Xabar ko‘rsatadi, qayta urinmaydi |
404 |
Topilmadi yoki ko‘rishga ruxsat yo‘q | Xabar ko‘rsatadi |
500 |
Server xatosi | Keyinroq urinib ko‘radi |
401javobidaWWW-Authenticatesarlavhasi bo‘ladi.- Resurs mavjudligini yashirish kerak bo‘lsa,
403o‘rniga404qaytariladi. - Auth kodidagi xato ruxsat berib yubormasligi kerak. Xato —
500, ruxsat esa rad etiladi. - Ichki xato tafsilotlari faqat logga yoziladi.
Shu bilan avtorizatsiya bo‘limi tugadi. Keyingi bo‘limda standart router o‘rniga gorilla/mux kutubxonasi bilan ishlashni ko‘ramiz.