Aus Linux-Magazin 03/2006

Schlanke Webanwendungen mit Cherrypy

© www.scx.hu

Cherrypy ist eine einfach zu benutzende Alternative zu umfangreichen Webentwicklungs-Frameworks wie PHP oder Zope. Es basiert auf der konsequent objektorientierten Skriptsprache Python.

In Python geschriebene Webanwendungen nutzen häufig die CGI-Schnittstelle. Als Nachteil ergibt sich eine schlechte Performanz, da der Skriptinterpreter mit jedem Seitenaufruf neu startet. Cherrypy, das in und für Python geschriebene Framework für dynamische Webseiten, geht sparsamer mit den Serverressourcen um: Jede Cherrypy-Anwendung enthält einen eigenen Webserver und läuft daher ohne Unterbrechung, während es zahlreiche HTTP-Anfragen bedient.

Es besitzt zudem eine schmale, effiziente Codebasis und ist einfach einzusetzen: Der Server startet nach dem Skriptaufruf ohne weitere Konfiguration. Praktisch ist dies besonders in der Entwicklungsphase. In Produktivumgebungen lässt sich Cherrypy auch über das »mod_proxy«-Modul oder die WSGI-Bridge in den Apache-Webserver integrieren [2].

Das Konzept

Cherrypy lag bei Redaktionsschluss in Version 2.1 auf der Website des Projekts [1] vor. Nach dem Entpacken muss Root lediglich »python setup.py install« aufrufen, um das Paket zu installieren. Die im Artikel enthaltenen Beispiele erfordern Cherrypy 2.1 oder neuer.

Bei traditionellen Webservern spiegelt die URL Ordner und Dateien wider. So liefert eine Anfrage an die URL »http://localhost:8080/helloworld/« bei einem Apache mit Standardkonfiguration die Datei »index.html« aus dem Verzeichnis »helloworld« zurück. Bei Cherrypy hingegen entsteht die Hierarchie aus einem Objektbaum im Programmcode, der seinen Ursprung im »cherrypy.root«-Element hat. Die obige Anfrage ruft also das Objekt »cherrypy.root.helloworld« auf. »helloworld« kann dabei entweder eine Methode oder eine Klasse sein.

Das in Listing 1 gezeigte “Hello World”-Programm verdeutlicht, wie Cherrypy einen Pfad der HTTP-Anfrage in einen Python-Methodenaufruf übersetzt. Zeile 1 importiert das Python-Modul »cherrypy«, das nach der Installation des Web-Framework zur Verfügung steht. Die Zeilen 3 bis 6 definieren die Main-Klasse, die die darauf folgende Zeile als Root-Objekt der Anwendung setzt. »cherrypy.server.start()« startet den in Cherrypy integrierten Webserver, der standardmäßig auf Port 8080 lauscht. Eine Anfrage an »http://localhost:8080/helloworld« gibt im Browser den Text zurück, den die »helloworld()«-Methode als Rückgabewert gesetzt hat, nämlich »Hello World« (Abbildung 1).

Listing 1: Hello
World

01 import cherrypy
02 
03 class Main:
04   def helloworld(self):
05     return "Hello World!"
06   helloworld.exposed = True
07 
08 cherrypy.root = Main()
09 cherrypy.server.start()
Abbildung 1: Objektorientierung in Cherrypy: Die Pfadangabe »helloworld« korrespondiert mit einem Objekt im Programmcode und nicht mit einem Ordner im Dateisystem des Servers.

Abbildung 1: Objektorientierung in Cherrypy: Die Pfadangabe »helloworld« korrespondiert mit einem Objekt im Programmcode und nicht mit einem Ordner im Dateisystem des Servers.

Öffentlich oder intern

Für Python-Programmierer dürfte das Beispiel mit Ausnahme der Zeile 6 keine Überraschungen enthalten. Diese Zeile legt »helloworld.exposed = True« fest, sodass die »helloworld()«-Methode »exposed« ist, also vom Benutzer über eine URL im Browser erreichbar. Methoden können in Cherrypy den Status »published« und »exposed« besitzen. Alle Methoden, die von »cherrypy.root« abgeleitet sind, gelten standardmäßig als »published« und sind über das HTTP-Protokoll nicht zu erreichen. Sie entsprechen damit den über ».htaccess« gesperrten und für administrative Aufgaben reservierten Verzeichnissen beim Einsatz eines Apache.

Wie bereits angedeutet kann der Benutzer nicht nur auf Methoden, sondern auch auf Klassen zugreifen. Cherrypy führt hier die Analogie zum Dateisystem eines klassischen Webservers weiter: Falls der Browser über die URL eine Klasse adressiert, führt Cherrypy die Methode »index()« innerhalb der entsprechenden Klasse aus. Entspricht der letzte Teil der URL hingegen einer Methode innerhalb einer Klasse, dann ruft Cherrypy diese auf.

Mit Hilfe der Methode »cherrypy.root« lassen sich die Objektbäume zweier Seiten vollständig trennen. Angenommen die beiden Seiten »http://localhost:8080/Seite1« sowie »http://localhost:8080/Seite2« sollen keine gemeinsamen Objekte besitzen. In diesem Fall setzt

cherrypy.root.Seite1 = Klasse1()
cherrypy.root.Seite2 = Klasse2()

statt einer »main()«-Methode zwei verschiedene Methoden als Einsprungpunkte für die beiden Seiten. Trotz dieser logischen Trennung laufen beide Seiten allerdings immer noch in einem Prozess ab.

Benutzereingaben mit Cherrypy

Die meisten Webapplikationen fragen Eingaben vom Benutzer ab und werten sie aus. Cherrypy macht es dem Programmierer leicht, auf Benutzereingaben zuzugreifen. Er darf Methoden einer Cherrypy-Applikation im HTML-»form«-Block als »action« angegeben. Dabei ist es egal, ob die Applikation die Werte über die »GET«- oder über die »POST«-Methode erhält.

Listing 2 zeigt eine Cherrypy-Applikation, die dem Benutzer einen Login- Screen präsentiert und ihm nach dem Absenden des Formulars seine Eingaben auf einer neuen Seite anzeigt. Zumindest wenn das Formular Checkboxen enthält, ist es erforderlich, in der Definition der Methode Defaultwerte anzugeben: Alle gängigen Browser übergeben zwar für leere Texteingabefelder auch einen leeren String. Bei nicht aktivierten Checkboxen findet sich aber die entsprechende Variable überhaupt nicht in der Liste der per »GET« oder »POST« übergeben Parameter. Cherrypy reicht den Methodenaufruf inklusive Parameter an Python weiter. Sind keine Defaultwerte angegeben, resultiert dies in einer Fehlermeldung (Abbildung 2).

Listing 2: Ein einfaches
Login-Formular

01 import cherrypy
02 
03 class Main:
04   def index(self):
05     return """
06       <form action="login" method="post">
07         Benutzername: <input type="text" name="username">
08         <br>
09         Passwort: <input type="text" name="password">
10         <br>
11         <input type="submit" value="Absenden">
12         <input type="reset" value="Reset">
13       </form>
14       """
15   index.exposed = True
16 
17   def login(self, username, password):
18   return """
19       Benutzername: %s
20       <br>
21       Passwort: %s
22       """ % (username, password)
23   login.exposed = True
24 
25 cherrypy.root = Main()
26 cherrypy.server.start()
Abbildung 2: Cherrypy liefert außer der Fehlermeldung auch ein Traceback, das die Korrektur von Fehlern erleichtert.

Abbildung 2: Cherrypy liefert außer der Fehlermeldung auch ein Traceback, das die Korrektur von Fehlern erleichtert.

Persistenz durch Sessions

Bisher ist das Formular noch nicht von allzu großem Nutzen, da es die eingegebenen Daten für spätere Anfragen nicht speichert. In der Webentwicklung kommen Sessions zum Einsatz, um die Zustandslosigkeit des HTTP-Protokolls zu überbrücken: Über Cookies oder eine an die URL angehängte Session-ID lässt sich ein Zusammenhang zwischen den HTTP-Requests eines bestimmten Benutzers herstellen.

Cherrypy unterstützt in der aktuellen Release zwar nur die Cookie-Methode, diese allerdings in einer für den Programmierer sehr angenehmen Weise: Das Framework verbirgt die HTTP-Kommunikation und stellt ihm stattdessen einfach das Dictionary »cherrypy.session« zur Verfügung, mit dem er Daten aus der Session lesen oder in die Session schreiben kann. In der »login()«-Methode aus Listing 2 etwa ließe sich also der eingegebene Benutzername in »cherrypy.session[\’username\’]« schreiben und mit Hilfe von »cherrypy.session.get(\’username\’)« wieder auslesen.

Cherrypy bietet verschiedene Backends für das Speichern von Sessions an. Zurzeit ist es möglich, die Session-Informationen im RAM, in Dateien oder in einer Datenbank zu speichern. Der Programmierer kann Sessions zudem eine Lifetime zuordnen, um nach einer bestimmten Zeit einen Logout zu erzwingen. Diese lässt sich in der Cherrypy-Konfiguration festegen.

Listing 3 zeigt ein einfaches Beispiel für eine Anwendung, die Sessions nutzt: Ein zweiter Aufruf von »http://localhost:8080/login« zeigt die bereits eingegebenen Login-Daten an. In Zeile 18 überprüft das Programm, ob die Methode Parameter erhalten hat, und startet gegebenfalls eine Session. Wird die Methode »login« ohne Parameter aufgerufen, nimmt die Anwendung an, dass sich der Benutzer bereits eingeloggt hat, und liest den Benutzernamen und das Passwort aus der Session aus.

