Назад | Перейти на главную страницу

Неправильное сжатие http-запросов, не могу найти, кто это делает

Мы наблюдаем очень странное искажение HTTP-ответов и не можем понять, что это делает. У нас есть сервер приложений, обрабатывающий запросы JSON. Иногда ответ возвращается в сжатом виде, но с неправильными заголовками, которые мешают браузеру правильно интерпретировать его.

Проблема носит временный характер и со временем меняет поведение. Вчера утром казалось, что он отказывает в 50% случаев, и на самом деле, похоже, он был привязан к одному из двух наших серверов с балансировкой нагрузки. Позже днем ​​он давал сбой только 20 раз из 1000 и не коррелировал с сервером приложений.

Два сервера приложений работают под управлением Apache 2.2 с mod_wsgi и стеком приложений Django. У них одинаковые конфигурации Apache и деревья исходного кода, и даже идентичные пакеты, установленные в Red Hat. Впереди аппаратный балансировщик нагрузки, марки и модели не знаю.

Akamai также является частью пищевой цепочки, хотя мы удалили Akamai, и проблема все еще была.

Вот хороший запрос и ответ:

* Connected to example.com (97.7.79.129) port 80 (#0)
> POST /claim/ HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: example.com
> Accept: */*
> Referer: http://example.com/apps/
> Accept-Encoding: gzip,deflate
> Content-Length: 29
> Content-Type: application/x-www-form-urlencoded
> 
} [data not shown]
< HTTP/1.1 200 OK
< Server: Apache/2
< Content-Language: en-us
< Content-Encoding: identity
< Content-Length: 47
< Content-Type: application/x-javascript
< Connection: keep-alive
< Vary: Accept-Encoding
< 
{ [data not shown]
* Connection #0 to host example.com left intact
* Closing connection #0
{"msg": "", "status": "OK", "printer_name": ""}

А вот и плохой:

* Connected to example.com (97.7.79.129) port 80 (#0)
> POST /claim/ HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: example.com
> Accept: */*
> Referer: http://example.com/apps/
> Accept-Encoding: gzip,deflate
> Content-Length: 29
> Content-Type: application/x-www-form-urlencoded
> 
} [data not shown]
< HTTP/1.1 200 OK
< Server: Apache/2
< Content-Language: en-us
< Content-Encoding: identity
< Content-Type: application/x-javascript
< Content-Encoding: gzip
< Content-Length: 59
< Connection: keep-alive
< Vary: Accept-Encoding
< X-N: S
< 
{ [data not shown]
* Connection #0 to host example.com left intact
* Closing connection #0
�V�-NW�RPR�QP*.I,)-���A���̼�Ԣ����T��Z�
��/

В отношении плохого ответа следует обратить внимание на две вещи:

  1. Он имеет два заголовка Content-Encoding, и браузеры, похоже, используют первый. Таким образом, они видят заголовок идентификационной кодировки и сжатое содержимое, поэтому они не могут интерпретировать ответ.

  2. Плохой ответ имеет дополнительный заголовок «X-N: S».

Возможно, если бы я мог узнать, какой посредник добавляет заголовки «X-N: S» в ответы, я смог бы найти виновника ...

Некоторые дополнительные подсказки

В соответствии с http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5:

  • идентичность Кодировка по умолчанию (идентификационная); использование каких-либо преобразований. Это кодирование содержимого используется только в заголовке Accept-Encoding и НЕ ДОЛЖНО использоваться в заголовке Content-Encoding.

Похоже, что Akamai игнорирует тот факт, что сервер может включать этот заголовок в свой ответ, и не удаляет его при изменении кодировки на «gzip».

Поскольку вышестоящий сервер «не должен» добавлять заголовок в первую очередь, это еще один способ решить эту проблему.

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

Как выглядит ваша архитектура?

Любой обратный прокси в пути запроса? Какие модули загружены в apache? Как выглядит конфигурация apache? Если отключить mod_deflate, это все равно происходит? Обрабатывает ли ваш вывод json скрипт php, который использует ob_start и обрабатывает собственное сжатие?