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 respuesta start_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:

WSGIScriptAlias /app /usr/local/apache/app.py

Ejemplo 2: ejecutar en un proceso (interprete) independiente con un usuario arbitrario diferente de apache (estilo FastCGI, mejorando seguridad y performance):

WSGIDaemonProcess site-1 user=trac group=trac threads=25
WSGIScriptAlias /site-1 /usr/local/apache/app.py
<Directory /usr/local/apache>
WSGIProcessGroup site-1
WSGIApplicationGroup %{GLOBAL}
</Directory>

Configuraci贸n lighttpd + 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.