Net-Base Magazín

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.

Zastaralé systémy. Refaktoring. Migrace.

Modernizovat existující software, aniž by byla ztracena doménová podstata systému.

Zastaralé systémy Delphi Refaktoring Uvedení do provozu

Zachovat doménovou logiku

Cenná podniková logika zůstává viditelná a není pohřbena pod úplnou přestavbou.

Rozplést kódovou bázi

Oddělit odpovědnosti, aby se nová rozhraní a nové služby mohly řízeně připojovat.

Plánovatelnost migrace

Postupné dodávání, testování a zavádění místo riskování provozu ostrým přechodem.

24.10.2026

Od tématu magazínu k projektové praxi

Vhodné stránky služeb a technické stránky k příspěvku

Scéna je nepříjemná, ale typická: noční úloha stahuje velký archiv, ukazatel průběhu stojí na 93 %. Pak krátký VPN výkyv, timeout, přerušení. Ráno leží v cílovém adresáři soubor, velikost „sedí“, ale při rozbalování se objeví jen „unexpected end of file“. Kdo pak reflexivně doplní „Resume“, rychle narazí na další okrajový případ: stahování proběhne, ale je složené ze dvou verzí.

Právě pro to je určen HttpClient Download mit Resume – ale pouze pokud s ním budeš zacházet jako s malou datovou pipeline: s jasnými pravidly, kdy můžeš připojovat, jak ověřovat věrnost verze (ETag/If-Range) a jak spravovat lokální mezistavy (Partial Files) tak, aby provoz a debugování nebyly hrou na odhad.

Cílový konflikt se dá jasně pojmenovat: šetření šířky pásma a času (pokračování místo restartu) stojí proti integritě a udržovatelnosti (žádné tiché mixování verzí, rozhodnutí musí být sledovatelná, reprodukovatelný chybový stav). Tento článek je postaven jako karta zvážení: přínosy, náklady, rizika, limity – a pragmatická linie, kdy Resume skutečně implementovat a kdy je lepší kvalitní retry.

Abwägungskarte: Zwei Ziele, ein harter Trade-off

Resume se nevyplatí proto, že je „moderní“, ale protože ti to okolnosti vynutí: velké soubory, nestabilní linky, časová okna v batchi, uživatelé, kteří stahování přeruší, nebo služby, které po restartu mají pokračovat tam, kde skončily. Současně je Resume místo, kam si nevědomky vnesete datovou korupci – a ta se často projeví až mnohem později (import selže, podpis neplatný, instalace se nespustí).

Situace Resume-Nutzen Typisches Risiko Rozumné rozhodnutí
Velké soubory přes WAN/VPN nebo mobilní sítě vysoký (čas, šířka pásma) „200 statt 206“ je připojeno naslepo Resume ano, ale defenzivně (Status/Content-Range/Validator)
„latest“-URL / artefakty bez vázání na verzi střední směs verzí po meziaktualizaci Resume jen se silným validátorem, jinak restart
Interní storage se stabilními ETagy vysoký nízké, pokud jsou hlavičky konzistentní Resume velmi vhodné, metadat persistovat
Malé soubory (několik desítek MB) nízký komplexita převažuje plné stažení + retry/backoff je většinou lepší
Proměnlivé proxy/CDN, nejasná situace s hlavičkami nejasný nekonzistentní validátory, těžké debugování pouze s dobrým logováním; jinak záměrně konzervativní

Proč obnovení stahování (Resume) je víc než „nastavení Range“

HTTP zná Byte-Range-Requests přes hlavičku Range. Důležitá, často přehlížená věta: podpora Range je volitelná. Server může Range ignorovat a odpovědět, jako by šlo o běžný GET – tedy 200 OK s celým tělem. Pro klienta to znamená: pravda je v Response, ne ve tvém záměru v Requestu.[Quelle]

Klient pro obnovení stahování, který „poslal Range“ zamění za „přijde část obsahu“, dělá přesně tu chybu, kterou jsi viděl na začátku scény: celý download se připojí k již částečně staženému souboru. Výsledkem je, že soubor vypadá dost velký, ale logicky je poškozený.

Signál úspěchu: 206 plus věrohodný Content-Range

