# curl --compressed: какие клиенты не запрашивают сжатие

Source: https://ipvolt.com/ru/guides/curl-compressed-accept-encoding
Markdown: https://ipvolt.com/ru/guides/curl-compressed-accept-encoding.md
Language: ru

[ipvolt — главная](https://ipvolt.com/ru.md) / [Руководства](https://ipvolt.com/ru/guides.md) / curl --compressed: какие клиенты не запрашивают сжатие

Интеграция
Проверено: 2026-09-27
Опубликовано: 2026-09-27
20 мин чтения
Автор: ipvolt

curl, Wget 1.x, urllib, node:http, PHP curl, Guzzle и java.net.http.HttpClient по умолчанию не шлют Accept-Encoding или шлют identity. Проверенные решения, замер байтов.

curl не отправляет заголовок `Accept-Encoding`, пока вы не передадите `--compressed`. GNU Wget 1.x и `urllib.request` в Python отправляют `Accept-Encoding: identity`, а `node:http` в Node, ext-curl в PHP, Guzzle и `java.net.http.HttpClient` в Java не отправляют этот заголовок вовсе. Сервер, который сжимает ответ только по запросу, возвращает им полный несжатый текст, и каждый из этих байтов проходит через ваш прокси. Requests, httpx, aiohttp, Scrapy, встроенный `fetch` в Node, axios, got, Go и браузеры уже запрашивают сжатие: для них включать нечего, и разве что необязательный декодер br ещё немного сократит объём некоторых страниц.

Каждое значение по умолчанию ниже зафиксировано в локальной лаборатории, которую ipvolt провёл 27 сентября 2026 года; версии указаны под каждой таблицей. Результаты синтетические: сервер и прокси на 127.0.0.1 отдавали локальную тестовую страницу, поэтому ни одно число байтов здесь не получено с публичного сайта и не взято из счёта провайдера.

## Кто запрашивает сжатие по умолчанию

### Не отправляют Accept-Encoding или отправляют identity

Сервер, который сжимает ответ только по запросу, отдаёт этим клиентам несжатый текст. Без заголовка: curl, node:http, node:https, PHP ext-curl, Guzzle, Laravel Http, Java HttpClient. `identity`: Wget, urllib, http.client.

| Клиент | Что сделать |
|---|---|
| curl | Добавьте `--compressed` |
| Wget | Добавьте `--compression=auto` |
| urllib, http.client | Перейдите на Requests или httpx |
| node:http, node:https | Перейдите на `fetch`, got или axios |
| PHP ext-curl | Задайте для `CURLOPT_ACCEPT_ENCODING` значение `''` |
| Guzzle, Laravel Http | Задайте для `decode_content` значение `'gzip'` |
| Java HttpClient | Отправьте `Accept-Encoding: gzip`, распакуйте через `GZIPInputStream` |

Запущенные версии: curl 8.7.1, 8.22.0; Wget 1.25.0; urllib.request, http.client (Python 3.13.15, 3.14.7); node:http, node:https (Node.js 22.23.3, 24.21.0, 26.10.0); PHP 8.5.8 ext-curl (libcurl 8.20.0); Guzzle 8.2.0, Laravel Http 13.33.0; Java 25.0.4.1 HttpClient.

- curl: заданный вручную `-H 'Accept-Encoding: gzip'` отправляется, но тело остаётся сжатым.
- Wget: с `--compression=auto` он отправил `gzip` и декодировал ответ.
- urllib.request и http.client возвращают сжатое тело в том виде, в каком оно пришло.
- node:http и node:https возвращают сжатое тело в том виде, в каком оно пришло.
- PHP ext-curl: при `CURLOPT_ACCEPT_ENCODING`, равном `''`, эта сборка libcurl отправила `deflate, gzip, br, zstd`. Заголовок, заданный вручную, отправляется, но ответ не декодируется.
- Laravel Http: `withOptions(['decode_content' => 'gzip'])`.
- Java HttpClient никогда не декодирует ответ: если он пришёл в gzip, оберните тело в `GZIPInputStream`.

### Уже запрашивают сжатие

Менять ничего не нужно: эти клиенты запрашивают сжатие и декодируют ответ.

| Клиент | Отправляемый заголовок |
|---|---|
| Requests | Python 3.13.15: `gzip, deflate`; Python 3.14.7: `gzip, deflate, zstd` |
| httpx | `gzip, deflate` |
| aiohttp | Python 3.13.15: `gzip, deflate`; Python 3.14.7: `gzip, deflate, zstd` |
| Scrapy | `gzip, deflate, br, zstd` |
| Встроенный fetch в Node.js | Node.js 22.23.3/24.21.0: `br, gzip, deflate`; Node.js 26.10.0: `br, gzip, deflate, zstd` |
| Go net/http | `gzip` |

Запущенные версии: Requests 2.34.2; httpx 0.28.1; aiohttp 3.14.3; Scrapy 2.19.0; встроенный fetch (Node.js 22.23.3, 24.21.0, 26.10.0); Go 1.27.1 net/http.

- Requests: пакет `brotli` добавляет br; на Python 3.13 пакет `backports.zstd` добавляет zstd.
- httpx: пакет `brotli` добавляет br, а пакет `zstandard` добавляет zstd.
- aiohttp: пакет `Brotli` добавляет br; на Python 3.13 пакет `backports.zstd` добавляет zstd.
- Встроенный fetch по `http://`: `gzip, deflate`.
- Go: если задать заголовок самостоятельно, декодирование отключается.

Если ваш клиент уже запрашивает сжатие, подтвердите это проверкой байтов ниже и, прежде чем добавлять какой-либо заголовок вручную, прочитайте раздел о скопированных заголовках браузера. Для изображений, видео и других уже сжатых данных сжатие ничего не даёт, каким бы клиентом вы ни пользовались.

Каждая строка — результат запуска в лаборатории, а не чтения исходного кода: 567 записанных ячеек, ни одна не помечена статусом source-read (прочитано в исходном коде). В [tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md) перечислены записи, на которых основана каждая строка. «Wget» здесь означает GNU Wget 1.x. GNU Wget2 по умолчанию запрашивает все кодирования, с которыми он собран ([wget.c](https://gitlab.com/gnuwget/wget2/-/blob/v2.3.0/src/wget.c#L4306-4331)), а Fedora 40 и новее устанавливает wget2 в качестве команды `wget` ([изменение в Fedora](https://fedoraproject.org/wiki/Changes/Wget2asWget)); это прочитано в исходном коде, Wget2 в лаборатории не запускался.

## curl: заголовка нет, пока вы не передадите --compressed

Обычный `curl URL` вообще не отправляет `Accept-Encoding`. В libcurl параметр [`CURLOPT_ACCEPT_ENCODING`](https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html) по умолчанию равен NULL, а это, согласно документации, значит, что libcurl «не отправляет заголовок `Accept-Encoding:` и не распаковывает полученное содержимое автоматически»; утилита curl меняет этот параметр только для `--compressed`. Ни одна из двух сборок curl в лаборатории не отправила этот заголовок ни напрямую, ни через `http://`-прокси, ни через CONNECT. [curl#11091](https://github.com/curl/curl/issues/11091) показывает то же самое на захвате `nc` для curl 7.88.1.

`--compressed` запрашивает все кодирования, которые умеет декодировать ваша сборка, а затем декодирует ответ:

- Системный curl 8.7.1 в macOS, собранный только с zlib, отправил `deflate, gzip`.
- curl 8.22.0 из Homebrew, собранный с brotli и zstd, отправил `deflate, gzip, br, zstd`.

Чтобы узнать, что запросит ваша сборка, посмотрите строку `Features:` в выводе `curl -V`: `libz` означает gzip и deflate, `brotli` добавляет br, а `zstd` добавляет zstd.

Поможет ли это, решают три детали:

- Это «просьба, а не приказ; сервер может отдать данные сжатыми, а может и нет» ([man-страница](https://curl.se/docs/manpage.html#--compressed)). curl не сообщает об ошибке, если сервер проигнорировал просьбу, и у него нет ключа, который превратил бы такой случай в ошибку ([curl#7516](https://github.com/curl/curl/issues/7516)), поэтому проверяйте байты, как показано ниже.
- Заданный вручную `-H 'Accept-Encoding: gzip'` отправляется, но curl не декодирует ответ. В лаборатории curl вывел поток gzip размером 17 750 байт вместо страницы размером 100 129 байт. Используйте `--compressed`, а не заголовок.
- `--no-compressed` снова отключает сжатие, например после строки `--compressed` в `.curlrc`.

Когда лабораторный сервер отправлял br или zstd, которые сборка из macOS не умеет декодировать, `curl --compressed` завершался с кодом выхода 61:

```text
curl: (61) Unrecognized content encoding type. libcurl understands deflate, gzip content encodings.
```

У распаковки есть собственная цена. man-страница предупреждает, что «даже крошечные передачи могут развернуться и породить огромное количество байтов», и советует `--max-filesize`. Этот параметр останавливает передачу, которая разрастается при распаковке через `--compressed`, только «начиная с 8.20.0» ([man-страница](https://curl.se/docs/manpage.html#--max-filesize)), поэтому системный curl 8.7.1 в macOS он не защищает. Это ограничение задокументировано; в лаборатории оно не проверялось.

Без `--compressed` сервер, который всё равно сжимает ответ, оставляет вас с сырыми байтами gzip, как в [curl#2836](https://github.com/curl/curl/issues/2836); это знакомый случай «бинарного вывода», и `--compressed` его исправляет. Сами флаги прокси описаны в [базовом руководстве по curl](/ru/guides/curl-proxy-setup).

## Python: urllib отправляет identity; Requests, httpx, aiohttp и Scrapy сжимают

- **urllib.request и http.client** отправляют `Accept-Encoding: identity` на CPython 3.13.15 и 3.14.7. http.client добавляет этот заголовок, если вы не задали свой, с комментарием «we don't support encodings such as x-gzip or x-deflate» (мы не поддерживаем кодирования вроде x-gzip или x-deflate) ([client.py](https://github.com/python/cpython/blob/v3.14.7/Lib/http/client.py#L1296-L1299)), и ни один из двух модулей не декодирует ответ. В лаборатории urllib.request возвращал ответы в gzip, br и zstd в том виде, в каком они пришли; http.client, через который urllib.request отправляет свои запросы, запускался только со своим заголовком по умолчанию, так что для http.client этот вывод опирается на исходный код. Если задать заголовок самостоятельно, вы лишь получите сжатые байты, которые придётся декодировать вручную, поэтому лучше сменить клиент. Скрипт, который обязан остаться на стандартной библиотеке, может отправить `Accept-Encoding: gzip` и, когда ответ содержит `Content-Encoding: gzip`, декодировать тело через [`gzip.decompress()`](https://docs.python.org/3.14/library/gzip.html#gzip.decompress); этот путь в лаборатории не запускался.
- **Requests 2.34.2** (с urllib3 2.8.0) берёт значение по умолчанию из urllib3 ([utils.py](https://github.com/psf/requests/blob/v2.34.2/src/requests/utils.py#L91-L93)): `gzip, deflate` на Python 3.13.15 и `gzip, deflate, zstd` на 3.14.7, где urllib3 использует [`compression.zstd`](https://docs.python.org/3.14/library/compression.zstd.html) из стандартной библиотеки. Установка `brotli` добавляет br; на 3.13 `backports.zstd` добавляет zstd. Начиная с urllib3 2.6.0 отдельный пакет `zstandard` больше не включает zstd ([request.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/util/request.py#L22-L41); прочитано в исходном коде, не запускалось). Настройка прокси описана в [руководстве по прокси в Python Requests](/ru/guides/python-requests-proxy).
- **urllib3 сам по себе**, через `urllib3.request()` или `PoolManager`, не добавляет заголовок сжатия. Его путь запроса сводится к http.client ([connection.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/connection.py#L525-L531)), что по исходному коду означает `identity`. Это прочитано в исходном коде; в лаборатории запускался Requests, а не urllib3 отдельно.
- **aiohttp 3.14.3** отправляет `gzip, deflate` на 3.13.15 и `gzip, deflate, zstd` на 3.14.7; `Brotli` добавляет br, а на 3.13 `backports.zstd` добавляет zstd. Из клиентов на Python в этом обзоре только он выбрасывает исключение на кодировании, которое не может декодировать; точное сообщение приведено ниже.
- **Scrapy 2.19.0** отправляет `gzip, deflate, br, zstd` на обеих версиях. Начиная со Scrapy 2.18.0 поддержка brotli и Zstandard обязательна, «поэтому `br` и `zstd` всегда включаются в заголовок `Accept-Encoding` запросов» ([примечания к выпуску](https://github.com/scrapy/scrapy/blob/2.19.0/docs/news.rst)).

### httpx и zstd на Python 3.14

httpx 0.28.1 отправляет `gzip, deflate` на обеих версиях Python. br он добавляет с пакетом `brotli`, а zstd — только со сторонним пакетом `zstandard`; в отличие от Requests и aiohttp, он не использует zstd из стандартной библиотеки Python 3.14 ([_decoders.py](https://github.com/encode/httpx/blob/0.28.1/httpx/_decoders.py#L381-L393)). [Документация HTTPX](https://www.python-httpx.org/) устанавливает оба декодера командой `pip install "httpx[brotli,zstd]"`. Для самого сжатия ничего из этого не нужно, поскольку gzip запрашивается всегда.

Это важно, когда сервер присылает кодирование, которое httpx не умеет декодировать: httpx возвращает сжатые байты и не выбрасывает исключения. На Python 3.14.7 без `zstandard` ответ в zstd дошёл до вызывающего кода как поток zstd размером 19 298 байт. Настройка прокси описана в [руководстве по прокси в HTTPX](/ru/guides/httpx-async-proxy).

## Node.js: встроенный fetch сжимает, node:http — нет

Встроенный `fetch` (undici) выбирает заголовок по схеме URL и линейке релизов ([исходный код, v26.10.0](https://github.com/nodejs/node/blob/v26.10.0/deps/undici/src/lib/web/fetch/index.js#L1562-L1576); [v24.21.0](https://github.com/nodejs/node/blob/v24.21.0/deps/undici/src/lib/web/fetch/index.js#L1514-L1528)):

- URL `https://`: `br, gzip, deflate` в Node.js 22.23.3 и 24.21.0 и `br, gzip, deflate, zstd` в 26.10.0.
- URL `http://`: `gzip, deflate` во всех трёх.
- Любой запрос с заголовком `Range`: `identity` во всех трёх.

Все три декодировали gzip и br. Расходятся они на zstd, в том числе на zstd, который сервер присылает без запроса:

- `fetch` в Node.js 22.23.3 не имеет декодера zstd и вернул сжатые байты без ошибки ([исходный код](https://github.com/nodejs/node/blob/v22.23.3/deps/undici/src/lib/web/fetch/index.js#L2149-L2170)).
- `fetch` в Node.js 24.21.0 декодировал zstd, который не запрашивал. Тело из четырёх склеенных кадров zstd вернулось только в виде первого кадра: 25 033 из 100 129 байт, без ошибки. axios 1.20.0 и got 16.0.0 на Node.js 22.23.3 и 24.21.0 тоже вернули только первый кадр.
- Node.js 26.10.0 декодировал все четыре кадра в `fetch`, axios и got.

`node:http` и `node:https` не отправляют `Accept-Encoding` ни в одном из трёх релизов и никогда не декодируют ответ; базовый HTTP-клиент Node не устанавливает этот заголовок ([_http_client.js](https://github.com/nodejs/node/blob/v26.10.0/lib/_http_client.js)). [Документация zlib](https://nodejs.org/api/zlib.html#compressing-http-requests-and-responses) в Node показывает ручной путь: задать заголовок самостоятельно и пропустить ответ через распаковщик. Переход на `fetch`, got или axios потребует меньше кода.

### Встроенный fetch и пакет node-fetch

npm-пакет `node-fetch` — отдельный клиент со своими значениями по умолчанию ([node-fetch#1556](https://github.com/node-fetch/node-fetch/discussions/1556)). На Node.js 24.21.0 node-fetch 3.3.2 отправил `gzip, deflate, br`, а node-fetch 2.7.0 — `gzip,deflate`, и оба декодировали ответ. axios 1.20.0 отправляет `gzip, compress, deflate, br` и добавляет zstd только с `transitional: { advertiseZstdAcceptEncoding: true }` ([http.js](https://github.com/axios/axios/blob/v1.20.0/lib/adapters/http.js#L54-L57)). got 16.0.0 отправил `gzip, deflate, br, zstd` во всех трёх релизах ([index.ts](https://github.com/sindresorhus/got/blob/v16.0.0/source/core/index.ts#L2248-L2258)). Ни одному из них изменения не нужны. Диспетчер прокси для встроенного `fetch` описан в [руководстве по настройке прокси для fetch в Node.js](/ru/guides/nodejs-fetch-proxy).

## Go, Wget, PHP и Java

### Go net/http запрашивает только gzip

Go 1.27.1 отправляет `Accept-Encoding: gzip`, декодирует ответ и удаляет `Content-Encoding` и `Content-Length` из ответа, который отдаёт вам ([transport.go](https://github.com/golang/go/blob/go1.27.1/src/net/http/transport.go#L199-L207)). Он не отправляет заголовок для запросов `HEAD`, для запросов с заголовком `Range` и при `DisableCompression: true`. Отсюда два следствия:

- Если задать `Accept-Encoding` самостоятельно, декодирование отключается: «if the user explicitly requested gzip it is not automatically uncompressed» (если пользователь явно запросил gzip, ответ не распаковывается автоматически). С `req.Header.Set("Accept-Encoding", "gzip")` лабораторный клиент на Go получил поток gzip размером 17 750 байт.
- В net/http нет декодеров br и zstd. Когда сервер присылал их без запроса, клиент получал сырые байты.

### GNU Wget 1.x отправляет identity

Wget 1.25.0 отправляет `Accept-Encoding: identity`. Для `--compression` руководство говорит о значении «none»: «Это значение по умолчанию» ([руководство](https://www.gnu.org/software/wget/manual/wget.html#HTTP-Options)); в списке команд `.wgetrc` на той же странице значением по умолчанию по-прежнему названо `auto`, но прогон в лаборатории соответствует `none`. С `--compression=auto` Wget отправил `gzip` и декодировал gzip — и больше ничего: br или zstd, присланные без запроса, пришли сырыми. Wget2 ведёт себя иначе, как отмечено выше.

### PHP: Guzzle, Laravel Http и ext-curl не отправляют Accept-Encoding

- **PHP ext-curl** (PHP 8.5.8 с libcurl 8.20.0) ничего не отправляет, потому что у `CURLOPT_ACCEPT_ENCODING` «значение по умолчанию null» ([руководство PHP](https://www.php.net/manual/en/curl.constants.php)). `CURLOPT_ACCEPT_ENCODING => ''` запрашивает все кодирования, которые поддерживает подключённая libcurl, в этой сборке `deflate, gzip, br, zstd`, и декодирует ответ. Строка `Accept-Encoding` в `CURLOPT_HTTPHEADER` отправляется, но ответ не декодируется.
- **Guzzle 8.2.0** намеренно убирает этот заголовок. Его обработчик cURL включает все декодеры, а затем добавляет пустую строку `Accept-Encoding:`, чтобы curl не отправил свою, с комментарием, что такая строка «will be interpreted as 'Accept-Encoding: *'», то есть будет прочитана как согласие на любое кодирование ([CurlFactory.php](https://github.com/guzzle/guzzle/blob/8.2.0/src/Handler/CurlFactory.php#L2609-L2622)). Тот же код есть во всех проверенных тегах от 6.5.0 до 8.2.0 (прочитано в исходном коде). Передайте в [`decode_content`](https://docs.guzzlephp.org/en/stable/request-options.html#decode-content) строку, например `'decode_content' => 'gzip'`, и Guzzle отправит её как заголовок ([Client.php](https://github.com/guzzle/guzzle/blob/8.2.0/src/Client.php#L1582-L1586)); `'gzip, deflate, br, zstd'` с обработчиком cURL тоже сработало. По умолчанию обработчик cURL всё равно декодирует gzip, br или zstd, которые сервер присылает без запроса. `StreamHandler` в Guzzle, который использует потоки PHP вместо ext-curl, декодировал gzip, но br и zstd вернул сырыми.
- **Laravel Http** (illuminate/http 13.33.0) создаёт обычный клиент Guzzle и наследует всё это ([PendingRequest.php](https://github.com/laravel/framework/blob/v13.33.0/src/Illuminate/Http/Client/PendingRequest.php)). И `withOptions(['decode_content' => 'gzip'])`, и `withHeaders(['Accept-Encoding' => 'gzip'])` отправили `gzip` и декодировали ответ.

### Java HttpClient никогда не декодирует

`java.net.http.HttpClient` на Temurin 25.0.4.1 не отправил `Accept-Encoding` и не декодировал ответ в gzip, который сервер прислал без запроса. Чтобы получить сжатие, отправьте `Accept-Encoding: gzip` самостоятельно и читайте тело через `java.util.zip.GZIPInputStream`, когда ответ содержит `Content-Encoding: gzip`, как это делает лабораторный [клиент на Java](https://ipvolt.com/downloads/accept-encoding-defaults/harness/clients/php-java/JavaHttpClientLab.java). Другие клиенты на Java не запускались.

## Accept-Encoding: identity, отсутствие заголовка и нечитаемый вывод

[RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-encoding) различает три состояния запроса:

- **Заголовка нет** (curl, node:http, ext-curl, Guzzle, Java): «пользовательский агент считает приемлемым любое кодирование содержимого».
- **`identity`** (urllib, Wget 1.x): «синоним „без кодирования“».
- **Пустое значение**: «пользовательский агент не хочет никакого кодирования содержимого в ответе».

Значит, стандарт позволяет серверу сжать ответ на запрос без заголовка, а «сжимать только по запросу» — практика серверов, а не правило RFC. Эту практику описывает документация серверов и CDN. Cloudflare выбирает gzip, Brotli, Zstandard или отсутствие сжатия «в зависимости от» значений в заголовке `accept-encoding` запроса, тарифного плана и подходящего правила сжатия ([Cloudflare](https://developers.cloudflare.com/speed/optimization/content/compression/), страница обновлена 17 апреля 2026 года). mod_deflate в Apache отправляет `Vary: Accept-Encoding`, чтобы сжатое содержимое не было «отправлено клиенту, который его не поймёт» ([mod_deflate](https://httpd.apache.org/docs/2.4/mod/mod_deflate.html)). Комментарий в Guzzle опирается на прочтение RFC; с серверами, которые следуют этой практике, запрос без заголовка получает несжатое тело. Лабораторный сервер следовал той же практике. Как часто реальные серверы сжимают ответ без запроса, не измерялось.

Некоторые сжимают. `gzip_static always` в nginx отдаёт сжатый gzip-файл, «не проверяя, поддерживает ли его клиент» ([nginx](https://nginx.org/en/docs/http/ngx_http_gzip_static_module.html)), а в curl#2836 описан реальный хост, который так делал. Когда лабораторный сервер отправлял gzip без запроса, curl без `--compressed`, Wget, urllib, `node:http`, PHP ext-curl, Java и Go с `DisableCompression` отдавали вызывающему коду поток gzip размером 17 750 байт; Guzzle и Laravel Http его декодировали. Если ответ одного из этих клиентов выглядит как двоичный мусор, первым делом проверьте его `Content-Encoding`.

## Проверьте байты на своём целевом сайте

Если для вашего клиента здесь нет сниппета подсчёта байтов, выполните приведённое ниже сравнение curl для того же URL через тот же прокси и сравните его `Content-Encoding` с заголовком ответа вашего клиента. Это измеряет ответ curl; другое кодирование или другой ответ сервера не дают замер байтов вашего клиента.

Сниппеты для curl, Requests, httpx и `node-fetch-bytes.mjs` ниже печатают байты тела по сети (wire body bytes): тело ответа в том виде, в каком оно прошло по сети, до любого декодирования. Заголовки ответа, записи TLS, обмен CONNECT и повторные запросы сюда не входят, поэтому это не то, за что выставляет счёт провайдер. В восьми лабораторных парах (их перечисляет [tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md)) один и тот же клиент загружал тестовую страницу через CONNECT со сжатием и без него, и эти дополнительные байты добавляли от 2 343 до 3 520 байт на ответ на участке между прокси и клиентом. Они снижали коэффициент, например с 5,19× по телу до 4,56× на участке прокси для curl 8.22.0, но не экономию: в каждой из этих пар трафик на участке прокси сокращался на разницу в размере тела плюс 87 байт. Чтобы замерить весь прогон через ваш прокси и пересчитать его по вашей ставке, используйте [Scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report).

Сниппет на Go печатает декодированный размер и `resp.Uncompressed`, который показывает, декодировал ли Go ответ, а связанный `node-fetch-verify.mjs` печатает заголовок, который отправил `fetch`; ни один из них не печатает байты по сети. Каждый сниппет запускался в лаборатории без изменений, только `https://example.com/` заменялся на loopback-URL, и приведённый вывод получен в этих запусках; сниппет на Go вдобавок компилировался вместе с одним лабораторным файлом, который доверяет CA лаборатории (он описан в разделе о методе). Укажите свой прокси в `PROXY_URL`. Если нужно доверять частному CA, используйте собственную настройку клиента, например `--cacert`, `NODE_EXTRA_CA_CERTS` или `tls.Config.RootCAs` в Go; никогда не отключайте проверку сертификатов.

### Проверка с curl

```sh
# Wire body bytes and the Content-Encoding the server chose (curl 7.84.0+ for %header{}).
curl -sS -o /dev/null -x "$PROXY_URL" \
  -w '%{size_download} %header{content-encoding}\n' https://example.com/
curl -sS -o /dev/null -x "$PROXY_URL" --compressed \
  -w '%{size_download} %header{content-encoding}\n' https://example.com/
```

С curl 8.22.0 из Homebrew на лабораторной тестовой странице первая строка напечатала `100129` без кодирования, а вторая — `19298 zstd`; системный curl 8.7.1 в macOS во второй строке напечатал `17750 gzip`. `size_download` в curl — это «размер переданного тела или данных без учёта заголовков», а `%header{}` требует curl 7.84.0 или новее ([write-out](https://curl.se/docs/manpage.html#-w)). Коэффициент для этой страницы — первое число, делённое на второе.

### Проверка с Requests и httpx

```python
import os

import requests

proxies = {"http": os.environ["PROXY_URL"], "https": os.environ["PROXY_URL"]}
with requests.get("https://example.com/", proxies=proxies, stream=True) as r:
    wire = r.raw.read(decode_content=False)  # body bytes as sent, still encoded
    print(r.headers.get("content-encoding"), len(wire))
```

Requests напечатал `gzip 17750` на Python 3.13.15 и `zstd 19298` на 3.14.7. В httpx `r.num_bytes_downloaded` считает байты в том виде, в каком они прочитаны, а `len(r.content)` — декодированное тело:

```python
import os

import httpx

with httpx.Client(proxy=os.environ["PROXY_URL"]) as client:
    r = client.get("https://example.com/")
    # wire body bytes (as received) vs decoded bytes your code sees
    print(r.headers.get("content-encoding"), r.num_bytes_downloaded, len(r.content))
```

Он напечатал `gzip 17750 100129` на Python 3.14.7 и `zstd 19298 100129` с установленным `zstandard`. urllib никогда не декодирует, поэтому длина того, что вы из него прочитали, — это уже тело по сети.

### Проверка с Node.js

Для встроенного `fetch` размер тела по сети даёт запись resource timing, которую Node создаёт для этого URL:

```js
// Wire body bytes of a built-in fetch, from Node's resource timing entry for the URL.
// Run: NODE_USE_ENV_PROXY=1 HTTPS_PROXY="$PROXY_URL" node node-fetch-bytes.mjs
import { setImmediate } from 'node:timers/promises';

const url = new URL('https://example.com/');
const res = await fetch(url);
const body = await res.arrayBuffer(); // already decoded by fetch

// Node adds the entry after the body has been read, so give the event loop a turn.
let entry;
for (let turn = 0; !entry && turn < 100; turn++) {
  await setImmediate();
  entry = performance.getEntriesByType('resource').findLast((e) => e.name === url.href);
}
performance.clearResourceTimings(); // the buffer stops at 250 entries unless you clear it

// encodedBodySize: the body as it crossed the network, before decoding (no headers, TLS or CONNECT)
console.log('content-encoding', res.headers.get('content-encoding'),
  'wire body bytes', entry?.encodedBodySize, 'decoded bytes', body.byteLength);
```

Через лабораторный прокси CONNECT он напечатал `content-encoding br wire body bytes 18451 decoded bytes 100129` на Node.js 22.23.3 и 24.21.0 и `content-encoding zstd wire body bytes 19298 decoded bytes 100129` на 26.10.0, и каждый вывод совпал с тем, что отправил лабораторный сервер. Ещё в 18 лабораторных ячейках на трёх релизах (напрямую по `http://`, напрямую по `https://` и через прокси CONNECT, каждый вариант со сжатием и без) `encodedBodySize` каждый раз совпадал с числом байтов тела, отправленных сервером; эти замеры перечислены в [tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md). Сразу после чтения тела записи ни разу не было — она появлялась только после одного оборота цикла событий, поэтому сниппет ждёт. Затем сниппет очищает записи, потому что буфер resource timing в Node по умолчанию вмещает только 250 записей ([observe.js](https://github.com/nodejs/node/blob/v26.10.0/lib/internal/perf/observe.js#L103)). Не используйте вместо этого `transferSize`: в каждой ячейке он был равен `encodedBodySize` плюс фиксированные 300 байт, тогда как через прокси участок между прокси и клиентом переносил на 3 431–3 520 байт больше, чем составляло тело.

[node-fetch-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-fetch-verify.mjs) печатает заголовок, который отправил `fetch` (`sent accept-encoding: br, gzip, deflate, zstd` на Node.js 26.10.0). Для `node:https`, который никогда не декодирует, [node-http-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-http-verify.mjs) считает тело по мере поступления, а это и есть тело по сети.

### Проверка с Go

```go
// Did Go ask for gzip and decode it for you? resp.Uncompressed says so.
// Run: go run go-verify.go   (with PROXY_URL set in the environment)
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
)

func main() {
	proxy, err := url.Parse(os.Getenv("PROXY_URL"))
	if err != nil {
		panic(err)
	}
	t := http.DefaultTransport.(*http.Transport).Clone()
	t.Proxy = http.ProxyURL(proxy)
	resp, err := (&http.Client{Transport: t}).Get("https://example.com/")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	// true: Go sent "Accept-Encoding: gzip" itself, received gzip and decoded it,
	// then removed Content-Encoding and set ContentLength to -1.
	fmt.Printf("uncompressed=%v content-encoding=%q content-length=%d decoded-bytes=%d\n",
		resp.Uncompressed, resp.Header.Get("Content-Encoding"), resp.ContentLength, len(body))
}
```

С Go 1.27.1 он напечатал `uncompressed=true content-encoding="" content-length=-1 decoded-bytes=100129`. `resp.Uncompressed` лишь сообщает, что Go декодировал ответ ([response.go](https://github.com/golang/go/blob/go1.27.1/src/net/http/response.go#L93-L100)); размера по сети в ответе уже нет. Чтобы посчитать байты по сети, задайте заголовок самостоятельно (тогда тело останется сжатым), измерьте его, а затем декодируйте через `compress/gzip`.

## Через прокси: CONNECT и absolute-form

Для URL `https://` клиент открывает туннель CONNECT и отправляет запрос внутри TLS. При сквозном TLS без перехвата TLS прокси не может прочитать или изменить `Accept-Encoding`: он передаёт зашифрованный ответ. Лабораторный регистратор не разбирал заголовки внутри туннелей CONNECT. Для URL `http://` большинство клиентов отправляют сам запрос на прокси в абсолютной форме (absolute-form), например `GET http://host/path`, поэтому прокси читает все заголовки: лабораторный прокси увидел `deflate, gzip, br, zstd` от curl 8.22.0 с `--compressed`, `identity` от Wget и `gzip` от Go. Промежуточный узел на таком пути мог бы также переписать заголовок или тело. Лабораторный прокси не делал ни того, ни другого, а реальные прокси не проверялись.

С URL `http://` два клиента повели себя иначе:

- Встроенный `fetch` в Node.js 22.23.3 и 24.21.0 с `NODE_USE_ENV_PROXY=1` пропускал URL `http://` через туннель CONNECT. Лабораторный регистратор не разбирал внутренний заголовок, но сам HTTP-запрос оставался открытым текстом, который прокси может прочитать: [CONNECT сам по себе не шифрует трафик](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect). Node.js 26.10.0 отправлял запрос в абсолютной форме.
- `StreamHandler` в Guzzle отправлял на прокси строку запроса в форме origin-form, если не был задан `request_fulluri`, и лабораторный прокси отклонял её с кодом 400.

Что входит в счёт, определяют правила каждого провайдера. Decodo, например, описывает входящий трафик как «каждый байт, полученный от целевого сайта, включая заголовки ответа и cookie», пишет, что для HTTPS «байты, прошедшие через туннель прокси, также учитываются в использовании трафика прокси», и приводит пример, в котором его собственная тестовая конечная точка заняла 0,85 кБ входящего трафика по `http://` против 3,96 кБ по `https://` ([справка Decodo](https://help.decodo.com/docs/proxy-traffic), прочитано 26 сентября 2026 года, страница изменена 23 апреля 2026 года). Decodo не уточняет, считает ли он сжатые или декодированные байты. Для HTTPS со сквозным TLS внутри CONNECT прокси считает зашифрованные байты, проходящие через туннель, включая сжатый ответ и накладные расходы TLS; это наш вывод, а не утверждение Decodo. Скрапинговые API и анблокеры, которые сами отправляют запрос на целевой сайт, выбирают собственные заголовки и тарифицируют трафик по-своему, поэтому сверьтесь с документацией своего провайдера.

## Копирование Accept-Encoding из браузера

Может возникнуть соблазн вставить в скрапер браузерный `Accept-Encoding: gzip, deflate, br, zstd`. Так вы просите у сервера кодирования, которые ваш клиент, возможно, не умеет декодировать, а в ряде клиентов заданный вручную заголовок ещё и отключает декодирование. Именно с этим заголовком лабораторный сервер выбрал zstd:

- curl (обе сборки), urllib, `node:http`, Go, PHP ext-curl, Java `HttpClient` и `StreamHandler` в Guzzle вернули сжатые байты: обычный ответ с нечитаемым телом.
- Requests и httpx делали то же самое всякий раз, когда не хватало подходящего декодера. На Python 3.13 Requests без дополнительных пакетов вернул сырыми и zstd, и br. На 3.14 он декодировал zstd, но вернул br сырым, когда сервер прислал br. httpx без `zstandard` вернул zstd сырым на обеих версиях Python, без исключения.
- `fetch` в Node.js 22.23.3 вернул zstd сырым; 24.21.0 и 26.10.0 его декодировали.
- Обработчик cURL в Guzzle декодировал и zstd, и br.
- aiohttp выбрасывал исключение всякий раз, когда у него не было декодера: br без `Brotli` и zstd на Python 3.13 без `backports.zstd`. На 3.14 он декодировал zstd.

Решение — позволить клиенту самому сформировать заголовок. Если нужны br или zstd, установите пакет декодера, который использует ваш клиент, например `brotli`, `backports.zstd` на Python 3.13 или `httpx[brotli,zstd]`; тогда клиент сам добавит нужный токен.

### aiohttp 3.14.3: `` Can not decode content-encoding: brotli (br). Please install `Brotli` ``

Когда сервер присылает br, а пакета `Brotli` нет, aiohttp 3.14.3 выбрасывает первое из этих исключений — одинаково на Python 3.13.15 и 3.14.7. Второе — вариант для zstd, который появляется на Python 3.13.15 без `backports.zstd` (loopback-URL сокращены):

```text
aiohttp.client_exceptions.ClientResponseError: 400, message='Can not decode content-encoding: brotli (br). Please install `Brotli`', url='…'
aiohttp.client_exceptions.ClientResponseError: 400, message='Can not decode content-encoding: zstandard (zstd). Please install `backports.zstd`', url='…'
```

Код 400 — собственный статус aiohttp для ответа, который он не может декодировать; лабораторный сервер ответил 200 ([http_parser.py](https://github.com/aio-libs/aiohttp/blob/v3.14.3/aiohttp/http_parser.py#L1147-L1159)). Установка `Brotli` или, во втором случае, `backports.zstd` устранила ошибку в лаборатории: после этого aiohttp декодировал br и zstd, включая тело из четырёх кадров zstd. Более короткое `Can not decode content-encoding: br` возникает в другой ветке того же файла: декодер установлен, но распаковать тело не удалось.

### Серверы, которые неправильно обрабатывают объявленный zstd

Само объявление кодирования может сломать запрос. OpenSearch 2.19.0 зависал, когда `Accept-Encoding` запроса включал zstd, как это бывает у сборок curl с поддержкой zstd. Ошибку исправили в 2.19.1 и 3.0.0 ([OpenSearch#17339](https://github.com/opensearch-project/OpenSearch/issues/17339)). Если какой-то хост уходит в тайм-аут только для клиентов с поддержкой zstd, запрос, который просит только gzip, покажет, не в согласовании zstd ли дело.

## Где сжатие не помогает

- **Уже сжатые данные**, например изображения, видео и архивы. «Медиафайлы, например уже сжатые изображения, не выигрывают от HTTP-сжатия» ([Web Almanac 2021](https://almanac.httparchive.org/en/2021/compression)).
- **Ответы, которые сервер или CDN оставляет несжатыми.** Cloudflare, например, документирует сжатие только ответов 200, 403 и 404, с минимальным размером 48 байт для gzip и 50 байт для Brotli и Zstandard ([Cloudflare](https://developers.cloudflare.com/speed/optimization/content/compression/)).
- **Запросы Range и HEAD.** Go не отправляет заголовок ни для тех, ни для других, а `fetch` в Node.js отправляет `identity` всякий раз, когда задан заголовок `Range`.
- **Отправка данных на сервер.** `--compressed` и его аналоги работают для скачивания; для тел запросов «стандартного способа сжатия нет» ([Everything curl](https://everything.curl.dev/http/modify/compression.html)).
- **Автоматизация браузера.** Браузеры согласовывают сжатие сами: MDN приводит `gzip, deflate, br, zstd` как типичное значение браузера ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding)), а Chrome по умолчанию декодирует zstd начиная с версии 123 ([Chrome Platform Status](https://chromestatus.com/feature/6186023867908096)), поэтому в Playwright или Puppeteer байты стоит сокращать в том, что скачивает браузер, а не в этом заголовке.

Для страниц, которые вы загружаете снова и снова, отдельный рычаг — условные запросы: ответ `304 Not Modified` вообще не содержит тела ([RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified); [мониторинг по ETag](/ru/blog/etag-monitoring-cache-control)).

## Сколько это экономит

Включать сжатие имеет смысл только клиентам из первой таблицы. Для них:

экономия $ ≈ страницы × несжатые байты текста на страницу × (1 − 1/коэффициент) ÷ 10⁹ × ваши $ за ГБ

Коэффициент берите из шага проверки на своих страницах (байты без сжатия, делённые на байты со сжатием), а ставку — из своего тарифа.

Сжатие снижает счёт, только когда вы платите за байты. На фиксированном тарифе, где цена зависит от Мбит/с или числа потоков, она остаётся прежней, хотя через канал проходит больше сжатых страниц. В статье [сколько стоит гигабайт у безлимитных резидентных прокси](/ru/blog/unlimited-residential-proxies-cost-per-gb) сравниваются эти два способа тарификации.

Вымышленный пример, а не измерение: 100 000 страниц HTML по 100 КБ (100 000 байт) — это 10 ГБ без сжатия. При коэффициенте 4 сжатие экономит 7,5 ГБ, при коэффициенте 10 — 9,0 ГБ. При вымышленной ставке от $3 до $8 за ГБ это примерно от $22,50 до $72 за один обход этих страниц.

Клиенту, который уже запрашивает сжатие, включение ничего не сэкономит: оно уже включено. Необязательный декодер br для Requests, httpx или aiohttp может ещё немного сократить объём некоторых страниц: на 23 страницах документации из лабораторного корпуса тела в br в сумме составили 277 665 байт против 325 873 для gzip, примерно на 15% меньше, но на синтетической странице br оказался больше gzip (18 451 против 17 750 байт).

Собственные коэффициенты лаборатории — не прогноз. Синтетическая тестовая страница сжалась в 5,64 раза с gzip и в 5,19 раза с zstd. В этом корпусе из 23 страниц документации CPython 3.14.7 несжатые тела были в 6,67 раза больше своего размера в gzip, в 6,61 раза больше размера в zstd и в 7,83 раза больше размера в br. Эти числа описывают только эти файлы.

Формула учитывает байты тела; в лаборатории заголовки, TLS и обмен CONNECT почти не менялись от сжатия, как показывает раздел о проверке. Как провайдер превращает байты в счёт (ГБ или ГиБ, минимальные объёмы, неудачные запросы), разбирается в [Scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report). Результат — оценка, а не счёт провайдера.

## Метод, ограничения и загрузки

ipvolt прогнал записанную матрицу из 567 ячеек один раз, 27 сентября 2026 года, на macOS 15.7.4 (Apple M4 Pro, arm64): подготовка с 02:43 до 02:44 UTC, затем вся матрица с 02:44 до 02:45 UTC. Сервер на Python на 127.0.0.1 отдавал синтетическую HTML-страницу размером 100 129 байт, а для некоторых ячеек — 23 страницы документации CPython 3.14.7, за прямым прокси со счётчиком байтов (counting forward proxy) на 127.0.0.1, который обрабатывал запросы как в абсолютной форме, так и через CONNECT. Без заголовка сервер отдавал страницу несжатой; в остальных случаях он выбирал из кодирований, перечисленных клиентом, предпочитая zstd, затем br, gzip и deflate. Принудительные режимы отправляли gzip, br, zstd, четыре кадра zstd или несжатый ответ независимо от запроса. Каждая HTTPS-ячейка доверяла одноразовому локальному CA через собственную настройку клиента, а в 21 контрольной ячейке без этого CA проверка сертификата каждый раз завершалась ошибкой. Сниппет на Go компилировался вместе с одним лабораторным файлом, который добавлял этот CA в `RootCAs` у `http.DefaultTransport` до того, как сниппет его клонировал (текст файла — `LAB_TRUST_GO` в [snippets.py](https://ipvolt.com/downloads/accept-encoding-defaults/harness/nodego/snippets.py)), поэтому доверие не зависело от `SSL_CERT_FILE`: go1.27.1 на macOS учитывает эту переменную, если не задано `GODEBUG=x509sslcertoverrideplatform=0`, а в модуле, где объявлен go 1.26, оно задано по умолчанию. Второй прогон из опубликованного архива, в пустом каталоге и с заново скачанными файлами, совпал со всеми 567 записями по каждому сравниваемому полю (`compare.py --strict`).

Версии: curl 8.7.1 (macOS, LibreSSL) и 8.22.0 (Homebrew, OpenSSL 3.6.4, brotli, zstd); GNU Wget 1.25.0; CPython 3.13.15 и 3.14.7 с Requests 2.34.2 (urllib3 2.8.0), httpx 0.28.1, aiohttp 3.14.3 и Scrapy 2.19.0; Node.js 22.23.3, 24.21.0 и 26.10.0 с nodejs.org с проверенными контрольными суммами, с axios 1.20.0, got 16.0.0 и node-fetch 3.3.2 и 2.7.0; Go 1.27.1; PHP 8.5.8 (статическая сборка, libcurl 8.20.0) с Guzzle 8.2.0 и illuminate/http 13.33.0; Temurin JDK 25.0.4.1.

Лаборатория не охватывала HTTP/2 и HTTP/3 (сервер предлагал только HTTP/1.1), сборки для Linux и Windows, браузеры, Wget2, urllib3 отдельно, curl_cffi, Apache HttpClient, OkHttp, Symfony HttpClient, .NET HttpClient, Rust reqwest, Ruby Net::HTTP и Faraday, другие сборки PHP и libcurl, а также релизы Java после 25. Значения по умолчанию меняются от релиза к релизу. Здесь использованы версии, которые были установлены или актуальны на момент прогона: системный curl 8.7.1 в macOS старше curl 8.22.0, статическая сборка PHP на три патч-релиза отставала от 8.5.11 на php.net, а Java 25 — новейший LTS-релиз, но не новейший feature-релиз. Прежде чем полагаться на какую-либо строку, повторите прогон лаборатории.

Все файлы лежат в `https://ipvolt.com/downloads/accept-encoding-defaults/`:

- [accept-encoding-lab.zip](https://ipvolt.com/downloads/accept-encoding-defaults/accept-encoding-lab.zip) содержит всё перечисленное ниже; его контрольная сумма — в [accept-encoding-lab.zip.sha256](https://ipvolt.com/downloads/accept-encoding-defaults/accept-encoding-lab.zip.sha256).
- [README.md](https://ipvolt.com/downloads/accept-encoding-defaults/README.md) объясняет, как запустить лабораторию, сравнить повторный прогон и читать запись.
- [results.json](https://ipvolt.com/downloads/accept-encoding-defaults/results.json) и [results.csv](https://ipvolt.com/downloads/accept-encoding-defaults/results.csv) содержат все 567 записей; в [tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md) собраны все таблицы, включая матрицу декодирования и точный текст ошибок.
- [environment.txt](https://ipvolt.com/downloads/accept-encoding-defaults/environment.txt) фиксирует ОС и вывод каждой команды проверки версии, [corpus-manifest.txt](https://ipvolt.com/downloads/accept-encoding-defaults/corpus-manifest.txt) — страницы документации, а [SHA256SUMS](https://ipvolt.com/downloads/accept-encoding-defaults/SHA256SUMS) — контрольную сумму каждого остального файла в архиве.
- Проверочные сниппеты: [curl-verify.sh](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/curl-verify.sh), [requests-verify.py](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/requests-verify.py), [httpx-verify.py](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/httpx-verify.py), [node-fetch-bytes.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-fetch-bytes.mjs), [node-fetch-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-fetch-verify.mjs), [node-http-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-http-verify.mjs) и [go-verify.go](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/go-verify.go).
- [render_tables.py](https://ipvolt.com/downloads/accept-encoding-defaults/render_tables.py) заново строит таблицы из `results.json` или из `harness/out/results.json` вашего собственного прогона, а [compare.py](https://ipvolt.com/downloads/accept-encoding-defaults/compare.py) сравнивает ваш повторный прогон с опубликованным.

Чтобы воспроизвести весь прогон, распакуйте архив, выполните в `harness/` сначала `./setup.sh`, затем `./run.sh`, а после этого `python3 ../compare.py ../results.json out/results.json`. В README перечислено, что скачивает setup и что нужно каждой группе ячеек. Аккаунт у прокси-провайдера не нужен.

ipvolt, который публикует это руководство, — прокси-сервис в разработке с оплатой за ГБ на старте. Измерения выполнены через локальный тестовый прокси; советы подходят для любого провайдера и для работы вовсе без прокси.

Если хотите узнать, когда откроется доступ к ipvolt, [запишитесь в список раннего доступа](https://ipvolt.com/#waitlist-closing). Одно письмо, когда откроется доступ. Больше ничего.

## Источники и дополнительное чтение

- [RFC 9110: CONNECT tunnels and the HTTPS scheme](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect)
- [Python 3.14 gzip: gzip.decompress and multi-member streams](https://docs.python.org/3.14/library/gzip.html#gzip.decompress)
- [Node.js 26.10.0: resource timing buffer limit](https://github.com/nodejs/node/blob/v26.10.0/lib/internal/perf/observe.js#L103)
- [RFC 9110 section 12.5.3: Accept-Encoding (no header, identity, empty value)](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-encoding)
- [RFC 9110 section 15.4.5: 304 Not Modified (no content)](https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified)
- [curl man page: --compressed (the page describes 8.23.0; this text is unchanged since the tested 8.22.0)](https://curl.se/docs/manpage.html#--compressed)
- [curl man page: --max-filesize and decompression (since 8.20.0)](https://curl.se/docs/manpage.html#--max-filesize)
- [curl man page: -w, %{size_download} and %header{} (added in 7.84.0)](https://curl.se/docs/manpage.html#-w)
- [libcurl: CURLOPT_ACCEPT_ENCODING (default NULL, no header and no decoding)](https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html)
- [curl issue #11091: no Accept-Encoding by default, captured with nc](https://github.com/curl/curl/issues/11091)
- [curl issue #7516: curl can only ask for compression](https://github.com/curl/curl/issues/7516)
- [curl issue #2836: raw gzip output when a server compresses unasked](https://github.com/curl/curl/issues/2836)
- [Everything curl: HTTP compression applies to downloads](https://everything.curl.dev/http/modify/compression.html)
- [CPython 3.14.7 http.client: Accept-Encoding identity](https://github.com/python/cpython/blob/v3.14.7/Lib/http/client.py#L1296-L1299)
- [urllib3 2.8.0 util/request.py: gzip, deflate, br and zstd tokens](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/util/request.py#L22-L41)
- [urllib3 2.8.0 connection.py: the request path adds no compression header](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/connection.py#L525-L531)
- [Requests 2.34.2 utils.py: default Accept-Encoding](https://github.com/psf/requests/blob/v2.34.2/src/requests/utils.py#L91-L93)
- [httpx 0.28.1 _decoders.py: br needs brotli, zstd needs zstandard](https://github.com/encode/httpx/blob/0.28.1/httpx/_decoders.py#L381-L393)
- [HTTPX documentation: optional brotli and zstd decoders](https://www.python-httpx.org/)
- [aiohttp 3.14.3 http_parser.py: Can not decode content-encoding](https://github.com/aio-libs/aiohttp/blob/v3.14.3/aiohttp/http_parser.py#L1147-L1159)
- [Scrapy 2.19.0 release notes: br and zstd required since 2.18.0](https://github.com/scrapy/scrapy/blob/2.19.0/docs/news.rst)
- [Python 3.14: compression.zstd](https://docs.python.org/3.14/library/compression.zstd.html)
- [Node.js 26.10.0 bundled undici fetch: Accept-Encoding by scheme and Range](https://github.com/nodejs/node/blob/v26.10.0/deps/undici/src/lib/web/fetch/index.js#L1562-L1576)
- [Node.js 24.21.0 bundled undici fetch](https://github.com/nodejs/node/blob/v24.21.0/deps/undici/src/lib/web/fetch/index.js#L1514-L1528)
- [Node.js 22.23.3 bundled undici fetch: no zstd decoder](https://github.com/nodejs/node/blob/v22.23.3/deps/undici/src/lib/web/fetch/index.js#L2149-L2170)
- [Node.js 26.10.0 core HTTP client (no Accept-Encoding)](https://github.com/nodejs/node/blob/v26.10.0/lib/_http_client.js)
- [Node.js zlib: compressing HTTP requests and responses](https://nodejs.org/api/zlib.html#compressing-http-requests-and-responses)
- [node-fetch discussion #1556: default gzip, deflate, br](https://github.com/node-fetch/node-fetch/discussions/1556)
- [axios 1.20.0 http adapter: default Accept-Encoding and zstd opt-in](https://github.com/axios/axios/blob/v1.20.0/lib/adapters/http.js#L54-L57)
- [got 16.0.0 core: default accept-encoding](https://github.com/sindresorhus/got/blob/v16.0.0/source/core/index.ts#L2248-L2258)
- [Go 1.27.1 net/http transport.go: DisableCompression and automatic gzip](https://github.com/golang/go/blob/go1.27.1/src/net/http/transport.go#L199-L207)
- [Go 1.27.1 net/http response.go: Response.Uncompressed](https://github.com/golang/go/blob/go1.27.1/src/net/http/response.go#L93-L100)
- [GNU Wget manual: --compression (none is the default)](https://www.gnu.org/software/wget/manual/wget.html#HTTP-Options)
- [GNU Wget2 2.3.0 wget.c: default Accept-Encoding](https://gitlab.com/gnuwget/wget2/-/blob/v2.3.0/src/wget.c#L4306-4331)
- [Fedora change: Wget2 as wget](https://fedoraproject.org/wiki/Changes/Wget2asWget)
- [PHP manual: cURL constants, CURLOPT_ACCEPT_ENCODING](https://www.php.net/manual/en/curl.constants.php)
- [Guzzle 8.2.0 CurlFactory.php: Accept-Encoding suppressed by default](https://github.com/guzzle/guzzle/blob/8.2.0/src/Handler/CurlFactory.php#L2609-L2622)
- [Guzzle 8.2.0 Client.php: a string decode_content becomes the header](https://github.com/guzzle/guzzle/blob/8.2.0/src/Client.php#L1582-L1586)
- [Guzzle request options: decode_content](https://docs.guzzlephp.org/en/stable/request-options.html#decode-content)
- [Laravel 13.33.0 PendingRequest.php: a plain Guzzle client](https://github.com/laravel/framework/blob/v13.33.0/src/Illuminate/Http/Client/PendingRequest.php)
- [Cloudflare: Content compression](https://developers.cloudflare.com/speed/optimization/content/compression/)
- [Apache HTTP Server 2.4: mod_deflate and proxy servers](https://httpd.apache.org/docs/2.4/mod/mod_deflate.html)
- [nginx: ngx_http_gzip_static_module (gzip_static always)](https://nginx.org/en/docs/http/ngx_http_gzip_static_module.html)
- [OpenSearch issue #17339: REST API hangs with Accept-Encoding zstd](https://github.com/opensearch-project/OpenSearch/issues/17339)
- [MDN: Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding)
- [Chrome Platform Status: Zstd Content-Encoding (Chrome 123)](https://chromestatus.com/feature/6186023867908096)
- [Web Almanac 2021: Compression](https://almanac.httparchive.org/en/2021/compression)
- [Decodo help: how proxy traffic is calculated (vendor documentation)](https://help.decodo.com/docs/proxy-traffic)

## Связанные руководства

- [Прокси в curl: флаг -x, переменные окружения, SOCKS5, аутентификация](https://ipvolt.com/ru/guides/curl-proxy-setup.md)
- [Прокси в Python Requests: словарь proxies, аутентификация, SOCKS5](https://ipvolt.com/ru/guides/python-requests-proxy.md)
- [Прокси для fetch в Node.js](https://ipvolt.com/ru/guides/nodejs-fetch-proxy.md)

## О ipvolt

Примеры используют обобщённые настройки прокси со ссылками на оригинальную техническую документацию. Поведение конкретного продукта уточняйте у своего провайдера. ipvolt пока в разработке.

[Читать оригинал на английском](https://ipvolt.com/guides/curl-compressed-accept-encoding.md)

## Узнайте, когда откроется доступ.

ipvolt · В разработке

Мы строим прокси-инфраструктуру для разработчиков и команд, работающих с данными. Оставьте email, чтобы получить уведомление, когда ipvolt будет готов.

Одно письмо, когда откроется доступ. Больше ничего.

[Получить ранний доступ](https://ipvolt.com/ru/guides/curl-compressed-accept-encoding#waitlist-closing)

[Конфиденциальность](https://ipvolt.com/privacy)

