WSGI

Web Server Gateway Interface

Python

  • O que é e por quê?
  • Web server, aplicação e middleware
  • Conclusão
  • + info e referências

PEP 333 v1.0

7 de dezembro de 2003

- Primeira versão

PEP 3333 v1.0.1

26 de setembro de 2010

- Versão atual, compatível com tudo da anterior;

- suporte a Python 3 (principalmente problemas relacionados a unicode)

O que é?

Especificação

Standard Python. Descrito em detalhes nas PEPs abaixo.

web server

ou gateway

aplicação

framework

W

S

G

I

O que é?

Interface

Uma camada que fica entre a applicação e o web server, criando assim um meio comum de comunicação entre ambos.

W

S

G

I

request

response

Por que?

Escolha

uWSGI

Gunicorn

CherryPy

Flask

Django

Falcon

WSGI

Poder escolher entre diferentes web servers e frameworks.


    {
        'HTTP_HOST': 'localhost',
        'PATH_INFO': '/healthcheck',
        'REQUEST_METHOD': 'GET',
        'SERVER_NAME': 'localhost',
        'SERVER_PORT': '80',
        'SERVER_PROTOCOL': 'HTTP/1.0',
        ...
        'wsgi.url_scheme': 'http',
        'wsgi.version': (1, 0),
        ...
    }

Por que?

Portabilidade

O environ WSGI é muito parecido com o environ CGI, e adiciona somente algumas chaves a mais. Assim, facilita a portabilidade de aplicações legadas.

Web Server

WSGI

Middleware

WSGI

Aplicação

WSGI

request

request

response

response

Por que?

Middlewares

Provê uma maneira simples de adicionar middlewares à aplicação...

...e encadeá-los

Web Server

socket

Web Server

bind

listen

accept

socket conectado

import socket

serversocket = socket.socket(...)
...
serversocket.bind(('localhost', 8888))
serversocket.listen(1)

while True:
    conn, addr = serversocket.accept()
    request = conn.recv(1024)
    print request

    response = ...

    conn.sendall(response)
    conn.close()

Implementando um web server simples

Web Server

accept

socket conectado

$ telnet localhost 8888
Trying 127.0.0.1 …
Connected to localhost.
GET /healthcheck HTTP/1.1

HTTP/1.1 200 OK
Working

HTTP request

TCP Connection

Web Server

class WSGIServer(object):
...
    def __init__(self, server_address):
        # socket
        self.headers_set = []
    ...
    def handle_one_request(self):
        # parse request, etc

        result = self.application(environ, self.start_response)
        self.finish_response(result)
        # vai pegar o status e headers de self.headers_set, concatenar
        # com result (response body), enviar e fechar a conexão
    ...
    def start_response(self, status, response_headers):
        server_headers = [...]
        self.headers_set = [status, response_headers + server_headers]
...
if __name__ == '__main__':
    # importa a app, seta o server_address, instancia WSGIServer e seta app
    server.serve_forever()  # handle_one_request

Implementação WSGI

Web Server

possíveis melhorias

  • Fazer o web server gerenciar mais de um request por vez;
  • melhorar aspectos de configuração;
  • tunar a performance;
  • etc & etc;
  • ou usar Gunicorn, uWSGI, ...

Aplicação

Aplicação

def application(environ, start_response):
    start_response("200 OK", [('Content-Type', 'text/plain')])
    return ["Working"]

Uma função ou classe Python chamável ( ! ) que retorna ao web server o status, o response body e response headers

response body

status

response headers

Aplicação

possíveis melhorias

  • Criar um gerenciamento de rotas: ao verificar PATH_INFO podemos delegar qual função ou classe manipula determinada url (via regex por exemplo);
  • adicionar um sistema de templates para tratar o response body;
  • etc & etc;
  • ou usar Flask, Django, ...

Middleware

Middleware

Simplificando, o middleware nada mais é do que uma parte do web server que recebe a aplicação e a aplicação em si. Pode realizar alterações tanto no request quanto no response.

class WSGIMiddleware(object):

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        return self.app(environ, start_response)

Middleware

Um middleware mais útil:  adiciona ao request um header customizado

class MyHeaderMiddleware(object):

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):

        def custom_start_response(status, headers):
            headers.append(('X-My-Header', "Made by MyHeaderMiddleware"))
            return start_response(status, headers)

        return self.app(environ, custom_start_response)

Conclusão

  • É uma interface simples e fácil de implementar. Cria uma forma consistente de um web server repassar dados para uma aplicação e esperar por uma resposta;
  • middlewares são uma ótima alternativa para extender a aplicação, mas muitos criticam o uso desenfreado.

 

+ info

  • Algumas outras linguagens também implementaram a especificação como Ruby (Rack), Javascript (JSGI), Perl (PSGI), etc;
  • possui poucos elementos para deploy e configuração. O utilitário Python Paste, por exemplo, tenta resolver isso (e um monte de outras coisas);

Algumas referências

- wsgi.org

- python.org/dev/peps/pep-3333

- lucumr.pocoo.org/2007/5/21/getting-started-with-wsgi

WSGI

By Alan

WSGI

Web Server Gateway Interface

  • 325