Advanced   Java   Services
Die Klasse URLConnection
Back Next Up Home

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:

GET / HTTP/1.1
User-Agent: Mozilla/4.0 (Windows 2000 5.0) Java/1.4.2
Host: 127.0.0.1
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive

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

top Back Next Up Home