WSGI Hello World。
#python #webserver #middleware #wsgi

如果您对Python的Web应用程序的开发感兴趣,那么这些首字母缩写词甚至可能从概念上讲是什么,甚至可能更清楚。

WSGI ,适合这位赞助人。该定义在PEP 3333中被重新训练。好吧,实际上,这适用于python的 3.x 版本( 2.x 版本的初始定义是PEP 333

在Python中包含的软件包中,我们可以找到一个参考WSGI Web服务器( wsiref.simple_server )和一个演示应用程序。

进行演示后,我们将开始工作并实施我们的第一个版本。

from wsgiref.simple_server import make_server, demo_app

IP = "0.0.0.0"
PUERTO = 8080
APP = demo_app

print(f"Iniciando aplicación APP en servidor WSGI en { IP }: { PUERTO }")
with make_server(IP, PUERTO, APP) as servidor_wsgi:
    print("Puedes finalizar con CTRL+C")
    servidor_wsgi.serve_forever()

如果我们执行刚刚编写的代码,我们将筹集 wsgi Web服务器,等待请愿 http 到端口 8080 。>

现在我们可以打开喜欢的浏览器并请求以下URL(http://localhost:8080)。而且,âh惊喜! variable ='value'

到达了这一点,并实现了标题中指示的目标,因此我们已经可以得出结论。但是不要担心,尽管不多,但我们将在这个主题上加深一点。

总结到极端,应用程序wsgi ,它必须是一定的 (一个函数或实现不利>的对象),它将接收到它 2参数。第一个是执行环境,第二个是回调,必须称呼它才能构建答案。

我们的演示应用程序向我们展示了执行环境的内容。具有环境变量值的字典,我们的Web服务器包含了一些其他值(例如 path_info ='/',其中包含我们上面要求的资源路由服务器)。另一方面,我们的申请将返回以交付给申请人的响应。

我们去创建我们的第一个WSGI应用程序,留下我们的代码,并具有类似的内容:

from wsgiref.simple_server import make_server


#=============================================================================
# Esta función es nuestra aplicación WSGI y, como tal, al ser llamada
# recibirá los 2 parámetros esperados:
#   * diccionario con el entorno de ejecución.
#   * callback para crear respuesta.
#=============================================================================
def mi_app_wsgi(entorno, responder):

    # Configuramos opciones de respuesta por defecto
    cabeceras = [('Content-type', 'text/plain; charset=utf-8')]

    # Iniciamos respuesta
    responder('200 OK', cabeceras)    
    respuesta = "Contenido devuelto por mi_app_wsgi."

    # El cuerpo de la respuesta no puede ser un string.
    # Debe ser una lista de bytes.
    return [respuesta.encode("utf-8")]


IP = "0.0.0.0"
PUERTO = 8080
APP = mi_app_wsgi


print(f"Iniciando aplicación APP en servidor WSGI en { IP }: { PUERTO }")
with make_server(IP, PUERTO, APP) as servidor_wsgi:
    print("Puedes finalizar con CTRL+C")
    servidor_wsgi.serve_forever()

新版本没有太大变化。我们已经解决了 mi_app_wsgi函数,它将接收2个预期参数,重要的是,它将返回一个字节 (如果我们返回,因为它与预期的不符)。

也有必要称为 calback 函数(在我们的具体情况下,我们称其为答案)。因此,我认为代码足够解释,不需要任何其他解释。

如果我们执行了新版本,并且再次请求http://localhost:8080 URL,我认为这是可以预见的,我们将获得的结果是什么。

我们也可以在这里留在这里,但是由于我们被放置,我们会做一些更精心的事情。

from wsgiref.simple_server import make_server
from base64 import b64decode



#=============================================================================
# Esta función es una aplicación WSGI y, como tal, al ser llamada
# recibirá los 2 parámetros esperados:
#   * diccionario con el entorno de ejecución.
#   * callback para crear respuesta.
#=============================================================================
def mi_app_wsgi(entorno, responder):

    # Configuramos opciones de respuesta por defecto
    cabeceras = [('Content-type', 'text/plain; charset=utf-8')]

    # Iniciamos respuesta
    responder('200 OK', cabeceras)    
    respuesta = "Contenido devuelto por mi_app_wsgi."

    # El cuerpo de la respuesta no puede ser un string.
    # Debe ser una lista de bytes.
    return [respuesta.encode("utf-8")]



#=============================================================================
# Esta clase es nuestra aplicación WSGI y, como tal, al ser llamada
# recibirá los 2 parámetros esperados:
#   * diccionario con el entorno de ejecución.
#   * callback para crear respuesta.
#=============================================================================
class AutenticacionBasica():

    USUARIO = "mi_usuario"
    PASSWORD = "mi contraseña"


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


    def __call__(self, entorno, responder):
        # Comprobamos si la solicitud tiene una cabecera de autenticación válida.
        # Si esto es así, llamamos a nuestra otra aplicación WSGI y devolveremos
        # lo que ésta nos devuelva.
        if self._autenticado(entorno.get('HTTP_AUTHORIZATION')):
            return self._app(entorno, responder)

        # Solicitamos autenticación para peticiones no autenticadas-
        return self._no_autenticado(entorno, responder)


    def _autenticado(self, cabecera_autenticacion):
        # Comprobamos si hemos recibido cabedera de autenticación
        if not cabecera_autenticacion:
            return False

        # Si hemos recibido cabedera de autenticación, decodificamos contenido y
        _, valor_codificado = cabecera_autenticacion.split(None, 1)
        valor_decodificado = b64decode(valor_codificado).decode('utf-8')
        username, password = valor_decodificado.split(':', 1)

        # comprobamos si usuario y contraseña se corresponden con valores aceptados
        # como válidos.
        return username == self.USUARIO and password == self.PASSWORD


    def _no_autenticado(self, entorno, responder):
        # Configuramos cabecras por defecto de respuesta
        cabeceras = [
            ('Content-type', 'text/plain; charset=utf-8'),
            ('WWW-Authenticate', 'Basic realm="Login"')
        ]

        # Iniicamos respuesta indicando que se requiere autenticación previa.
        responder('401 Authentication Required', cabeceras)
        respuesta = "Autenticación de usuario es requerida."

        return [respuesta.encode("utf-8")]



IP = "0.0.0.0"
PUERTO = 8080
APP = AutenticacionBasica(mi_app_wsgi)


print(f"Iniciando aplicación APP en servidor WSGI en { IP }: { PUERTO }")
with make_server(IP, PUERTO, APP) as servidor_wsgi:
    print("Puedes finalizar con CTRL+C")
    servidor_wsgi.serve_forever()

在这种情况下,我们将 类作为WSGI应用程序。他的所有 __呼叫__ 将根据WSGI中指定的内容接收预期参数,此外(在他的瞬间)中,同样的WSGI适用了上一个示例而没有修改。

在此示例中,我们看到了如何提交 Midleware ,在我们的情况下,将迫使用户先前的身份验证,然后再启动我们的初始应用程序(不必在此进行修改)。由于代码的简单性,我们将所有内容都保存在唯一的来源中,但是, mi_app_wsgi ,而不是简单的功能,它可能是一个复杂的应用程序 flask flask p。 EJ。和身份验证-boba类可以实施令牌JWT 的精心验证。

我认为,现在是结论这篇文章的好时机。我希望我贡献了对您有用的东西。