Building a Simple Web Server with Python

When you think of Web development in Python, you might think of popular Web frameworks like Django or Flask. While these are good for large applications used by many people simultaneously, Python’s standard libary is good enough for a small project that’s only used by one person at a time.

I recently created a Web-based tool for sending files across different computers at home, mainly between my desktop computer and laptop. I’ll walk through how I wrote this tool using Python’s standard library modules.

(Yes, I know flash drives exist, but I don’t have any available and I’d rather not buy one if I’m not going to use it very often.)

Basic Web Server with http.server

The http.server module provides classes for building a basic Web server. This isn’t meant to be a complete tutorial (the official documentation is quite good), but I’ll provide a basic outline of how to use the module.

The minimal code to start a server is:

import http.server

server = http.server.HTTPServer(("", 8000), MyRequestHandler)
server.serve_forever()

The first parameter to the HTTPServer constructor is the server address, which is a tuple consisting of a host address and a port. The host address determines where the server will listen: For example, specifying “localhost” means the server will only listen to connections from the same system, while the empty string means to listen on all interfaces (only for IPv4; to support IPv6 use ::).

The second parameter is the request handler class, which specifies how requests should be handled. The module provides a BaseHTTPRequestHandler class you can derive from to build your own handler. The subclass should override the do_METHOD functions to handle each HTTP method. For example, here is a request handler that simply responds with a 404 to all GET requests:

class NotFoundRequestHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        response_data = b"Not found" # Repsonse data must be sent as bytes
        self.send_response(http.HTTPStatus.NOT_FOUND) # Status codes are in the separate http module
        self.send_header("Content-Type", "text/plain")
        self.send_header("Content-Length", len(response_data))
        self.end_headers()
        self.wfile.write(response_data)

Web Application in a Single File

For this project, I wanted to keep everything in a single file so that it would be easy to run. I decided to use a single-page application (SPA) architecture, which meant that I only had to serve a single static page and didn’t have to deal with any templating.

The static page for the frontend is a hardcoded string. This page contains an inline script to handle browsing and uploading files via API calls (using old-fashioned JavaScript which should work in Internet Explorer 10 or later).

The backend is the request handler, which handles GET and POST requests:

  • GET: If the path is / then the handler serves the hardcoded HTML page. Otherwise, it uses SimpleHTTPRequestHandler (provided by the http.server module) to serve the file at that path.
  • POST: There are two API endpoints. The /send endpoint saves a file and the /dirlist endpoint returns a directory listing.

Conclusion

Python’s standard library provides decent but fairly rudimentary support for building Web applications. I’ve had to implement things like routing, request parsing, and security checks myself, things that you might expect from a “proper” Web framework. Still, in cases where you don’t need the full power of such a framework, the standard library can be useful.

Reply to this post via: E-mail, LinkedIn, Twitter
Philip Chung
Philip Chung
Software Developer