Coś z zupełnie innej beczki: wydajność - ilość requestów
A te kilka słów chcę napisać, bo z wydajnością jest często po prostu źle. Bardzo często jest tak, że do załadowania jednej strony potrzebnych jest kilka(naście|dziesiąt) odwołań do serwera. Warto tutaj zaznaczyć, że klient (przeglądarka) nie może nawiązywać dowolnej ilości połączeń do serwera, dobrze zachowujący się klient nawiązuje jednocześnie co najwyżej dwa połączenia do jednego serwera (patrz RFC 2068). Co się dzieje, jeśli w ramach tych dwóch połączeń do załadowania strony trzeba ściągnąć 150 elementów, różnego rodzaju obrazków, plików ze skryptami, definicji stylów CSS, łatwo się domyślić. Jak to można rozwiązać?
Można rozdzielić treść dynamiczną od treści statycznej. Obrazki, skrypty, arkusze stylów mogą być pobierane z innych serwerów, niż "główna" treść. Pozwala to na równoległe pobranie większej ilości danych w jednostce czasu (bo jeśli serwerów jest 6, to przeglądarka może nawiązać 12 połączeń). Ale jeszcze lepiej, by przeglądarka tych połączeń nie musiała nawiązywać. Nie chodzi mi tu o różne techniki "konsolidacji" plików (Data URI Support), ale o efektywne wykorzystanie mechanizmów cache (pamięci podręcznej). Bardzo często mam okazję oglądać, jak przy każdym kolejnym ładowaniu strony, przeglądarka wysyła żądania o praktycznie każdy element graficzny tej strony. Co prawda dostaje od serwera odpowiedź 304 i treść nie jest pobierana, ale samo żądanie jest wysyłane. Po co? Czy obrazki zmieniają się tak szybko? Skrypty? Arkusze stylów? Śmiem wątpić. Ustawienie "czasu życia" (czyli w praktyce na przykład nagłówka Expires) takiego obrazka nawet na godzinę spowodowałoby, że tych żądań zakończonych odpowiedzią serwera 304 byłoby zdecydowanie mniej. To nie jest tak, że w przypadku "bezpiecznych aplikacji webowych" zawsze należy ustawić nagłówek Cache-control na no-store!
W przypadku aplikacji ASP.NET zauważyłem, że często wykorzystywany jest mechanizm WebResource.axd. Według informacji znajdującej się tu: Don’t run production ASP.NET Applications with debug=”true” enabled mechanizm ten jest "samooptymalizujący się", czyli "na produkcji" automatycznie ustawiany jest "długi czas życia" zwracanych w ten sposób treści. Jeśli treści te zwracane są bez stosownych nagłówków, to można założyć, że aplikacja jest właśnie w wersji debug, co w trakcie testów penetracyjnych może być interesującą informacją. Trochę irytujące może być natomiast obserwowanie, jak po raz kolejny pobierane są te same skrypty i obrazki.
Fiddler pozwala na łatwe ukrycie odwołań do obrazków czy sesji, w których serwer zwrócił odpowiedź 304. Przy zapisywaniu takiej sesji (no trzeba mieć historię działań) okazuje się nagle, że poza 100 sesji widocznych w UI jest jeszcze kilkaset sesji (odwołań do plików), które zostały wyfiltrowane. To naprawdę jest spory problem.
Warto wspomnieć o narzędziach wspomagających optymalizację stron pod względem ich wydajności. Po pierwsze wspominany już Fiddler ma rozszerzenie Timeline, które pozwala w graficznej formie przedstawić proces ładowania strony. Warto też zapoznać się z Fiddler PowerToy - Part 2: HTTP Performance. Po drugie potężna wtyczka Firebug ma rozszerzenie YSlow, które potrafi przeanalizować wskazaną stronę i wskazać obszary wymagające poprawy, a następnie odesłać do odpowiedniego fragmentu Best Practices for Speeding Up Your Web Site.