自创Web框架之过渡Django框架
自创Web框架之过渡Django框架
Web框架,其实就是web应用的建立;比如网页版的QQ、b站等等
web应用又是什么呢?可以理解为基于游览器的一些应用程序,用户只需要有游览器即可,不需要再安装其他软件;
比如你打开一个url,web服务器返回一个html页面,那么你在搜索或者url拼接路径搜索的时候web服务器是怎么知道要返回什么给你呢?下面介绍一下:
- 软件开发架构
C/S架构:客户端与服务端
B/S架构:游览器与服务端
ps:b/s本质就是c/s架构 - http协议
四大特性
基于TCP、IP作用于应用层之上的协议
基于请求响应
无状态
无连接(短连接)>>>长连接:websocket
数据格式
请求首行(http协议版本,网络请求的方法) 请求头(一大堆的kv键值对) /r/n # 换行符不能省略 请求体(存放的是一些数据,并不是每种请求方式都有请求体,get没有请求体,post有请求体) # 请求方式 get:朝服务器索要数据,比如输入网址获得相应的数据 post:朝服务器提交数据,刺入用户登录输入用户名和密码后,提交到后端做身份效验

相应格式
响应首行(http协议版本,网络请求的方法) 响应头(一大堆k,v键值对) /r/n # 换行符不能省略 响应体(交给给浏览器展示给用户看的数据)

