← Blog'a Dön

HTTP İsteği Attığında Arkada Ne Olur?

HTTP İsteği Attığında Arkada Ne Olur?
Bir İsteğin Tam Anatomisi
Retrofit ya da Ktor ile birkaç satır kod yazıyorsunuz. Bir fonksiyon çağırıyorsunuz. Veri geliyor. Bu kadar basit görünüyor.
Ama o birkaç satır kodun tetiklediği süreç çok daha uzun ve katmanlı. Bu süreci başından sonuna anlamak hem daha iyi kod yazmanızı hem de sorunları çok daha hızlı teşhis etmenizi sağlar.

HTTP Nedir?
HTTP (Hypertext Transfer Protocol), istemci ile sunucu arasındaki iletişimin dilini tanımlayan protokoldür. Her HTTP iletişimi bir istek (request) ve bir yanıt (response) çiftinden oluşur.
İstemci — sizin Android uygulamanız — bir istek gönderir. Sunucu bu isteği değerlendirir ve bir yanıt üretir. İstek-yanıt döngüsü tamamlandığında o iletişim biter. HTTP kendi başına durum saklamaz — her istek bağımsızdır.
Bu tasarım interneti son derece ölçeklenebilir kılar. Sunucu her isteği bağımsız değerlendirir, istemciyi hatırlamak zorunda değildir.

İstek Anatomisi: Üç Ana Parça
Bir HTTP isteği üç bölümden oluşur.
Başlık satırı isteğin özeti gibidir. HTTP metodunu, hedef URL'i ve HTTP versiyonunu içerir. Örneğin GET /api/users/42 HTTP/1.1 satırı sunucuya "42 numaralı kullanıcıyı ver" demektir.
HTTP metotları farklı niyetleri ifade eder. GET veri istemek için kullanılır ve yan etkisi olmadığı varsayılır. POST yeni veri oluşturmak için kullanılır. PUT mevcut veriyi tamamen güncellemek için kullanılır. PATCH kısmi güncelleme için tercih edilir. DELETE silme işlemi için kullanılır. Bu metotlar yalnızca ismi farklı çağrılar değildir — sunucu bu metodu okur ve ona göre farklı davranır.
Başlıklar (Headers) isteğe dair meta bilgileri taşır. Content-Type gönderilen verinin formatını bildirir. Authorization kimlik doğrulama bilgisini taşır. Accept istemcinin hangi formatları anlayabildiğini söyler. User-Agent isteği yapan uygulamayı tanımlar. Başlıklar isteğin zarfı gibidir — içerik hakkında bilgi verir ama içerik değildir.
Gövde (Body) isteğin taşıdığı gerçek veridir. GET istekleri genellikle gövde taşımaz çünkü ne istediği URL'de bellidir. POST ya da PUT istekleri ise sunucuya göndermek istediği veriyi gövdede taşır.

Adım Adım: İstek Gönderildiğinde Ne Olur?
Android uygulamanızda bir HTTP isteği başlatıldığında süreç şu şekilde ilerler.
Retrofit gibi bir kütüphane kullandığınızda yazdığınız arayüz tanımı bir HTTP isteğine dönüştürülür. Metot adı, parametreler ve annotasyonlar bir araya gelerek istek nesnesi oluşturulur. Bu dönüşüm sizin için otomatik gerçekleşir.
İstek nesnesi oluşturulduktan sonra OkHttp gibi bir HTTP istemcisine teslim edilir. OkHttp önce interceptor zincirini işler. Her interceptor isteği alır, üzerinde istediklerini yapar ve bir sonraki interceptor'a iletir. Kimlik doğrulama başlığı eklemek, loglama yapmak, önbelleği kontrol etmek — bunların hepsi interceptor'lar aracılığıyla gerçekleşir.
Interceptor zinciri tamamlandıktan sonra OkHttp bağlantıyı ele alır. Önce bağlantı havuzunu (connection pool) kontrol eder. Bu sunucuya daha önce açılmış ve hâlâ kullanılabilir bir bağlantı var mı? Varsa yeni TCP bağlantısı kurmak yerine mevcut bağlantı yeniden kullanılır. Bu optimizasyon gecikmeyi önemli ölçüde azaltır.
Kullanılabilir bağlantı yoksa sırayla DNS çözümlemesi, TCP bağlantısı ve TLS el sıkışması gerçekleşir. Bu üç adım tamamlandıktan sonra HTTP isteği gerçekten gönderilir.

