Potrzeba automatycznego przekierowania strony WWW do innego adresu URL pojawia się całkiem często. Dość typowe są na przykład serwisy typu download, gdzie faktyczne ściągnięcie pliku poprzedzone jest krótkim oczekiwaniem i odpowiednim komunikatem. Służy to głównie temu, by użytkownik omyłkowo nie rozpoczął procesu ściągania więcej niż raz.
Przyjrzyjmy się dzisiaj sposobom na dokonywanie takich przekierowań. Jeśli bowiem chwilę się nad tym zastanowić, to okazuje się, że można je przeprowadzać na różnych poziomach protokołów HTTP i nie tylko. Wśród możliwych metod można wyróżnić choćby takie:
window.location
. Ustawienie tej właściwości na adres URL powoduje automatyczne wykonanie przekierowania. Do działania wymaga to naturalnie obsługi Javascriptu po stronie klienta, więc może służyć do odfiltrowania tych klientów, którzy nie spełniają tego warunku. Dotyczy to na przykład przeglądarek tekstowych, takich jak Lynx.<meta>
. HTML przewiduje możliwość odświeżenia strony po określonym czasie, z opcjonalnym przekierowaniem do innego URL-a. Korzysta się w tym celu ze znacznika <meta>
:
Właśnie ta metoda jest zwykle wykorzystywana do implementacji wspomnianego na początku opóźnionego ściągania plików.
Location
). Istnieje cała grupa takich kodów o numerach zaczynających się od 300, jak na przykład 301 (Moved Permanently), będący trwałym przekierowaniem, czy 302/307 (Found/Temporary Redirect), wskazujące na mniej lub bardziej tymczasowe odesłanie do innego adresu.Jeśli przypadkiem zastanawiamy się, który rodzaj przekierowania powinniśmy zastosować, to spieszę z odpowiedzią, że prawie na pewno dobrym wyborem będzie któryś z dwóch środkowych elementów listy. Uzasadnieniem jest tu głównie chęć współpracy z robotami wyszukiwarek internetowych. Nie powinniśmy mianowicie spodziewać się, by uruchamiały one kod Javascript na przeglądanych przez siebie stronach, bo kosztowałoby to je zbyt dużo zasobów. Z drugiej strony istnieje też duża szansa, że nie będą one “świadome” “przekierowań” dokonywanych na poziomie systemu DNS, przez co mogą one potraktować dostępność tych samych treści z dwóch różnych adresów jako świadome duplikowanie contentu i próbę ich oszukania.
W grę wchodzą naturalnie jeszcze kwestie praktyczne. Nie każdy dysponuje własną domeną lub możliwością zmiany jej rekordów DNS. Nie każdy może też zmieniać ustawienia serwera HTTP, na którym funkcjonuje jego serwis. Wtedy przydatne są przekierowania dokonywane po stronie klienta np. za pomocą tagów HTML.
Oprócz ciasteczek (cookies) dwoma podstawowymi sposobami przekazywania parametrów na wejście serwera HTTP są metody znane jako GET i POST. Ta pierwsza wykorzystuje do tego sam adres URL, umieszczając dodatkowe dane po znaku zapytania, np.: /forum/showthread.php?id=12345&filter=none. W przypadku tej drugiej parametry są przekazywane poprzez treść samego żądania HTTP; z punktu widzenia użytkownika są więc one niewidoczne.
Metoda GET zwykle służy do wymiany danych między stronami połączonymi za pomocą zwykłych linków. POST z kolei wykorzystuje się do wysyłania informacji wprowadzanych przez użytkownika w różnego rodzaju formularzach. Przekierowanie następuje wówczas po jego wysłaniu, co zwykle czyni się odpowiednim przyciskiem (submit).
Bywa jednak tak, że chcemy dokonać takiego przekierowania – z ustalonymi parametrami – po zwykłym kliknięciu na link, z pominięciem wypełniania formularza przez użytkownika. Dobrym przykładem jest sytuacja, gdy nasza strona korzysta w jakiś sposób z innego serwisu, do którego przejście wymaga logowania. Jeśli chcielibyśmy, by odbywało się ono automatycznie – po kliknięciu jakiegoś linku – to musimy wysłać odpowiednie żądanie HTTP z parametrami przesłanymi metodą POST. Do tego nie wystarczy niestety sam znacznik <a>
.
Rozwiązaniem jest wtedy użycie dodatkowej strony przekierowującej, na której umieścimy już odpowiednio “wypełniony” formularz:
Oczywiście nazwy i wartości parametrów (zapewne generowane dynamicznie po stronie serwera) zależą ściśle od tego, dokąd chcemy nasz wyrób formularzopodobny wysłać. Wszystkie je deklarujemy jednak jako <input type="hidden" />
, bo w założeniu użytkownik nie powinien ich (łatwo) zobaczyć. Ponadto, jeśli – tak jak wyżej – mówimy o loginie/haśle czy innych danych, które powinno się chronić przed niepowołanym dostępem, to powinniśmy jeszcze wysyłać razem z naszą stroną nagłówki HTTP zabraniające cache‘owania:
W końcu, skoro mamy już gotowy “formularz”, to trzeba jeszcze zadbać o to, by wysłał się on sam natychmiast po załadowaniu strony przekierowującej. Do tego już trzeba wykorzystać skrypt uruchamiany w przeglądarce:
Tak przygotowaną stronę możemy podlinkować pod nasz serwis. Jak widać trochę z tym zabawy, ale tak to jest, gdy chcemy zrobić coś niestandardowego :)
Dawno, dawno temu miałem dość oryginalny pomysł na program użytkowy. Miała to być (o wiele) lepsza wersja konsoli Windows, której wyższość miała się objawiać w wyglądzie oraz możliwościach; pewne inspiracje czerpałem tutaj z terminali linuksowych oraz basha (nie, nie chodzi tu o serwis z cytatami z IRC-a ;P). Jak większość “genialnych” pomysłów, także i ten nie doczekał się realizacji. Przyczyną było to, iż nie za bardzo wówczas wiedziałem, jak można zapewnić, aby aplikacje konsolowe funkcjonowały w ramach projektowanego terminala tak, jak to robią w domyślnym oknie konsoli w Windows. Większość problemu rozbijała się o to, jak pobierać dane przez ów program produkowane i jak przekazywać do niego te wpisywane przez użytkownika.
Konsolka mała i ciasna, ale własna
Jako że było to bardzo dawno temu, nie znałem wtedy jeszcze takich terminów jak ‘standardowe wejście/wyjście’, ‘proces potomny’ czy ‘pipe‘, które byłyby tutaj bardzo pomocne. Dowiedziałem się o nich więcej dopiero znacznie później, przy czym wiedza ta w większości odnosiła się do systemu zgoła innego niż Windows :)
Pomyślałem jednak, że do problemu można by wrócić – zwłaszcza, że pytanie o to, jak uruchomić program z przekierowanym wejściem i wyjściem, pojawia się stosunkowo często. Okazało się, że nie jest to specjalnie trudne i sprowadza się właściwie do trzech kroków – z których tylko pierwszy może być nieco zakręcony. Cała procedura (w Windows) może wyglądać na przykład tak:
CreatePipe
), które posłużą nam do odbierania wyjścia od i dostarczania wejścia do procesu potomnego. Należy przy tym zwrócić uwagę na dwie rzeczy:
SECURITY_ATTRIBUTES
(tak, tej którą w 95% przypadków się ignoruje) i przekazując ją do funkcji tworzącej pipe.CreateProcess
). Musimy mu podać właściwe końce rurek w strukturze STARTUPINFO
oraz poinstruować Windows, by były one wykorzystywane (flaga STARTF_USESTDHANDLES
). Ponadto musimy wskazać, że chcemy dziedziczyć uchwyty i że utworzony proces konsolowy nie powinien pokazywać okienka (CREATE_NO_WINDOW
) – to już przekazujemy w parametrach CreateProcess
.WaitForMultipleObjects
. Natomiast organizacja wejścia zależy już od naszej aplikacji. Warto pamiętać, że w standardowej konsoli jest ono buforowane wierszami, zatem i my powinniśmy wysyłać coś do procesu potomnego dopiero wtedy, gdy zbierzemy całą linijkę danych wejściowych.Łatwe, prawda? ;-) W innych systemach operacyjnych robi się to minimalnie inaczej (pipe
, fork
, dup2
, …), ale ogólna idea jest podobna. Jak widać, kilkoma małymi rurkami można zdziałać całkiem sporo :]