R05_05.PDF
(
526 KB
)
Pobierz
Szablon dla tlumaczy
W tym rozdziale:
•
Struktura odpowiedzi
•
Przesyłanie standardowej odpowiedzi
•
Stosowanie trwałych połączeń
•
Buforowanie odpowiedzi
•
Kody statusu
•
Nagłówki HTTP
•
Rozwiązywanie problemów
•
Sześć sposobów wyciągania korzyści z apletów
Rozdział 5.
Przesyłanie informacji HTTP
W poprzednim rozdziale dowiedzieliśmy się, że aplet ma dostęp do różnego rodzaju informacji — informacji o
kliencie, o serwerze, o zleceniu i nawet o sobie samym. Czas więc abyśmy się zapoznali z tym, co aplet może
zrobić z tymi informacjami — dowiemy się jak są ustalane i przesyłane informacje.
Rozdział ten zaczyna się od ogólnej charakterystyki sposobu, w jaki aplet odsyła standardową odpowiedź HTTP.
W tym rozdziale omówimy również szczegółowo niektóre metody, które omówiliśmy tylko pobieżnie w
poprzednich przykładach. Dalej powiemy jak zmniejszyć obciążenie związane z utrzymywaniem połączenia z
klientem, dowiemy się również jak w tym celu wykorzystać buforowanie odpowiedzi. Następnie poznamy parę
dodatkowych, przydatnych zastosowań HTML-u i HTTP takich jak np. odsyłanie błędów, i innych kodów
statusu, przesyłanie niestandardowych informacji nagłówkowych, przekierowywanie zlecenia, wykorzystywanie
ściągania klienta, obsługa wyjątków apletu, ustalanie momentu rozłączenie klienta oraz wpisywanie danych do
dziennika zdarzeń serwera.
W przeciwieństwie do swojego odpowiednika z poprzedniego wydania niniejszej książki, rozdział ten nie
opisuje szczegółowo generowania treści HTML-owej. Jest on wprowadzeniem do następnych rozdziałów
książki, w których omówionych zostanie szereg oddzielnych osnów.
Struktura odpowiedzi
Aplety HTTP odsyłają trzy, różne rodzajowo kwestie: pojedynczy kod statusu, dowolną liczbę nagłówków
HTTP oraz treść odpowiedzi.
Kod statusu
jest liczbą całkowitą, która opisuje, jak się łatwo można domyśleć
status odpowiedzi. Kod statusu może informować o sukcesie bądź niepowodzeniu może również poinformować
oprogramowanie klienta, iż należy powziąć dodatkowe kroki w celu zakończenia zlecenia. Numerycznemu
kodowi statusu często towarzyszy
reason phrase,
które opisuje status językiem bardziej przystępnym dla ludzi.
Zwykle kod statusu działa „w tle” i jest interpretowany przez oprogramowanie przeglądarki. W niektórych
przypadkach, kiedy pojawiają się problemy, przeglądarka może pokazać kod statusu użytkownikowi.
Najbardziej chyba znanym kodem statusu jest kod 404NotFound, przesyłany przez serwer WWW, kiedy ten nie
może znaleźć żądanego URL-u.
W poprzednim rozdziale zapoznaliśmy się ze sposobem, w jaki klient wykorzystuje nagłówki HTTP w celu
przesłania dodatkowych informacji razem ze zleceniem. W tym rozdziale zobaczymy jak aplet może przesyłać te
nagłówki jako część swojej odpowiedzi,
Korpus odpowiedzi jest główną treścią odpowiedzi. Dla strony HTML, korpusem odpowiedzi jest sam HTML.
W przypadku grafiki, korpus odpowiedzi jest złożony z bitów, które składają się na obrazek. Korpus odpowiedzi
może mieć różny typ oraz różną długość; klient czytając oraz interpretując nagłówki HTTP zawarte w
odpowiedzi, wie czego może się spodziewać.
Standardowe aplety są znacznie mniej skomplikowane od apletów HTTP — odsyłają tylko korpus odpowiedzi
do swojego klienta. Co się jednak tyczy podklasy
GenericServlet
, to może ona przedstawiać API, które dzieli
pojedynczy korpus odpowiedzi na bardziej skomplikowaną strukturę, dając wrażenie odsyłania wielokrotnych
pozycji ewidencyjnych. W rzeczywistości jest to dokładnie to co robią aplety HTTP. Na najniższym poziomie,
serwer WWW przesyła całą odpowiedź do klienta jako strumień bitów. Wszystkie metody, które ustalają kody
statusu lub nagłówki są w stosunku do tego abstrakcjami.
Jest rzeczą ważną, aby zrozumieć, mimo iż programista apletów nie musi znać szczegółów protokołu HTTP, że
protokół ten jednak ma wpływ na kolejność z jaką aplet wywołuje swoje metody. Cechą charakterystyczną
protokołu HTTP jest to, że kod statusu oraz nagłówki muszą zostać przesłane przed korpusem odpowiedzi.
Dlatego właśnie aplet musi dopilnować, aby zawsze ustalić najpierw swój kod statusu oraz nagłówki zanim
jeszcze prześle klientowi jakikolwiek korpus odpowiedzi. Aplet może umieścić swój korpus odpowiedzi w
pamięci podręcznej, żeby uzyskać większą swobodę, jednak kiedy korpus odpowiedzi zostanie już wysłany,
odpowiedź uważana jest jako zatwierdzona, wtedy kod statusu oraz nagłówki nie mogą już zostać zmienione.
Przesyłanie standardowej odpowiedzi
Nasze rozważania na temat odpowiedzi apletów rozpoczniemy od powtórnego przyjrzenia się pierwszemu
apletowi, którego przedstawiliśmy w tej książce jako pierwszego, mowa oczywiście o aplecie
HelloWorld
(aplet
HelloWorld
został pokazany w przykładzie 5.1). Mamy nadzieję, iż w tej chwili wydaje się on już
znacznie prostszy niż w rozdziale 2 „Podstawy Apletów HTTP”.
Przykład 5.1.
Jeszcze raz „Hello”
import java.io.* ;
import javax.servlet.* ;
import javax.servlet.http. *;
public class HelloWorld extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res. setContentType (" tekst/html") ;
PrintWriter out = res.getWriter();
out.println("<HTML>") ;
out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>") ;
out.println("<BODY>") ;
out.println("<BIG>Hello World</BIG>") ;
out.println("</BODY></HTML>") ;
}
}
Aplet ten używa dwóch metod oraz jednej klasy, które do tej pory zostały omówione tylko skrótowo. Metoda
setContentType()
ServletResponse
(odpowiedzi serwera) ustala typ treści odpowiedzi, aby był on typem
określonym.
public void ServletResponse.setContentType(String typ)
W aplecie HTTP metoda ta ustala nagłówek HTTP
Content-Type
.
Metoda
getWriter()
odsyła
PrintWriter
w przypadku pisania danych odpowiedzi opartych na znakach:
public PrintWriter ServletResponse.getWriter() throws IOException
Program wykonujący zapis koduje znaki zgodnie z zestawem znaków, podanym w typie treści. Jeżeli nie został
określony żaden zestaw znaków, tak jak to najczęściej ma miejsce, program wykonujący zapis używa kodowania
ISO-8859-1 (Latin-1) właściwego dla języków zachodnio-europejskich. Zestawy znaków zostały omówione
szczegółowo w rozdziale 13 „Internacjonalizacja”, na ten moment zapamiętajmy tylko, że dobrze jest zawsze
ustalić typ treści przed otrzymaniem
PrintWriter
. Metoda ta zgłasza wyjątek
IllegalStateException
—
w przypadku gdy metoda
getOutputStream()
została już wywołana do tej odpowiedzi; która to z kolei
metoda zgłasza wyjątek
UnsupportedEncodingException
jeżeli kodowanie strumienia wyjściowego jest nie
jest obsługiwane lub nieznane.
Poza możliwością wykorzystania
PrintWriter
w celu odesłania odpowiedzi, aplet może posłużyć się specjalną
podklasą
java.io.OutoutStream
, ażeby móc pisać dane binarne — mowa o
ServletOutputStream
, która
została zdefiniowana w
javax.servlet
. Klasę
ServletOutputStream
można uzyskać za pomocą metody
getOutputStream()
:
public ServletOutputStream ServletResponse.getOutputStream () throws IOException
Metoda ta odsyła
ServletOutputStream
dla pisania binarnych danych odpowiedzi. Nie jest w takim
przypadku wykonywane żadne kodowanie. Metoda ta zgłasza wyjątek
IllegalStateeException
jeżeli
getWriter()
została już dla tej odpowiedzi wywołana.
Klasa
ServletOputputStream
przypomina standardową klasę Javy —
PrintStream
. W Interfejsie API 1.0,
klasa ta byłą używana dla całego strumienia wyjściowego apletu (zarówno tekstowego jak i binarnego).
Jednakże w wersji 2.0 Interfejsu API oraz późniejszych, została ograniczona tylko do obsługi danych binarnych.
Będąc bezpośrednią podklasą
OutputStream
, klasa ta zapewnia dostęp do metod klasy
OutputStream
takich
jak:
write()
,
flush()
oraz
close()
.Poza powyższymi metodami klasa dodaje również swoje własne
print()
i
println()
klasy
ServletOutputStream
, umożliwiające pisanie większości elementarnych
Javowskich typów danych (w celu uzyskania kompletnego zestawienia patrz Uzupełnienie A: „Interfejs API —
charakterystyka ogólna”). Jedyna różnica pomiędzy interfejsem
ServletOutputStream
a interfejsem klasy
PrintStream
, jest taka, że metody
print()
oraz
println()
klasy
servletOutputStream
nie mogą (nie
jest dokładnie jasne dlaczego) drukować bezpośrednio parametrów typu
Object
czy
char[]
.
Korzystanie ze połączeń stałych
Połączenia stałe (
persistent connections
) mogą zostać wykorzystane w celu optymalizacji sposobu, w jaki aplet
odsyła treść do klienta. Aby zrozumieć na czym polega taka optymalizacja musimy najpierw zapoznać się z
działaniem połączeń HTTP. Będziemy je poznawali możliwie najmniej szczegółowo, tak tylko aby poznać
ogólną zasadę działania. Problem jest omówiony dogłębnie w książce Clintona Wong’a
„HTTP Pocket
Refference”
.
Kiedy klient np. przeglądarka, chce złożyć do serwera zlecenie na określony dokument sieci WWW, rozpoczyna
poprzez ustanowienie połączenia do portu serwera. Właśnie poprzez to połączenie klient składa swoje zlecenie
oraz otrzymuje odpowiedź serwera. Klient daje znać, że jego zlecenie zostało zakończone przesyłając czystą
linię; serwer zaś, żeby poinformować, że odpowiedź została zakończona przerywa połączenie poprzez port.
Na powyższym etapie wszystko przebiega bez zakłóceń, lecz zastanówmy się jak wyglądałaby sytuacja, kiedy
wyszukana strona zawierałaby znaczniki
<IMG>
lub znaczniki
<APPLET >
, które obligują klienta do odczytania
większej ilości treści z serwera? W takim przypadku tworzone jest jeszcze jedno połączenie portowe. Jeżeli
strona zawiera 10 znaków graficznych wraz z apletem składającym się z 25 klas, daje to razem 36 połączeń
potrzebnych do przesłania strony. Wobec takich utrudnień nie dziwi zdenerwowanie internautów długimi
czasami oczekiwań w Internecie. Taką sytuacją można porównać do zamawiania pizzy poprzez składanie
zamówienia na każdą jej warstwę.
Znacznie lepszym rozwiązaniem jest wykorzystywanie jednego połączenia do pobrania więcej niż jednej strony
— metoda zwana trwałym połączeniem. Problem z trwałym połączeniem polega na tym, że klient i serwer
muszą jakoś uzgodnić gdzie zaczyna się odpowiedź serwera a gdzie zaczyna się następne zlecenie klienta.
Rozwiązaniem, które się nasuwa jest takie, że można by wykorzystać w tym celu jakiś element składniowy taki
jak np. czysta linia. Co by się jednak stało gdyby już sama odpowiedź zawierała czystą linię? Idea trwałego
połączenia polega na tym, że serwer informuje klienta o tym jakie rozmiary będzie miał korpus odpowiedzi,
ustalając nagłówek
Content-Length
jako część odpowiedzi. Klient wie dzięki temu, że jeżeli wszystko będzie
zgodne będzie miał znowu kontrolę nad połączeniem.
Większość serwerów wewnętrznie zarządza nagłówkiem
Content-Length
dla plików statycznych, które są
przez nie podawane; nagłówek
Content-Length
jest ustanawiany aby dostosować długość pliku. Aby określić
długość treści generowanego przez serwer wydruku wyjściowego, serwer korzysta z pomocy apletu. Aplet może
ustanowić odpowiedź
Content-Length
i zyskać w ten sposób korzyści płynące ze stosowania trwałego
połączenia dla treści dynamicznej poprzez użycie metody
setContentLength()
:
public void ServletResponse.setContentLength(int len)
Metoda ta ustala długość (w bitach) treści odsyłanej przez serwer. W przypadku apletu HTTP, metoda ustanawia
nagłówek HTTP
Content-Length
. Zauważmy, że stosowanie tej metody jest opcjonalne. Jeżeli jednak
zdecydujemy się na jej zastosowanie, nasze aplety będą mogły czerpać korzyści płynącyce ze stosowania
trwałych połączeń, jeżeli takie się pojawią. Klient będzie również w stanie wyświetlać dokładne monitorowanie
stopnia bieżącego zaawansowania podczas ładowania.
Jeżeli wywołujemy metodę
setContentLength()
,musimy pamiętać o dwóch bardzo ważnych sprawach: aplet
musi wywołać tą metodę przed wysłaniem korpusu odpowiedzi oraz o tym, że podana długość musi być
dokładnie odwzorowana. W razie najmniejszej rozbieżności (nawet o jeden bit) musimy liczyć się z
potencjalnymi problemami.
Buforowanie odpowiedzi
Począwszy od wersji 2.2 Interfejsu API aplety maja kontrolę nad tym czy serwer buforuje swoją odpowiedź czy
nie oraz mogą mieć wpływ na wielkość bufora używanego przez serwer. W poprzednich wersjach API
większość serwerów wdrażała buforowanie odpowiedzi jako sposób na poprawienie wydajności; wielkość
bufora była determinowana przez serwer. Ogólnie rzecz biorąc serwery miały bufory wielkości około 8K.
Bufor pamięci pozwala apletowi na pisanie pewnej ilości wydruku wyjściowego z gwarancją, że odpowiedź nie
będzie od razu zatwierdzona. Jeżeli aplet wykryje błąd, kod statusu oraz nagłówki będą mogły być jeszcze
zmienione (do czasu opróżnienia bufora).
Buforowanie odpowiedzi jest również prostym sposobem uniknięcia stosunkowo trudnego szacowania długości
treści. Aplet może wykorzystać buforowanie aby automatycznie obliczyć długość treści, tak jak to zostało
zaprezentowane na przykładzie 5.2.
Przykład 5.2.
Aplet wykorzystujący buforowania do automatycznej obsługi trwałych połączeń
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class KeepAlive extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setBufferSize(8*1024); // 8K buffer
// Poproś o bufor 16k bitów; nie ustalaj długości treści
res.setBufferSize(16 * 1024);
PrintWriter out = res. getWriter () ;
Plik z chomika:
lazarusp22
Inne pliki z tego folderu:
uukjsrpa.zip
(2849 KB)
uukjsrpc.zip
(2849 KB)
uukjsrpb.zip
(2849 KB)
R06_05.PDF
(842 KB)
R04_05.PDF
(597 KB)
Inne foldery tego chomika:
Java Servlet i Java Server Pages
Java Servlet. Programowanie
Java.Servlet.i.Java.Server.Page.SPECIAL.Tech-eBook-Uuk
Zgłoś jeśli
naruszono regulamin