Subsections
CherryPy genera e usa alcune variabili e funzioni speciali. Sono molto facili da usare, ma
altrettanto potenti. In questo capitolo vedremo cosa sono queste variabili e funzioni, mentre nel prossimo impareremo ad usarle.
Questa è la variabile usata più comunemente. Contiene tutte le informazioni sulle richiesta
pervenute da un client. E' un'istanza di classe che contiene alcune variabili membro che
sono generate da CherryPy per ogni richiesta. Le variabili membro usate più comunemente sono:
- request.headerMap: è un dizionario Python contenente tutte le chiavi e i valori inviati
dal client nell'intestazione della richiesta.
Notate che tutte le chiavi sono sempre convertite in minuscolo. Per esempio, per trovare il tipo
di browser usato dal client, usate request.headerMap['user-agent']
(notate che queste informazioni possono non essere inviate dal client)
- request.simpleCookie: è un oggetto simpleCookie contenente il cookies inviato dal client.
Notate che questa informazione è disponibile anche in request.headerMap['cookie'].
Controllate l'HowTo per imparare ad usare i cookie con CherryPy.
- request.base: stringa contenente l'URL base del sito. E' equivalente a 'http://'+request.headerMap['host']
- request.path e request.paramMap: la prima contiene il percorso della pagina che è stata inizialmente richiesta. Caratteri '/' iniziali o finali sono rimossi (se necessario).
La seconda è un dizionario contenente una chiave ed un valore per ogni parametro che il client
invia (via GET o POST). Per esempio, se l'URL è:
http://localhost:8000/dir/page?key1=value1&key2=value2
avremo:
request.base == 'http://localhost:8000'
and
request.path == 'dir/page'
and
request.paramMap == {'key1': 'value1', 'key2': 'value2'}
- request.originalPath e request.originalParamMap: queste variabili sono una copia di
request.path e request.paramMap. Ma come vedremo nella prossima sezione, è possibile
modificare request.path e request.paramMap.
In questo caso, request.originalPath e request.originalParamMap mantengono
i valori originali.
- request.browserUrl: stringa contenente l'URL come appare nella finestra del browser.
- request.method: Stringa contenente o GET o POST, per indicare che tipo di richiesta è stata fatta.
- request.wfile (solo per uso avanzato): date un'occhiata all'HowTo su "Come uploadare un file direttamente du disco" per maggiori informazioni all'uso.
Questa è la seconda variabile usata più comunemente (dopo request).
Contiene tutte le informazioni sui responsi che saranno inviati al client.
E' un'instanza di classe che contiene alcune variabili membro che sono generate
da CherryPy o dal vostro programma.
- response.headerMap: è un dizionario Python che contiene tutte le chiavi e i valori
che verranno inviati nell'intestazione delle risposte.
Di default, CherryPy genera le seguente coppie chiave/valore:
"status": 200
"content-type": "text/html"
"server": "CherryPy 0.1"
"date": current date
"set-cookie": []
"content-length": 0
Nel prossimo capitolo impareremo come usare e modificare questi valori.
- response.body: stringa contenente il corpo della risposta. Questa variabile può essere usata solo in 3 funzioni speciali (vedi sotto)
- response.simpleCookie: oggetto simpleCookie usato per inviare cookies al browser. Notate che i cookie possono anche essere inviati usando response.headerMap['cookie'].
Date un'occhiata all'HowTo per imparare l'uso dei cookie con CherryPy.
response.sendResponse e response.wfile (solo per uso avanzato): usato per lo streaming. Date un'occhiata alla sezione dell'HowTo chiamata "How to use streaming with CherryPy" per maggiori informazioni.
Nel vostro codice potete definire funzioni speciali che modificheranno il comportamento del server. Per definire queste funzioni, usate la sintassi Python e definitele fuori dalle CherryClass. Quando usate moduli differenti, potete definire la stessa funzione in moduli differenti. In questo caso, CherryPy concatenerà i corpi di tutte le funzioni nello stesso ordine di lettura dei file.
Ecco l'algoritmo che il server usa quando riceve una richiesta (se non specificato, l'operazione
si riferisce ad ogni tipo di contenuto):
- arriva la richiesta
- Genera tutte le variabili membro di request
- Chiama initRequest (che può modificare request.path e request.paramMap)
- Determina se questa richiesta corrisponde a contenuto statico o dinamico (basato su request.path
e la sezione staticContent del file di configurazione)
- (Solo per contenuto dinamico) Chiama initNonStaticRequest (che può modificare request.path e request.paramMap)
- (solo per contenuto statico) Legge il file statico e genera i valori di response.headerMap e response.body in modo appropriato
- (solo per contenuto dinamico) Chiama il metodo dell'istanza CherryClass, con alcuni argomenti (basati su request.path e
request.paramMap) e genera i valori di response.headerMap e response.body in accordo con i risultati
- (solo per contenuto statico) Chiama initResponse (che può modificare response.headerMap e response.body)
- (solo per contenuto dinamico) Chiama initResponse (che può modificare response.headerMap e response.body)
- (solo per contenuto statico) Invia un responso al browser (basato su response.headerMap e response.body)
- (solo per contenuto dinamico) Invia un responso al browser (basato su response.headerMap e response.body)
Come potete vedere, initRequest e initNonStaticRequest possono essere usate per
un aggiustamento fine dell'URL o dei parametri, o per fare qualsiasi lavoro che deve
essere eseguito su ogni richiesta.
initResponse e initNonStaticResponse possono essere usate per cambiare l'intestazione della risposta o del corpo, prima che venga invita al client.
Questa funzione è chiamata da CherryPy quando avviene un errore durante la costruzione della pagina.
Guardate la prossima sezione per un esempio.
Se usate un server thread-pool o process-pool, sarà chiamata la funzione corrispondente (rispettivamente
initThread o initProcess) per ogni nuovo thread/processo creato.
Queste funzioni possono essere usate per esempio se volete avere per ogni thread/processo
una propria connessione ad un database (l'HowTo chiamato "Sample deployment
configuration for a real-world website" spiega come farlo).
initThread prende un argomento chiamato threadIndex contenente l'indice
del thread che deve essere creato. Per esempio, se volete creare 10 threads, threadIndex avrà i valori da 0 a 9.
Il codice in initProgram viene copiato all'inizio del file generato, in modo da essere la prima cosa ad essere eseguita.
Potete usare le funzioni speciali se avete bisogno di eseguire del codice prima che
vengano istanziate le CherryClass.
Quindi, il server crea tutte le instanze delle CherryClass e quindi chiama la funzione
speciale initServer. Questo è basilarmente il posto dove mettere tutti i passi
di inizializzazione necessari.
initAfterBind viene chiamata dopo che il socket si è messo in "ascolto". Per esempio,
su sistemi Unix-based, dovrete far partitre CherryPy come root se volete che si metta
in ascolto sulla porta 80. La funzione speciale initAfterBind può essere usata
per cambiare l'utente proprietario del processo in ascolto in uno non privilegiato.
(l'HowTo chiamato "Sample deployment
configuration for a real-world website" spiega come farlo).
Questa funzione speciale è chiamata dal server quando riceve una richiesta di tipo POST,
prima di analizzare i dati POST. Questo vi permette per esempio di dire al server di non
analizzare i dati POST (settando la variabile request.parsePostData a 0) e quindi
potete analizzare i dati POST voi stessi (leggendoli da request.rfile). Controllate l'HowTo chiamato "How to stream uploaded files directly to disk" per maggiori informazioni.
Abbiamo detto di voler mettere su un sito per i nostri clienti. Vogliamo che i nostri clienti
abbiano il proprio URL:
http://host/customerName, ma che la pagina sia sempre la stessa per ogni cliente, così
da non dover creare un metodo per ogni cliente.
Tutto ciò che dovete fare è usare initNonStaticRequest per convertire l'URL http://host/customerName in
http://host?customer=customerName. Tutto questo sarà trasparente all'utente.
Scriviamo il seguente codice:
def initNonStaticRequest():
if request.path:
request.paramMap['customer']=request.path
request.path=""
CherryClass Root:
mask:
def index(self, customer=""):
<html><body>
Hello, <py-eval="customer">
</body></html>
E questo è tutto !
Compilate il file, fate partire il server e provate gli URL, come http://localhost:8000/customer1o http://localhost:8000/world
Per inviare un redirect al browser, tutto quello che dovete fare è inviare un codice di stato 302 (invece
di 200), e generare un valore location nell'intestazione della risposta. Questo può essere fatto facilmente usando la variabile speciale response.headerMap:
CherryClass Root:
mask:
def index(self):
<html><body>
<a href="loop">Click here to come back to this page</a>
</body></html>
view:
def loop(self):
response.headerMap['status']=302
response.headerMap['location']=request.base
return "" # A view should always return a string
In questo esempio, aggiungeremo una linea alla fine di ogni pagina che è generata dal server.
Questa linea conterrà il tempo impiegato per costruire la pagina. Naturalmente, vogliamo questa linea
solo per le pagine HTML dinamiche.
Tutto quello che dobbiamo fare è usare initNonStaticRequest per memorizzare la partenza, e initNonStaticResponse
per aggiungere la linea contenente il tempo impiegato per la costruzione.
Ecco il codice:
import time
def initNonStaticRequest():
request.startTime=time.time()
def initNonStaticResponse():
if response.headerMap['content-type']=='text/html':
response.body+='<br>Time: %.04fs'%(time.time()-request.startTime)
CherryClass Root:
mask:
def index(self):
<html><body>
Hello, world
</body></html>
Et voila
Questo può essere fatto usando la funzione speciale onError.
Usate response.headerMap e response.body per fare quello che desiderate.
L'esempio che segue mostra come configurare il tutto per inviare una mail
ogni volta che viene incontrato un errore:
use Mail
def onError():
# Get the error in a string
import traceback, StringIO
bodyFile=StringIO.StringIO()
traceback.print_exc(file=bodyFile)
errorBody=bodyFile.getvalue()
bodyFile.close()
# Send an email with the error
myMail.sendMail("erreur@site.com", "webmaster@site.com", "", "text/plain", "An error occured on your site", errorBody)
# Set the body of the response
response.body="<html><body><br><br><center>"
response.body+="Sorry, an error occured<br>"
response.body+="An email has been sent to the webmaster"
response.body+="</center></body></html>"
CherryClass MyMail(Mail):
function:
def __init__(self):
self.smtpServer='smtp.site.com'
CherryClass Root:
mask:
def index(self):
<html><body>
<a py-attr="request.base+'/generateError'" href="">
Click here to generate an error</a>
</body></html>
def generateError(self):
<html><body>
You'll never see this: <py-eval="1/0">
</body></html>
Questo esempio mostra anche l'uso del modulo standard Mail compreso in CherryPy.
See About this document... for information on suggesting changes.