一、web框架
框架即framework,特指为一个开放性问题而设计的具有一定约束性的支撑结构。使用框架可以快速的开发特定的系统。
浏览器与server交互的列子:
浏览器作为客户端,server.py作为server服务端。
- 浏览器通过url向服务端发送请求
- 服务端接受到请求后就可以给客户端发送数据
- 发送的数据可以被浏览器渲染成一个页面
其实所有的web框架都是在这个的前提下做的一步一步的封装。这就是第一步!什么功能都没有,仅仅完成连接和最简单地数据发送:
# 导入socket模块
import socket
# 拿到浏览器发送的信息并处理浏览器即客户端发送的请求并返回数据
def handle_request(client):
buf = client.recv(1024)
client.send("HTTP/1.1 200 ok \r\n\r\n".encode('utf8')) client.send("<h1 style='color:red'>Hello zhangrenguo</h1>".encode('utf8'))
# 建立socket对象连接绑定IP和端口
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', 8001))
server.listen(5) # 接受客户端的socket请求,并给客户发送信息
while True:
coon, addr = server.accept()
handle_request(coon)
coon.close()# 执行main函数
if __name__ == '__main__':
main()
二、web应用
对于所有的web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
上面就已经简单的实现了一个web项目,但是进一步处理的话返回的应该是个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 style='color:red'>Hello zhangrenguo</h1>
</body>
</html>
index.html
# 导入socket模块
import socket# 处理浏览器即客户端发送的请求并返回数据
def handle_request(client):
buf = client.recv(1024)
client.send("HTTP/1.1 200 ok \r\n\r\n".encode('utf8'))
with open('index.html', 'rb')as f:
data = f.read()
client.send(data)# 建立socket对象连接绑定
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', 8001))
server.listen(5) # 接受客户端的socket请求,并给客户发送信息
while True:
coon, addr = server.accept()
handle_request(coon)
coon.close()if __name__ == '__main__':
main()
server.py
web应用的流程:
1、浏览器发送一个http请求
2、服务器收到请求,并生成一个HTML文件
3、服务器把HTML文件d作为http响应的body发送给浏览器
4、浏览器收到http响应,从HTTP body取出HTML文档并显示
三、web服务器
wsgi:web server gateway interface
以上已经建立了一个最简单的web框架了,但是我们还是要不断地进行封装才能完善。
首先socket需要不断地连接,重复的做很麻烦。
我们需要用到请求发来的一些内容但是字符串提取还需要解析很麻烦。
我们需要返回一些数据需要设定一些内容也很麻烦。
所以http的解析和http的设定都交给web服务器来搞定。 wsgi是Python里面非常厉害的一个web服务器
我们先看看浏览器发给我们的内容:
GET / HTTP/1.1
Host: 127.0.0.1:8001
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36
Sec-Fetch-Dest: document
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8001
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36
Sec-Fetch-Dest: image
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Referer: http://127.0.0.1:8001/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
基于wsgi服务器的框架,帮我们建立封装socket对象,帮我们解析http并帮我们设置响应头。
# 导入socket模块
import socket# python内置的web服务器,我们可以用它做检测用
# 我们引入这个模块下的函数make_server,但是这个函数时类实例化完成的。
from wsgiref.simple_server import make_serverdef application(environ,start_response):
start_response("200 ok",[('content-type','text/html')])
return [b'<h1>Hello zrg!</h1>']# make_server(ip地址,端口号,一个函数名字)
# 创建好socket对象并帮我们执行函数
httpd = make_server('',8080,application)# 来启动整个程序
httpd.serve_forever()
start-response是帮我们设定响应头,第一个参数是状态码,第二个参数是一个列表,列表里面是一个元组,每一个元组是一个键值对,而每一个键值对就是我们响应头。如果想给响应头设置什么内容,在这里仅仅写一个元组就可以了。
environ是一个请求字典对象,是wsgi把请求的数据都解析封装好了。我们需要拿哪个键的时候直接通过这个字典然后写键就可以拿到值了。
return 返回的就是响应体了。
根据不同路径返回不同的内容:
# __author:zhangrenguo
# date:# 导入socket模块
import socket# python内置的web服务器,我们可以用它做检测用
# 我们引入这个模块下的函数make_server
from wsgiref.simple_server import make_serverdef application(environ, start_response):
start_response("200 ok", [('content-type', 'text/html')])
# return [b'<h1>Hello zrg!</h1>']
# 拿到url路径
# print('environ的内容',environ)
# print(environ['PATH_INFO'])
path = environ['PATH_INFO']
if path == '/index':
return [b'<h1>index!</h1>']
elif path == '/book':
return [b'<h1>book!</h1>']
else:
return [b'<h1>404</h1>']# make_server(ip地址,端口号,一个函数名字)
# 创建好socket对象并帮我们执行函数
httpd = make_server('', 8088, application)# 来启动整个程序
httpd.serve_forever()
最基本的判断路径
# __author:zhangrenguo
# date:# 导入socket模块
import socket# python内置的web服务器,我们可以用它做检测用
# 我们引入这个模块下的函数make_server
from wsgiref.simple_server import make_server# def index():
# return [b'<h1>index!</h1>']
def index(request):
return [b'<h1>index!</h1>']# def book():
# return [b'<h1>book!</h1>']
def book(request):
return [b'<h1>book!</h1>']def routers():
urlpatterns = [
('/index', index),
('/book', book),
]
return urlpatternsdef application(environ, start_response):
start_response("200 ok", [('content-type', 'text/html')]) path = environ['PATH_INFO']
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == path:
func = item[1]
break if func:
return func(environ)
else:
return [b'<h1>404</h1>'] # if path == '/index':
# # return index()
# return index(environ) #可以通过environ去哪请求的信息
# elif path == '/book':
# # return book()
# return book(environ)
# else:
# return [b'<h1>404</h1>']# make_server(ip地址,端口号,一个函数名字)
# 创建好socket对象并帮我们执行函数
httpd = make_server('', 8089, application)# 来启动整个程序
httpd.serve_forever()
解耦。循环
这样可以直接加路径,加对应的处理函数。
前后端如果交互的话,需要模板!
在HTML里:
在后端代码里:做替换
# __author:zhangrenguo
# date:# 导入socket模块
import socket# python内置的web服务器,我们可以用它做检测用
# 我们引入这个模块下的函数make_server
from wsgiref.simple_server import make_server
import timedef index(request):
return [b'<h1>index!</h1>']def book(request):
return [b'<h1>book!</h1>']def current_time(request):
cur_time = time.ctime(time.time())
f = open('current_time.html','rb')
data = f.read() data = str(data,'utf8').replace('!cur_time!',str(cur_time)) return [data.encode('utf8')]def routers():
urlpatterns = [
('/index', index),
('/book', book),
('/current_time', current_time),
]
return urlpatternsdef application(environ, start_response):
start_response("200 ok", [('content-type', 'text/html')]) path = environ['PATH_INFO']
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == path:
func = item[1]
break if func:
return func(environ)
else:
return [b'<h1>404</h1>']# make_server(ip地址,端口号,一个函数名字)
# 创建好socket对象并帮我们执行函数
httpd = make_server('', 8083, application)# 来启动整个程序
httpd.serve_forever()
server
<!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>current_time: !cur_time! </h1>
</body>
</html>
html
四、http协议
请求和响应:
请求request:浏览器客户端给服务端发请求。
响应response:服务端给浏览器回复信息。
请求分为请求头和请求体:通过两个换行来分开。请求方式如果是get请求就没有请求体,数据都在url后面。如果是post请求就既有请求头又有请求体,数据都在请求体力。
请求头是浏览器要告诉server端关于这次请求的一些内容。
响应头是server端告诉浏览器这次回送的一些内容。
响应体就是html文件。
五、web框架的工作模式
MVC与MTV模式
Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:
Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:
- M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
- T 代表模板 (Template):负责如何把页面展示给用户(html)。
- V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:
一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。
1.虚拟环境的安装
2.web应用 C/S B/S 架构
3.http协议介绍
4.状态码
5.原生socket
6.框架演变
7.项目演变
一、虚拟环境安装
什么是虚拟环境?
1.对真实环境的一个拷贝版本
2.是实时有效的,可以独立存在运行
3.可以在计算机上拷贝多个虚拟环境
为什么要使用虚拟环境?
1.保证真实环境的纯净性
2.框架的多版本共存
3.方便做版本迭代
4.降低多框架共存的维护成本
安装虚拟环境
一、pycharm 创建
二、cmd中创建虚拟环境
第一步:新建一个文件夹专门管理虚拟环境
第二步:通过pip3 安装虚拟环境
pip3 install virtualenv
第三步:
二、web应用 架构
c/s cilent server
b/s browser server
三、http协议
什么是http协议
# HTTP(HyperText Transport Protocol)是超文本传输协议
# 基于TCP/IP协议基础上的应用层协议,底层实现仍为socket
# 基于请求-响应模式:通信一定是从客户端开始,服务器端接收到客户端一定会做出对应响应
# 无状态:协议不对任何一次通信状态和任何数据做保存
# 无连接:一次连接只完成一次请求-响应,请求-响应完毕后会立即断开连接
http工作原理
# 一次http操作称之为一个事务,工作过程可分为四步
# 1.客户端与服务端建立连接
# 2.客户端发送一个http协议指定格式的请求
# 3.服务器端接收请求后,回应一个http协议指定格式的响应
# 4.客户端将服务器的响应显示展现给用户
\r\n是结束标志。
状态码
# 1打头:消息通知
# 2打头:请求成功
# 3打头:重定向
# 4打头:客户端错误
# 5打头:服务器端错误
# 1.通过pip3安装虚拟环境:
# -- pip3 install virtualenv# 2.前往目标文件夹:
# -- cd 目标文件夹 (D:\Virtualenv)# 3.创建纯净虚拟环境:
# -- virtualenv 虚拟环境名 (py3-env1)# 4.终端启动虚拟环境:
# -- cd py3-env1\Scripts
# -- activate# 5.进入虚拟环境下的python开发环境
# -- python3# 6.关闭虚拟环境:
# -- deactivate# 7.PyCharm的开发配置
# 添加:创建项目 -> Project Interpreter -> Existing interpreter -> Virtualenv Environment | System Interpreter -> 目标路径下的python.exe
# 删除:Setting -> Project -> Project Interpreter -> Show All
五、原生socket
服务端,前台
服务器后端:
import socket
# 设置响应头(包含响应行)
RESP_HEADER = b’HTTP/1.1 200 OK\r\nContent-type:text/html;charset=utf-8\r\n\r\n’
# 设置服务器socket相关信息
server = socket.socket()
server.bind((‘localhost’, 8808))
server.listen(5)
print(“服务: http://localhost:8808”)
while True:
# 获取B以http协议发来的请求
client, address = server.accept()
data = client.recv(1024)
# 数据报文 包含 请求行 请求头 请求体
print(data)
# 手动以http协议完成响应
# 数据报文 包含 响应行 响应头 响应体
client.send(RESP_HEADER)
# /index => 响应主页
# /login => 登录页面
# 错误 => 404
# 数据data, 字节形式 => 字符串形式
strData = str(data, encoding=’utf-8′)
# 解析请求的数据, 分析得到路由
my_route = strData.split(‘\r\n’)[0].split(‘ ‘)[1]
# 后台没有设置的路由,统统以404来处理
dt = b’404′
# 设置的路由返回响应的页面文件
if my_route == ‘/index’:
with open(’02_index.html’, ‘rb’) as f:
dt = f.read()
if my_route == ‘/login’:
with open(’02_login.html’, ‘rb’) as f:
dt = f.read()
# /favicon.ico该请求是往后台请求标签图标
if my_route == ‘/favicon.ico’:
with open(‘favicon.ico’, ‘rb’) as f:
dt = f.read()
# 响应体
client.send(dt)
# 一次循环,代表一次响应,也就是一次事务的完成, 要关闭http请求连接
client.close()