Sunucu Tarafı: Kara Kutu
İstek sunucuya ulaştıktan sonra kontrol tamamen sunucunun elindedir. Android uygulaması bu noktada yalnızca bekler.
Sunucu isteği alır, kimlik doğrulamasını kontrol eder, ilgili iş mantığını çalıştırır, gerekirse veritabanına başvurur, yanıtı hazırlar ve geri gönderir. Bu sürecin ne kadar süreceğini istemci bilemez ve kontrol edemez. Timeout süresi bu belirsizliği yönetmenin temel aracıdır.

Yanıt Anatomisi: Durum Kodu Her Şeyi Söyler
Sunucunun gönderdiği yanıt da benzer bir yapıya sahiptir. Ama yanıtın en kritik bileşeni HTTP durum kodudur.
Durum kodları üç basamaklı sayılardır ve ilk rakam kategorisini belirler.
2xx başarı demektir. 200 OK standart başarı yanıtıdır. 201 Created yeni bir kaynak oluşturulduğunu bildirir. 204 No Content işlem başarılı ama döndürülecek veri yok demektir.
3xx yönlendirme demektir. İstenen kaynak başka bir URL'e taşınmıştır. İstemci yeni URL'e istek atmalıdır.
4xx istemci hatası demektir. Hata sizin tarafınızdadır. 400 Bad Request isteğin formatı yanlış demektir. 401 Unauthorized kimlik doğrulama gerekiyor demektir. 403 Forbidden kimlik doğrulandı ama erişim izni yok demektir. 404 Not Found istenen kaynak bulunamadı demektir. 429 Too Many Requests çok fazla istek atıldı demektir.
5xx sunucu hatası demektir. Hata sunucu tarafındadır. 500 Internal Server Error sunucuda beklenmedik bir sorun oluştu demektir. 503 Service Unavailable sunucu geçici olarak kullanılamıyor demektir.
Bu kodları doğru okumak hata yönetiminin temelidir. 4xx ile 5xx arasındaki farkı bilmek, yeniden deneme mantığını (retry logic) doğru yazmak için kritiktir. 5xx hatası geçici olabilir ve yeniden deneme mantıklıdır. 4xx hatası genellikle geçici değildir ve yeniden denemek durumu değiştirmez.

Önbellekleme: Aynı İsteği Tekrar Atmamak
HTTP'nin güçlü ama çoğunlukla göz ardı edilen özelliklerinden biri önbellekleme mekanizmasıdır.
Sunucu yanıtına Cache-Control başlığı ekleyerek bu yanıtın ne kadar süre geçerli olduğunu belirtebilir. İstemci bu talimatı uyarsa aynı istek belirtilen süre boyunca tekrar sunucuya gönderilmez, doğrudan önbellekten yanıtlanır.
OkHttp bu mekanizmayı destekler. Disk önbelleği yapılandırıldığında sunucunun izin verdiği yanıtlar yerel olarak saklanır. Hem ağ trafiği azalır hem de yanıt süreleri kısalır hem de uygulama çevrimdışı modda kısmen çalışmaya devam edebilir.

Geliştirici Perspektifinden Bakış
Bu süreci anlamak hata ayıklamayı kökten değiştirir.
Bir ağ sorunu yaşandığında önce durum koduna bakın. Kod 401 mi? Kimlik doğrulama başlığını kontrol edin. Kod 404 mü? URL'yi kontrol edin. Kod 500 mü? Sorun sizde değil sunucudadır, loglara bakılması gerekir.
Interceptor'ları akıllıca kullanın. Token yenileme (token refresh) mantığını her API çağrısına yazmak yerine bir interceptor'a koyun. Loglama interceptor'u geliştirme sürecinde tüm istek ve yanıtları görmenizi sağlar.
Ve timeout değerlerini varsayılanda bırakmayın. Bağlantı timeout'u, okuma timeout'u ve yazma timeout'u uygulamanızın beklentilerine göre ayrı ayrı ayarlanmalıdır. Çok kısa timeout gereksiz hatalara, çok uzun timeout donmuş bir kullanıcı arayüzüne yol açar.