Custom web framework for semi-finished products

It can be said that Web services are basically extended on the basis of more than ten lines of code. This code is their ancestor.

The user’s browser will send data to the server when it enters the address. What data will the browser send? How do you do it? Who is this? Your website is the rule. Can his Internet play still according to his rule?

Therefore, there must be a unified rule, so that when you send messages and receive messages, there is a format basis and can not be written at random.

This rule is the HTTP protocol. After the browser sends the request information or the server responds to the response information, it must follow this rule.

HTTPThe protocol mainly specifies the communication format between the client and the server. How does the HTTP protocol specify the message format?

Then let’s take a look at the response message that browsers receive when we visit the blog website.

The response related information can be seen in the network tab of the browser debug window.

clickview sourceThe following is shown as follows:

We found that the message needed to send and receive must be in a certain format, so we need to know about the HTTP protocol.

HTTPIntroduction of the agreement

HTTPProtocol format requirements for sending and receiving messages

Each HTTP request and response follow the same format. A HTTP contains two parts of Header and Body, where Body is optional. There is one in the Header of the HTTP responseContent-TypeThe content format of the response. astext/htmlRepresent the HTML web page.

HTTP GETThe format of the request:

HTTPThe format of the response:

A maiden version of the custom web framework

After the supplementary learning above, we know that to make the web server end of our own write up, we must let our Web server add the response state according to the rules of the HTTP protocol when answering the message to the client, so that we have implemented a positive one.The Web framework.

We have briefly demonstrated the essence of the web framework through more than ten lines of code.

Next let’s continue to improve our custom web framework.

Return different contents according to different paths

Is this the end of this? How can our Web service return different content according to the URL of the user request?

A trivial matter, we can get the path of requesting URL from the relevant data, and then take the path to make a judgement.

"""
Return different contents according to different paths in URL"""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # Bind IP and port
sk.listen() # Monitorwhile 1:
# Wait for a connection
conn, add = sk.accept()
data = conn.recv(8096) # Receiving the message sent by the client# Take the path from data
data = str(data, encoding="utf8") # Converts the received byte type data to a string.# \r\n segmentation
data1 = data.split("\r\n")[0]
url = data1.split()[1] # urlIs the access path separated from the messages sent by the browser.
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # Because the HTTP protocol should be followed, the reply message should also be added to the status line.# Return different contents according to different pathsif url == "/index/":
response = b"index"elif url == "/home/":
response = b"home"else:
response = b"404 not found!"
conn.send(response)
conn.close()

Returning different contents according to different paths — function version

The above code solves the need for different URL paths to return different contents.

But the question is coming again. If there are many, many ways to decide what to do? Do you want to write if judgment by one by one? Of course not, we have a smarter way.

"""
According to different paths in URL to return different contents -- function version"""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # Bind IP and port
sk.listen() # Monitor# It will be returned to different parts of the content to be encapsulated into functionsdef index(url):
s = "This is a {} page!".format(url)
return bytes(s, encoding="utf8")
def home(url):
s = "This is a {} page!".format(url)
return bytes(s, encoding="utf8")
while 1:
# Wait for a connection
conn, add = sk.accept()
data = conn.recv(8096) # Receiving the message sent by the client# Take the path from data
data = str(data, encoding="utf8") # Converts the received byte type data to a string.# \r\n segmentation
data1 = data.split("\r\n")[0]
url = data1.split()[1] # urlIs the access path separated from the messages sent by the browser.
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # Because the HTTP protocol should be followed, the reply message should also be added to the status line.# Different contents are returned according to different paths. Response is the specific response body.if url == "/index/":
response = index(url)
elif url == "/home/":
response = home(url)
else:
response = b"404 not found!"
conn.send(response)
conn.close()

Returning different contents according to different paths — function advanced edition

It seems that the above code should be judged by if one by one. What should we do? We still have a way! As long as the mind does not slide, the method is always more than the problem.

"""
According to different paths in URL, return different contents -- advanced version of function."""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # Bind IP and port
sk.listen() # Monitor# It will be returned to different parts of the content to be encapsulated into functionsdef index(url):
s = "This is a {} page!".format(url)
return bytes(s, encoding="utf8")
def home(url):
s = "This is a {} page!".format(url)
return bytes(s, encoding="utf8")
# Define the correspondence between a URL and the function to be executed.
list1 = [
("/index/", index),
("/home/", home),
]
while 1:
# Wait for a connection
conn, add = sk.accept()
data = conn.recv(8096) # Receiving the message sent by the client# Take the path from data
data = str(data, encoding="utf8") # Converts the received byte type data to a string.# \r\n segmentation
data1 = data.split("\r\n")[0]
url = data1.split()[1] # urlIs the access path separated from the messages sent by the browser.
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # Because the HTTP protocol should be followed, the reply message should also be added to the status line.# Return different contents according to different paths
func = None # Defines a variable that holds the name of the function to be executed.for i in list1:
if i[0] == url:
func = i[1]
breakif func:
response = func(url)
else:
response = b"404 not found!"# Return to a specific response message conn.send(response)
conn.close()

Return to a specific HTML file

