16.4 Das Common Gateway Interface
CGI (Common Gateway Interface) ist eine Beschreibung einer Schnittstelle http://cgi-spec. golux.com/, mit der externe Programme mit Informations-Servern, meistens Web-Servern, Daten austauschen. Die aktuelle Version ist CGI/1.1. Diese ausgeführten Programme werden kurz CGI-Programme genannt und können in allen erdenklichen Programmiersprachen verfasst sein. Häufig sind es Shell-/Python- oder Perl-Skripte (oft wird dann die Bezeichnung CGI-Skripte verwendet). Die Unterscheidung zwischen Skript und Programm ist bei CGI schwammig. Traditionell ist eine compilierte Quelldatei ein Programm, und Programme, die mit einem Interpreter arbeiten, sind ein Skript. Wir werden im Folgenden allerdings »Programm« und »Skript« synonym verwenden. Für uns ist es erst einmal egal, ob ein Programm oder ein Skript ausgeführt wird, denn wir wollen diese Programme aus Java nutzen und nicht selber schreiben. Auf der Server-Seite ergänzen und verdrängen Java Server Pages beziehungsweise Servlets immer stärker CGI-Programme.
Die CGI-Programme werden von einem Browser durch eine ganz normale URL angesprochen. Der Browser baut eine Verbindung zum Server auf, und dieser erkennt anhand des Pfads oder anderer Kriterien (Dateiendung oder spezielle Dateiflags), ob es sich um eine ganz normale Web-Seite handelt oder um ein Skript. Wenn es ein Skript ist, dann führt der Server das Skript aus, welches eine HTML-Datei erzeugt. Diese wird übertragen und im Browser dargestellt. Der Aufrufer einer URL merkt keinen Unterschied (außer vielleicht in der Performance) zwischen erstellten, also dynamischen, und statischen Seiten. Die CGI-Programme sind also immer eine Angelegenheit des Servers, der uns mit aktuellen Daten versorgt.
16.4.1 Parameter für ein CGI-Programm
Beim Aufruf eines CGI-Programms können Parameter übergeben werden, bei einer Suchmaschine etwa der Suchbegriff. Es gibt nun zwei Möglichkeiten, wie diese Parameter zum Skript kommen und somit vom Web-Server verarbeitet werden.
|
Die Parameter (auch Query-Strings genannt) werden an die URL angehängt (GET-Methode). Das Skript liest die Daten aus der CGI-Umgebungsvariablen QUERY_STRING aus. |
|
Die Daten werden zur Standardeingabe des Web-Servers gesendet (POST-Methode). Das Skript muss dann aus dieser Eingabe lesen. |
GET und POST unterscheiden sich auch in der Länge der übertragenen Daten. Bei vielen Systemen ist die Länge einer GET-Anfrage beschränkt auf 1024 Byte. POST-Anfragen sind längenunbegrenzt.
Daten werden nach der GET-Methode verschickt
Die Daten sind mit dem CGI-Programmnamen verbunden und gehen beide zusammen auf die Reise. Der Anfrage-String (Query-String) wird hinter ein Fragezeichen gesetzt, das Et-Zeichen »&« trennt mehrere Anfragezeichenketten. Unter Java setzen wir einfach einen Befehl ab, indem wir ein neues URL-Objekt erzeugen und anschließend den Inhalt auslesen:
meineURL = new URL( "http", "...", "cgi-bin/trallala?tri" );
Das CGI-Skript holt sich seinerseits die Daten aus der Umgebungsvariablen QUERY_STRING. Das folgende Kapitel zeigt, wie diese Abfragezeichenketten komfortabel durch die Klasse URLEncoder zusammengebaut werden. Werfen wir jedoch erst einen Blick auf die Variablen.
Daten holen mit der POST-Methode
Die Klasse URLConnection bietet die schon bekannte Methode getOutputStream() an, die eine Verbindung zur Eingabe des CGI-Scripts möglich macht (POST-Methode):
// CGI-Script schickt die Daten zurück
PrintStream o = new PrintStream( cgiConnection.getOutputStream() );
o.println( data );
o.close();
16.4.2 Kodieren der Parameter für CGI-Programme
Wenn aus einer HTML-Datei mit Formularen über Submit Daten an das CGI-Programm übermittelt werden, dann werden diese Daten kodiert. Dies liegt daran, dass viele Zeichen in URL nicht erlaubt sind. Betrachten wir daher folgenden Ausschnitt aus einer Web-Seite:
<form method="get" action="/cgi-bin/caller.cgi">
<p>Name:
<input type="text" name="name" value="">
<p>E-Mail:
<input type="text" name="email" value="">
<p>
<input type="submit" name="submit" >
</form>
Die Seite besitzt zwei Felder mit den Namen name und email. Dazu kommt noch ein Submit-Button, der, falls aktiviert, die Daten an das CGI-Programm caller.cgi weitergibt. Wenn wir die Felder mit irgendeinem Inhalt füllen und Submit drücken, sehen wir die URL häufig in der Adressleiste des Browsers. Dort erscheint, ohne Zeilenumbruch, zum Beispiel:
http://oho.de/cgi-bin/caller.cgi?
name=Ulli+Ullenboom&email=ulliull@ulli.com&submit=Submit
Da in einer URL keine Leerzeichen erlaubt sind, werden sie durch Pluszeichen kodiert. Es gibt noch weitere Zeichen, die kodiert werden, so das Plus- oder das Gleichheitszeichen oder auch das Und-Symbol. Von diesen Zeichen wird die Hex-Repräsentation als ASCII übersandt, aus »Ulli + Tanja« wird dann »Ulli+%2B+Tanja«. Aus dem Leerzeichen wird ein Plus und aus dem Plus wird %2B.
Neben der Textkodierung fällt noch auf, dass in der übermittelten Zeile jeder Feldname und das Feld mit seinem Feldinhalt übermittelt wird. Somit lässt sich leicht der Inhalt eines Felds heraussuchen, denn nach dem Feldnamen ist ein Gleichheitszeichen eingefügt. Das Ende der Inhalte ist durch ein Und-Zeichen gekennzeichnet.
Wollten wir einen String dieser Art zu einer URL zusammenbauen, um etwa eine Anfrage an ein Suchprogramm zu formulieren, dann müssen wir den String nicht kodieren. Dies übernimmt die Java-Klasse URLEncoder.
Hier klicken, um das Bild zu Vergrößern
Listing 16.6 URLEncodeTest.java
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class URLEncoderDemo
{
static void enc( String s )
{
try
{
System.out.println( URLEncoder.encode( s, "UTF-8" ) );
}
catch ( UnsupportedEncodingException e )
{
e.printStackTrace();
}
}
public static void main( String args[] )
{
enc( "String mit Leerezeichen" ); // String+mit+Leerezeichen
enc( "String%mit%Prozenten" ); // String%25mit%25Prozenten
enc( "String*mit*Sternen" ); // String*mit*Sternen
enc( "String+hat+ein+Plus" ); // String%2Bhat%2Bein%2BPlus
enc( "String/mit/Slashes" ); // String%2Fmit%2FSlashes
enc( "String\"mit\"Gänsen" ); // String%22mit%22G%C3%A4nsen
enc( "String:Doppelpunkten" ); // String%3ADoppelpunkten
enc( "String=ist=alles=gleich" ); // String%3Dist%3Dalles%3Dgleich
enc( "String&String&String" ); // String%26String%26String
enc( "String.mit.Punkten"); // String.mit.Punkten
}
}
class java.net.URLEncoder
|
|
static String encode( String s, String enc ) throws UnsupportedEncodingException
Kodiert einen String s mit einer bestimmten Encoding. |
class java.net.URLDecoder
|
|
static String decode( String s, String enc ) throws UnsupportedEncodingException
Dekodiert einen String s mit einer bestimmten Encoding. |
16.4.3 Eine Suchmaschine ansprechen
Wir wollen nun direkt eine Suchmaschine ansprechen und so das Verhalten eines Anfrageprogramms nachbilden. Unser Programm sammelt dazu alle Suchbegriffe als Parameter auf der Kommandozeile, falls keine Parameter vorhanden sind, wird nach »Teletubbies on Tour« gesucht. Anschließend kodiert die Klasse URLEncoder den Such-String, und der Inhalt wird hinter die URL des CGI-Programms gehängt, noch getrennt durch ein Fragezeichen. Dieses wird als Anfrage für die Suchmaschine Google verpackt und weggeschickt. Anschließend wird in einer Schleife die HTML-Datei zeilenweise ausgegeben.
Listing 16.7 GoogleSeeker.java
import java.io.*;
import java.net.*;
public class GoogleSeeker
{
public static void main( String args[] ) throws Exception
{
String s = "";
if ( args.length == 0 )
s = "Teletubbies On Tour";
else
for ( int i = 0; i < args.length; i++ )
s += args[i] + " ";
s.trim();
s = "q=" + URLEncoder.encode( s, "UTF-8" );
URL u = new URL( ">http://www.google.com/search?" + s );
BufferedReader in = new BufferedReader(
new InputStreamReader( u.openStream() ) );
String line, response = null;
while ( (line = in.readLine()) != null )
response += line+"\n";
System.out.print( response );
}
}
|