2011-12-20 8 views
16

Nasza aplikacja internetowa (ASP.NET Web Forms) ma stronę, która wyświetli ostatnio wygenerowany plik PDF dla użytkowników. Ponieważ plik PDF jest czasami dość duży, wprowadziliśmy podejście "strumieniowe", aby wysłać je do przeglądarki klienta w porcjach.Dlaczego program ASP.NET zastępuje nagłówek Content-Length nagłówkiem kodowania transferu podczas ręcznego płukania odpowiedzi?

Pomimo wysyłania danych w porcjach, znamy pełny rozmiar pliku przed jego wysłaniem, dlatego odpowiednio ustawiamy nagłówek Content-Length. To działało w naszym środowisku produkcyjnym przez jakiś czas (i nadal działa w naszym środowisku testowym z praktycznie identyczną konfiguracją) do dziś. Zgłoszono problem polegający na tym, że Chrome próbował otworzyć plik PDF, ale zawiesiłby się z zablokowaną animacją "Ładowanie".

Ponieważ wszystko działało bez zarzutu w naszym środowisku testowym, mogłem użyć Firebug, aby przyjrzeć się nagłówkom odpowiedzi, które powracały w obu środowiskach. W środowisku testowym widziałem odpowiedni nagłówek "Content-Length", podczas gdy w produkcji został on zastąpiony nagłówkiem Transfer-Encoding: chunked. Chrome tego nie lubi, stąd zawieszenie.

Czytałem niektóre artykuły i posty mówiące o tym, jak nagłówek Transfer-Encoding może się wyświetlać, gdy nie ma nagłówka Content-Length, ale my określamy nagłówek Content-Length i wszystko wydaje się działać podczas uruchamiania ten sam kod dla tego samego pliku PDF na serwerze testowym.

Zarówno serwery testowe, jak i produkcyjne korzystają z usług IIS 7.5, a obie mają włączoną funkcję dynamicznej i statycznej kompresji.

Oto kod w pytaniu:

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(); 
    } 
} 

miałem szczęście zobaczyć takie samo zachowanie na mojej lokalnej stacji roboczej tak pomocą debuggera udało mi się zobaczyć, że „Transfer-Encoding: pakietowego” nagłówek jest ustawiany na drugim przejściu przez pętlę while podczas połączenia z "Flush". W tym momencie odpowiedź ma zarówno nagłówek Content-Length, jak i nagłówek Transfer-Encoding, ale w pewnym momencie, gdy odpowiedź dotrze do przeglądarki Firebug pokazuje tylko nagłówek Transfer-Encoding.

UPDATE

myślę, że to w dół do śledzone za pomocą kombinacji wysyłania danych w „kawałki” I załączając „” filtru do obiektu HttpResponse (byliśmy przy użyciu filtra do śledzenia rozmiar obszaru wyświetlania jest wysyłany do każdej strony). Nie ma sensu używać filtru HTTP przy wysyłaniu pliku PDF do przeglądarki, więc wyczyszczenie filtra rozwiązało nasz problem. Postanowiłem zagłębić się nieco głębiej wyłącznie z ciekawości i zaktualizowałem to pytanie, gdyby ktokolwiek inny natknął się na ten problem w przyszłości.

Mam prostą aplikację na AppHarbor, która odtwarza problem: http://transferencodingtest.apphb.com/. Jeśli zaznaczysz zarówno "Użyj filtra?" i "Wyślij w kawałki?" w polach, powinieneś zobaczyć nagłówek "transfer-encoding: chunked" (za pomocą narzędzi do Chrome, Firebug, Fiddler, cokolwiek innego). Jeśli jedno z pól nie jest zaznaczone, otrzymasz odpowiedni nagłówek długości treści. Kod bazowym jest maksymalnie na github, dzięki czemu można zobaczyć, co dzieje się za kulisami:

https://github.com/appakz/TransferEncodingTest

