Advanced
Java
Services
|
Die Klasse URLConnection |
Die Implementierungen der Klasse URLConnection
Es kostet ein wenig Mühe, die verschiedenen Implementierungen der abstrakten Klasse URLConnection aus den Archiven rauszufischen. Hier das Ergebnis meiner Recherche.
Die Initialisierung einer URLConnection
Die realen Unterklassen von URLConnection werden nicht per Konstruktor initialisiert. Stattdessen
benützt man, wie schon früher erwähnt, die Methode openConnection() aus der Klasse URL.
URLConnection uConn = url.openConnection() ;
Das Objekt uConn hat natürlich (auch) den Typ einer realen Unterklasse von URLConnection. Geben Sie im
folgenden Applet eine URL-Adresse ein und erzeugen Sie mit dem linken Button ein Objekt vom Typ URL und
mit dem rechten Button ein Objekt vom Typ URLConnection und beobachten Sie die Ausgaben. Probieren Sie
verschiedene Protokolle wie ftp, gopher, https und file. Beachten Sie daß file drei slashes benötigt,
also "file:///..." und beobachten sie, was passiert, wenn Sie hier einen slash vergessen oder ein
nicht existierendes Protokoll eingeben.
Man sieht, daß der Typ des gelieferten Objekts vom Protokoll abhängt. Für eine http-Protokoll
bekommt man also immer ein Objekt vom Typ HttpURLConnection. Wir werden das später noch ausnützen.
Man sieht außerdem, daß nicht wirklich eine Verbindung aufgebaut wird. Sie können x-beliebige Adressen
eingeben wie "http://so ein schmarrn", die nicht existieren können und erhalten trotzdem ein
zunächst noch gültiges HttpURLConnection Objekt.
GET und POST mit URLConnection
Da GET und POST zum HTTP-Protokoll gehören, gehen wir von einer dazu passenden URL aus und holen uns
dazu eine URLConnection.
URL url = new URL("http://www.xxx.zzz/path/to/file.xyz");
URLConnection uConn = url.openConnection();
1) InputStream als erstes Öffnen
Wir holen uns einen InputStream mit
InputStream inStream = uConn.getInputStream();
D.h. etwa, wir wollen die Datei file.xyz übertragen bekommen. Datenübertragung mit GET und POST erläuterten Mechanismus kommt eine Datei aber nicht von selbst daher, sondern wird vom Client beim Server angefordert. Wenn also die Methode getInputStream() einen InputStream liefert, dann heißt das, daß diese Methode zuerst eine (versteckte) Anforderung an den Server schickt (schicken muß!). Der Server reagiert darauf so, daß er einen Antwortheader sendet und die gewünschte Datei im BODY der Antwort schickt. getInputStream() nimmt die Antwort entgegen, unterdrückt den Header und liefert den BODY als InputStream. Schreibt man sich mit Hilfe der Klasse ServerSocket einen einfachen WebServer, der auf Anfragen eines Client lauscht, so kann man dieses Verhalten bestätigen. Der Header, den getInputStream() (heimlich) sendet, beinhaltet eine GET-Anforderung und sieht folgendermaßen aus:
Der gelieferte InputStream hat übrigens den Typ sun.net.www.protocol.http.HttpConnection$HttpInputStream.
Es handelt sich also um eine nested Klasse.
Nachträgliches Öffnen eines OutputStreams (ist nicht möglich)
Generell muß man zum Öffnen eines OutputStreams vorher die Methode uConn.setDoOutput() mit dem
Argument true rufen, sonst wird eine ProtocolException geworfen.
uConn.setDoOutput(true);
Trotzdem kann man nach dem Öffnen eines InputStreams keinen OutputStream mehr öffnen. Wiederum
wird eine ProtocolException geworfen.
Daten mit GET senden
Will man mit der versteckten GET-Anfrage Daten senden, so müssen diese an die URL-Adresse angehängt
werden. Das sieht dann so aus.
URL url = new URL("http://www.xxx.zzz/path/to/file.xyz?urlcodierterDatenString");
URLConnection uConn = url.openConnection();
InputStream inStream = uConn.getInputStream();
oder kürzer
URL url = new URL("http://www.xxx.zzz/path/to/file.xyz?urlcodierterDatenString");
InputStream inStream = url.openStream();
Beim Öffnen des InputStreams wird dann die GET-Anfrage mit den Daten gesendet.
2) OutputStream als erstes Öffnen
uConn.setDoOutput(true);
OutputStream outStream = uConn.getOutputStream();
sun.net.www.http.PosterOutputStream. In diesen OutputStream
kann man schreiben, aber die Daten werden zunächst nicht gesendet (beachte den Namen des Streams)
InputStream öffnen (zusätzlich nach dem OutputStream !)
Dies geht und man erhält wieder ein Objekt vom Typ sun.net.www.protocol.http.HttpConnection$HttpInputStream.
Auch in diesem Fall sendet getInputStraem() eine versteckte Anfrage an den Server, aber diesmal
handelt es sich um eine POST-Anfrage. Zusammen mit der POST-Anfrage werden die Daten verschickt, die man
in den (Poster)OutputStream geschrieben hat.
Und so sieht der POST-Header aus
POST / HTTP/1.1
User-Agent: Java/1.4.2
Host: 127.0.0.1
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 5
Aus dem POST Header ersieht man, daß erwartet wird, daß die Daten URL-encoded sind. Dafür muß man
.
Vor dem Öffnen eines InputStreams die ÜbertragungsMethode wählen
Da wir ja wissen, daß unser URLConnectionObjekt vom Typ einer Unterklasse von HttpURLConnection ist,
können wir folgendes wagen:
if(uConn instanceof HttpURLConnection) //sun.net.www.protocol.http.HttpConnection
{
HttpURLConnection httpConn = (HttpURLConnection)uConn;
httpConn.setRequestMethod("POST") ;
InputStream inStream = uConn.getInputStream();
}
Damit sendet getInputStream() eine versteckte POST-Anfrage, allerdings ohne daß Daten gesendet
werden. Das Öffnen eines OutputStreams nach dem Öffnen des Inputs endet auch hier mit einer
ProtocolException. Will man also mit der POST-Methode Daten senden, muß man wie vorher zuerst
den OutputStream öffnen, die Daten im PosterOutputStream deponieren und anschließend den
InputStream öffnen, der dann automatisch die POST-Anfrage plus Daten sendet und auf eine Antwort
wartet. Die letzte Variante ist damit nur theoretisch interessant, in der Praxis wird man die
POST-Methode ja nur dann wählen, wenn man Daten an den Server übertragen will.
Zusammenfassung
Daten mit GET senden
URL url = new URL("http://www.xxx.zzz/path/to/file.xyz?urlcodierterDatenString");
InputStream inStream = url.openStream();
inStream.read(antwort);
inStream.close();
Daten mit POST senden
URL url = new URL("http://www.xxx.zzz/path/to/file.xyz");
URLConnection uConn = url.openConnection();
uConn.setDoOutput(true);
OutputStream outStream = uConn.getOutputStream();
outStream.write(data);
outStream.close();
// Daten mit POST senden :
InputStream inStream = uConn.getInputStream();
inStream.read(antwort);
inStream.close();