Když obnovení skutečně funguje, uvidíš typicky:

  • Stav 206 Partial Content místo 200 OK
  • Content-Range s Range-Unit bytes a očekávaným startovacím offsetem
  • konzistentní validátory (např. ETag), pokud je používáš k ověření verze

Tyto kontroly nejsou „nice to have“. RFC 9110 explicitně stanoví, že příjemce nesmí odpověď 206 s neznámou Range-Unit skládat s uloženou reprezentací. Praktický důsledek: bez korektně interpretovaného Content-Range žádné připojování (append).[Quelle]

If-Range a ETag: čistý postup proti míchání verzí

Jádro problému při pokračování není technika připojování, ale otázka: Stahuješ stále tentýž zdroj? HTTP poskytuje pro tento účel validátory. ETag (Entity Tag) je nejpřesnější páka: server-side identifikátor konkrétní reprezentace. Last-Modified je datum, často užitečné, ale méně ostré (časové rozlišení, repackaging, různé mezistupně přes CDN).

Mechanismus „Range pouze pokud jde opravdu o stejnou verzi“ se jmenuje If-Range: pošleš Range plus podmínku. Pokud validátor sedí, dostaneš Range; pokud nesedí, má server poslat kompletní zdroj. U ETagů platí, že podmínka je splněna pouze při silném ETag-matchi (strong comparison). To není věc interpretace, ale tak to standard předepisuje.[Quelle]

Provozní realita zůstává: pokud server Range nepodporuje, musí If-Range ignorovat. Zní to akademicky, ale je to přímé zadání pro tvůj klient: musíš počítat i s 200 OK a z toho vyvodit tvrdé rozhodnutí (restartovat stahování, ne připojovat).[Quelle]

Strategie částečných souborů: lokální protějšek HTTP sémantiky

Obnovení znamená: spravuješ lokální stav. A tento stav musí zůstat konzistentní i po pádu, restartu, paralelním spuštění nebo uživatelské akci („znovu kliknout“). Čistá strategie částečných souborů se skládá ze tří artefaktů:

  • Částečný soubor jako jediný zápisový cíl během stahování (např. foo.zip.part)
  • Metadata uložena odděleně (např. foo.zip.part.meta.json): URL, čas, ETag, Last-Modified, očekávaná délka (pokud známá), případně Content-Type, a lokální délka při posledním čistém flushu
  • Atomické dokončení: až po úplném stažení a kontrole konzistence bude přejmenováno/nahrazeno na finální název

Proč metadata? Bez nich při dalším spuštění znáš jen délku souboru – ale nevíš, zda odpovídá právě této verzi na serveru. Právě tato informace rozhoduje, zda můžeš pokračovat.

HttpClient Download mit Resume: Entscheidungslogik, die du testen kannst

System.Net.HttpClient ti poskytuje Requests, Responses a Streams. Robustnost plyne z tvé rozhodovací matice. Pokud ji jasně sformuluješ, můžeš ji také jasně otestovat (včetně „Server ignoriert Range“, „Validator mismatch“, „416“).

Minimální postup ve 6 krocích

  1. Zjištění lokálního stavu: Existuje .part? Přečíst délku jako offset. Načíst metadata.
  2. Rozhodnout o možnosti Resume: Pokus o Resume jen pokud je Offset > 0 a v metadatech je alespoň jeden použitelný Validator (ETag bevorzugt).
  3. Sestavit request: Nastavit Range od offsetu. Navíc nastavit If-Range (ETag, jinak Last-Modified).
  4. Klasifikovat response:
    • 206: Content-Range parsovat, Range-Unit bytes zkontrolovat, startovací offset musí přesně sedět. Pouze pak Append.
    • 200: nikdy nepřipojovat. Stav částečného souboru odstranit nebo izolovat (karanténa), stáhnout znovu.
    • 416 Range Not Satisfiable: Offset už nesedí (lokálně nebo na serveru). Resetovat stav a znovu začít.
    • jinak: chybová cesta s jasnou diagnózou (logovat Statuscode + Header).
  5. Zapsat do streamu: po blocích, pravidelně flushovat, aktualizovat metadata (např. „poslední flush při délce X“).
  6. Dokončení: Kontrola velikosti/konzistence (pokud možno). Poté atomicky přejmenovat/nahrazit.

RangeHeaderValue: kein Detail, sondern Fehlerprävention

