Allgemeine Frage zum BaseHTTPRequestHandler

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
KartoffelKiffer
User
Beiträge: 4
Registriert: Sonntag 2. März 2014, 19:23

Hallo,

ich bin neu in der Python-Programmierung und hoffe, dass mir bei meinem Problem geholfen werden kann.

Hier ist der Code, der mir Probleme bereitet:

Code: Alles auswählen

import string,cgi,time
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
import glob    
    

class MyHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        try:
		self.send_response(200)
		self.send_header('Content-type', 'text/html')
		self.end_headers()
		path = curdir + self.path + sep
		listing = os.listdir(path)

		self.wfile.write('<html><head><meta http-equiv="refresh" content="5"></head><body>')

		self.wfile.write('<img src="Camera/2013-02-24_00-29-55_654.jpg" />')

		self.wfile.write('</body></html>')
		
		return
                
        except IOError:
            self.send_error(404,'File Not Found: %s' % self.path)
     

    def do_POST(self):
        global rootnode
        try:
		do_GET(self)
		
		# nothing else to do here
            
        except :
            pass

def main():
    try:
        server = HTTPServer(('', 8080), MyHandler)
        print 'started'
        server.serve_forever()
    except KeyboardInterrupt:
        print 'down'
        server.socket.close()

if __name__ == '__main__':
    main()
Dieses Script liegt in einem Verzeichnis, das mehrere Ordner mit Bildern enthält. In dem Beispiel oben soll ein Bild aus dem Verzeichnis "Camera" angezeigt werden. Der HTML-Code bewirkt, dass die Seite nach fünf Sekunden neu geladen werden soll. Diesen Mechanismus wollte ich verwenden, um ganz simpel eine Diashow per Browser zu ermöglichen.

Jedoch scheitere ich gerade an der Basis, ich erhalte folgende Fehlermeldung in der Konsole:
OSError: [Errno 20] Not a directory: './Camera/2013-02-24_00-29-55_654.jpg/'
Ich sehe auch ein, dass (...).jpg/ kein Verzeichnis ist, nur weshalb möchte er an dieser Stelle ein Verzeichnis laden?

Wenn ich den Header auf "image/jpeg" umstelle und den Inhalt der jeweiligen Bilder lade und ausgebe, funktioniert es ohne Probleme. Jedoch benötige ich leider "text/html" und das Tag "src" zur Darstellung.

Mache ich etwas grunsätzlich falsch oder führt dieser Weg mit etwas Umarbeitung zum Glück?

Ich freue mich auf eine nette Zusammenarbeit :)


Gruß
KK
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Überleg dir doch mal, wie oft "do_GET" aufgerufen wird. Noch besser: bau dir in die Funktion ein print-Statement ein und lasse dir mal "self.path" ausgeben. Es sind wahrscheinlich mehr Aufrufe als du denkst. Und die müssen natürlich auch unterschiedlich behandelt werden ;-)
Das Leben ist wie ein Tennisball.
KartoffelKiffer
User
Beiträge: 4
Registriert: Sonntag 2. März 2014, 19:23

Hallo "Du" :D,

ich habe eine print-Meldung ausgegeben und do_GET wird definitiv nur ein mal aufgerufen. self.path steht hier auf "/", weil ich direkt "localhost:8080" aufrufe.

Bevor die Exception geworfen wird, bekomme ich auch noch folgende Meldung:

Code: Alles auswählen

127.0.0.1 - - [02/Mar/2014 19:50:31] "GET / HTTP/1.1" 200 -
>>>/     # dies ist meine print-Meldung
127.0.0.1 - - [02/Mar/2014 19:50:31] "GET /Camera/2013-02-24_00-29-55_654.jpg HTTP/1.1" 200 -
Da ich das Script aus dem root-Verzeichnis aufrufe, müsste von den Pfaden her alles gut sein. Demnach wäre die Bild-URL folgende: http://localhost:8080/Camera/2013-02-24 ... 55_654.jpg.
KartoffelKiffer
User
Beiträge: 4
Registriert: Sonntag 2. März 2014, 19:23

