Bir kahve dükkanının WiFi ağı üzerinden iki gigabaytlık bir video yüklemek, tam bir iyimserlik testi gibidir. İlerleme çubuğunun yüzde yetmişe doğru ağır ağır ilerlemesini izlersiniz ve tam o sırada bağlantı kopar. Yükleme başarısız olur. Tekrar denediğinizde ise sunucu yepyeni bir dosya bekler. Sıfırdan başlamak zorunda kalırsınız. Kullanıcı tarafından oluşturulan videolarla çalışan bir uygulama geliştiriyorsanız, bu durum bir uç örnek değil, aksine bir normdur. tus protokolü, özellikle bu sorunu ortadan kaldırmak için geliştirilmiştir. Sıradan HTTP üzerinden çalışan ve yüklemelere bir hafıza kazandıran açık bir standarttır. Ağ geri geldiğinde, dosya aktarımı tam kaldığı yerden devam eder.

Standart Yüklemeler Neden Bozulur

Standart multipart dosya yüklemeleri, tüm veri yükünü (payload) tek bir işlem olarak ele alır. Tarayıcı veya uygulama bir TCP bağlantısı açar, baytları akış (stream) halinde gönderir ve sonunda bir 200 OK yanıtı bekler. Eğer kullanıcı LTE'den WiFi'ye geçtiği için veya dizüstü bilgisayar uyku moduna girdiği için bağlantı sıfırlanırsa, sunucunun hangi baytların güvenli bir şekilde ulaştığını bilmesinin bir yolu yoktur. Çoğu framework, kısmi veriyi doğrudan çöpe atar. Kullanıcı ise başarısız olmuş bir form ve kötü bir ruh haliyle baş başa kalır. Video dosyaları bu acıyı daha da artırır; çünkü bu dosyalar büyüktür, genellikle kararsız ağlara sahip mobil cihazlardan yüklenirler ve sıklıkla dosyanın tamamı bozulmadan işlenemeyen formatlarda kodlanırlar.

Tus Oyunun Kurallarını Nasıl Değiştiriyor

Tus, yükleme işlemini tek seferlik bir teslimat yerine, durum bilgisi içeren (stateful) bir görüşme olarak yeniden kurgular. İstemci, dosyayı tek bir sürekli bayt püskürtmesi şeklinde göndermek yerine, veri yükünü parçalara ayırır. Daha da önemlisi sunucu, şimdiye kadar aldığı baytların tam sayısını, yani offset değerini hatırlar. Yeniden başlatmayı mümkün kılan şey bu durum sürekliliğidir (state persistence). Protokol kasıtlı olarak basittir. WebSockets, gRPC veya tescilli SDK'lar gerektirmez. Zaten bildiğiniz HTTP yöntemlerini kullanır.

Yeniden Başlatmayı Sağlayan Üç İstek

Her tus yüklemesi öngörülebilir bir döngüyü takip eder.

İlk olarak istemci, bilinen bir tus uç noktasına (endpoint) bir POST isteği gönderir. Başlıklar (headers) dosyayı tanımlar. Upload-Length başlığı, nihai boyutu bayt cinsinden belirtir; dosya adı veya içerik türü gibi isteğe bağlı meta veriler ise Upload-Metadata başlığında, base64 ile kodlanmış anahtar-değer çiftlerinin virgülle ayrılmış bir listesi olarak iletilir. Sunucu boş bir yükleme kaynağı oluşturur ve benzersiz bir URL'ye işaret eden bir Location başlığı ile birlikte 201 Created durumuyla yanıt verir. Bu URL, yüklemenin yaşamı boyunca kullanacağı adrestir.

Ardından PATCH isteği gelir. İstemci, o benzersiz URL'ye ham ikili veri (binary data) parçaları gönderir. Veri yüküne iki kritik başlık eşlik eder. Content-Type mutlaka application/offset+octet-stream olmalıdır ve Upload-Offset, bu parçanın başladığı bayt konumuyla eşleşmelidir. Sunucu, offset değerinin kendi kayıtlarıyla eşleşip eşleşmediğini doğrular. Eğer eşleşmiyorsa, sunucu bozulmuş durumdan korunmak için 409 Conflict hatası döndürür. Her şey yolundaysa, sunucu baytları ekler, dahili offset değerini günceller ve yeni Upload-Offset ile birlikte 204 No Content yanıtı döndürür. Parça boyutu yapılandırılabilir, ancak genel uygulama birkaç yüz kilobayt ile birkaç megabayt arasında değişmektedir. Daha küçük parçalar daha fazla HTTP yükü (overhead) oluşturur ancak hatalardan daha hızlı kurtulur. Daha büyük parçalar git-gel (round trip) sayısını azaltır ancak yükleme sırasında başarısız olurlarsa daha fazla bant genişliği israfına yol açar.

Son olarak HEAD isteği gelir. Bu, güvenlik ağıdır. Eğer bir PATCH işlemi bir parçanın ortasında, örneğin beş megabaytlık bir dilimin üç megabaytından sonra başarısız olursa bağlantı kopar. İstemci ağ erişimini tekrar kazandığında, yükleme URL'sine bir HEAD isteği gönderir. Sunucu mevcut Upload-Offset ile yanıt verir. İstemci karşılaştırır