It perfectly solves the problem that different URL returns different contents. But I don’t want to just return a few strings. I want to return the complete HTML content to the browser. What should I do?

No problem. Whatever it is, it is converted to byte data. We can open the HTML file, read out its internal binary data, and then send it to the browser.

"""
According to different paths in URL, return different contents -- advanced version of function.Return to a separate HTML page"""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # Bind IP and port
sk.listen() # Monitor# It will be returned to different parts of the content to be encapsulated into functionsdef index(url):
# Read the content of the index.html page
with open("index.html", "r", encoding="utf8") as f:
s = f.read()
# Return byte datareturn bytes(s, encoding="utf8")
def home(url):
with open("home.html", "r", encoding="utf8") as f:
s = f.read()
return bytes(s, encoding="utf8")
# Define the correspondence between a URL and the function to be executed.
list1 = [
("/index/", index),
("/home/", home),
]
while 1:
# Wait for a connection
conn, add = sk.accept()
data = conn.recv(8096) # Receiving the message sent by the client# Take the path from data
data = str(data, encoding="utf8") # Converts the received byte type data to a string.# \r\n segmentation
data1 = data.split("\r\n")[0]
url = data1.split()[1] # urlIs the access path separated from the messages sent by the browser.
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # Because the HTTP protocol should be followed, the reply message should also be added to the status line.# Return different contents according to different paths
func = None # Defines a variable that holds the name of the function to be executed.for i in list1:
if i[0] == url:
func = i[1]
breakif func:
response = func(url)
else:
response = b"404 not found!"# Return to a specific response message conn.send(response)
conn.close()

Make web pages dynamic

This web page can be displayed, but it is static. The content of the page will not change. What I want is a dynamic website.

No problem, I have a way to solve it. I chose to use string substitution to achieve this requirement. (using timestamps to simulate dynamic data)

"""
According to different paths in URL, return different contents -- advanced version of function.Return to the HTML pageMake web pages dynamic"""import socket
import time
sk = socket.socket()
sk.bind(("127.0.0.1", 8080)) # Bind IP and port
sk.listen() # Monitor# It will be returned to different parts of the content to be encapsulated into functionsdef index(url):
with open("index.html", "r", encoding="utf8") as f:
s = f.read()
now = str(time.time())
s = s.replace("@@oo@@", now) # Define special symbols in web pages and replace special symbols in advance with dynamic data.return bytes(s, encoding="utf8")
def home(url):
with open("home.html", "r", encoding="utf8") as f:
s = f.read()
return bytes(s, encoding="utf8")
# Define the correspondence between a URL and the function to be executed.
list1 = [
("/index/", index),
("/home/", home),
]
while 1:
# Wait for a connection
conn, add = sk.accept()
data = conn.recv(8096) # Receiving the message sent by the client# Take the path from data
data = str(data, encoding="utf8") # Converts the received byte type data to a string.# \r\n segmentation
data1 = data.split("\r\n")[0]
url = data1.split()[1] # urlIs the access path separated from the messages sent by the browser.
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # Because the HTTP protocol should be followed, the reply message should also be added to the status line.# Return different contents according to different paths
func = None # Defines a variable that holds the name of the function to be executed.for i in list1:
if i[0] == url:
func = i[1]
breakif func:
response = func(url)
else:
response = b"404 not found!"# Return to a specific response message conn.send(response)
conn.close()

All right, at this pause…

Server programs and Applications

For the real development of Python web program, it is usually divided into two parts: server program and application program.

The server program is responsible for encapsulating the socket server and sorting out all kinds of data requested when it comes.

The application is responsible for the specific logical processing. In order to facilitate the development of application programs, there are many Web frameworks, such as Django, Flask, web.py and so on. Different frameworks have different ways of development, but in any case, applications developed must be servers.Program coordination, to provide services for users.

In this way, the server program needs to provide different support for different frameworks. This chaotic situation is not good for servers or frameworks. For the server, different frameworks are needed to support the framework, and only the servers that support it can be used by the developed applications.

At this time, standardization becomes particularly important. We can set up a standard, so long as the server program supports this standard and the framework supports this standard, then they can cooperate with it. Once the standard is determined, both sides are implemented. In this way, the server can support more standard supporting frameworks.To use more servers that support the standard.

WSGI（Web Server Gateway Interface）It is a specification that defines the interface format between the web application written in Python and the web server program to decouple the web application from the web server program.

The common WSGI servers are uwsgi and Gunicorn. The independent WSGI server provided by the Python standard library is called wsgiref.DjangoThe development environment uses this module to do the server.。

Continue from here…

wsgiref

We use the wsgiref module to replace the socket server part of our own web framework:

jinja2

The above code implements a simple dynamic. I can completely query the data from the database, then replace the corresponding content in my HTML, and then send it to the browser to complete the rendering. This process is equivalent to the HTML template rendering data. In essence, it is the use of some special features in HTML contentDifferent symbols are used to replace the data to be displayed. The special symbol I use here is what I define. Actually, there is a ready tool for template rendering.jinja2

The principle of a template is string substitution. As long as we follow the syntax rules of the jinja2 in the HTML page, the inside will be replaced in accordance with the specified syntax to achieve the dynamic return.