Create a Web Server with Python

To create a Web Server with Python it is necessary to be familiar with some basic concepts of execution threads and communication protocols. In this example, the Web Server returns an HTML page and a JPG image within the same page to exemplify how to return text and binary content in different requests that are ultimately displayed as the same page in the browser.

It is not very complicated to create a Web Server in Python, we show you the code and we explain each step:

import socketserver
from http import server

#geekole.com

HTML_PAGE="""\
<html>
<head>
<title>Web Server Example</title>
</head>
<body>
<center><h1>Web Server Example</h1></center>
<center><img src="image.jpg" width="400" height="225"></center>
</body>
</html>
"""

class RequestHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = HTML_PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/image.jpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'image/jpeg')
            self.end_headers()
           
            fileObj = open("D:/image_path/image.jpg","rb")
            image = fileObj.read()
            self.wfile.write(image)

        else:
            self.send_error(404)
            self.end_headers()

class ThreadedHTTPServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

address = ('', 8000)
server = ThreadedHTTPServer(address, RequestHandler)
server.serve_forever()

Let’s take a closer look at how each block of code works. The first thing we do is declare a string with the HTML content of the index.html page that we will return when the service is invoked:

HTML_PAGE="""\
<html>
<head>
<title>Web Server Example</title>
</head>
<body>
<center><h1>Web Server Example</h1></center>
<center><img src="imagen.jpg" width="400" height="225"></center>
</body>
</html>
"""

Then we create a RequestHadler class:

class RequestHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = HTML_PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/image.jpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'image/jpeg')
            self.end_headers()
           
            fileObj = open("D:/image_path/image.jpg","rb")
            image = fileObj.read()
            self.wfile.write(image)

        else:
            self.send_error(404)
            self.end_headers()

This class will be responsible for responding to Web requests made by the user by invoking the following web addresses:

  • ‘/’
  • ‘/index.html’
  • ‘/image.jpg’

We create a class that will allow us to launch an independent execution thread for each Web request and we call it ThreadedHttpServer:

class ThreadedHTTPServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

In the final lines of our code we start running our web server indefinitely on port 8000:

address = ('', 8000)
server = ThreadedHTTPServer(address, RequestHandler)
server.serve_forever()

It is necessary that a real image exists on the computer where you are executing this script, in this example we have specified the path and access to the image in the line of code that we show you below:

fileObj = open("D:/image_path/image.jpg","rb")
Make sure it’s a valid image and you have read permission to the file.

One important thing to note when creating a service like this is that when you return information to a user who makes the request from their browser, you must not only return the content of an HTML file or the binary data of an image, but also you must return additional information that will allow the browser to understand what you are sending. This information is the header of a response in an http request. In our example you can see that we do this in the following lines:

            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'image/jpeg')
            self.end_headers()

We are returning, among other things, the type of response (200 successful), the conditions for the reception and treatment that the browser must give to the information and the type of content that we are returning with “Content-Type” and the string “image /jpg”. Finally, we close the header block with the end_headers() function.

Result

When executing the script on Windows for example, it is likely that the operating system will ask you for confirmation of access security. This is because you are using a port that is not normally used, 8000. On Linux or Mac you will probably have to do something similar.

If you write in the browser: http://localhost:8000/

You will get the following result, but with the image you used for the example:

Create a Web Server with Python
Web Server with Python

As you can see, creating a Web Server with Python is not very difficult, but it is necessary to understand new concepts about http communication so that everything works correctly.

More information on the official Python page: https://docs.python.org/3/library/http.server.html