WSGI es una interface simple y universal entre los servidores web y las aplicaciones web o frameworks (ver m谩s en PEP 333)
WSGI es similar a la especificaci贸n Java Servlet o ASP/ASP.NET. En general, es mucho m谩s simple que dichas especificaciones, y se basa en el estandard CGI con mejoras "pit贸nicas" para hacerla reentrante, persistente, etc.
Resumen de la Especificaci贸n
Del lado de la aplicaci贸n, se especifica un punto de entrada (objeto, m茅todo, funci贸n), con dos par谩metros: las variables de entorno (
environ
y la funci贸n para iniciar la respuestastart_response(status,response_headers)
que env铆a el estado y los encabezados), y debe devolver un iterable con los datos para enviar al cliente.Del lado del servidor, se invoca la aplicaci贸n por cada pedido que recibe del cliente HTTP, con las variables de entorno establecidas (estilo CGI)
Ejemplo
# Aqui va mi 'Hola PyAr!, pero con WSGI, una maravilla de Python. from wsgiref.simple_server import make_server def hello(environ, start_response): start_response('200 OK',[('Content-type','text/plain')]) return ['Hola PyAr!'] httpd = make_server('',8000, hello).serve_forever()
(copiado de un mail "hello-word" de la lista)
Variables de entorno (diccionario {{{environ}}})
El diccionario environ
que se recibe con cada pedido HTTP, contiene las variables est谩ndard de la especificaci贸n CGI, entre ellas:
REQUEST_METHOD: m茅todo "GET", "POST", tec.
SCRIPT_NAME : la parte inicial de la "ruta", que corresponde a la aplicaci贸n
PATH_INFO: la segunda parte de la "ruta", determina la "ubicaci贸n" virtual dentro de la aplicaci贸n
QUERY_STRING: la porci贸n de la URL que sigue al "?", si existe
CONTENT_TYPE, CONTENT_LENGTH de la petici贸n HTTP
SERVER_NAME, SERVER_PORT, que combinadas con SCRIPT_NAME y PATH_INFO dan la URL
SERVER_PROTOCOL: la versi贸n del protocolo ("HTTP/1.0" or "HTTP/1.1")
Variables HTTP
Configuraci贸n apache + mod_python
mod_python tiene varios handlers o "controladores" (ver documentaci贸n):
Handler PSP: utilizado para procesar documentos .psp con c贸digo python y html mezclado (similar a PHP)
Handler CGI: emula el entorno CGI (no confundir con WSGI). No es reentrante ni persistente, y es el m茅todo m谩s lento para ejecutar scripts web, pero a su vez es hist贸ricamente "compatible" con scripts viejos.
Handler Publisher: es un poco mas de "alto nivel". En general, se usar铆a si uno quiere hacer una aplicaci贸n sencilla, con las url mapeadas autom谩ticamente a funciones, etc.
Handler propio: m谩s rapido, pero a costa de tener que programar a mas "bajo nivel" (directamente con las interfaces de apache). Aplicaciones mas avanzadas que requieren un mayor control sobre las url, encabezados, etc., usan handlers propios (ejemplo: trac, moin, etc.):
Igualmente, estos Handlers no son compatibles con WSGI, por eso no recomendar铆a usar ninguno de ellos directamente, sino a trav茅s del wrapper WSGI (con ModPythonGateway) que es un handler "propio" que traduce las peticiones al estandar WSGI. Es algo mucho mas estandar, valga la redundancia, y el d铆a de ma帽ana se puede usar cualquier servidor compatible con python, no solo apache.
Adem谩s, puede utilizarse directamente mod_wsgi (ver siguiente secci贸n).
Ejemplos de configuraci贸n (tanto en /etc/apache2/... en un archivo .htaccess en el mismo directorio):
# handler Publisher: # se ejecutar谩 cualquier archivo .py del directorio, llamando a la funci贸n de la url: # http://www.mysite.com/hello.py/say ejecutara el script hello.py, funcion say <Directory /var/www/html/python/> SetHandler mod_python PythonHandler mod_python.publisher PythonDebug On </Directory> # Handler PSP: # se ejecutar谩 cualquier archivo .psp (c贸digo python embebido en texto html) <Directory /var/www/html/psp/> AddHandler mod_python .psp PythonHandler mod_python.psp </Directory> # Handler CGI: # se ejecutar谩 los scripts .py (scripts normales de python) simil linea de comandos <Directory /var/www/cgi-bin/> SetHandler mod_python PythonHandler mod_python.cgihandler Options ExecCGI </Directory> # handler propio: # se ejecuta el archivo myscript.py funci贸n handler(req) <Directory /mywebdir> AddHandler mod_python .py PythonHandler myscript PythonDebug On </Directory>
Para configurar una aplicaci贸n wsgi en mod_python:
SetHandler python-program PythonHandler modpython_gateway::handler PythonOption wsgi.application app::WSGIApp PythonPath "['C:/Archivos de programa/Apache Software Foundation/Apache2.2/htdocs/app'] + sys.path" PythonOption SCRIPT_NAME /app
Descripci贸n:
Se habilita el handler propio
Se establece el handler a ejecutar (en este caso, el wrapper wsgi)
Se especifican las opciones de la aplicaci贸n wsgi (app es el nombre de archivo, WSGIApp es el punto de entrada)
Se agrega el script de la aplicaci贸n al path para poder ejecutarla
Se establece el nombre del script a mostrar (sino, en ocasiones, apache puede informar mal o de manera distinta el nombre de script con problemas en el ruteo de urls)
Configuraci贸n apache + mod_wsgi
Para usar WSGI directamente desde apache, existe mod_wsgi, que es un m贸dulo mas reciente, totalmente codificado en C para una mejor performance y estabilidad, que simplifica y resuelve las carencias de mod_python:
Ejemplo 1: ejecutar en el mismo proceso que apache (no independiente, estilo mod_python/php/etc.). En este caso se mapea la url /app al script wsgi app.py:
Ejemplo 2: ejecutar en un proceso (interprete) independiente con un usuario arbitrario diferente de apache (estilo FastCGI, mejorando seguridad y performance):
Configuraci贸n lighttpd + wsgi
http://cleverdevil.org/computing/24/python-fastcgi-wsgi-and-lighttpd
http://svn.saddi.com/py-lib/trunk/fcgi.py (en realidad es un handler FastCGI compatible con WSGI)
Ejemplo "avanzado"
Con respecto a la diferencia con PHP/PSP, la mayor铆a de las aplicaciones web en python tienen un solo punto de entrada (un solo .py), que funciona como "despachador", dependiendo de que url te piden, se llama a una funci贸n o a otra (generalmente se usa la variable de entorno SCRIPT_NAME o similar, o directamente usar cherrypy, django, turbogears, etc., para que ruteen las peticiones a las clases/funciones que correspondan)
Ejemplo muy simple con WSGI:
def App(environ, start_response): "Punto de entrada WSGI" if environ['SCRIPT_NAME'].endswith("xxxx"): respuesta_html = xxxx(environ) elif environ['SCRIPT_NAME'].endswith("yyyy"): respuesta_html = yyyy(environ) else: respuesta_html = "<html><body><p>la url es inv谩lida!</p></body></html>" start_response ("200 Ok", [('Content-Type','text/html')]) yield respuesta_html
Entonces, si te llaman www.tuservidor.com/aplicacion/xxxx haces una cosa (xxxx), mientras que si llaman a www.tuservidor.com/aplicacion/yyyy haces otra (yyyy). En comparaci贸n con php/psp, ser铆a como llamar a www.tuservidor.com/aplicacion.psp?funcion=xxxx o www.tuservidor.com/aplicacion.psp?funcion=yyyy.
Esto es un poco mas dif铆cil de entender, pero a la larga es mas flexible porque no te limita a tener un archivo (estructura "f铆sica") para cada direcci贸n (estructura "l贸gica"), limpiando un poco la url de extensiones .py, signos de interrogaci贸n, etc. , haci茅ndolas mas f谩ciles de entender para el usuario.