HttpClient не отправляет Accept-Encoding в Windows 2008 R2

У меня есть консольное приложение .NET Core 2.0, которое выполняет запрос GET.

Похоже, опубликованная версия не отправляет заголовки Accept-Encoding для сжатия на тестовой машине, но работает на моей локальной машине.

Я не могу найти каких-либо других предварительных условий, которые могли бы привести к сбою сжатия. Оба используют пакет SDK для .NET Core 2.1.4.

Я протестировал консольное приложение, запустив dotnet Console.dll в обеих средах.

  1. Опубликовать в VS2017
  2. Перейдите в выходную папку и запустите dotnet Console.dll. Убедитесь, что заголовок присутствует в Fiddler.
  3. Скопируйте всю выходную папку и разверните на сервере
  4. Запустите dotnet Console.dll еще раз и проверьте отсутствие заголовка на сервере с помощью Fiddler.

Я пробовал и HttpClient, и RestSharp, и я очень озадачен.

Доказательство концепции, которая переходит на страницу, которая повторяет заголовки запроса:

 var handler = new HttpClientHandler()
            {
                AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
            };

 using (var client = new HttpClient(handler))
 {
      response = client.GetStringAsync("http://scooterlabs.com/echo").Result;
 }

Локальная среда (Win10)

GET http://scooterlabs.com/echo HTTP/1.1
Connection: Keep-Alive
Accept-Encoding: gzip, deflate
Host: scooterlabs.com

Сервер (Win2008 R2 на AWS)

GET http://scooterlabs.com/echo HTTP/1.1
Connection: Keep-Alive
Host: scooterlabs.com

person Jun Wei Lee    schedule 09.02.2018    source источник
comment
Это заголовок запроса. Я не уверен, что использует scooterlabs. Редактировать: я пытался использовать WebClient, и, кажется, он отлично работает на сервере, так что что-то в реализации HttpClient, похоже, не работает?   -  person Jun Wei Lee    schedule 09.02.2018
comment
HttpClient работает нормально. Вы не используете HttpClient в своем примере, вы используете RestClient. В любом случае, если бы сжатие не работало, это заметили бы тысячи разработчиков еще 5 лет назад.   -  person Panagiotis Kanavos    schedule 09.02.2018
comment
Напишите минимальный воспроизводимый пример и используйте Fiddler для проверки HTTP-запроса и ответа. Если заголовки запроса есть, а служба не сжимает ответ, это не проблема с HttpClient.   -  person Panagiotis Kanavos    schedule 09.02.2018
comment
А что, если вы сами добавите заголовок (и удалите AutomaticDecompression)?   -  person Evk    schedule 09.02.2018
comment
@JunWeiLee, другими словами, я использую HttpClient на Core 2.0, и сжатие работает. Вы предполагаете, что это не так. сервер не является HttpClient. Если заголовок не поступает на сервер, возможно, что-то (например, брандмауэр) удалило его. Поддерживает ли сервер сжатие в первую очередь? Как вы настроили сервер? Что такое это сервер?   -  person Panagiotis Kanavos    schedule 09.02.2018
comment
@PanagiotisKanavos OP означает, что он работает с машины A, но не работает (заголовок не отправляется) с машины B (где машина B является сервером).   -  person Evk    schedule 09.02.2018
comment
@PanagiotisKanavos Сервер в данном случае не имеет значения. запрос не содержит заголовка Accept-Encoding. Я ничего не предполагаю, Fiddler подтверждает, что заголовок не отправлен.   -  person Jun Wei Lee    schedule 09.02.2018
comment
@Evk Ручное добавление заголовков в дополнение к настройке обработчика, похоже, работает как на локальном компьютере, так и на сервере. Действительно странно, почему разница в окружающей среде вызвала это. Опубликуйте это как ответ, и я приму это! client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));   -  person Jun Wei Lee    schedule 09.02.2018
comment
Это все еще довольно странно. Я бы лучше проверил, что распаковка действительно работает, потому что, если он не хочет сам устанавливать этот заголовок - может быть, потому, что он не сможет распаковать ответ?   -  person Evk    schedule 09.02.2018
comment
@Evk Я проверил это, получив google.com с принудительным заголовком. Сценарий 1) Отключить сжатие в HttpClientHandler . Проверьте полученные двоичные данные. Сценарий 2) Включить сжатие в HttpClientHandler. Проверьте полученный открытый текст. Таким образом, он получает сжатые данные и может автоматически распаковывать их.   -  person Jun Wei Lee    schedule 09.02.2018
comment
Где вы взяли заголовок? Из журнала самой dotnet Console.dll или с помощью журнала IIS? Поскольку я подозреваю, что вы используете IIS в качестве прокси для процесса dotnet   -  person William SY Wong    schedule 09.02.2018
comment
@WilliamSYWong Заголовки взяты из Fiddler. WebClient работает нормально, и если я заставлю HttpClient добавить заголовок, он тоже будет работать нормально.   -  person Jun Wei Lee    schedule 09.02.2018
comment
Я должен спросить так: ваш сервер использовал IIS? Поскольку IIS обычно используется в качестве прокси-сервера для запуска процесса dotnet (путем перезапуска dotnet в случае сбоя)   -  person William SY Wong    schedule 09.02.2018
comment
@PanagiotisKanavos Прошу прощения за предыдущий язвительный комментарий. Я удалил его и обновил вопрос, чтобы сделать его более ясным, заменив слово server на another machine.   -  person Jun Wei Lee    schedule 09.02.2018
comment
@WilliamSYWong Веб-сервер здесь не имеет значения, так как это консольное приложение. Это проблема с http request заголовками, отсутствующими Accept-Encoding в консольном приложении.   -  person Jun Wei Lee    schedule 09.02.2018
comment
нет, если вы используете IIS для пересылки вашего запроса, он может изменить заголовок вашего запроса   -  person William SY Wong    schedule 09.02.2018
comment
Давайте продолжим обсуждение в чате.   -  person Jun Wei Lee    schedule 09.02.2018


Ответы (3)


Думаю, это связано с тем, что библиотека WinHttp, которая по умолчанию используется HttpClient в Windows не поддерживает gzip\deflate в версиях Windows до Windows 8.1+. Если поддерживается — WinHttp также установит заголовок Accept-Encoding. Итак, в Windows Server 2008, когда .NET маршрутизирует запрос через WinHttp, он либо устанавливает этот параметр и игнорирует его, либо проверяет, поддерживается ли этот параметр, а если нет, то просто не устанавливает его.

Если вы устанавливаете этот заголовок вручную (например, client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));) - опция по-прежнему игнорируется, но заголовок проходит, и сервер возвращает сжатый ответ. Если поддерживается — WinHttp распаковывает этот ответ и удаляет заголовок Content-Encoding, поэтому ответ будет получен в распакованном виде в .NET. Если не поддерживается - ответ будет приходить сжатым, и .NET сам распаковает его, если вы установите AutomaticDecompression.

Итак, в заключение - в версиях Windows до 8.1 кажется, что вам нужно установить как AutomaticDecompression, так и связанные заголовки Accept-Encoding, чтобы это работало должным образом.

person Evk    schedule 09.02.2018
comment
В Windows 7, если вы установите вручную заголовок (что-то вроде: httprequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate;q=0.8"); и не укажете AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;, поток будет приходить сжатым одним из предпочтительных методов (gzip, если он доступен в примере кода). System.IO.Compression.GZipStream и System.IO.Compression.DeflateStream могут использоваться для распаковки потока и копирования его в MemoryStream для окончательного StreamReader.ReadToEnd([MemoryStream]). - person Jimi; 11.02.2018

Не ответ, хотя я пытался воспроизвести это на Azure Win Server 2008 R2 с разными серверами Echo (.NET Core SDK 2.1.4)

// http://scooterlabs.com/echo output

[headers] => Array
(
    [Connection] => Keep-Alive
    [Host] => scooterlabs.com
)


// http://httpbin.org/headers output
{
  "headers": {
    "Connection": "close",
    "Host": "httpbin.org"
  }
}

// https://postman-echo.com/headers output
{
    "headers": {
        "host": "postman-echo.com",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https"
    }
}

В Win10 у меня действительно есть эти заголовки.

// http://scooterlabs.com/echo output
[headers] => Array
(
    [Connection] => Keep-Alive
    [Accept-Encoding] => gzip, deflate
    [Host] => scooterlabs.com
)

// http://httpbin.org/headers output
{
  "headers": {
    "Accept-Encoding": "gzip, deflate",
    "Connection": "close",
    "Host": "httpbin.org"
  }
}

// https://postman-echo.com/headers output
{
    "headers": {
        "host": "postman-echo.com",
        "accept-encoding": "gzip, deflate",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https"
    }
}

что заставляет меня думать, что заголовок Accept-Encoding HttpClient действительно не поддерживается в WS 2008 R2.

person Ivan Zaruba    schedule 09.02.2018
comment
Спасибо, только что подтвердил с помощью виртуальной машины Windows 8.1, что она действительно установлена. В сочетании с ответом @Evk мы можем сделать вывод, что это может быть то, на что может захотеть обратить внимание команда Core, поскольку она действительно может справиться со сжатием. - person Jun Wei Lee; 09.02.2018

Основываясь на ответах Ивана и Евка, кажется, что это проблема, характерная для более старых версий Windows (старше, чем Win8.1). Вот как обойти и успешно справиться со сжатием в старых версиях Windows.

   var handler = new HttpClientHandler()
                {
                    AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
                };

   using (var client = new HttpClient(handler))
   {
        client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
        client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
        response = client.GetStringAsync("http://scooterlabs.com/echo").Result;
   }

AutomaticDecompression должен быть установлен в дополнение к заголовкам, иначе вместо этого вы получите сжатую полезную нагрузку.

person Jun Wei Lee    schedule 09.02.2018