Jak sprawić, by serwer zwracał skompresowaną odpowiedź: poradnik krok po kroku dotyczący oszczędzania transferu
Spis treści
- Wprowadzenie: jeden nagłówek potrafi zmniejszyć transfer kilkukrotnie
- Przygotowanie wstępne
- Podstawowe pojęcia w prostych słowach
- Gzip, deflate, brotli, zstd: porównanie algorytmów
- Krok 1: wysyłamy żądanie i sprawdzamy, czy odpowiedź jest skompresowana
- Krok 2: mierzymy rzeczywiste oszczędności w pythonie
- Krok 3: ten sam pomiar w node.js
- Krok 4: dlaczego odpowiedź przychodzi nieskompresowana
- Krok 5: pułapki przy pracy z kompresją
- Krok 6: co nie ma sensu kompresować
- Weryfikacja wyniku
- Typowe błędy i rozwiązania
- Dodatkowe możliwości
- Faq
- Podsumowanie
Jeden nagłówek w żądaniu HTTP może zmniejszyć ilość pobieranych danych nawet kilkukrotnie. Mowa o negocjowaniu kompresji między klientem a serwerem. Jeśli pracujesz z proxy i płacisz za każdy gigabajt transferu, ten temat ma bezpośredni wpływ na Twój rachunek. W tym poradniku pokażemy, jak sprawić, by serwer zwracał skompresowaną odpowiedź, jak zmierzyć realne oszczędności w Twoim projekcie i jakie pułapki na Ciebie czekają.
Wprowadzenie: jeden nagłówek potrafi zmniejszyć transfer kilkukrotnie
Kompresja HTTP działa zaskakująco prosto. Klient informuje serwer, jakie algorytmy kompresji rozumie. Serwer wybiera odpowiedni, kompresuje treść odpowiedzi i wysyła ją. Klient rozpakowuje dane po swojej stronie. W rezultacie przez sieć przesyłany jest nie oryginalny HTML czy JSON, ale jego skompresowana wersja, która często waży trzy do pięciu razy mniej.
Co zyskasz po przeczytaniu. Po przeczytaniu tego poradnika będziesz umiał włączyć kompresję po stronie klienta, sprawdzić, czy serwer faktycznie zwraca skompresowaną odpowiedź, zmierzyć oszczędności transferu w bajtach przed i po, a także diagnozować sytuacje, w których kompresja z jakiegoś powodu nie działa. To wszystko jest kluczowe, gdy przesyłasz ruch przez proxy Proxeon i płacisz za gigabajty.
Dla kogo jest ten poradnik. Materiał jest przeznaczony dla deweloperów, specjalistów od scrapowania, inżynierów automatyzacji i wszystkich, którzy piszą klienty do pracy z HTTP przez proxy. Poziom średniozaawansowany. Nie będziemy omawiać, z czego ogólnie składa się zużycie transferu. Temu poświęcony jest osobny artykuł. Tutaj skupimy się wyłącznie na kompresji.
Co musisz wiedzieć wcześniej. Wystarczy podstawowe zrozumienie, czym jest żądanie i odpowiedź HTTP, czym są nagłówki i jak uruchomić polecenie w terminalu. Jeśli kiedykolwiek wykonywałeś żądanie przez curl lub pisałeś skrypt w Pythonie albo Node.js, poradzisz sobie bez trudu.
Ile czasu to zajmie. Przeczytanie i powtórzenie wszystkich przykładów zajmie około sześćdziesięciu minut. Pierwsze praktyczne rezultaty zobaczysz już po dziesięciu minutach, gdy porównasz rozmiar skompresowanej i nieskompresowanej odpowiedzi na własne oczy.
Przygotowanie wstępne
Zanim zaczniesz, upewnij się, że masz wszystko, czego potrzebujesz. To zaoszczędzi czas i uchroni Cię przed błędami w trakcie.
Wymagane narzędzia
- curl w wersji 7.72 lub nowszej. W wydaniach z 2026 roku brotli i zstd są domyślnie obsługiwane na większości systemów.
- Python w wersji 3.10 lub nowszej z zainstalowaną biblioteką requests, a do brotli dodatkowo pakiet brotli lub brotlicffi.
- Node.js w wersji 18 lub nowszej. Moduł zlib jest wbudowany i obsługuje gzip, deflate, brotli.
- Dostęp do proxy Proxeon, jeśli chcesz mierzyć oszczędności dokładnie w tych warunkach, w jakich pracujesz na co dzień.
- Dowolny edytor tekstu do pisania skryptów.
Wymagania systemowe
Nadaje się każdy nowoczesny system: Windows, macOS lub Linux. Wszystkie przykłady są wieloplatformowe. Dwa gigabajty pamięci RAM wystarczą. Nie ma specjalnych wymagań co do procesora, choć przy kompresji dużych wolumenów algorytm brotli na maksymalnym poziomie może zauważalnie obciążyć jedno rdzeń.
Co zainstalować i sprawdzić
- Otwórz terminal i wykonaj polecenie sprawdzające wersję curl:
curl --version - Spójrz na pierwszą linię wyniku. Jest tam podana wersja. Upewnij się, że na liście możliwości znajduje się brotli i, jeśli to możliwe, zstd.
- Sprawdź Pythona poleceniem
i zainstaluj zależności:python --versionpip install requests brotli - Sprawdź Node.js poleceniem
node --version
Wskazówka: Jeśli curl w Twoim systemie został zbudowany bez brotli, zainstaluj go przez oficjalny menedżer pakietów swojego systemu operacyjnego. W korporacyjnych wydaniach z 2026 roku brotli prawie zawsze jest włączony domyślnie.
Kopie zapasowe. W tym poradniku nie zmieniamy konfiguracji działających serwerów ani nie dotykamy produkcyjnych danych. Wysyłamy tylko żądania i mierzymy odpowiedzi. Dlatego kopie zapasowe nie są wymagane. Jeśli jednak później zdecydujesz się włączyć kompresję na własnym serwerze WWW, koniecznie zapisz oryginalny plik konfiguracyjny przed jego edycją.
✅ Weryfikacja: Wszystkie trzy narzędzia odpowiadają na polecenie sprawdzające wersję i pokazują numer. Oznacza to, że przygotowanie jest zakończone, możesz przejść dalej.
Podstawowe pojęcia w prostych słowach
Zanim zaczniesz naciskać przyciski, wyjaśnijmy terminologię. To zajmie pięć minut, ale uchroni Cię przed zamieszaniem w dalszej części.
Jak działa negocjowanie kompresji
Kompresja HTTP opiera się na trzech nagłówkach. Zrozumienie ich roli rozwiązuje większość problemów.
Accept-Encoding u klienta. To nagłówek, który Twój klient wysyła wraz z żądaniem. Wymienia algorytmy kompresji, które klient potrafi rozpakować. Na przykład, ciąg
Accept-Encoding: gzip, br, zstd mówi serwerowi: zrozumiem gzip, brotli lub zstd, wybierz dowolny z nich. Jeśli tego nagłówka nie ma, serwer zakłada, że klient chce odpowiedź nieskompresowaną.Content-Encoding w odpowiedzi. To nagłówek, który serwer dodaje do swojej odpowiedzi. Informuje, jakim algorytmem dokładnie skompresowano treść. Jeśli widzisz
Content-Encoding: br oznacza to, że treść jest skompresowana algorytmem brotli i klient musi ją rozpakować. Jeśli tego nagłówka nie ma w odpowiedzi, treść przyszła w oryginalnej formie.Vary po stronie serwera. Nagłówek Vary mówi pamięciom podręcznym i proxy, że odpowiedź zależy od określonych nagłówków żądania. Dla kompresji krytyczna jest wartość
Vary: Accept-Encoding. Oznacza ona, że dla klienta z gzip i dla klienta bez kompresji powinny być przechowywane różne wersje w pamięci podręcznej. Bez tego nagłówka pamięć podręczna może zwrócić skompresowaną odpowiedź klientowi, który nie umie jej rozpakować, i odwrotnie.Kluczowa idea negocjacji
Zapamiętaj sekwencję. Klient prosi przez Accept-Encoding. Serwer decyduje i odpowiada przez Content-Encoding. Pośrednie ogniwa kierują się nagłówkiem Vary. Jeśli choć jedno ogniwo tego łańcucha jest zerwane, otrzymasz nieskompresowaną odpowiedź i przepłacisz za transfer.
Wskazówka: Nawet jeśli Twoja biblioteka HTTP automatycznie dodaje Accept-Encoding, zawsze sprawdzaj faktyczny nagłówek odpowiedzi. Automatyka czasem milczy, a transfer ucieka.
gzip, deflate, brotli, zstd: porównanie algorytmów
Istnieją cztery popularne algorytmy kompresji dla HTTP. Różnią się stopniem kompresji i obciążeniem procesora. Omówimy każdy z nich i zestawimy liczby w tabeli.
gzip
Najstarszy i najbardziej uniwersalny. Obsługiwany absolutnie wszędzie: każdy serwer, każdy klient, każde proxy. Zapewnia dobrą kompresję danych tekstowych przy umiarkowanym obciążeniu. Jeśli nie wiesz, co wybrać, zacznij od gzip.
deflate
Bliski krewny gzip, wewnątrz używa tego samego algorytmu, ale z inną otoczką. W praktyce spotykany rzadziej i czasem błędnie zaimplementowany na serwerach. Stopień kompresji podobny do gzip. Nie ma szczególnych powodów, aby wybierać deflate zamiast gzip.
brotli
Nowoczesny algorytm zaprojektowany specjalnie dla sieci. Na danych tekstowych kompresuje zauważalnie lepiej niż gzip, szczególnie HTML, CSS i JSON. Ceną za to jest wyższe obciążenie procesora przy maksymalnych poziomach kompresji. Dekompresja jest szybka. Oznaczany w nagłówkach jako br.
zstd
Szybki, nowoczesny algorytm z elastyczną konfiguracją poziomów. Daje stopień kompresji porównywalny z brotli, ale działa szybciej pod względem szybkości kompresji. Wsparcie w sieci rośnie, do 2026 roku większość aktualnych serwerów i klientów go rozumie. Oznaczany jako zstd.
Tabela porównawcza dla typowej odpowiedzi tekstowej
Weźmy przykładową odpowiedź JSON o rozmiarze 1000 kilobajtów w wersji nieskompresowanej. Liczby są orientacyjne, zależą od treści, ale oddają właściwy porządek wielkości.
- Bez kompresji: 1000 KB, oszczędność 0 procent, minimalne obciążenie procesora.
- gzip poziom 6: około 190 KB, oszczędność około 81 procent, niskie obciążenie.
- deflate poziom 6: około 195 KB, oszczędność około 80 procent, niskie obciążenie.
- brotli poziom 5: około 165 KB, oszczędność około 83 procent, średnie obciążenie.
- brotli poziom 11: około 140 KB, oszczędność około 86 procent, wysokie obciążenie.
- zstd poziom 3: około 175 KB, oszczędność około 82 procent, niskie obciążenie.
- zstd poziom 19: około 150 KB, oszczędność około 85 procent, średnie obciążenie.
Wniosek jest prosty. Na danych tekstowych każda kompresja zmniejsza transfer około pięciokrotnie. Różnica między algorytmami wynosi kilka procent. Dlatego dla oszczędzania transferu przez proxy najważniejszy jest nie konkretny algorytm, ale sam fakt, że kompresja jest włączona.
Wskazówka: Jeśli tylko pobierasz dane, a nie wysyłasz, obciążenie Twojego procesora dotyczy tylko dekompresji, a ta jest szybka we wszystkich algorytmach. Możesz więc śmiało prosić o najkorzystniejszy pod względem stopnia kompresji wariant.
✅ Weryfikacja: Rozumiesz, że brotli i zstd są zwykle nieco skuteczniejsze niż gzip na tekście, ale gzip jest najbardziej kompatybilny. To wystarczy do praktyki.
Krok 1: Wysyłamy żądanie i sprawdzamy, czy odpowiedź jest skompresowana
Cel etapu. Nauczyć się widzieć nagłówki Content-Encoding i rzeczywisty rozmiar treści. Bez tego nie można zmierzyć oszczędności.
Sprawdzenie przez curl
- Otwórz terminal.
- Najpierw zapytaj o zasób bez kompresji, aby poznać oryginalny rozmiar. Wykonaj:
curl -s -o /dev/null -w "%{size_download}" https://example.com/api/data - Zanotuj liczbę. To rozmiar nieskompresowanej odpowiedzi w bajtach.
- Teraz poproś o kompresję. Flaga --compressed automatycznie dodaje Accept-Encoding i rozpakowuje odpowiedź:
curl -s --compressed -o /dev/null -w "%{size_download}" https://example.com/api/data - Porównaj dwie liczby. Druga powinna być zauważalnie mniejsza przy tej samej treści.
Ważne: Wskaźnik size_download w curl przy użyciu --compressed odzwierciedla rozmiar już rozpakowanych danych, a nie to, ile przeszło przez sieć. Aby zobaczyć rzeczywisty wolumen sieciowy, użyj nagłówka odpowiedzi i pomiarów pośrednich, o których powiemy w kroku pomiaru.
Patrzymy na nagłówki odpowiedzi
- Wykonaj żądanie z flagą wyświetlającą nagłówki:
curl -s -I --compressed https://example.com/api/data - Znajdź w wyniku linię Content-Encoding. Jeśli jest tam gzip, br lub zstd, serwer zwrócił skompresowaną odpowiedź.
- Znajdź linię Vary. Obecność Accept-Encoding w niej oznacza poprawną konfigurację buforowania.
Wskazówka: Aby jawnie wskazać konkretny algorytm, dodaj nagłówek ręcznie:
curl -s -H "Accept-Encoding: br" -I https://example.com/api/data W ten sposób sprawdzisz, czy serwer obsługuje właśnie brotli.Praca przez proxy Proxeon
Aby mierzyć oszczędności w rzeczywistych warunkach, skieruj żądanie przez proxy. W curl robi się to flagą -x:
curl -s --compressed -x http://login:hasło@adres_proxeon:port -o /dev/null -w "%{size_download}" https://example.com/api/dataW ten sposób zobaczysz, czy kompresja przechodzi przez proxy i czy coś nie wycina nagłówków po drodze.
Oczekiwany rezultat. Widzisz dwie liczby: rozmiar bez kompresji i rozmiar z kompresją. Widzisz też nagłówek Content-Encoding w odpowiedzi. To oznacza, że mechanizm działa.
Możliwy problem: jeśli obie liczby są takie same i brakuje Content-Encoding, serwer nie zwrócił kompresji. Przyczyny omówimy w osobnym rozdziale.
✅ Weryfikacja: W odpowiedzi z flagą --compressed występuje linia Content-Encoding z jednym z algorytmów. Krok wykonany.
Krok 2: Mierzymy rzeczywiste oszczędności w Pythonie
Cel etapu. Uzyskać dokładne liczby ruchu sieciowego przed i po kompresji za pomocą działającego skryptu, który można zastosować do własnego zadania.
Prosty pomiar przez requests
Biblioteka requests domyślnie sama dodaje Accept-Encoding i rozpakowuje odpowiedź. Aby zmierzyć dokładnie rozmiar sieciowy, spojrzymy na długość surowej treści przed rozpakowaniem.
- Utwórz plik measure.py.
- Wklej następujący kod:
import requests
url = "https://example.com/api/data"
# Żądanie bez kompresji
r_plain = requests.get(url, headers={"Accept-Encoding": "identity"})
size_plain = len(r_plain.content)
# Żądanie z kompresją
r_comp = requests.get(url, headers={"Accept-Encoding": "gzip, br, zstd"})
encoding = r_comp.headers.get("Content-Encoding", "brak")
size_wire = int(r_comp.headers.get("Content-Length", 0))
size_body = len(r_comp.content)
print("Bez kompresji, bajty:", size_plain)
print("Algorytm kompresji:", encoding)
print("Przez sieć około, bajty:", size_wire)
print("Po rozpakowaniu, bajty:", size_body)
if size_plain and size_wire:
saved = 100 - size_wire * 100
print("Oszczędność transferu, procenty:", saved)Uwaga: Wartość Content-Length nie zawsze jest obecna, zwłaszcza przy transmisji strumieniowej chunked. Jeśli jej brak, użyj dokładniejszej metody poniżej.
Dokładny pomiar wolumenu sieciowego
Aby zmierzyć dokładnie to, co przeszło przez sieć, wyłącz automatyczne rozpakowywanie i policz bajty surowego strumienia.
import requests
url = "https://example.com/api/data"
sess = requests.Session()
# Wyłączamy auto-rozpakowywanie, aby zobaczyć surowy rozmiar
r = sess.get(url, headers={"Accept-Encoding": "gzip, br, zstd"}, stream=True)
raw_bytes = 0
for chunk in r.raw.stream(8192, decode_content=False):
raw_bytes += len(chunk)
print("Algorytm:", r.headers.get("Content-Encoding", "brak"))
print("Surowe bajty przez sieć:", raw_bytes)Porównaj raw_bytes z rozmiarem nieskompresowanego żądania. Różnica to Twoje rzeczywiste oszczędności.
Pomiar przez proxy Proxeon
Dodaj parametr proxies, aby uzyskać liczby w warunkach produkcyjnych:
proxies = {
"http": "http://login:hasło@adres_proxeon:port",
"https": "http://login:hasło@adres_proxeon:port",
}
r = sess.get(url, headers={"Accept-Encoding": "gzip, br, zstd"}, proxies=proxies, stream=True)Wskazówka: Przepuść pomiar kilka razy i uśrednij. Dynamiczne odpowiedzi zmieniają rozmiar, więc pojedynczy pomiar może wprowadzić w błąd.
Oczekiwany rezultat. Skrypt wypisuje algorytm kompresji i liczbę surowych bajtów, która jest mniejsza niż rozmiar nieskompresowanej odpowiedzi. Jeśli oszczędność wynosi siedemdziesiąt i więcej procent na zasobie tekstowym, wszystko działa prawidłowo.
✅ Weryfikacja: W wyniku algorytm nie jest równy słowu brak, a surowych bajtów jest mniej niż bez kompresji. Świetnie.
Krok 3: Ten sam pomiar w Node.js
Cel etapu. Uzyskać działające narzędzie pomiarowe w JavaScript dla tych, którzy piszą klienty w Node.
Pomiar surowego strumienia
- Utwórz plik measure.js.
- Wklej kod, który liczy bajty przed rozpakowaniem:
const https = require('https');
const url = 'https://example.com/api/data';
function measure(acceptEncoding) {
return new Promise((resolve) => {
const req = https.get(url, { headers: { 'Accept-Encoding': acceptEncoding } }, (res) => {
let bytes = 0;
res.on('data', (chunk) => { bytes += chunk.length; });
res.on('end', () => {
resolve({ enc: res.headers['content-encoding'] || 'brak', bytes });
});
});
req.end();
});
}
(async () => {
const plain = await measure('identity');
const comp = await measure('gzip, br, zstd');
console.log('Bez kompresji, bajty:', plain.bytes);
console.log('Algorytm:', comp.enc);
console.log('Skompresowano przez sieć, bajty:', comp.bytes);
const saved = Math.round(100 - (comp.bytes * 100) / plain.bytes);
console.log('Oszczędność, procenty:', saved);
})();Ważne: W tym przykładzie czytamy surowy strumień z res i nie podłączamy zlib. Oznacza to, że licznik bytes pokazuje dokładnie wolumen sieciowy. To jest dokładnie to, za co płacisz dostawcy proxy.
Ręczne rozpakowywanie w Node
Jeśli potrzebujesz również przeczytać zawartość, rozpakuj strumień za pomocą wbudowanego modułu zlib:
const zlib = require('zlib');
let stream = res;
const enc = res.headers['content-encoding'];
if (enc === 'gzip') stream = res.pipe(zlib.createGunzip());
else if (enc === 'br') stream = res.pipe(zlib.createBrotliDecompress());
else if (enc === 'deflate') stream = res.pipe(zlib.createInflate());Wskazówka: Dla zstd w najnowszych wersjach Node.js istnieje zlib.createZstdDecompress. Jeśli Twoja wersja go nie zawiera, zaktualizuj Node lub użyj osobnego pakietu npm.
Oczekiwany rezultat. Node wypisuje oszczędność w procentach, porównywalną z tym, co uzyskałeś w Pythonie i curl.
✅ Weryfikacja: Trzy narzędzia dają zbliżone liczby oszczędności. Oznacza to, że Twoje pomiary są wiarygodne.
Krok 4: Dlaczego odpowiedź przychodzi nieskompresowana
Cel etapu. Nauczyć się diagnozować, dlaczego kompresja nie zadziałała, i usuwać przyczynę. To najczęstszy problem w praktyce.
Przypadek pierwszy: klient nie poprosił
Najczęstsza przyczyna. Twój klient HTTP nie wysłał nagłówka Accept-Encoding, a serwer uczciwie zwrócił nieskompresowaną odpowiedź. Tak bywa, gdy ręcznie formujesz nagłówki i zapominasz o kompresji, albo gdy używasz niskopoziomowego gniazda.
- Sprawdź, co dokładnie trafia na serwer. W curl dodaj flagę -v i znajdź linię z Accept-Encoding w nagłówkach wychodzących.
- Jeśli linii nie ma, dodaj ją jawnie przez -H lub flagę --compressed.
- W Pythonie upewnij się, że nie nadpisałeś nagłówka pustą wartością.
Uwaga: Niektóre biblioteki, gdy ręcznie ustawisz jakikolwiek nagłówek, przestają dodawać swoje domyślne wartości. Jeśli ręcznie ustawiasz User-Agent, sprawdź, czy Accept-Encoding nie zniknął przy okazji.
Przypadek drugi: serwer nie umie
Serwer może w ogóle nie wspierać kompresji albo nie wspierać żądanego algorytmu. Wtedy zwraca nieskompresowaną odpowiedź, co jest zgodne ze standardem.
- Poproś o różne algorytmy po kolei: najpierw gzip, potem br, potem zstd.
- Sprawdź, przy którym z nich pojawia się Content-Encoding w odpowiedzi.
- Jeśli przy żadnym, serwer nie obsługuje kompresji. Na obcym serwerze nie możesz tego zmienić, ale możesz wybrać inny endpoint lub API, jeśli istnieje.
Wskazówka: Wiele API zwraca kompresję tylko dla odpowiedzi większych niż określony rozmiar. Małe odpowiedzi serwer często zostawia nieskompresowane celowo, ponieważ narzut na kompresję przewyższa korzyści.
Przypadek trzeci: pośrednik wyciął nagłówek
Między Tobą a serwerem może stać węzeł buforujący, brama lub proxy, które usuwa lub zmienia nagłówki kompresji. Czasem pośrednik rozpakowuje odpowiedź na własne potrzeby i oddaje Ci już rozpakowany wariant.
- Wykonaj żądanie bezpośrednio i przez proxy, porównaj nagłówki Content-Encoding.
- Jeśli bezpośrednio kompresja jest, a przez pośrednika nie ma, to pośrednik ingeruje.
- Przy pracy przez proxy Proxeon kompresja jest przekazywana w sposób transparentny, więc jeśli widzisz różnicę, szukaj problemu po stronie serwera docelowego lub jego CDN.
Oczekiwany rezultat. Dokładnie wiesz, na którym z trzech ogniw gubi się kompresja, i rozumiesz, co z tym zrobić.
✅ Weryfikacja: Potrafisz jednym zdaniem wyjaśnić, dlaczego konkretna odpowiedź przyszła nieskompresowana. Diagnostyka opanowana.
Krok 5: Pułapki przy pracy z kompresją
Cel etapu. Uniknąć subtelnych błędów, które psują dane lub zniekształcają pomiary.
Podwójna kompresja
Czasem treść jest już skompresowana na poziomie aplikacji, a serwer kompresuje ją ponownie. Albo odwrotnie: kompresujesz treść żądania, a proxy lub biblioteka robią to ponownie. Podwójna kompresja prawie nie daje zysku, a czasem nawet zwiększa rozmiar i na pewno marnuje procesor.
- Sprawdź, czy w odpowiedzi nie ma dwóch wartości w Content-Encoding, na przykład gzip i br jednocześnie.
- Nie kompresuj ręcznie tego, co biblioteka i tak skompresuje automatycznie.
- Jeśli widzisz łańcuch kodowań, rozpakowuj w odwrotnej kolejności.
Uszkodzony strumień
Przerwanie połączenia lub błąd pośrednika może spowodować, że skompresowany strumień przyjdzie niekompletny. Podczas rozpakowywania otrzymasz błąd lub obcięte dane.
- Zawsze obudowuj rozpakowywanie obsługą błędów.
- Przy błędzie rozpakowywania powtórz żądanie, zamiast czytać uszkodzone dane.
- Porównaj faktyczny rozmiar z Content-Length, jeśli jest podany.
Uwaga: Nigdy nie zapisuj częściowo rozpakowanych danych jako wyniku. Uszkodzony JSON wygląda wiarygodnie, ale doprowadzi do ukrytych błędów dalej w potoku.
Ręczne rozpakowywanie, gdy biblioteka tego nie robi
Jeśli wyłączyłeś auto-rozpakowywanie w celu dokładnego pomiaru lub używasz niskopoziomowego klienta, będziesz musiał rozpakowywać ręcznie. Przykład w Pythonie:
import gzip, brotli, zlib
def decompress(data, encoding):
if encoding == "gzip":
return gzip.decompress(data)
if encoding == "br":
return brotli.decompress(data)
if encoding == "deflate":
return zlib.decompress(data)
return dataWskazówka: Jeśli rozpakowywanie deflate kończy się błędem, spróbuj wywołać zlib.decompress z parametrem wbits równym minus piętnaście. Niektóre serwery zwracają czysty deflate bez otoczki zlib.
Oczekiwany rezultat. Umiesz ręcznie rozpakować każdy z obsługiwanych formatów i poprawnie obsługujesz błędy strumienia.
✅ Weryfikacja: Twój skrypt nie pada na uszkodzonej odpowiedzi, lecz powtarza żądanie. Odporność osiągnięta.
Krok 6: Co nie ma sensu kompresować
Cel etapu. Nie marnować procesora i czasu na kompresję tego, co już jest skompresowane. To oszczędza zasoby bez utraty korzyści w transferze.
Już skompresowane formaty
Niektóre dane są przechowywane w formatach, które wewnętrznie już używają kompresji. Próba ich ponownego skompresowania nie ma sensu: zysk to ułamek procenta, a procesor obciąży się na próżno.
- Obrazy: JPEG, PNG, WebP, AVIF są już skompresowane wewnętrznie.
- Wideo: MP4, WebM, MKV zawierają mocno skompresowany strumień wideo.
- Audio: MP3, AAC, OGG są skompresowane z natury.
- Archiwa: ZIP, RAR, 7z, gz to już skompresowane kontenery.
Dla takich zasobów Accept-Encoding nie da oszczędności w treści. Co więcej, serwer zwykle sam ich nie kompresuje ponownie, bo jest skonfigurowany według listy typów MIME.
Co warto kompresować
- HTML, CSS, JavaScript.
- Odpowiedzi API JSON i XML.
- Zwykły tekst, CSV, logi.
- SVG, ponieważ to w zasadzie tekst.
Wskazówka: Jeśli pobierasz głównie pliki multimedialne, oszczędność z kompresji będzie bliska zeru. Tutaj zysk daje co innego: żądanie tylko potrzebnych rozmiarów i formatów, a nie sam fakt kompresji. Ale to już temat zarządzania transferem, a nie kompresji jako takiej.
Oczekiwany rezultat. Nie marnujesz zasobów na kompresję formatów binarnych i stosujesz kompresję tylko tam, gdzie naprawdę pomaga.
✅ Weryfikacja: Potrafisz w sekundę powiedzieć, czy warto skompresować dany typ odpowiedzi. Zrozumienie ukształtowane.
Weryfikacja wyniku
Czas upewnić się, że wszystko skonfigurowałeś poprawnie. Przejdź przez listę kontrolną.
Lista kontrolna działania
- Twój klient wysyła nagłówek Accept-Encoding z potrzebnymi algorytmami.
- W odpowiedzi występuje Content-Encoding z jednym z tych algorytmów dla zasobów tekstowych.
- Skrypt pomiarowy pokazuje wolumen sieciowy mniejszy niż nieskompresowany co najmniej o siedemdziesiąt procent dla tekstu.
- Przez proxy Proxeon kompresja jest zachowana, liczby zgadzają się z bezpośrednim żądaniem.
- Rozpakowywanie nie generuje błędów, a dane czytają się poprawnie.
- Formatów binarnych nie próbujesz kompresować.
Jak przetestować
- Weź trzy różne endpointy: jeden z JSON, jeden z HTML, jeden z obrazem.
- Przepuść każdy przez swój skrypt pomiarowy.
- Upewnij się, że na pierwszych dwóch oszczędność jest wysoka, a na trzecim bliska zeru.
Wskaźniki sukcesu. Dla tekstowego API stabilnie widzisz oszczędność w zakresie od siedemdziesięciu do dziewięćdziesięciu procent. Dla mediów oszczędność jest minimalna i to normalne. Przez proxy liczby nie ulegają pogorszeniu.
✅ Weryfikacja: Wszystkie sześć punktów listy kontrolnej zostało spełnionych. Kompresja jest skonfigurowana i zmierzona poprawnie.
Typowe błędy i rozwiązania
Poniżej zebraliśmy częste problemy w formacie: problem, przyczyna, rozwiązanie.
Odpowiedź nie jest kompresowana, mimo że Accept-Encoding został wysłany
Przyczyna: serwer nie obsługuje kompresji dla tego typu treści lub dla odpowiedzi o takim rozmiarze. Rozwiązanie: spróbuj innego algorytmu i upewnij się, że zasób jest tekstowy i wystarczająco duży.
Oszczędności w curl nie widać, size_download się nie zmienia
Przyczyna: flaga --compressed pokazuje rozmiar po rozpakowaniu. Rozwiązanie: mierz wolumen sieciowy osobnym skryptem bez auto-rozpakowywania, jak w krokach z Pythonem i Node.
Biblioteka zwraca śmieci zamiast tekstu
Przyczyna: wyłączyłeś auto-rozpakowywanie, ale nie rozpakowałeś strumienia ręcznie. Rozwiązanie: określ Content-Encoding i zastosuj odpowiednią funkcję rozpakowującą.
Błąd przy rozpakowywaniu deflate
Przyczyna: serwer zwrócił surowy deflate bez otoczki. Rozwiązanie: wywołaj rozpakowywanie z parametrem wbits minus piętnaście.
Przez proxy kompresja znika
Przyczyna: na ścieżce stoi węzeł zmieniający nagłówki, najczęściej CDN docelowej witryny. Rozwiązanie: porównaj bezpośrednie żądanie i żądanie przez proxy, zidentyfikuj ogniwo. Proxy Proxeon przekazuje nagłówki w sposób transparentny, więc problem zwykle leży po stronie serwera.
Różny rozmiar odpowiedzi przy powtórzonych pomiarach
Przyczyna: treść jest dynamiczna i zmienia się między żądaniami. Rozwiązanie: uśredniaj kilka pomiarów i porównuj przy identycznych parametrach żądania.
Content-Length nie występuje
Przyczyna: transmisja strumieniowa chunked nie podaje długości z góry. Rozwiązanie: licz bajty ręcznie w miarę czytania strumienia, jak w przykładach skryptów.
Podwójna kompresja obciąża procesor
Przyczyna: treść jest kompresowana dwukrotnie na różnych poziomach. Rozwiązanie: usuń ręczną kompresję tam, gdzie robi ją biblioteka lub serwer.
Dodatkowe możliwości
Kiedy opanujesz podstawowy scenariusz, jest pole do rozwoju.
Wybór priorytetu algorytmów
W nagłówku Accept-Encoding można podać wagę przez wartości q, podpowiadając serwerowi preferencje. Na przykład
Accept-Encoding: zstd;q=1.0, br;q=0.9, gzip;q=0.8 prosi o zstd, jeśli to możliwe, potem brotli, potem gzip. Nie wszystkie serwery uwzględniają wagi, ale wiele respektuje kolejność.Buforowanie rozpakowanych danych
Jeśli wielokrotnie odwołujesz się do tego samego zasobu, buforuj rozpakowany wynik po swojej stronie. To zmniejsza zarówno transfer, jak i obciążenie procesora od ponownego rozpakowywania.
Masowy pomiar według listy URL
Owiń skrypt pomiarowy w pętlę po liście endpointów i zbierz tabelę oszczędności. Dzięki temu znajdziesz najcięższe nieskompresowane odpowiedzi w swoim projekcie i zajmiesz się nimi w pierwszej kolejności.
Wskazówka: Prowadź dziennik oszczędności w bajtach na dobę. Pomnożone przez cenę gigabajta dadzą wymierną korzyść finansową z włączonej kompresji przy pracy przez proxy.
✅ Weryfikacja: Potrafisz zebrać zbiorczą tabelę oszczędności dla kilku zasobów jednym uruchomieniem skryptu.
FAQ
Czy zawsze należy prosić o brotli zamiast gzip?
Jeśli tylko pobierasz, dekompresja we wszystkich algorytmach jest szybka, więc możesz prosić o najbardziej efektywny. W praktyce w Accept-Encoding podaj wszystkie trzy: gzip, br, zstd. Serwer wybierze najlepszy z dostępnych.
Ile transferu oszczędza kompresja w API tekstowym?
Zwykle od siedemdziesięciu do dziewięćdziesięciu procent. To znaczy, że odpowiedź, która ważyła gigabajt, przejdzie przez sieć jako sto pięćdziesiąt lub dwieście megabajtów. Oszczędność przy płatności za gigabajty jest bezpośrednia i zauważalna.
Czy kompresja wpływa na szybkość odpowiedzi?
Mniejsza ilość danych przesyła się szybciej, zwłaszcza na wolnych łączach. Niewielkie opóźnienie na kompresję po stronie serwera zwykle z nawiązką rekompensuje skrócenie czasu transmisji.
Dlaczego curl pokazuje taki sam rozmiar z flagą kompresji i bez?
Ponieważ --compressed wyświetla rozmiar już rozpakowanego ciała. Rzeczywisty wolumen sieciowy jest mniejszy. Mierz surowy strumień osobnym skryptem.
Czy można skompresować treść żądania POST?
Tak, w tym celu klient ustawia Content-Encoding w żądaniu, ale serwer musi umieć je rozpakować. Nie wszystkie serwery to obsługują, więc sprawdź dokumentację API.
Czy kompresja działa przez proxy Proxeon?
Tak. Proxy przekazuje nagłówki Accept-Encoding i Content-Encoding w sposób transparentny, więc wszystkie oszczędności są zachowane. Dlatego warto mierzyć od razu przez proxy, w warunkach produkcyjnych.
Co zrobić, jeśli serwer nie zwraca kompresji?
Upewnij się, że prosisz o kompresję i że zasób jest tekstowy. Jeśli serwer nadal milczy, nie możesz zmienić obcego serwera, ale możesz wybrać inny endpoint lub skompresować dane na swojej warstwie buforującej.
Czy warto kompresować obrazy przez Accept-Encoding?
Nie. Formaty takie jak JPEG i WebP są już skompresowane. Dodatkowa kompresja nie da zysku i tylko obciąży procesor.
Jak wybrać między zstd a brotli?
Przy pobieraniu różnica w transferze wynosi kilka procent. Podawaj oba w Accept-Encoding i pozwól serwerowi zdecydować. Jeśli serwer obsługuje tylko jeden, otrzymasz właśnie ten.
Czy Vary jest potrzebny przy pracy klienta?
Jako klient nie ustawiasz Vary, to serwer go ustawia. Ale warto go rozumieć: wyjaśnia, dlaczego pamięć podręczna czasem zwraca wariant skompresowany, a czasem nieskompresowany.
Podsumowanie
Przeszedłeś drogę od teorii do działających pomiarów. Teraz rozumiesz, jak negocjowana jest kompresja przez Accept-Encoding, Content-Encoding i Vary. Umiesz prosić o kompresję w curl, Pythonie i Node.js, a przede wszystkim mierzyć rzeczywisty wolumen sieciowy przed i po. Wiesz, dlaczego odpowiedź czasem przychodzi nieskompresowana i jak diagnozować to według trzech typowych przyczyn. Zapoznałeś się z pułapkami: podwójną kompresją, uszkodzonym strumieniem i ręcznym rozpakowywaniem. I nie marnujesz już zasobów na kompresję obrazów, wideo i archiwów.
Co dalej. Przepuść skrypt pomiarowy przez wszystkie główne endpointy swojego projektu. Znajdź te, gdzie kompresja nie jest włączona, i poproś o nią jawnie. Prowadź dziennik zaoszczędzonych bajtów, aby widzieć korzyść finansową przy pracy przez proxy Proxeon. Kiedy opanujesz podstawowy scenariusz, przejdź do masowego pomiaru po liście URL i priorytetów algorytmów przez wartości q.
Kompresja to jeden z najtańszych sposobów na obniżenie rachunku za transfer. Jeden poprawnie wysłany nagłówek potrafi zmniejszyć ilość danych kilkukrotnie. Teraz to narzędzie jest w Twoich rękach i możesz je stosować świadomie, z dokładnymi liczbami.