1-Django之web框架的本质
前言
由上一篇HTTP协议,我们简单的知道HTTP那点事儿。但是我们的目的是在此基础上编写web程序。所以,接下来通过一个个示例了解,web框架的本质——通俗的说,web框架封装了socket、数据库操作、路由分发、模板配置等,留给我们现成的接口,让我们更专注业务逻辑本身。
一个简单的web示例
import socket
# 1. 创建socket对象
sk = socket.socket()
# 2. 绑定IP和端口
sk.bind(('127.0.0.1', 8888))
# 3. 监听
sk.listen(5)
# 4. 循环监听
while 1:
conn, addr = sk.accept() # 等待连接
received_data = conn.recv(8192) # 接收数据
print(received_data) # b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8888\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/73.0.3683.103 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\nCookie: csrftoken=FQW7H4SEVPRqdqIr4vSeiP3EdjX2C0JY7VwCdmXevoXcPjiAMBtNptkiZLHqXo4d\r\n\r\n'
conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 接收数据
conn.send(b'<h1>Successful</h1>')
conn.close() # 关闭连接
现在,使用浏览器地址栏访问http://127.0.0.1:8888/
,就会得到Successful
。
根据不同路径返回不同内容
第一版·普通版
import socket
# 创建socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))
# 监听
sk.listen()
while True:
# 等待连接
conn, addr = sk.accept()
# 接收数据
data = conn.recv(8192)
data = data.decode('utf-8')
url = data.split()[1]
print(url)
# 返回状态行
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
if url == '/oumei':
conn.send(b'<h1>oumei</h1>')
elif url == '/rihan':
conn.send(b'<h1>rihan</h1>')
else:
conn.send(b'<h1>404</h1>')
# 关闭连接
conn.close()
第二版·函数版
import socket
# 创建socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))
# 监听
sk.listen()
def oumei(url):
ret = 'oumei - {}'.format(url)
return ret.encode('utf-8')
def rihan(url):
ret = 'rihan//// - {}'.format(url)
return ret.encode('utf-8')
while True:
# 等待连接
conn, addr = sk.accept()
# 接收数据
data = conn.recv(8192)
data = data.decode('utf-8')
url = data.split()[1]
print(url)
# 返回状态行
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
if url == '/oumei':
ret = oumei(url)
elif url == '/rihan':
ret = rihan(url)
else:
ret = b'404 not found'
conn.send(ret)
# 关闭连接
conn.close()
第三版·函数进阶版
import socket
# 创建socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))
# 监听
sk.listen()
def oumei(url):
ret = 'oumei - {}'.format(url)
return ret.encode('utf-8')
def rihan(url):
ret = 'rihan//// - {}'.format(url)
return ret.encode('utf-8')
def guochan(url):
ret = 'guochan - {}'.format(url)
return ret.encode('utf-8')
list = [
('/oumei', oumei),
('/rihan', rihan),
('/guochan', guochan),
]
while True:
# 等待连接
conn, addr = sk.accept()
# 接收数据
data = conn.recv(8192)
data = data.decode('utf-8')
url = data.split()[1]
print(url)
# 返回状态行
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
func = None
for i in list:
if i[0] == url:
func = i[1]
break
if func:
ret = func(url)
else:
ret = b'404 not found'
conn.send(ret)
# 关闭连接
conn.close()
第四版·反射版
ps:仅针对当前脚本使用的反射。
import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8888))
sk.listen()
class Server(object):
""" 模拟多个页面 """
def europe(self):
return "<h1>europe</h1>".encode('utf8')
def kkc(self):
return "<h1>kkc</h1>".encode('utf8')
def notfond(self):
return "<h1>404 not fond</h1>".encode('utf8')
while 1:
# 等待请求
conn, address = sk.accept()
# 获取数据
data = conn.recv(8192).decode('utf8')
# 处理请求拿到请求路径
# print(data)
url = data.split(' ', 2)[1][1:]
# print(url, data)
# 返回数据
server_obj = Server()
if hasattr(server_obj, url):
res = getattr(server_obj, url)()
else:
res = server_obj.notfond()
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
conn.send(res)
conn.close()
返回HTML页面
首先在同级目录有个index.html
页面:
<!DOCTYPE html>
<html lang="en">
<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>index page</h1>
</body>
</html>
然后写server
端:
import socket
# 创建socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))
# 监听
sk.listen()
def oumei(url):
ret = 'oumei - {}'.format(url)
return ret.encode('utf-8')
def rihan(url):
ret = 'rihan//// - {}'.format(url)
return ret.encode('utf-8')
def guochan(url):
ret = 'guochan - {}'.format(url)
return ret.encode('utf-8')
def index(url):
with open('index.html', 'rb') as f:
ret = f.read()
return ret
list = [
('/oumei', oumei),
('/rihan', rihan),
('/guochan', guochan),
('/index', index),
]
while True:
# 等待连接
conn, addr = sk.accept()
# 接收数据
data = conn.recv(8192)
data = data.decode('utf-8')
url = data.split()[1]
print(url)
# 返回状态行
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
func = None
for i in list:
if i[0] == url:
func = i[1]
break
if func:
ret = func(url)
else:
ret = b'404 not found'
conn.send(ret)
# 关闭连接
conn.close()
返回动态页面
在同级目录有个tiem.html
页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>当前时间是: @@time@@ </h1>
</body>
</html>
在来实现代码:
import socket
import time
# 创建socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(('0.0.0.0', 8000))
# 监听
sk.listen()
def oumei(url):
ret = 'oumei - {}'.format(url)
return ret.encode('utf-8')
def rihan(url):
ret = 'rihan//// - {}'.format(url)
return ret.encode('utf-8')
def guochan(url):
ret = 'guochan - {}'.format(url)
return ret.encode('utf-8')
def index(url):
with open('index.html', 'rb') as f:
ret = f.read()
return ret
def timer(url):
now = time.strftime('%Y-%m-%d %H:%M:%S')
with open('time.html', 'r', encoding='utf-8') as f:
data = f.read()
data = data.replace('@@time@@', now)
return data.encode('utf-8')
list = [
('/oumei', oumei),
('/rihan', rihan),
('/guochan', guochan),
('/index', index),
('/time', timer),
]
while True:
# 等待连接
conn, addr = sk.accept()
# 接收数据
data = conn.recv(8096)
data = data.decode('utf-8')
url = data.split()[1]
print(url)
# 返回状态行
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
func = None
for i in list:
if i[0] == url:
func = i[1]
break
if func:
ret = func(url)
else:
ret = b'404 not found'
conn.send(ret)
# 关闭连接
conn.close()
总结
正如文章开始所示,web框架本质就是一个socket服务端。
web框架功能:
- socket收发消息
- 根据不同的路径返回不同的内容
- 可以返回动态页面(使用字符串替换等方式进行模板渲染)
Python中主流web框架:
欢迎斧正,that's all see also:[简说Python Web异步框架](https://www.yuanrenxue.com/tricks/introduce-python-asynchronous-framework.html)