13.4Mit GET und POST Daten übergeben *
Beim Aufruf einer Webseite können wir Parameter übergeben – beim Ansprechen einer Suchmaschine etwa den Suchbegriff. Es gibt nun zwei Möglichkeiten, wie diese Parameter zum Server kommen:
Die Parameter (auch Query-Strings genannt) werden an die URL angehängt (GET-Methode).
Die Daten werden zur Standardeingabe des Webservers gesendet (POST-Methode). Das Serverprogramm 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 auf 1.024 Byte beschränkt. POST-Anfragen sind in ihrer Länge unbegrenzt.
Daten nach der GET-Methode verschicken
Im Fall der GET-Anfrage steht der Anfrage-String (Query-String) hinter dem Fragezeichen, das wiederum hinter der Pfadangabe steht. Mehrere Query-Strings trennt das &-Zeichen. Unter Java setzen wir einfach einen Befehl ab, indem wir ein neues URL-Objekt erzeugen und anschließend den Inhalt auslesen.
Daten nach der POST-Methode versenden
Die Klasse URLConnection bietet die schon bekannte Methode getOutputStream() an, die eine Verbindung zur Eingabe des serverseitigen Programms möglich macht (POST-Methode).
13.4.1Kodieren der Parameter für Serverprogramme
Da nicht alle Zeichen in einer URL-Zeile erlaubt sind, müssen sie umkodiert werden. So sind zum Beispiel keine Leerzeichen gültig; sie werden durch ein Pluszeichen umkodiert. Es gibt noch weitere zu übersetzende Zeichen, so das Plus-, Gleichheits- und Und-Zeichen. Von diesen Symbolen wird die Hex-Repräsentation als ASCII übersandt, aus »Ulli + Tina« wird dann »Ulli+%2B+Tina«. Aus dem Leerzeichen wird ein Plus, und aus dem Plus wird »%2B«.
Wollten wir einen String dieser Art zu einer URL zusammenbauen, um etwa eine Anfrage an ein Suchprogramm zu formulieren, müssen wir den String nicht kodieren. Dies übernimmt die Java-Klasse URLEncoder; den Weg zurück übernimmt URLDecoder.
Listing 13.7com/tutego/insel/net/URLEncoderDemo.java, main()
String utf = StandardCharsets.UTF_8.name();
o.println( URLEncoder.encode( "L e e r z eichen", utf ) ); // L+e+e+r+z+eichen
o.println( URLEncoder.encode( "20%Prozent%", utf ) ); // 20%25Prozent%25
o.println( URLEncoder.encode( "hat+ein+Plus", utf ) ); // hat%2Bein%2BPlus
o.println( URLEncoder.encode( "/temp/data/", utf ) ); // %2Ftemp%2Fdata%2F
o.println( URLEncoder.encode( "Sagt \"Gänse\"", utf ) ); // Sagt+%22G%C3%A4nse%22
o.println( URLEncoder.encode( ":Doppelpunkt:", utf ) ); // %3ADoppelpunkt%3A
o.println( URLEncoder.encode( "a=b=c", utf ) ); // a%3Db%3Dc
o.println( URLEncoder.encode( "Und&Co", utf ) ); // Und%26Co
o.println( URLEncoder.encode( "..Punkte..", utf ) ); // ..Punkte..
Die Klasse URLEncoder bietet encode(…) und URLDecoder entsprechend decode(…):
static String encode(String s, String enc) throws UnsupportedEncodingException
Kodiert einen String s mit einem bestimmten Encoding.
static String decode(String s, String enc) throws UnsupportedEncodingException
Dekodiert einen String s mit einem bestimmten Encoding.
13.4.2In Wikipedia suchen und mit GET-Request absenden
Wikipedia bietet eine API, mit denen sich Aufgaben wie die Suche nach Begriffen oder das Ändern von Seiten automatisieren lassen. Nehmen wir an, wir wollten nach »GmbH & Co. KG« suchen, dann hat für eine Suche mit dem Ausgabeformat Text die Wikipedia-Such-URL folgenden Aufbau: https://de.wikipedia.org/w/api.php?action=query&generator=search&format=txt&gsrsearch=GmbH_%26_Co._KG. Wir können gut erkennen, dass im Such-String das Leerzeichen durch einen Unterstrich ersetzt ist und das & durch %26.
Resultat der Anfrage ist ein Ergebnis im Textformat, das Zeilen wie diese enthält:
(
[pageid] => 16945
[ns] => 0
[title] => Gesellschaft mit beschränkter Haftung (Deutschland)
)
[2016] => Array
(
[pageid] => 2016
[ns] => 0
[title] => GmbH & Co. KG
)
In der URL war gut der kodierte Suchbegriff abzulesen, den wir in unserem folgenden Java-Beispiel frei parametrisieren wollen. Unser Programm soll Suchbegriffe als Parameter auf der Kommandozeile entgegennehmen, daraus eine korrekte Anfrage-URL formulieren und alle Suchergebnisse auf der Konsole ausgeben:
Listing 13.8com/tutego/insel/net/WikipediaSeeker.java, WikipediaSeeker
public static void main( String[] args ) throws Exception {
String search = args.length > 0 ? String.join( "_", args ) : "Java (Programmiersprache)";
search = URLEncoder.encode( search, StandardCharsets.UTF_8.name() );
URL url = new URL( "http://de.wikipedia.org/w/api.php?action=query&generator=search& format=txt&gsrsearch=" + search );
// [title] => Java (Programmiersprache)
Pattern titlePattern = Pattern.compile( "\\s+\\[title\\] => (.*)" );
try ( Scanner scanner = new Scanner( url.openStream(),
StandardCharsets.UTF_8.name() ) ) {
while ( scanner.hasNextLine() ) {
Matcher matcher = titlePattern.matcher( scanner.nextLine() );
if ( matcher.matches() )
System.out.println( matcher.group(1) );
}
}
}
}
Der erste Teil des Programms kümmert sich um die Parameter, die alle zusammengehängt und dann vom URLEncoder in eine korrekte Form gebracht werden – falls kein Parameter vorhanden ist, sucht unser Programm nach »Java (Programmiersprache)«. Den kodierten Such-String hängen wir an die Basis-URL und öffnen eine Verbindung. Der Scanner läuft Zeile für Zeile durch das Ergebnis, doch interessieren uns nicht alle Zeilen, sondern nur die, die aussehen wie »[title] => «, denn sie enthalten unsere Suchergebnisse. Ein Pattern beschreibt genau das, was wir suchen, und wenn der Matcher einen Fund hat, gibt uns das Programm nur das Ergebnis rechts vom Pfeil aus.
13.4.3POST-Request absenden
Ein POST-Request überträgt die Parameter nicht in der URL, sondern setzt sie in einen Block, der zum Server übertragen wird. Gegenüber einem GET ändert sich einiges, was das folgende Beispiel (zu einem fiktiven Server) zusammenfasst:
Listing 13.9com/tutego/insel/net/PostRequest.java, main()
"param2=" + URLEncoder.encode( "value2", "UTF-8" );
URL url = new URL( "http://li.la.lu.lo/post/" );
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod( "POST" );
connection.setDoInput( true );
connection.setDoOutput( true );
connection.setUseCaches( false );
connection.setRequestProperty( "Content-Type",
"application/x-www-form-urlencoded" );
connection.setRequestProperty( "Content-Length", String.valueOf(body.length()) );
try ( Writer writer = new OutputStreamWriter( connection.getOutputStream() ) ) {
writer.write( body );
writer.flush();
try ( Scanner scanner = new Scanner( connection.getInputStream() ) ) {
while ( scanner.hasNextLine() )
System.out.println( scanner.nextLine() );
}
}
Der MIME-Typ »application/x-www-form-urlencoded« steht für ein Webformular, muss aber je nach Typ angepasst werden.
[+]Tipp
Für POST-Anfragen gibt es Open-Source-Bibliotheken, die die Serveranfrage vereinfachen. Mehr Informationen geben die Abschnitte Abschnitt 13.8, »Apache HttpComponents und Commons Net *«, und 15.2.10, »PUT/POST/DELETE-Sendungen mit der Jersey-Client-API absetzen«.