Net-Base Magazin

System.Net.HttpClient: Download mit Resume – Range-Requests, ETag-Prüfung und saubere Partial-File-Strategie

Wenn Downloads abbrechen, ist Resume verlockend – und riskant. So kombinierst du Range-Requests, If-Range/ETag und eine robuste .part-Strategie, ohne stille Dateikorruption zu bauen.

Örökölt rendszerek. Refaktorálás. Migráció.

Meglévő szoftver modernizálása anélkül, hogy a rendszer szakmai tartalma elveszne.

Legacy rendszerek Delphi Refaktorálás Éles üzembe vétel

Üzleti logika megőrzése

Az értékes üzleti logika látható marad, és nem temetik el egy teljes újraépítés alatt.

Kódbázis modularizálása

A felelősségi körök elkülönítése, hogy az új felületek és szolgáltatások kontrolláltan csatlakozhassanak.

Tegyük tervezhetővé a migrációt

Lépésenként szállítani, tesztelni és bevezetni ahelyett, hogy a működést egy éles váltással kockáztatnánk.

24.10.2026

A magazintémától a projektgyakorlatig

A bejegyzéshez tartozó szolgáltatási és technikai oldalak

A jelenet kellemetlen, de tipikus: egy éjszakai feladat egy nagy archívumot tölt le, a haladássáv 93%-nál áll. Aztán egy rövid VPN-megszakadás, időtúllépés, megszakítás. Reggel a célkönyvtárban található egy fájl, a méret „stimmel”, de a kicsomagolásnál csak a „a fájl váratlan vége” üzenet jelenik meg. Aki ilyenkor reflexszerűen a folytatást (Resume) kapcsolja be, könnyen a következő szélső esettel találja szemben magát: a letöltés végbemegy, de két külön verzióból áll össze.

Erre való egy HttpClient-letöltés folytatással – de csak akkor, ha olyan, mint egy kis adatcsővezetékhez kezeled: világos szabályokkal, hogy mikor fűzhetsz hozzá, hogyan ellenőrzöd a verzióhűséget (ETag/If-Range) és hogyan kezeled a helyi köztes állapotokat (részfájlok, Partial Files), hogy az üzemeltetés és a hibakeresés ne váljon találgatássá.

A célkonfliktus egyértelműen megnevezhető: sávszélesség és idő megtakarítása (folytatás újraindítás helyett) áll szemben a integritással és karbantarthatósággal (nincs néma verziókeverés, követhető döntések, reprodukálható hibakép). Ez a cikk egy mérlegelési térkép: előnyök, ráfordítás, kockázatok, határok – és egy pragmatikus irányvonal, mikor érdemes valóban implementálni a folytatást, és mikor jobb egy jól megválasztott újrapróbálkozás.

Mérlegelési térkép: két cél, egy kemény kompromisszum

A folytatás nem azért éri meg, mert „modern”, hanem mert a környezeted kényszeríti: nagy fájlok, instabil kapcsolatok, időablakok batch-feladatoknál, felhasználók, akik megszakítják a letöltéseket, vagy szolgáltatások, amelyek újraindulás után ott akarnak folytatni, ahol abbahagyták. Ugyanakkor a folytatás az a pont, ahol észrevétlenül adatkorruptiót építhetünk be – és ez gyakran csak jóval később derül ki (import meghiúsul, aláírás érvénytelen, telepítő nem fut le).

Helyzet Folytatás előnye Jellemző kockázat Indokolt döntés
Nagy fájlok WAN/VPN-en vagy mobilhálózaton magas (idő, sávszélesség) „200 a 206 helyett“ esetén vakon hozzáfűzés Folytatás igen, de defenzíven (Status/Content-Range/validátor)
„latest” URL-ek / verzióhoz nem kötött artefaktumok közepes verziókeveredés köztes frissítés után Folytatás csak erős validátorral, különben teljes újratöltés
Belső tárhely stabil ETag-ekkel magas alacsony, ha a fejléc konzisztens Folytatás nagyon alkalmas, metadatok perzisztálása
Kis fájlok (néhány tucat MB) alacsony a komplexitás meghaladja az előnyt Teljes letöltés + Retry/Backoff általában jobb
Változó proxyk/CDN-ek, bizonytalan fejléc-helyzet bizonytalan inkonzisztens validátorok, nehéz hibakeresés Csak jó naplózással; különben tudatosan konzervatív