.NET nabízí pro hlavičku Range typovanou třídu RangeHeaderValue. To není jen „krásný kód“: snižuje syntaktické chyby v hlavičkách a dělá logy srozumitelnější, protože generuje konzistentní hodnoty. Microsoft při tom dokumentuje i provozně relevantní hranici: servery nemusí podporovat Range-Requests; Accept-Ranges je indikátor, ne záruka.[Quelle]

Složený příklad: když „200 OK“ zničí Resume

Typické úskalí a jak je v logu rozpoznáš

Accept-Ranges: užitečný signál, ale bez záruky

Mnoho týmů používá Accept-Ranges jako indikaci „server podporuje resume“. MDN popisuje hlavičku přesně takto jako indikátor podpory („vše kromě none„). To je praktické pro diagnostiku a telemetrii. Přesto: nikdy se neredukuj jen na to. Proxy, auth-gateway nebo CDN mohou chování změnit. Tvoje logika proto musí vždy vycházet ze status kódu (206 vs. 200) a z Content-Range, ne z nadějného signálu v Accept-Ranges.[Zdroj]

Slabé ETagy (W/…) a transformace

Slabé ETagy (W/"…") se objevují častěji, než bychom si přáli. Pro If-Range je ale rozhodující silná shoda ETagu. V praxi to znamená: pokud dostaneš pouze weak ETag, je resume méně spolehlivé. Můžeš jej nadále použít, ale měl bys postupovat konzervativněji (např. při nejmenších nesrovnalostech restartovat) a u zvlášť kritických souborů doplnit out-of-band kontrolu integrity (hash z manifestu/API), pokud je dostupná.

Neznámá celková délka (chunked) a chybějící ověřitelnost

Pokud nepřichází Content-Length (např. chunked transfer), ztrácíš jednoduchou kontrolu dokončení „lokální délka == očekávaná délka“. Resume může přesto fungovat, ale potřebuješ spolehlivé validátory a kvalitní logging. Bez těchto opor bude hledání chyb zdlouhavé, protože ani nepoznáš, zda ti chybí bajty nebo jich je příliš.

Paralelizace: až když máš základy stabilní

Načítat více rozsahů paralelně je možné, ale násobí to problémy se stavem: správa segmentů, náhodné zápisy, slučování, protokolování chyb, retry pro segment. Pro mnoho procesně blízkých softwarových řešení je to přehnané. Stabilní zisk často přinese už sekvenční download + resume + jasná rozhodovací matice. Paralelizace se vyplatí až tehdy, když máš prokázanou stabilní podporu Range a konkrétní měření ukážou, že omezení skutečně leží v síti nebo na serveru.

Debugging, který přinese jasno za 5 minut

Chyby při obnovení přenosu jsou zřídkakdy „jen špatný if“. Obvykle jde o kombinaci infrastruktury (Proxy/CDN), konfigurace serveru, timeoutů a lokálního stavu. Proto se vyplatí strukturované protokolování pro každý pokus. Ne jako textová zeď, ale jako konzistentní pole:

  • Požadavek: URL (bez tajných údajů), metoda, Range (start/konec), If-Range (ETag nebo datum).
  • Odpověď: Stavový kód, Accept-Ranges, ETag, Last-Modified, Content-Length, Content-Range (surový a parsovaný).
  • Lokální stav: cesta k části (.part), délka části před požadavkem, režim zápisu (Append/Overwrite), délka po zápisu.
  • Rozhodnutí: „Resume accepted“, „Resume rejected (200) – RESTart“, „416 – reset“, „Validator mismatch – RESTart“.

Pomocí právě těchto dat můžeš testovat hypotézy: „Server ignoruje Range?“, „Mění se ETag mezi požadavky?“, „Je offset špatně určen?“, „Zapisuje současně druhý proces?“ – aniž bys musel vytahovat Wireshark.

Kdy vědomě neimplementovat obnovení

Nejčistší architektonické rozhodnutí může být někdy nezařadit obnovení – nikoli ze snadnosti, ale protože ve tvém scénáři přináší více povrchů pro chyby než užitku:

  • URL bez vázání na verzi: Pokud se pod stejnou URL pravidelně objevuje nový obsah, je obnovení bez silného validátoru riziko integrity.
  • Žádné použitelné validátory: Pokud ani ETag ani Last-Modified nejsou konzistentní, je „pokračování“ sázkou. U kritických importů je to často horší než kontrolovaný RESTart.
  • Stažení malé a časté: Zde jsou přehlednější retry strategie (timeout, backoff, případně mirror-URL) udržovatelnější a v provozu snáze vysvětlitelné.