Należy pamiętać, że do powtórzenia błędu lokalnie trzeba by skonfigurować lokalną witrynę w IIS 7.5 (7 może również pracować, Nie próbowałem). Serwer deweloperski ASP .NET dostarczany z programem Visual Studio NIE ROBISZ problemu.

Dodałem trochę więcej szczegółów na blogu tutaj: 'Content-Length' Header Replaced With 'Transfer-Encoding: Chunked' in ASP .NET

+0

Wiem, że to stare pytanie, ale wykonując podobne badania natknąłem się na [ten znakomity post] (http://geekswithblogs.net/GruffCode/archive/2012/01/02/lsquocontent-lengthrsquo-header-replaced-withsls-transact-encoding-chunkedquo-in-asp- .net.aspx) wyjaśniające ten problem. Aby stworzyć ten problem, potrzeba określonych okoliczności. Mam nadzieję, że to pomoże przyszłemu czytelnikowi. – user158017

+1

To jest wpis, który napisałem po zadaniu pytania, nie otrzymaniu odpowiedzi, a następnie w końcu wymyślić kilka kroków, aby konsekwentnie go odtworzyć. Zaktualizowałem oryginalne pytanie z linkami do przykładowej aplikacji, która je odtwarza, ale przypuszczam, że powinienem dodać także link do posta na blogu. –

Odpowiedz

4

Od an article on MSDN wydaje się, że można wyłączyć pofragmentowane kodowanie:

appcmd set config /section:asp /enableChunkedEncoding:False 

enter image description here

Ale to wymienione w ASP settings , więc może nie mieć zastosowania do odpowiedzi wygenerowanej z programu obsługi ASP.NET.

+1

Już sprawdziłem te ustawienia, ale nie miały one wpływu na tę kwestię. –

3

Po wywołaniu Response.Flush() ciało odpowiedzi jest w trakcie wysyłania do klienta, więc do odpowiedzi nie można dodać żadnych dodatkowych nagłówków. Uważam za mało prawdopodobne, aby drugie połączenie z Response.Flush() dodało w tym momencie nagłówek Transfer-Encoding.

Mówisz, że masz włączoną opcję kompresji. To prawie zawsze wymaga odrzutu. Więc byłoby sensowne, aby przed kompresją serwer znał Content-Length, może zastąpić nagłówek nagłówka Transfer-Encoding i podzielić odpowiedź. Jednak nawet przy włączonej kompresji na kliencie klient musi jawnie podać obsługę kompresji w nagłówku żądania Accept-Encoding, ponieważ serwer nie może skompresować odpowiedzi. Czy sprawdziłeś to w swoich testach?

W ostatecznej notatce, ponieważ dzwonisz pod numer Response.Flush(), spróbuj ustawić Response.Buffer = True i Response.BufferOutput = False. Wygląda na to, że mają one sprzeczne działanie w zakresie działania Response.Flush(). Zobacz komentarz na dole: this page i this page.

+0

Zgadzam się, że nie ma sensu, że nagłówki "zmieniają się" w drugim wywołaniu Flush, ale próbowałem tego samego kodu zi bez wysyłania danych w mniejszych porcjach, a przeglądarka rejestruje tylko otrzymane nagłówek "Transfer-Encoding", gdy używanych jest wiele wywołań do spłukiwania. Pracuję nad małą przykładową aplikacją, która będzie repro i opublikuje ją, gdy ją otrzymam. –

0

Miałem podobny problem, gdy pisałem duży plik CSV (plik nie istniał Zapisuję linię ciąg po linii, powtarzając kolekcję w pamięci i generując linię), wywołując Response.Write w strumieniu odpowiedzi z BufferOutput ustawiony na fałsz, ale rozwiązanie to zmienić

Reponse.ContentType = 'text/csv' do Reponse.ContentType = 'application/octet-stream'

Gdy typ zawartość nie została ustawiona dodano aplikacji/oktet, strumień kilka innych nagłówków reakcji, takim jak Content-Encoding - gzip