Contents
- WebEssence of frame
- Custom web framework for semi-finished products
- HTTP GETThe format of the request:
- HTTPThe format of the response:
- A maiden version of the custom web framework
- Return different contents according to different paths
- Returning different contents according to different paths — function version
- Returning different contents according to different paths — function advanced edition
- Return to a specific HTML file
- Make web pages dynamic
- Server programs and Applications
- Django
- DjangoBasic three pieces of basic set:
- What is the redirection?
- Start Django report wrong:
WebEssence of frame
We can understand this: all Web applications are essentially a socket server, and the user’s browser is a socket client. In this way, we can implement the Web framework ourselves.
Custom web framework for semi-finished products
import socket sk = socket.socket() sk.bind(("127.0.0.1", 80)) sk.listen() while True: conn, addr = sk.accept() data = conn.recv(8096) conn.send(b"OK") conn.close()
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?
Let’s first print out what messages we receive on the server side.
import socket sk = socket.socket() sk.bind(("127.0.0.1", 80)) sk.listen() while True: conn, addr = sk.accept() data = conn.recv(8096) print(data) # Print out the message sent by the browserConn.send (b"OK") conn.close()
Output:
b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nDNT: 1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=RKBXh1d3M97iz03Rpbojx1bR6mhHudhyX5PszUxxG3bOEwh1lxFpGOgWN93ZH3zv\r\n\r\n'
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-Type
The content format of the response. astext/html
Represent 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.
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('127.0.0.1', 8000)) sock.listen() while True: conn, addr = sock.accept() data = conn.recv(8096) # The message to the reply is added to the response state line conn.send(b"HTTP/1.1 200 OK\r\n\r\n") conn.send(b"OK") conn.close()
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() # Monitor 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 if 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 functions def 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 functions def 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] break if 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 functions def index(url): # Read the content of the index.html page with open("index.html", "r", encoding="utf8") as f: s = f.read() # Return byte 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] break if 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 functions def 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] break if 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:
""" According to different paths in URL, return different contents -- advanced version of function.Return to the HTML pageMake web pages dynamicWsgiref module version""" import time from wsgiref.simple_server import make_server # It will be returned to different parts of the content to be encapsulated into functions def index(url): with open("index.html", "r", encoding="utf8") as f: s = f.read() now = str(time.time()) s = s.replace("@@oo@@", now) 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), ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # Setting the state code and header information of the HTTP response url = environ['PATH_INFO'] # Take the URL of the user input func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8090, run_server) print("I'm waiting for you at 8090.") httpd.serve_forever()
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
Download jinja2:
pip install jinja2

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h1>Name: {{name}}</h1> <h1>Hobbies:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
index2.htmlfile
Use jinja2 to render the index2.html file:
from wsgiref.simple_server import make_server from jinja2 import Template def index(): with open("index2.html", "r") as f: data = f.read() template = Template(data) # Generate template files ret = template.render({"name": "Alex", "hobby_list": ["Perm", "Bubble bar"]}) # Fill the data into the template return [bytes(ret, encoding="utf8"), ] def home(): with open("home.html", "rb") as f: data = f.read() return [data, ] # Defining the correspondence of a URL and a function URL_LIST = [ ("/index/", index), ("/home/", home), ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # Setting the state code and header information of the HTTP response url = environ['PATH_INFO'] # Take the URL of the user input func = None # The function to be executed for i in URL_LIST: if i[0] == url: func = i[1] # Go to the previously defined URL list to find the function that URL should perform. break if func: # If you can find a function to execute return func() # Return the execution result of a function else: return [bytes("404No page", encoding="utf8"), ] if __name__ == '__main__': httpd = make_server('', 8000, run_server) print("Serving HTTP on port 8000...") httpd.serve_forever()
Now the data is written by ourselves. Can we query the data from the database to fill the pages?
Using pymysql to connect to the database:
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8") cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select name, age, department_id from userinfo") user_list = cursor.fetchall() cursor.close() conn.close()
Create a test user table:
CREATE TABLE user( id int auto_increment PRIMARY KEY, name CHAR(10) NOT NULL, hobby CHAR(20) NOT NULL )engine=innodb DEFAULT charset=UTF8;
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.
Django
DjangoOfficial website downloading page
Install (install the latest LTS version):
pip3 install django==1.11.9
Create a Django project:
The following command creates a Django project named “MySite”:
django-admin startproject mysite
Directory introduction:
mysite/ ├── manage.py # Management documentsMySite__init__.pySettings.py configurationUrls.py routing--> URLThe corresponding relation with the functionWsgi.py runserver command uses wsgiref module to make simple web server.
Run the Django project:
python manage.py runserver 127.0.0.1:8000
Template file configuration:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, "template")], # templateFolder location 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
Static file configuration:
STATIC_URL = '/static/' # HTMLStatic folder prefix used in STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), # Static file storage location ]
Can’t you see it? There is a picture of the truth:
At the beginning of learning, you can temporarily disable the CSRF Middleware in the configuration file to facilitate the form submit test.
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
DjangoBasic three pieces of basic set:
from django.shortcuts import HttpResponse, render, redirect
HttpResponse
A string parameter inside the incoming is returned to the browser.
For example:
def index(request): # Business logic code return HttpResponse("OK")
render
In addition to the request parameter, a template file to be rendered and a dictionary parameter for preserving specific data are also accepted.
Fill the data into the template file, and finally return the result to the browser. (similar to the jinja2 we use above)
For example:
def index(request): # Business logic code return render(request, "index.html", {"name": "alex", "hobby": ["Perm", "Bubble bar"]})
redirect
A URL parameter is accepted to indicate the jump to the specified URL.
For example:
def index(request): # Business logic code return redirect("/home/")
What is the redirection?
Practice:
DjangoVersion login
Start Django report wrong:
Django Start the times wrong UnicodeEncodeError…
It’s usually because of this mistake.Computer nameFor Chinese, change the name of the computer to restart the computer.