Miért több a letöltés-folytatás, mint „Range beállítása”

A HTTP ismeri a byte-tartomány-kéréseket a Range-Headeren keresztül. A fontos, gyakran figyelmen kívül hagyott megállapítás: a Range-támogatás opcionális. A szerver figyelmen kívül hagyhatja a Range-et és úgy válaszolhat, mintha egy normál GET lenne – tehát 200 OK-val és teljes törzzsel. A kliens számára ez azt jelenti: az igazság a válaszban áll, nem a kérésed szándékában.[Forrás]

Egy letöltés-folytató kliens, amely a „Range elküldve” és a „részsztartalom érkezik” között összemos, pontosan azt a hibát követi el, amit a bevezető jelenetben láttál: egy teljes letöltés egy már részben letöltött fájlhoz kerül hozzáfűzésre. Eredmény: a fájl méretre elég nagynak tűnik, de logikailag sérült.

Sikerjel: 206 plusz ésszerű Content-Range

Ha a letöltés-folytatás valóban működik, tipikusan a következőt látod:

  • Státusz 206 Partial Content a 200 OK helyett
  • Content-Range a Range-Unit bytes-szal és a várt kezdőoffsettel
  • konzisztens validátorok (pl. ETag), ha verzióazonosság ellenőrzésére használod őket

A vizsgálatok nem „nice to have”. Az RFC 9110 kifejezetten kimondja, hogy a fogadó fél nem állíthat össze egy 206-os választ ismeretlen Range-Unittal egy tárolt reprezentációból. Gyakorlati következmény: helyesen értelmezett Content-Range nélkül nincs hozzáfűzés.[Forrás]

If-Range és ETag: a tiszta út a verziókeveredés ellen

A folytatás alapvető problémája nem maga az hozzáfűzés technikája, hanem az a kérdés: ugyanazt az erőforrást töltöd-e le még mindig? A HTTP erre validátorokat ad. ETag (Entity Tag) ebben a tekintetben a legprecízebb eszköz: a szerver-oldali azonosító egy konkrét reprezentációhoz. A Last-Modified egy dátum, gyakran használható, de kevésbé éles (időfelbontás, újracsomagolás, különböző köztes állapotok CDN-eken keresztül).

A mechanizmus arra, hogy „Range csak akkor, ha valóban ugyanaz a verzió”, a If-Range névre hallgat: elküldöd a Range-et plusz egy feltételt. Ha a validátor megfelel, a szerver kiszolgálja a tartományt; ha nem, a szerver a teljes erőforrást küldi. ETag-ek esetén a feltétel csak akkor teljesül, ha erős ETag-egyezés van (erős összehasonlítás). Ez nem értelmezési kérdés, a szabvány így írja elő.[Forrás]

A gyakorlat azonban megmarad: ha a szerver nem támogatja a Range-et, akkor a If-Range-et figyelmen kívül kell hagynia. Ez bár tudományosnak hangzik, közvetlen követelmény a kliensed számára: számítanod kell 200 OK-ra is, és ebből határozott döntést kell hoznod (újrakezdés, ne fűzz hozzá).[Forrás]

Részfájl-stratégia: a helyi megfelelő a HTTP szemantikának

Letöltés-folytatás azt jelenti, hogy helyi állapotot kezelsz. És ez az állapot stabilnak kell maradnia összeomlás, újraindítás, párhuzamos indítás vagy felhasználói művelet („még egyszer kattintás”) után is. Egy tiszta részfájl-stratégia három artefaktumból áll:

  • Részfájl mint az egyetlen írási hely a letöltés során (pl. foo.zip.part)
  • Metadaten külön tárolva (pl. foo.zip.part.meta.json): URL, időpont, ETag, Last-Modified, várt Länge (ha ismert), esetleg Content-Type, valamint a helyi hossz az utolsó tiszta Flush-kor
  • Atomarer Abschluss: csak a teljes letöltés és a plausibilitás-ellenőrzés után nevezzük át/cseréljük a végleges névre

Miért Metadaten? Mert különben a következő indításkor csak a fájl hosszát ismered – de nem azt, hogy az valóban ehhez a szerververzióhoz tartozik-e. Pont ez az információ dönt arról, hogy folytathatod-e.

HttpClient Download mit Resume: Entscheidungslogik, die du testen kannst

System.Net.HttpClient ad kéréseket, válaszokat és streameket. A robusztusság a döntési mátrixodból fakad. Ha azt tisztán megfogalmazod, tesztelni is tudod (beleértve a „Server ignoriert Range”, „Validator mismatch”, „416”).

Minimaler Ablauf in 6 Schritten

  1. Lokalzustand ermitteln: Létezik-e .part? A hosszát offsetként olvasd. Metadatok betöltése.
  2. Resume-Fähigkeit entscheiden: Resume-ot csak akkor próbálj meg, ha az Offset > 0 und a metadatokban legalább egy használható validátor szerepel (ETag előnyben).
  3. Request aufbauen: Állítsd be a Range-et az Offsettől. Továbbá állítsd be az If-Range-t (ETag, különben Last-Modified).
  4. Response klassifizieren:
    • 206: Content-Range parsolása, Range-Unit bytes ellenőrzése, a kezdő offsetnek pontosan egyeznie kell. Csak ezután fűzd hozzá.
    • 200: soha ne fűzz hozzá. A részleges állapotot eldobni vagy karanténba helyezni, majd újra letölteni.
    • 416 Range Not Satisfiable: Az offset már nem stimmel (helyben vagy a szerveren). Állapot visszaállítása és újraindítás.
    • egyébként: hibakezelés egyértelmű diagnózissal (statuskód + header naplózása).
  5. Stream schreiben: blokkokban írni, rendszeresen flush-olni, metadatokat frissíteni (pl. „utolsó flush hossza X”).
  6. Abschluss: Méret-/plauzibilitás-ellenőrzés (ha lehetséges). Ezután atomikusan átnevezni/cserélni.

RangeHeaderValue: kein Detail, sondern Fehlerprävention

.NET kínál a Range-headerhez a tipizált osztályt RangeHeaderValue. Ez nem csak „szebb kód“: csökkenti a szintaktikai header-hibákat és értelmezhetőbbé teszi a logokat, mert konzisztens értékeket állítasz elő. A Microsoft dokumentálja az üzemeltetési szempontból releváns határt is: a szerverek nem kötelesek támogatni a Range-kéréseket; a Accept-Ranges egy jelzés, nem garancia.[Quelle]

Konstruiertes Beispiel: Wenn „200 OK“ dein Resume kaputtmacht

Tipikus buktatók és hogyan ismerd fel őket a naplóban

Accept-Ranges: hasznos jelzés, de nem garancia

Sok csapat az Accept-Ranges-t használja arra a jelzésre, hogy „a szerver tud folytatni”. Az MDN pontosan így írja le a headert mint támogatottsági indikátort („minden, kivéve none”). Diagnosztikához és telemetriához ez praktikus. Ennek ellenére: soha ne dönts kizárólag ez alapján. Egy proxy, egy hitelesítési átjáró vagy egy CDN megváltoztathatja a viselkedést. A logikádnak ezért mindig a státuszkódon (206 vs. 200) és a Content-Range-en kell alapulnia, nem az Accept-Ranges adta reménysugáron.[Forrás]

Gyenge ETag-ek (W/…) és transzformációk

A gyenge ETag-ek (W/"…") gyakoribban fordulnak elő, mint szeretnénk. Az If-Range esetén azonban erős ETag-egyezés döntő. Gyakorlatban ez azt jelenti: ha csak weak ETag-et kapsz, a folytatás kevésbé megbízható. Használhatod továbbra is, de konzervatívabbnak kell lenned (pl. apró eltéréseknél újraindítani), és különösen kritikus fájloknál érdemes kiegészítő, csatornán kívüli integritásellenőrzést alkalmazni (manifestből/API-ból származó hash), ha elérhető.

Ismeretlen teljes hossz (chunked) és hiányzó plauzibilitás

Ha nincs Content-Length (pl. chunked transfer), elveszítheted az egyszerű végellenőrzést: „lokális hossz == várható hossz”. A folytatás ettől még működhet, de jó validatorokra és részletes naplózásra van szükséged. Ezek nélkül a hibakeresés nehézkes lesz, mert még azt sem tudod megmondani, hogy hiányoznak-e bájtok vagy túl sok van belőlük.

Párhuzamosítás: csak miután az alapok rendben vannak

Több Range párhuzamos letöltése lehetséges, de megsokszorozza az állapotkezelési problémákat: szegmenskezelés, véletlenszerű írás (Random-Write), merge, hibajelentés, retry szegmensenként. Sok folyamatközeli szoftvermegoldás számára ez túlzás. A stabil nyereség gyakran már az alábbiakkal elérhető: soros letöltés + folytatás + világos döntési mátrix. A párhuzamosítás csak akkor éri meg, ha igazoltad a stabil Range-támogatást és a mérések konkrétan azt mutatják, hogy valóban a hálózati vagy szerverkorlát miatt vagy korlátozott.

Hibakeresés, amely 5 perc alatt tisztázza a helyzetet

Resume-hibák ritkán „csak egy rossz if”. Többnyire infrastruktúra (Proxy/CDN), szerverkonfiguráció, timeoutok és helyi állapot kombinációjáról van szó. Ezért érdemes próbánként strukturált naplózást vezetni. Nem szabad hosszú szöveges tömeget írni, hanem következetes mezőket:

  • Kérelem: URL (titkok nélkül), metódus, Range (kezdő/vég), If-Range (ETag vagy dátum).
  • Válasz: státuszkód, Accept-Ranges, ETag, Last-Modified, Content-Length, Content-Range (nyers és feldolgozott).
  • Helyi állapot: Part-Pfad, .part hossza a kérés előtt, írási mód (Append/Overwrite), hossz írás után.
  • Döntés: „Folytatás elfogadva“, „Folytatás elutasítva (200) – újraindítás“, „416 – reset“, „Validator mismatch – RESTart“.

Pontosan ezekkel az adatokkal tesztelni tudsz hipotéziseket: „A szerver ignorálja a Range fejlécet?“, „Változik az ETag a kérések között?“, „Helytelenül határozzák meg az offszetet?“, „Egy másik folyamat is ír bele?“ – anélkül, hogy elővennéd a Wiresharkot.

Mikor érdemes szándékosan nem implementálni a Resume-t

A legtisztább architektúra-döntés néha az, ha elhagyod a Resume-t — nem kényelmi okból, hanem mert az adott forgatókönyvben több hibafelületet teremt, mint hasznot:

  • URL verziókötés nélkül: Ha ugyanazon az URL-en rendszeresen új tartalom van, a Resume erős validátor nélkül integritási kockázatot jelent.
  • Nincs használható validátor: Ha sem az ETag, sem a Last-Modified nem konzisztens, a „folytatás” tét. Kritikus importoknál ez gyakran rosszabb, mint egy kontrollált újraindítás.
  • Kis, gyakori letöltések: Ilyen esetben a retry-stratégiák (Timeout, Backoff, esetleg Mirror-URL) karbantarthatóbbak és üzemeltethetőbbek.

Pragmatikus biztonsági hálók, amelyek megtérülnek

Karantén törlés helyett

Ha egy Resume-próba elbukik, ne töröld reflexszerűen a .part-ot. Nevezd át (pl. .part.bad + idõbélyeg). Ez láthatóvá teszi a szerver-/proxy-problémákat, mert később össze tudod vetni a response-fejlécet és a fállapotot. És megakadályozza, hogy egy ritka hiba az „eltakarítással” eltűnjön az elemzésből.

Zárolás a párhuzamos indítások ellen

