A Simple Python HTTP Server
Although, we aren’t gonna need it in this article but it’s always good to setup a virtual environment when working with Python. Check out my article on how to create a virtual environment for Python: /blog/python/how-to-create-a-python-virtual-environment/.
To create a simple Python HTTP Server, we are going to use two modules called http.server
and socketserver
. They both are part of Python’s Standard Library, we don’t need to install them.
Important! This material is made for learning purposes. DO NOT use it in production. http.server
is not recommended for production. It only implements basic security checks.
Let’s create a file called server.py
and define our Server
class there.
|
|
The preceding code-block will create a running server, listening, by default, on a port chosen by your OS and serving the current working directory.
How it works
On lines 8,9 the Server
class initiates with two arguments - server_address
and handler
.
|
|
The server_address
is a tuple taking two values. The first value is the host, which is 127.0.0.1
for localhost
. The second value is the port number, which by default is 0
, this allows the operating system to choose itself on which port to serve. The handler
, by default, accepts SimpleHTTPRequestHandler
class. SimpleHTTPRequestHandler
is part of the http.server
module and is responsible for handling the client requests.
You can see how the handler is used by a TCPServer
instance on line 14. TCPServer
itself is part of the socketserver
module and instantiates with 3 arguments: server_address
, RequestHandlerClass
, and bind_and_activate
. We’ll skip the bind_and_activate
argument in this article. For the other two, you already understand what they do.
|
|
On line 15, we call server_address
from the newly created TCPServer
instance to print the server information on line 17. Here, the port number is set by the OS, already. We set serving_at
as the variable name here to escape confusion with the variable on line 10.
|
|
On line 18, we call the serve_forever()
method. It runs the server in a loop and never exits unless the program gets terminated.
|
|
Finally, on lines 21, 22 we instantiate the Server
class and call its serve
method.
|
|
Creating a custom handler
You can create a custom handler to be used by the TCPServer
instead of SimpleHTTPRequestHandler
. For simplicity, let’s define our handler in the same server.py file.
|
|
The Handler
class inherits from SimpleHTTPRequestHandler
. We keep it empty for now. You’ll see soon how we can customize it. Since we’ve defined a custom handler, the Server
class instantiates with the handler attribute equal to our custom Handler
class on line 25.
|
|
Serving a custom directory
Now, what if we want to serve on a different directory. Let’s say we have a directory called public
containing a few HTML files and images. To serve that directory we must modify the Handler
class defined in the previous passage.
|
|
Here, we initiate our Handler
class by calling the __init__
of the parent class and modifying the directory
argument of it. All other non-keyword and keyword arguments remain the same with *args
and **kwargs
called. It worths mentioning that in Python3.9 the directory
argument accepts a path-like object.
Basic routing
SimpleHTTPRequestHandler
class allows us to manage the requests coming from a client via do_GET()
, do_POST()
and do_HEAD()
methods. Since our Handler
class inherits from SimpleHTTPRequestHandler
, we can define custom routes by overriding these methods. In this article, we do so only to do_GET()
method and define custom routes for GET
requests.
|
|
On lines 11-15, we say that if the root path (/
) is requested then the server should look for the index.html
file. And if the requested path is /lyrics
, then the server should look for the lyrics.html
file.
Notice the return
statement at the end:
|
|
Since we override the do_GET()
method, we must call the default one from the parent class at the end so the handler knows how to process the GET
requests.
We can do more with do_GET()
and even create automatic routing to look for the corresponding HTML
files for each path, etc. But that’s a topic for another article or for you to experiment and find it out yourself. 🙂
The code in this article is available in my repo here: github.com/oorkan/a-simple-python-http-server.
I hope you enjoyed it. Cheers! 🍻
References
The Python Standard Library (@3.9, lup: March 20, 2021)
socketserver — A framework for network servers (@3.9, lup: March 20, 2021)
http.server — HTTP servers (@3.9, lup: March 20, 2021)
Python *args and **kwargs by Programiz