1.简介
web框架的本质:socket服务端与浏览器的通信
socket服务端功能划分:
1.负责与浏览器收发消息(socket通信) --》wsgiref/uWsgi/gunicorn等web服务网关接口和服务器
2.根据用户访问不同的路径执行不同的函数 --》路由系统(url与函数的对应关系)
3.从HTML读取出内容并且完成字符串的替换 --》jinja2(模板语言)
2.静态网站


"""
这是一个静态的web网站,返回什么数据类型就是什么,而现在网站都是动态的。
"""
import socket
def f1(request):
"""
处理用户请求,并返回相应的内容
:param request: 用户请求的所有信息
:return:
"""
# 读取本地二进制文件并返回(在这里是自己写模板,可以任意后缀名文件并不一定需要html后缀)
f = open(\'index.fsw\',\'rb\')
data = f.read()
f.close()
return data
def f2(request):
f = open(\'aricle.tpl\',\'rb\')
data = f.read()
f.close()
return data
# 路由与函数的对应关系(路由系统)
routers = [
(\'/xxx\', f1),
(\'/ooo\', f2),
]
def run():
# 获取socket对象
sock = socket.socket()
# 绑定ip地址和端口
sock.bind((\'127.0.0.1\',8080))
# 开始监听(设置最大监听数5个)
sock.listen(5)
while True:
conn,addr = sock.accept() # 夯住,等待用户连接
# 获取用户发送的数据
data = conn.recv(8096)
# 直接转换为字符串
data = str(data,encoding=\'utf-8\')
print(data)
# 根据http协议划分请求头和请求体\r\n\r\n
headers,bodys = data.split(\'\r\n\r\n\')
# 根据已有的http协议数据结构切分元素
temp_list = headers.split(\'\r\n\')
# 分别获取请求方法、请求url地址、请求协议类型
method,url,protocal = temp_list[0].split(\' \')
conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
func_name = None # 设置标志位
for item in routers:
# 遍历url与函数对应关系表,并判断当前请求url是否相等
if item[0] == url:
# 能对应就获取函数名并停止循环
func_name = item[1]
break
if func_name:
# 有这个函数就加括号调用并传入参数
response = func_name(data)
else:
response = b"404"
# 返回函数处理后的结果
conn.send(response)
conn.close()
if __name__ == \'__main__\':
run()
View Code


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<th>root</th>
<th>root@qq.com</th>
</tr>
</tbody>
</table>
</body>
</html>
View Code


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>用户登录</h1>
<form>
<p><input type="text" placeholder="用户名" /></p>
<p><input type="password" placeholder="密码" /></p>
</form>
</body>
</html>
View Code
3.动态网站


"""动态网站则是在静态网站的基础之上,进行字符串的替换,以完成网站页面的实时更新效果"""
import socket
def f1(request):
"""
处理用户请求,并返回相应的内容
:param request: 用户请求的所有信息
:return:
"""
f = open(\'index.fsw\',\'rb\')
data = f.read()
f.close()
return data
def f2(request):
"""
运用时间戳的方式,初步实现动态网站
:param request:
:return:
"""
f = open(\'aricle.tpl\',\'r\',encoding=\'utf-8\')
data = f.read()
f.close()
import time
# 获取时间戳
ctime = time.time()
# 调用字符串的replace()替换方法换成时间戳,页面每次刷新显示的数据都不一样
data = data.replace(\'@@sw@@\',str(ctime))
# 返回bytes()类型数据
return bytes(data,encoding=\'utf-8\')
def f3(request):
"""
获取数据库数据,只要数据库数据有更新,则页面刷新之后都会显示
:param request: 用户请求的信息
:return:
"""
import pymysql
# 创建连接对象
conn = pymysql.connect(host=\'127.0.0.1\', port=3306, user=\'root\', passwd=\'yang123\', db=\'yangyu\')
# 获取游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 执行sql语句查询数据库数据
cursor.execute("select id,username,password from userinfo")
# 获取表中所有数据
user_list = cursor.fetchall()
# 关闭游标对象
cursor.close()
# 关闭连接对象
conn.close()
content_list = []
for row in user_list:
# 遍历数据库查询的数据,拼接字符串
tp = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" %(row[\'id\'],row[\'username\'],row[\'password\'])
# 把拼接的字符串添加到列表
content_list.append(tp)
# 调用.join方法把列表转换为字符串
content = "".join(content_list)
f = open(\'userlist.html\',\'r\',encoding=\'utf-8\')
template = f.read()
f.close()
# 模板渲染(模板+数据)完成字符串的替换
data = template.replace(\'@@sdfsdffd@@\',content)
return bytes(data,encoding=\'utf-8\')
def f4(request):
"""
调用第三方模块,实现页面模板的渲染
:param request:
:return:
"""
import pymysql
# 创建连接对象
conn = pymysql.connect(host=\'127.0.0.1\', port=3306, user=\'root\', passwd=\'yang123\', db=\'yangyu\')
# 获取游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 执行sql语句查询数据库数据
cursor.execute("select id,username,password from userinfo")
# 获取表中所有数据
user_list = cursor.fetchall()
# 关闭游标对象
cursor.close()
# 关闭连接对象
conn.close()
f = open(\'hostlist.html\',\'r\',encoding=\'utf-8\')
data = f.read()
f.close()
# 基于第三方工具实现的模板渲染
from jinja2 import Template
template = Template(data)
# 调用render()方法完成字符串的替换,这里要注意,前后端特殊语法要相同
data = template.render(user_list=user_list,user=\'sdfsdfsdf\')
return data.encode(\'utf-8\')
# 路由与函数的对应关系
routers = [
(\'/xxx\', f1),
(\'/ooo\', f2),
(\'/userlist.htm\', f3),
(\'/host.html\', f4),
]
def run():
# 获取socket对象
sock = socket.socket()
# 绑定ip地址和端口
sock.bind((\'127.0.0.1\',8080))
# 开始监听(设置最大监听数5个)
sock.listen(5)
while True:
conn,addr = sock.accept() # 夯住,等待用户连接
# 获取用户发送的数据
data = conn.recv(8096)
# 直接转换为字符串
data = str(data,encoding=\'utf-8\')
# 根据http协议划分请求头和请求体\r\n\r\n
headers,bodys = data.split(\'\r\n\r\n\')
# 根据已有的http协议数据结构切分元素
temp_list = headers.split(\'\r\n\')
# 分别获取请求方法、请求url地址、请求协议类型
method,url,protocal = temp_list[0].split(\' \')
conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
func_name = None # 设置标志位
for item in routers:
# 遍历url与函数对应关系表,并判断当前请求url是否相等
if item[0] == url:
# 能对应就获取函数名并停止循环
func_name = item[1]
break
if func_name:
# 有这个函数就加括号调用并传入参数
response = func_name(data)
else:
response = b"404"
# 返回函数处理后的结果
conn.send(response)
conn.close()
if __name__ == \'__main__\':
run()
View Code


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<!-- 自定义字符串替换的特殊语法 -->
<th>@@sw@@</th>
<th>root@qq.com</th>
</tr>
</tbody>
</table>
</body>
</html>
View Code


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
{% for row in user_list %}
<!--使用第三方模板,就要遵循他的语法规则-->
<tr>
<td>{{row.id}}</td>
<td>{{row.username}}</td>
<td>{{row.password}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{user}}
</body>
</html>
View Code


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>用户登录</h1>
<form>
<p><input type="text" placeholder="用户名" /></p>
<p><input type="password" placeholder="密码" /></p>
</form>
</body>
</html>
View Code


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<!--自定义模板特殊语法-->
@@sdfsdffd@@
</tbody>
</table>
</body>
</html>
View Code
4.总结
有以上我们模拟网站(socket服务端)和浏览器(socket客户端)的知识知道了:
1.http是建立在tcp之上的,无状态的,短链接,一次请求一次响应。 而TCP是不断开的长连接。
2.http协议是固定的键值对组合,每个键值对之间由\r\n分割,请求头和请求体之间则是由两个\r\n\r\n分割。而响应头和响应体也是这样的组合。
3.自己写的网站必须具备以下要素:
a.socket服务端
b.根据url的不同,返回不同的内容(url与函数的对应关系)
c.返回字符串给用户(模板引擎渲染:HTML充当模板和特殊字符,自己定义任意数据)
而web框架的种类也是根据以上三点相结合:
框架自带a,b,c Tornado
[第三方a],b,c wsgiref服务网关接口、Django
[第三方a],b,[第三方c] wsgiref服务网关接口、Flask、jinja2模板
按照另一种维度划分:
重量级:Django
轻量级:Tornado、Flask