响应状态码
http状态码由三个十进制数组成,第一个十进制数定义了状态码的类型,响应分为五种:信息响应(100-199),成功响应(200-299),重定向响应(300-399),客户端错误(400-499)和服务端错误(500-599)
ps: 公司还会定义状态码,一般是以10000开头的
请求方式
get请求: 向别人(服务器)索要数据
post请求: 向别人提交数据(比如表单)
“撸起袖Web框架之“撸起袖子加油干”
为了方便理解请求网页并且返回数据的过程,写下一套下面的程序帮助理解
import socket
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,addr = server.accept()
data = conn.recv(1024)
data = data.decode('utf-8')
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
current_path = data.split(' ')[1]
if current_path == '/index':
with open(r'01.html','rb') as f:
conn.send(f.read())
elif current_path == '/login':
conn.send(b'hello')
else:
conn.send(b'nothing')
conn.close()
通过上述例子,能够简单的理解通过get请求方式得到的页面是如何返回,但是我们个人手写服务端存在很多的问题,如果客户请求不同页面那么我们就待写很多的if/else,数据处理起来也比较繁琐...通过一个模块久能解决这些问题
过wsgWeb框架之通过wsgiref加油干
# wsgiref模块解决上述两个问题
from wsgiref.simple_server import make_server
def run(request, response):
'''
:param request:请求相关的所有数据
:param response: 响应相关的所有数据
:return: 返回游览器的数据
'''
response('200 OK',[])
current_path = request.get('PATH_INFO')
if current_path == '/index':
return [b'index']
elif current_path == '/login':
return [b'login']
else:
return [b'404 error']
if __name__ == '__main__':
server = make_server('127.0.0.1',8000,run)
server.serve_forever() # 启动服务端
优化封装优化处理
'''
封装的过程主要解决:
网址的匹配问题
网址多匹配如何解决
功能复杂代码如何解决,放在一个结构不清晰
'''
'''服务端'''
from wsgiref.simple_server import make_server
from views import *
from urls import *
'''
urls.py 路由与视图函数的对应关系
views.py主要存视图函数
templates文件夹主要存放HTML文件
拆分功能只需要在urls.py中书写对应关系,views.py中书写后端业务逻辑即可
'''
def run(env,response):
'''
:param env:请求相关的所有数据
:param response: 相应相关的所有数据
:return: 返回给游览器的数据
'''
response('200 ok',[])
# 从env返回的大字典中拿出用户输入内容--->key
current_path = env.get('PATH_INFO')
# if current_path == '...':
# ...
# ...
func = None
for url in urls:
if current_path == url[0]:
# 匹配成功,将url对应的函数名,赋值给func
func = url[1]
break
if func:
res = func()
else:
res = error()
return [res.encode('utf-8')]
if __name__ == '__main__':
server = make_server('127.0.0.1',8005,run)
server.serve_forever()
'''
urls.py 路由与视图函数的对应关系
'''
from views import *
urls = [
('/index',index),
('/login',login)
]
'''
views.py主要存视图函数
下面统称为函数
'''
def index():
return 'index'
def login():
return 'login'
def error():
return '404 error'
动静网页
- 静态网页: 数据不变的,不需要实时变化的,数据写死的
- 动态网页: 数据来源与后端代码(代码、数据库),数据实时变化等特点
示例:将时间同步到html页面上
'''服务端'''
from wsgiref.simple_server import make_server
from urls import *
'''
urls.py 路由与视图函数的对应关系
views.py主要存视图函数
templates文件夹主要存放HTML文件
拆分功能只需要在urls.py中书写对应关系,views.py中书写后端业务逻辑即可
'''
def run(env,response):
'''
:param env:请求相关的所有数据
:param response: 相应相关的所有数据
:return: 返回给游览器的数据
'''
response('200 ok',[])
# 从env返回的大字典中拿出用户输入内容--->key
current_path = env.get('PATH_INFO')
# if current_path == '...':
# ...
# ...
func = None
for url in urls:
if current_path == url[0]:
# 匹配成功,将url对应的函数名,赋值给func
func = url[1]
break
if func:
res = func()
else:
res = error()
return [res.encode('utf-8')]
if __name__ == '__main__':
server = make_server('127.0.0.1',8001,run)
server.serve_forever()
'''
urls.py 路由与视图函数的对应关系
'''
from views import *
urls = [
('/index',index),
('/login',login),
('/get_time',get_time)
]
'''
views.py主要存视图函数
下面统称为函数
'''
def index():
return 'index'
def login():
return 'login'
def error():
return '404 error'
def get_time():
from datetime import datetime
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('AAA',current_time)
return data
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<style>
#d1{
font-size: 48px;
color: rebeccapurple;
}
</style>
<body>
<div class="select2-container">
<div class="add-row">
<div id="d1" class="col-md-8 col-lg-offset-2">
AAA
</div>
</div>
</div>
</body>
</html>
jinjia2模块
该模块是flask框架必备的模块,这里只使用jinjia2模块来写模板语法
需求: 将后端字典展示在HTML页面上
数据库
需求: 操作MySQL数据并且展示到html页面上
注意: 数据是在后端处理完之后发送到前端的
'''服务端'''
from wsgiref.simple_server import make_server
from urls import *
'''
urls.py 路由与视图函数的对应关系
views.py主要存视图函数
templates文件夹主要存放HTML文件
拆分功能只需要在urls.py中书写对应关系,views.py中书写后端业务逻辑即可
'''
def run(env,response):
'''
:param env:请求相关的所有数据
:param response: 相应相关的所有数据
:return: 返回给游览器的数据
'''
response('200 ok',[])
# 从env返回的大字典中拿出用户输入内容--->key
current_path = env.get('PATH_INFO')
# if current_path == '...':
# ...
# ...
func = None
for url in urls:
if current_path == url[0]:
# 匹配成功,将url对应的函数名,赋值给func
func = url[1]
break
if func:
res = func(env)
else:
res = error(env)
return [res.encode('utf-8')]
if __name__ == '__main__':
server = make_server('127.0.0.1',8001,run)
server.serve_forever()
'''
urls.py 路由与视图函数的对应关系
'''
from views import *
urls = [
('/index',index),
('/login',login),
('/get_time',get_time),
('/get_dict',get_dict),
('/get_db',get_db)
]
def get_db(env):
import pymysql
from jinja2 import Template
conn = pymysql.connect(
user='root',
password='123456',
port=3306,
host='127.0.0.1',
database='info',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from emp;'
rows = cursor.execute(sql)
res = cursor.fetchall()
print(res) # [{'id': 1, 'username': 'alan', 'password': '123'}, {'id': 2, 'username': 'alearn', 'password': '456'}]
with open(r'get_db.html','r',encoding='utf8') as f3:
data = f3.read()
temp = Template(data)
total_res = temp.render(data_list=res)
return total_res
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<h1 style="text-align: center">用户数据</h1>
<div class="col-md-8 col-lg-offset-2">
<table class="table table-striped table-hover">
<thead>
<tr class="success" style="text-align: center">
<td>id</td>
<td>username</td>
<td>password</td>
</tr>
</thead>
<tbody>
{%for user_dict in data_list%}
<tr class="info" style="text-align: center">
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.username }}</td>
<td>{{ user_dict.password }}</td>
</tr>
{%endfor%}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>


自写框架梳理
- wsgiref模块
- 封装了socket代码
- 处理了http数据格式
- 根据功能的不同拆分成不同的文件夹
- urls.py 路由与视图函数对应的关系
- views.py 视图函数
- templates 模板文件夹
- 步骤
- 第一步添加路由与视图函数的对应关系
- 去views书写功能代码
- 如果需要使用到html则取模板文件夹中书写操作

浙公网安备 33010602011771号