Servir archivos con el módulo SimpleHTTPServer de Python

Para pruebas rápidas, configurar un servidor es más complicado que hacer la aplicación en sí. En este artículo, usaremos el módulo SimpleHTTPServer para ejecutar rápidamente una aplicación de Python y acceder a ella a través del navegador.

Introducción

Los servidores son software o hardware de computadora que procesa solicitudes y entrega datos a un cliente a través de una red. Existen varios tipos de servidores, siendo los más comunes los servidores web, los servidores de bases de datos, los servidores de aplicaciones y los servidores de transacciones.

Servidores web ampliamente utilizados como apache, Mono y [Rompecabezas](https://jigsaw.w3 .org/) requieren bastante tiempo para configurarse cuando se prueban proyectos simples y el enfoque de un desarrollador cambia de producir la lógica de la aplicación a configurar un servidor.

El módulo SimpleHTTPServer de Python es una herramienta útil y directa que los desarrolladores pueden usar para varios casos de uso, siendo el principal una forma rápida de servir archivos desde un directorio.

Elimina el laborioso proceso asociado con la instalación e implementación de los servidores web multiplataforma disponibles.

Nota: Si bien SimpleHTTPServer es una excelente manera de servir fácilmente archivos desde un directorio, no debe usarse en un entorno de producción. De acuerdo con los documentos oficiales de Python, “solo implementa comprobaciones de seguridad básicas”.

¿Qué es un servidor HTTP

HTTP significa Protocolo de transferencia de hipertexto. Pensemos en un protocolo como un idioma hablado como el inglés. El inglés tiene un conjunto de reglas y vocabulario. Por lo tanto, si ambos entendemos las reglas y el vocabulario que define el idioma inglés, entonces podemos comunicarnos en el idioma de manera efectiva.

Al igual que los seres humanos, los dispositivos electrónicos también se comunican entre sí. Por lo tanto, necesitan un 'conjunto de reglas y vocabulario' para pasar y recibir información de forma activa entre ellos.

Un protocolo es un conjunto estándar de reglas que facilita la comunicación exitosa entre dispositivos electrónicos. Estos conjuntos de reglas mutuamente aceptadas e implementadas incluyen los comandos utilizados para iniciar el envío y la recepción de datos, los tipos de datos que se transmitirán entre dispositivos, cómo detectar errores en los datos, cómo se confirman las transferencias de datos exitosas y mucho más.

Por ejemplo, cuando realiza una búsqueda simple usando un navegador, había dos sistemas esenciales involucrados: el Cliente HTTP y el Servidor HTTP.

El cliente, comúnmente conocido como navegador, puede ser un programa elaborado como Google Chrome o Firefox, pero también puede ser tan simple como una aplicación CLI. El cliente envía su solicitud al servidor, que procesa las solicitudes HTTP y proporciona una respuesta al cliente. En el caso de los navegadores, la respuesta suele ser una página HTML.

Módulo SimpleHTTPServer de Python

Cuando necesita un servidor web rápido, configurar un servidor de nivel de producción es una exageración masiva.

El módulo SimpleHTTPServer de Python es una herramienta que ahorra trabajo y que puede aprovechar para convertir cualquier directorio de su sistema en un servidor web sin complicaciones. Viene empaquetado con un servidor HTTP simple que ofrece controladores de solicitudes estándar GET y HEAD.

Con un servidor HTTP incorporado, no es necesario que instale ni configure nada para que su servidor web esté en funcionamiento.

Nota: El módulo SimpleHTTPServer de Python se fusionó con el módulo http.server en Python 3. A lo largo de este artículo, usaremos la versión de Python 3, pero si está usando Python 2, puede intercambiar http.server por SimpleHTTPServer y debería funcionar en la mayoría de los casos.

Uso de la línea de comandos

La forma más sencilla de iniciar un servidor web que sirve el directorio en el que se ejecuta el comando es simplemente navegar al directorio de su proyecto usando la terminal y ejecutar:

python 2

1
$ python -m SimpleHTTPServer 8000

python 3

1
$ python3 -m http.server 8000

Al ejecutar este comando, podrá acceder a los archivos en su directorio a través de su navegador en localhost: 8000:

listado del directorio de aplicaciones

Como puede ver, el servidor proporciona una interfaz de usuario de directorio simple en la que puede acceder a cualquiera de los archivos. Esta es la forma más sencilla de servir archivos directamente de forma local a través de HTTP.

Uso predeterminado de Python

Por una razón u otra, ejecutar este servidor a través de la línea de comandos podría no ser adecuado para nuestro caso de uso. En momentos como este, podemos usar el servidor directamente en nuestro código usando el objeto SimpleHTTPRequestHandler. Pero primero, debemos configurarlo con un servidor de socket.

Debajo del protocolo HTTP están UDP (Protocolo de datagramas de usuario) o TCP (Protocolo de control de transmisión), que son protocolos de transporte que manejan el transporte de datos de una ubicación de red a otra. Dado que estamos ejecutando un servidor HTTP, nuestra aplicación utilizará el protocolo TCP, a través de una Dirección de socket TCP que contiene una dirección IP y un número de puerto. Esto se puede configurar con socketserver.TCPServer de Python, que hemos implementado a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import http.server
import socketserver

PORT = 8000

handler = http.server.SimpleHTTPRequestHandler

with socketserver.TCPServer(("", PORT), handler) as httpd:
    print("Server started at localhost:" + str(PORT))
    httpd.serve_forever()

Nota: El código fallará con el error AttributeError: __exit__ para las versiones de Python < 3.6. Esto se debe a que en versiones anteriores socketserver.TCPServer no admite el uso con administradores de contexto (la palabra clave with). En estos casos, debe llamar a server_close() para detener el servidor.

Por defecto, SimpleHTTPRequestHandler sirve archivos del directorio actual y subdirectorios relacionados. Como sugiere el nombre, es un simple controlador de solicitudes HTTP. Siendo el servidor simple que es, solo le permite recuperar datos y no publicarlos en el servidor. Y debido a esto, solo implementa los métodos HTTP GET y HEAD a través de do_GET() y do_HEAD().

Los parámetros pasados ​​a TCPServer representan la dirección IP y el número de puerto. Al dejar la dirección IP vacía, el servidor escucha todas las direcciones IP disponibles, mientras configuramos el puerto en 8000. Esto significa que entonces sería accesible en localhost:8000.

Finalmente, httpd.server_forever() inicia el servidor, escucha y responde a las solicitudes entrantes de un cliente.

El servidor se puede iniciar simplemente ejecutando el archivo:

1
$ python3 simple-server.py

Y al igual que con el uso de la línea de comandos, ahora podemos acceder al directorio a través de nuestro navegador web:

listado del directorio de aplicaciones

Personalización de rutas

Otro enfoque que podemos tomar es crear una clase personalizada que amplíe SimpleHTTPRequestHandler y maneje nuestras solicitudes con alguna funcionalidad personalizada. Para hacer esto, implementamos nuestra propia función do_GET().

Pero antes de llegar a eso, digamos que tenemos un archivo HTML que queremos servir, mywebpage.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
  <title>Using Python's SimpleHTTPServer Module</title>
  <style>
    #rectangle {
      height: 50px;
      width: 100px;
      background-color: #00f28f;
    }
  </style>
</head>
<body>
  <h2>Rectangle served by SimpleHTTPServer</h2>
  <div id="rectangle"></div>
</body>
</html>

Para servir este HTML desde una ruta que no es /mywebpage.html, podemos usar nuestro controlador personalizado para servirlo en cualquier ruta que queramos. En este ejemplo, solo lo serviremos en la ruta raíz, /:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import http.server
import socketserver

class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.path = 'mywebpage.html'
        return http.server.SimpleHTTPRequestHandler.do_GET(self)

# Create an object of the above class
handler_object = MyHttpRequestHandler

PORT = 8000
my_server = socketserver.TCPServer(("", PORT), handler_object)

# Star the server
my_server.serve_forever()

Nuevamente, ejecutar este script nos permitirá acceder a él a través del navegador:

rectángulo servido en el navegador

Sin embargo, hay muchas más personalizaciones que podemos hacer con la respuesta a través de la referencia “auto”, que veremos en la siguiente sección.

Devolución de HTML dinámico

Un uso común de los servidores web es servir HTML generado dinámicamente. Aunque este es solo un servidor muy simple, también puede realizar esta tarea. Además de enviar HTML dinámico, también podemos configurar diferentes códigos de estado, encabezados, etc. En el siguiente ejemplo, configuramos algunos encabezados y devolvemos HTML dinámico que se genera usando el parámetro de consulta nombre:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import http.server
import socketserver
from urllib.parse import urlparse
from urllib.parse import parse_qs

class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        # Sending an '200 OK' response
        self.send_response(200)

        # Setting the header
        self.send_header("Content-type", "text/html")

        # Whenever using 'send_header', you also have to call 'end_headers'
        self.end_headers()

        # Extract query param
        name = 'World'
        query_components = parse_qs(urlparse(self.path).query)
        if 'name' in query_components:
            name = query_components["name"][0]

        # Some custom HTML code, possibly generated by another function
        html = f"<html><head></head><body><h1>Hello {name}!</h1></body></html>"

        # Writing the HTML contents with UTF-8
        self.wfile.write(bytes(html, "utf8"))

        return

# Create an object of the above class
handler_object = MyHttpRequestHandler

PORT = 8000
my_server = socketserver.TCPServer(("", PORT), handler_object)

# Star the server
my_server.serve_forever()

Y ejecutar este código con la URL http://localhost:8000?name=Billy producirá:

serving dynamic html

¡Cualquier valor que establezca para el parámetro de consulta nombre aparecerá en la pantalla! Incluso puede omitir el parámetro de consulta nombre y ver qué sucede.

Como puede ver, la creación de un controlador de solicitudes personalizado nos permite manipular las respuestas tanto como nos gustaría al cambiar la implementación del método do_GET y no tenemos tal control sobre nuestras respuestas con la implementación predeterminada. .

Lo mismo se puede hacer con el método HTTP HEAD (a través de la función do_HEAD()), pero dado que es muy similar al método GET, lo dejaremos como ejercicio para el lector.

Conclusión

Python nos proporciona el módulo SimpleHTTPServer (o http.server en Python 3) que se puede usar para servir archivos de forma rápida y sencilla desde un directorio local a través de HTTP. Esto se puede usar para muchas tareas de desarrollo u otras tareas internas, pero no está diseñado para producción.

Esta es una gran solución para uso local ya que servidores web como apache, Mono y Rompecabezas son mucho más difíciles de configurar y, a menudo, son excesivos para las actividades de desarrollo.