Listing 3: Persistenz durch
Sessions

01 import cherrypy
02 
03 class Main:
04   def index(self):
05     return """
06       <form action="login" method="post">
07         Benutzername: <input type="text" name="username">
08         <br>
09         Passwort: <input type="text" name="password">
10         <br>
11         <input type="submit" value="Absenden">
12         <input type="reset" value="Reset">
13       </form>
14         """
15   index.exposed = True
16 
17   def login(self, username=None, password=None):
18     if username != None or password != None:
19       cherrypy.session['username'] = username
20       cherrypy.session['password'] = password
21     else:
22       username = cherrypy.session.get('username')
23       password = cherrypy.session.get('password')
24     return """
25         Benutzername: %s
26         <br>
27         Passwort: %s
28         """ % (username, password)
29   login.exposed = True
30 
31 cherrypy.root = Main()
32 cherrypy.config.update({'sessionFilter.on': True})
33 cherrypy.server.start()

Zeile 32 des Listings verändert die Cherrypy-Konfiguration, da die Session-Funktionalität standardmäßig deaktiviert ist: Ein Aufruf von »cherrypy.config.update« mit einem Dictionary als Argument, das die zu ändernden Konfigurationsoptionen enthält, ist bereits ausreichend. Nähere Informationen über das Konfigurationssystem bietet das Wiki des Cherrypy-Projekts [3].

Filter: Cherrypy erweitern

Der schlank gehaltene Core von Cherrypy implementiert nur die Basisfunktionalität, die das HTTP-Protokoll vor dem Programmierer verbirgt und Anfragen der Seitenbesucher an entsprechende Objekte der Applikation weiterleitet. Weitere Features realisiert Cherrypy als Plugins oder so genannte Filter. Ein Filter muss von der Klasse »BaseFilter« abgeleitet werden. »BaseFilter« enthält eine Reihe von virtuellen Methoden, die der Programmierer in einer eigenen Klasse mit Code füllt.

Über diese Schnittstellen klinken sich Filter in den normalerweise verdeckten Verarbeitungsprozess der HTTP-Anfragen ein und beeinflussen die Verarbeitung an mehreren Stellen. Dem Filter stehen dazu alle wichtigen Low-Level-Informationen aus dem HTTP-Protokoll wie die IP des Clients, die angeforderte URL und die Header der HTTP-Anfrage zur Verfügung [4].

Cherrypy liefert in der Standarddistribution eine Reihe von Filtern mit [5]. Die Session-Funktionalität ist beispielsweise auch als Filter implementiert. Weitere Builtin-Filter sind der »staticfilter« [6] zum Ausliefern statischer HTML-Dateien, der »gzipfilter« für die Gzip-Komprimierung der ausgehenden Daten sowie die »encoding«- und »decoding«-Filter, die Zeichenfolgen etwa aus der UTF-8-Kodierung nach Iso-8859-1 oder umgekehrt verwandeln. Der »tidyfilter« erlaubt es, die generierten Webseiten vom bekannten HTML-Syntaxchecker Tidy [7] überarbeiten zu lassen, bevor der Empfänger sie zu sehen bekommt. Filter sind abhängig vom Pfad der HTTP-Anfrage in der Konfigurationsdatei aktivierbar.

Fazit

Cherrypy ist ein schlankes, einfach zu handhabendes Framework für die Entwicklung von Webanwendungen in der konsequent objektorientierten Skriptsprache Python. Es vermeidet sowohl die steile Lernkurve des Application Servers Zope als auch die Performanzeinbußen, die bei der CGI-Schnittstelle durch das wiederholte Neustarten des Befehlsinterpreters entstehen. Weiterführende, teilweise allerdings noch lückenhafte Informationen zu Cherrypy sind unter [8] zu finden. (pkr)

Infos

[1] Cherrypy-Website: [http://www.cherrypy.org]

[2] Cherrypy mit Apache als WSGI-Server: [http://www.cherrypy.org/wiki/ModPythonWSGI]

[3] Cherrypy-Configsystem: [http://www.cherrypy.org/wiki/ConfigSystem21]

[4] Filter anwenden und selbst schreiben: [http://www.cherrypy.org/wiki/Filters21]

[5] Liste der mitgelieferten Filtermethoden: [http://www.cherrypy.org/trunk/docs/book/chunk/ch03s03.html#id3151279]

[6] Static-Filter benutzen: [http://www.cherrypy.org/wiki/StaticContent21]

[7] HTML-Checker Tidy: [http://tidy.sourceforge.net/]

[8] Das noch unvollendete Cherrypy-Buch: [http://www.cherrypy.org/wiki/CherryPyBook]

Der Autor

Michael Göttsche besucht den 13. Jahrgang eines Gymnasiums in Bargteheide. Daneben beschäftigt er sich mit verschiedenen Themen der Software-Entwicklung.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben