web框架学习
HTTP协议(超文本协议)
四大特性
基于TCP/IP之上作用于应用层
基于请求响应
发是请求,给是响应
无状态
不保存用户状态,连一次就给忘了
无连接
eg:one night love
数据格式
请求格式
请求首行(请求方式,协议版本等)
请求头(一大堆K:V键值对)
\\r\\n
请求头(真正的数据 发post请求的时候才有 如果get请求不会有)
响应格式
响应首行
响应头
\\r\\n
响应体
响应状态码
用特定的数字表示一些数据
1xx:服务端已经接收到了你的数据 正在处理 你可以提交其他数据
2xx:服务端成功响应(200请求成功)
3xx:重定向
4xx:请求错误(404 请求资源不存在 403 拒绝访问)
5xx:(服务器内部错误(500))
请求方式
get请求
朝别人要数据
post请求
向别人提交数据(eg:用户登录)
纯手撸web框架
- 手动书写socket
- 手动处理http格式数据
简单c/s连接
#服务端
import socket
server = socket.socket()
server.bind((\'127.0.0.1\', 8081))
server.listen(5)
while True:
conn,addr = server.accept()
data = conn.recv(1024)
conn.send(b\'HTTP/1.1 200 OK\\r\\n\\r\\n\')
print(data)
conn.send(b\'hello baby\')
conn.close()
稍微复杂web框架
客户端请求什么,就返回什么,eg:客户端发送http://127.0.0.1:8081/index
则服务器返回给客户端index
import socket
server = socket.socket()
server.bind((\'127.0.0.1\', 8081))
server.listen(5)
while True:
conn,addr = server.accept()
conn.send(b\'HTTP/1.1 200 OK\\r\\n\\r\\n\')
data = conn.recv(1024)
print(data)
data = data.decode(\'utf8\')
current_path = data.split(\'\\r\\n\')[0].split(\' \')[1]
print(current_path)
if current_path == \'/index\':
conn.send(b\'index\')
#服务端还可以打开html文件,将文件中的东西显示给客户端
# with open(r\'index.html\', \'rb\') as f:
# conn.send(f.read())
else:
conn.send(b\'404 error\')
conn.close()
基于wsgiref
如果我不想写上面代码中的socket连接和里面的index等内容,客户端发送100个不同的请求,我也不能手撸100遍啊!那也太累了吧,所以我们就利用了wsgiref模块,帮我们操作起来更简单和方便,我们可以把在wsgiref.py中的必要代码写在相对应的文件内,以下是各个文件中要放的东西。
urls.py 路由与视图函数对象关系
views.py 放的是视图函数(处理业务逻辑的)
templates 模板文件夹(一堆html文件)
wsgiref.py文件
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return:
"""
response(\'200 OK\',[])
current_path = env.get(\'PATH_INFO\') #env里面有 很多数据,我们筛选有用的数据就行
# 先定义一个变量名 用来存储后续匹配到的函数名
func = None
# for循环 匹配后缀
for url in urls:
if current_path == url[0]:
func = url[1] # 一旦匹配成功 就将匹配到的函数名赋值给func变量
break # 主动结束匹配
# 判断func是否有值
if func:
res = func(env)
else:
res = error(env)
return [res.encode(\'utf-8\')]
if __name__ == \'__main__\':
server = make_server(\'127.0.0.1\',8080,run)
# 实时监听该地址 只要有客户端来连接 统一交给run函数去处理
server.serve_forever() # 启动服务端,永远等着客户端来连接
urls.py
from views import *
urls = [
(\'/index\',index), #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
(\'/login\',login),
(\'/xxx\',xxx),
]
views.py
from urls import urls
def index(env):
return \'index\'
def login(env):
return \'login\'
def error(env):
return \'404 error\'
def xxx(env):
return \'xxx\'
客户端通过访问服务器获取字典
我们这里需要用到一个模块jinja2
我们需要先去下载这个模块from jinja2 import Template
具体了解jinja2
请点击链接https://www.cnblogs.com/yanjiayi098-001/p/11701150.html
wsgiref.py文件
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return:
"""
response(\'200 OK\',[])
current_path = env.get(\'PATH_INFO\') #env里面有 很多数据,我们筛选有用的数据就行
# 先定义一个变量名 用来存储后续匹配到的函数名
func = None
# for循环 匹配后缀
for url in urls:
if current_path == url[0]:
func = url[1] # 一旦匹配成功 就将匹配到的函数名赋值给func变量
break # 主动结束匹配
# 判断func是否有值
if func:
res = func(env)
else:
res = error(env)
return [res.encode(\'utf-8\')]
if __name__ == \'__main__\':
server = make_server(\'127.0.0.1\',8080,run)
# 实时监听该地址 只要有客户端来连接 统一交给run函数去处理
server.serve_forever() # 启动服务端,永远等着客户端来连接
urls.py
urls = [
(\'/get_user\',get_user), #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
]
views.py
def get_user(env):
d = {\'name\':\'jason\',\'pwd\':\'123\',\'hobby\':[\'read\',\'running\',\'music\']}
with open(r\'get_user.html\',\'r\',encoding=\'utf-8\') as f:
data = f.read()
temp = Template(data) #将data数据传给这个temp,做处理
res = temp.render(user=d) # 将字典d传递给前端页面 页面上通过变量名user就能够获取到该字典
return res
get_user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
#jinja2模块,可以对字典 进行以下取值,同时这是jinja变量取值 {{ }}的语法
<p>{{ user }}</p>
<p>{{ user.name }}</p>
<p>{{ user[\'pwd\'] }}</p>
<p>{{ user.get(\'hobby\') }}</p>
</body>
</html>
动静态页面
静态页面:就是一个写死的页面
动态页面:可以通过更改后端的数据,来反应到浏览器的页面上
eg:1.后端获取当前时间展示到前端
2.后端获取数据库中的数据展示到前端
客户端通过访问服务器获取当前时间
那么如果用户访问服务端,则客户端页面就会显示当前时间,这样该怎么做呢?
我们要知道,页面就是要用到html,如果时间写在HTML,那么通过编码格式,他已经不再是时间了,那么怎样将时间显示在页面呢?
做法:我们要在wsgiref模块的基础上,先在html中写一串特定的字符,在后端将这串html和获取的时间作交换,具体看代码
wsgiref.py文件
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return:
"""
response(\'200 OK\',[])
current_path = env.get(\'PATH_INFO\') #env里面有 很多数据,我们筛选有用的数据就行
# 先定义一个变量名 用来存储后续匹配到的函数名
func = None
# for循环 匹配后缀
for url in urls:
if current_path == url[0]:
func = url[1] # 一旦匹配成功 就将匹配到的函数名赋值给func变量
break # 主动结束匹配
# 判断func是否有值
if func:
res = func(env)
else:
res = error(env)
return [res.encode(\'utf-8\')]
if __name__ == \'__main__\':
server = make_server(\'127.0.0.1\',8080,run)
# 实时监听该地址 只要有客户端来连接 统一交给run函数去处理
server.serve_forever() # 启动服务端,永远等着客户端来连接
urls.py
from views import *
urls = [
(\'/get_time\',get_time), #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
]
views.py
from urls import *
from datetime import datetime
def get_time():
current_time = datetime.now().strftime(\'%Y-%m-%d %X\')
with open(r\'get_time.html\',\'r\',encoding=\'utf-8\') as f: #这是一串字符串
data= f.read()
data = data.replace(\'$$time$$\',current_time)
return data
get_time.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
$$time$$
</body>
</html>
客户端通过访问服务器获取数据库数据
获取数据库数据现在就和获取字典的方法差不多像了,只不过我们需要建一个数据库,通过链接数据库,去数据库里面拿值
wsgiref.py文件
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
:param env: 请求相关的所有数据
:param response: 响应相关的所有数据
:return:
"""
response(\'200 OK\',[])
current_path = env.get(\'PATH_INFO\') #env里面有 很多数据,我们筛选有用的数据就行
# 先定义一个变量名 用来存储后续匹配到的函数名
func = None
# for循环 匹配后缀
for url in urls:
if current_path == url[0]:
func = url[1] # 一旦匹配成功 就将匹配到的函数名赋值给func变量
break # 主动结束匹配
# 判断func是否有值
if func:
res = func(env)
else:
res = error(env)
return [res.encode(\'utf-8\')]
if __name__ == \'__main__\':
server = make_server(\'127.0.0.1\',8080,run)
# 实时监听该地址 只要有客户端来连接 统一交给run函数去处理
server.serve_forever() # 启动服务端,永远等着客户端来连接
urls.py
urls = [
(\'/get_db\',get_db), #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
]
views.py
import pymysql
def get_db(env):
conn = pymysql.connect(
host = \'127.0.0.1\',
port = 3306,
user = \'root\',
password = \'root\',
database = \'day56\',
charset = \'utf8\',
autocommit = True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = "select * from userinfo"
cursor.execute(sql) #提交sql语句,这个出发的是执行的对象并不是一个值
res = cursor.fetchall()
print(res)
with open(r\'get_db.html\',\'r\',encoding=\'utf-8\') as f:
data = f.read()
temp = Template(data)
ret = temp.render(user_list = res) # 将字典d传递给前端页面 页面上通过变量名user就能够获取到该字典
return ret
get_db.html
我们这里用到了bootstrap搭建页面,这就是一个典型的动态页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">用户列表</h1>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>pwd</th>
</tr>
</thead>
<tbody>
{% for user_dict in user_list %}
<tr>
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.name }}</td>
<td>{{ user_dict.pwd }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
python三大主流web框架
A:socket部分
B:路由与视图函数对应关系
C:模板语法
Django | Flask | Tornado |
---|---|---|
大而全 自带的功能特别多 类似于航空母舰 有时候过于笨重 | 小而精 自带的功能特别少 类似于游骑兵第三方的模块特别多,如果将flask第三方模块全部加起来 完全可以超过django比较依赖于第三方模块 | 异步非阻塞 牛逼到可以开发游戏服务器 |
A用的别人的 wsgiref B自己写的 C自己写的 | A用的别人的 werkzeug(基于wsgiref) B自己写的 C用的别人的 jinja2 | 三者全是自己写的 |