Halt, ich verstehe, was du meinst! Sekunde :D
KartoffelKiffer
User
Beiträge: 4
Registriert: Sonntag 2. März 2014, 19:23

Wie blöd, ich danke dir tausendfach für deine Hilfe!

Logischerweise war der Denkfehler der, dass auch das Bild eine eigene Anfrage absetzt....

Code: Alles auswählen

		
		self.send_response(200)

		if self.path == '/' :
			self.send_header('Content-type', 'text/html')
			self.end_headers()
			self.wfile.write('<html><head><meta http-equiv="refresh" content="5"></head><body>')
			self.wfile.write('<img src="./Camera/2013-02-24_00-29-55_654.jpg" />')
			self.wfile.write('</body></html>')

		if self.path.endswith('.jpg') :
			self.send_header('Content-type', 'image/jpeg')
			self.end_headers()
			f = open(curdir + sep + self.path)
		        self.wfile.write(f.read())
		        f.close()
Quick&Dirty, was aber schon ausreicht.

Vielen Dank nochmal!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Manchmal braucht es eben nur einen kleinen Schubser in die richtige Richtung :D

Es gibt auch noch einige Dinge, welche du an deinem Code noch verbessern solltest. Ich habe sie einfach mal von obe nach unten aufgeschrieben:

- Du scheinst nicht alle importierten Module auch zu verwenden. Da solltest du ein wenig aufräumen. Vielleicht liegt es auch nur daran, dass du deinen Code gekürzt hast, dann ist es in Ordnung.

- Dem Styleguide nach (schau dir mal PEP 8 an, da sind einige nütlzliche Konventionen aufgeführt), sollte jedes Modul sein eigenes Import-Statement haben. Also:

Code: Alles auswählen

import string
import cgi
import time
from os import curdir, sep
...
Oftmals ist es auch sinnvoll die Importe zu ordnen. Zum Beispiel alphabetisch.

- Du solltest den 200er Code auch wirklich nur dann senden, wenn du wirklich alles ausliefern kannst. So könnte es zum Beispiel vorkommen, dass das Bild nicht vorhanden ist.

- Das Zusammenbauen des Pfads solltest du so nicht machen, dafür gibt es die "os.path.join"-Methode:

Code: Alles auswählen

path = os.path.join(curdir, selfpath)
Das nimmt dir einiges an Arbeit (und Fehlerquellen) ab.

- Bist du sicher, dass du "curdir" meinst und nicht das Verzeichnis der py-Datei? Dessen Pfad findest du in der globalen "__file__"-Variable.

- Es gibt mehrzeilige Strings:

Code: Alles auswählen

self.wfile.write(
        '''<html><head><meta http-equiv="refresh" content="5"></head><body>
              <img src="Camera/2013-02-24_00-29-55_654.jpg" />
          </body></html>''')
- Das "return" am Ende von "do_GET" ist überflüssig. Wenn du keinen Wert zurückgibst, dann solltest du es einfach weglassen.

- Vergiss, dass es "global" überhaupt gibt. Werte betreten eine Funktion über Parameter und verlassen sie über "return".

- Ein leeres except, ohne die Angabe der abzufangenden Fehler, ist eine äußerst schlechte Idee. Damit fängst du nämlich wirklich jeden Fehler ab. Darunter fallen auch "NameError"s, was überlicherweise auf einen Programmierfehler hindeutet. So ein versteckter Fehler ist extrem schwer zu entdecken. Lasse dein Programm lieber "abschmieren" als dass es in einem inkonsistenten Zustand weiterarbeitet. Dann wird es früher oder später eh abstürzen, zusätzlich kann aber noch alles mögliche unerwartete passieren.

- Dateien solltest du mittels with-Statement öffnen, dann musst du sie nicht mehr per Hand schließen. Viel wichtiger: auch im Fehlerfall werden sie geschlossen:

Code: Alles auswählen

with open(filename) as fp:
    slf.wfile.write(fp.read())
Das Leben ist wie ein Tennisball.
Antworten