Ha két folyamat egyszerre írja ugyanazt a .part-ot, az összes HTTP-validátor értéktelenné válik. Egy exkluzív lock (fájlzár vagy rendszerwide mutex) ezért nem luxus, hanem alapvédelem. A metaadatok tartalmazhatnak tulajdonos-információt (instancia-ID), hogy a „árva” letöltéseket tisztán fel tudd ismerni és takarítani tudd.

Gyorsreferencia-szabályok, amikre valóban szükséged van

  • Append csak 206 esetén – és csak ellenőrzött Content-Range mellett (unit bytes, kezdő offset egyezik).
  • 200 azt jelenti: újraindítás (overwrite), soha ne fűzd hozzá egy .part fájlhoz.
  • If-Range csökkenti a verziókeveredést, de nem helyettesíti a státusz/Content-Range kiértékelésének kötelezettségét.
  • 416 reset-jelzés: a helyi offset már nem stimmel; állapotot elvetni/karanténozni.

Záró megállapítás: Előbb integritás, aztán optimalizálás

Egy HttpClient-letöltés folytatással akkor jó, ha unalmas: csak akkor adja meg a Range fejlécet, ha a helyi állapot megbízható, csak akkor folytatja a letöltést, ha 206 állapotkód és ellenőrzött Content-Range áll rendelkezésre, és megakadályozza a verziók keveredését If-Range és validátorok segítségével. Minden más inkább egy „gyorsan mutat” funkció, amely később időt rabol, mert a hibák ritkák és akkor alig reprodukálhatók.

Ha Updater, Importstrecken vagy Services számára robusztus letöltési pipeline-t (Resume, Logging, Partial-File-Strategie, Betriebskanten) szeretnél tisztán felépíteni, ezt gyakran egy rövid architektúra-ellenőrzéssel tisztázni lehet – beleértve azt a kérdést is, hogy a komplexitás egyáltalán megéri-e a te környezetedben. Vedd fel a kapcsolatot, és beszéld meg a tervet Net-Base-vel.

Források és további információk

A szakmai főállításokat az alábbi külső források alapján szerkesztői szempontból értékeltük.

  1. RFC 9110: HTTP Semantics (www.rfc-editor.org)
    A HTTP Range-kérések opcionálisak; a szerverek figyelmen kívül hagyhatják a Range-et és normál GET-ként válaszolhatnak, ezért a kliensnek a státuszkódot és a fejlécet kell kiértékelnie a vak folytatás helyett.
  2. HTTP range requests – HTTP | MDN (developer.mozilla.org)
    Az Accept-Ranges jelzés a Range-támogatásra, de a klienseknek a válasz viselkedését (206/Content-Range) robusztusan ellenőrizniük kell.
  3. RangeHeaderValue Class (System.Net.Http.Headers) | Microsoft Learn (learn.microsoft.com)
    .NET a RangeHeaderValue osztállyal tipizált reprezentációt nyújt a Range-fejléc számára; a szervereknek nem kötelező támogatni a Range-kéréseket.

Projektet vagy modernizációs kezdeményezést beszélj meg Net-Base-vel.

Következő lépés

Ha a téma valós projektté válik, az architektúrát, a meglévő rendszert és az üzemeltetést már korán együtt kell értékelni.

Nemcsak egyedi kérdésekben támogatunk, hanem akkor is, amikor forráskódrészletekből, örökölt rendszerekkel kapcsolatos témákból vagy portálötletekből robusztus vállalati projektet kell kialakítani.

  • A jelenlegi állapotot, a célállapotot és a műszaki kockázatokat együttesen értékeljük.
  • REST, az adathozzáférés, a portálok és a Rollout nem kerülnek utólagos teendőkként elhalasztásra.
  • Már korán láthatja, melyik út gazdaságilag és üzemeltetési szempontból életképes.

Bejegyzés megosztása

Ezt a bejegyzést közvetlenül megosztani

LinkedIn, X, XING, Facebook, WhatsApp és e-mail azonnal elérhetők. Instagramhoz linket és rövid szöveget közvetlenül előkészítünk.

E-mail

Az Instagram egy új lapon nyílik meg. A link és a rövid szöveg előzetesen a vágólapra másolódik.

Hozzászólás írása

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert