В нашем веб-приложении (ASP.NET Web Forms) есть страница, на которой пользователям будет отображаться недавно созданный файл PDF.Поскольку PDF-файл иногда бывает довольно большим, мы реализовали «потоковый» подход для отправки его клиентскому браузеру порциями.
Несмотря на отправку данных порциями, мы знаем полный размерфайл до его отправки, поэтому мы правильно установили заголовок Content-Length.Это работает в нашей производственной среде некоторое время (и продолжает работать в нашей тестовой среде с практически идентичной конфигурацией) до сегодняшнего дня.Описанная проблема заключалась в том, что Chrome пытался открыть файл PDF, но зависал с застрявшей анимацией «Загрузка».
Поскольку в нашей тестовой среде все еще работало нормально, я смог использовать Firebug, чтобы посмотретьв заголовках ответа, которые возвращались в обеих средах.В тестовой среде я видел правильный заголовок «Content-Length», а в производстве его заменили на Transfer-Encoding: chunked header.Chrome это не нравится, поэтому зависание.
Я читал некоторые статьи и посты о том, как заголовок Transfer-Encoding может отображаться, если заголовок Content-Length не указан, но мыуказав заголовок Content-Length и все по-прежнему работает при выполнении одного и того же кода для одного и того же файла PDF на тестовом сервере.
И на тестовом, и на рабочем серверах работает IIS 7.5, и на обоих включены динамическое и статическое сжатие.
Вот код, о котором идет речь:
var fileInfo = new FileInfo(fileToSendDown);
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "filename=test.pdf");
Response.AddHeader("Content-Length", fileInfo.Length.ToString());
var buffer = new byte[1024];
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
int read;
while ((read = fs.Read(buffer, 0, 1024)) > 0)
{
if (!response.IsClientConnected) break;
Response.OutputStream.Write(buffer, 0, read);
Response.Flush();
}
}
Мне повезло увидеть такое же поведение на моей локальной рабочей станции, поэтому с помощью отладчика я смог увидеть, что «Transfer-Кодировка: chunked заголовок устанавливается на 2-й проход через цикл while во время вызова Flush.В этот момент ответ имеет как заголовок Content-Length, так и заголовок Transfer-Encoding, но каким-то образом, когда ответ достигает браузера, Firebug показывает только заголовок Transfer-Encoding.
UPDATE
Я думаю, что я проследил это до использования комбинации отправки данных в виде «кусков» И присоединения «Filter» к объекту HttpResponse (мы использовали фильтр для отслеживания размерасостояние просмотра отправляется на каждую страницу).У нас нет смысла использовать HTTP-фильтр при отправке PDF в браузер, поэтому очистка фильтра здесь решила нашу проблему.Я решил заглянуть немного глубже просто из любопытства и обновил этот вопрос, если кто-нибудь еще когда-нибудь столкнется с этой проблемой в будущем.
У меня есть простое приложение на AppHarbor, которое воспроизводит проблему:http://transferencodingtest.apphb.com/. Если вы отметите оба параметра «Использовать фильтр?»и "Отправить кусками?"В боксах вы должны увидеть заголовок 'Transfer-Encoding: Chunked' (используя инструменты разработчика Chrome, Firebug, Fiddler и т. д.).Если ни один из флажков не установлен, вы получите правильный заголовок длины содержимого.Базовый код работает на github, поэтому вы можете видеть, что происходит за кулисами:
https://github.com/appakz/TransferEncodingTest
Обратите внимание, что для локального воспроизведения необходимо настроить локальный веб-сайт в IIS 7.5.(7 тоже может сработать, я не пробовал).Сервер разработки ASP .NET, поставляемый с Visual Studio, НЕ воспроизводит проблему.
Я добавил некоторые дополнительные сведения в сообщение в блоге здесь: Заголовок «Content-Length» заменен на «Transfer-»Кодировка: Chunked 'в ASP .NET