Pragmatická bezpečnostní síť, která se vyplatí

Karanténa místo mazání

Pokud se pokus o resume nezdaří, neodstraňuj reflexivně .part. Přejmenuj ji (např. .part.bad + časové razítko). To odkryje problémy se serverem/proxy, protože později můžeš porovnat response hlavičky se stavem souboru. A zabráníš tomu, aby vzácný problém „úklidem“ přímo zmizel z analýzy.

Zamykání proti současným startům

Pokud dva procesy současně zapisují do téže .part, jsou všechny HTTP validátory bezcenné. Exkluzivní lock (file lock nebo systémový mutex) není proto luxus, ale základní ochrana. Metadata mohou navíc nést informaci o vlastníkovi (ID instance), aby jsi mohl „opuštěná“ stahování spolehlivě rozpoznat a uklidit.

Krátká pravidla, která opravdu potřebuješ

  • Připojovat (Append) pouze při 206 – a jen s ověřeným Content-Range (jednotka bytes, počáteční offset sedí).
  • 200 znamená: začít znovu (overwrite), nikdy nepřipojovat k částečnému souboru.
  • If-Range snižuje míchání verzí, ale nenahrazuje povinnost vyhodnotit stavový kód a Content-Range.
  • 416 je signál resetu: lokální offset už neodpovídá, stav zahodit/umístit do karantény.

Závěr: nejdřív integrita, pak optimalizace

Stahování pomocí HttpClient s podporou obnovení je dobré tehdy, když je nudné: nastaví Range jen pokud je lokální stav spolehlivý, naváže obnovení pouze při odpovědi 206 a ověřeném Content-Range, a zabrání míchání verzí přes If-Range a validátory. Všechno ostatní jsou „vypadá rychle“ funkce, které ti později snědí čas, protože chyby jsou vzácné a pak těžko reprodukovatelné.

Pokud chceš pro updatery, importní toky nebo služby pečlivě nastavit robustní download-pipeline (Resume, Logging, Partial-File-Strategie, Betriebskanten), dá se to často vyřešit krátkou architektonickou kontrolou – včetně otázky, zda se složitost ve tvém prostředí vůbec vyplatí. Kontaktuj a projednej záměr s Net-Base.

Zdroje a další informace

Hlavní odborná tvrzení byla redakčně zařazena na základě následujících externích zdrojů.

  1. RFC 9110: HTTP Semantics (www.rfc-editor.org)
    HTTP Range-Requests jsou volitelné; servery mohou Range ignorovat a odpovědět jako při běžném GET, proto musí klient vyhodnotit statusový kód a hlavičky místo slepého navázání.
  2. HTTP range requests – HTTP | MDN (developer.mozilla.org)
    Accept-Ranges je signál podpory Range, ale klienti musí robustně kontrolovat chování odpovědi (206/Content-Range).
  3. RangeHeaderValue Class (System.Net.Http.Headers) | Microsoft Learn (learn.microsoft.com)
    .NET poskytuje třídou RangeHeaderValue typizovanou reprezentaci hlavičky Range; servery nemusí podporovat Range-Requests.

Projednat projekt nebo modernizační záměr s Net-Base.

další krok

Když se z tématu stane reálný projekt, měly by být architektura, stávající systém a provoz posuzovány společně již v rané fázi.

Podporujeme nejen při jednotlivých otázkách, ale i v případě, že se z útržků zdrojového kódu, legacy témat nebo nápadů na portál má vyvinout robustní podnikový projekt.

  • Současný stav, cílový stav a technická rizika jsou hodnoceny společně.
  • REST, přístup k datům, portály a rollout nebudou přesunuty do pozdějších fází.
  • Včas zjistíte, která varianta je ekonomicky i provozně životaschopná.

Sdílet příspěvek

Sdílet tento příspěvek přímo

LinkedIn, X, XING, Facebook, WhatsApp a e-mail jsou ihned k dispozici. Pro Instagram připravíme odkaz a krátký text.

E-mail

Instagram se otevře v nové záložce. Odkaz a krátký text budou předtím zkopírovány do schránky.

Napsat komentář

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