Skip to content

Building a Simple HTTP Server

Python includes a simple HTTP server in the standard library.

Great for:

  • local demos
  • serving static files

Not ideal for production.

If you run:

bash
python -m http.server 8000

Then open:

  • http://localhost:8000
custom_http_server.py
from http.server import BaseHTTPRequestHandler, HTTPServer
 
 
class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-Type", "text/plain")
        self.end_headers()
        self.wfile.write(b"Hello from Python HTTP server")
 
 
if __name__ == "__main__":
    server = HTTPServer(("127.0.0.1", 8000), Handler)
    print("Serving on http://127.0.0.1:8000")
    server.serve_forever()
  • do_GET handles HTTP GET requests
  • send_response sets status code
  • headers must be sent before the body
diagram what http.server answers, and what it refuses mermaid
SimpleHTTPRequestHandler maps a URL path onto the current working directory and serves whatever it finds. It generates a listing for a directory, returns 404 for a missing file, and refuses every method except GET and HEAD. All four responses below were fetched from a server actually running.
sketch Four requests to a running http.server p5.js
A server was started on a temporary directory containing one file, and each of these requests was actually made. The responses are what came back, including the 501 for POST -- the built-in handler implements only GET and HEAD, so it is a file viewer rather than a web framework.
pch.quizTag pch.quizDefaultTitle
  1. `python -m http.server` serves which directory?

    pch.quizShowAnswer

    B — The current working directory — Whatever folder you started it in. Run it in the wrong place and it will serve your source, your `.env` and anything else that is there.

  2. What does a POST to the built-in handler return?

    pch.quizShowAnswer

    D — 501 Unsupported method — Verified. `SimpleHTTPRequestHandler` implements only GET and HEAD, so it is a file viewer rather than a framework — to handle POST you subclass it and write `do_POST`.

  3. You request a path that is a directory. What comes back?

    pch.quizShowAnswer

    C — 200 with a generated listing (or index.html if present) — Measured: 200 with a 299-byte generated listing. If an `index.html` exists it is served instead, which is what makes this useful for previewing a static site.

  4. Why should this server never be exposed beyond localhost?

    pch.quizShowAnswer

    B — No authentication, no TLS, and its root is whatever directory you happened to be in — It also binds all interfaces by default, so on a shared network the whole directory is readable. Bind it to 127.0.0.1 and treat it as a local preview tool.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading