手撸web框架
web应用分析
什么是web应用?
Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件。典型的浏览器/服务器架构的产物。
针对于web应用的分析:
1 不需要下载和更新,只要一个适用的浏览器
2 不需要耗费用的户硬盘空间,或者很少
3 跨平台使用
软件开发的架构:
1 c/s 服务器和客户端
2 b/c 服务器与浏览器(客户端)
浏览器和socket实现
手撸简易版web框架
import socket
server = socket.socket() # 默认是tcp协议
server.bind(("127.0.0.1", 8080))
server.listen(4) #
while True:
conn, addr = server.accept()
data = conn.recv(1024)
conn.send(b'404')
conn.close()
# 浏览器不能识别
http
按照http协议的改进版
import socket
server = socket.socket() # 默认是tcp协议
server.bind(("127.0.0.1", 8080))
server.listen(4) #
while True:
conn, addr = server.accept()
data = conn.recv(1024)
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
data = str(data, encoding="utf-8")
print(data)
path = data.split("\r\n")[0].split(" ")[1]
if path == "/login":
with open("login.html", 'rb')as f:
conn.send(f.read())
else:
conn.send(b'404')
conn.close()
http协议请求数据格式
""" GET / HTTP/1.1\r\n # 请求首行 Host: 127.0.0.1:8080\r\n # 请求头,都是key,value的键值对 Connection: keep-alive\r\n Cache-Control: max-age=0\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\n Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n \r\n """
wsgiref和浏览器实现
基于第三方库wsgiref实现
不用自己去处理socket连接问题
from wsgiref.simple_server import make_server
def run(request, response):
print(request)
response("200 ok", [("name", "lynn")]) # 固定写法,后边裂变式一个个元组,会以响应头key,value键值对的形式的返回给客户端
return [b'hello world'] # 固定格式,必须是列表
server = make_server("127.0.0.1", 8080, run)
server.serve_forever()
进阶
from wsgiref.simple_server import make_server
def login():
with open("login.html", 'rb')as f:
data = f.read()
return data
def register():
with open("register.html", 'rb')as f:
data = f.read()
return data
url = [
("/login", login),
("/register", register),
]
def run(request, response):
print(request)
response("200 ok", [("name", "lynn")]) # 固定写法,后边裂变式一个个元组,会以响应头key,value键值对的形式的返回给客户端
path = request.get("PATH_INFO")
for u in url:
if path == u[0]:
return [u[1]()]
return [b'hello world'] # 固定格式,必须是列表
if __name__ == '__main__':
server = make_server("127.0.0.1", 8080, run)
server.serve_forever()
动态页面
页面代码虽然没有变,但是显示的内容却是可以随着时间、环境或者数据库操作的结果而发生改变的
静态网页
随着html代码的生成,页面的内容和显示效果就基本上不会发生变化了——除非你修改页面代码
import time from wsgiref.simple_server import make_server def get_time(): return time.strftime("%Y") url = [ ("/get_time", get_time) ] def run(request, response): response("200 ok", [("name", "lynn")]) # 固定写法,后边裂变式一个个元组,会以响应头key,value键值对的形式的返回给客户端 path = request.get("PATH_INFO") for u in url: if path == u[0]: return [u[1]().encode("utf-8")] return [b'hello world'] # 固定格式,必须是列表 if __name__ == '__main__': server = make_server("127.0.0.1", 8080, run) server.serve_forever()
终极版本分文件
urls.py
url = [ ("/login", login), ("/register", register), ]
views.py
def login(): with open("login.html", 'rb')as f: data = f.read() return data def register(): with open("register.html", 'rb')as f: data = f.read() return data
jinja2实现页面渲染
什么是模板渲染?
后端数据直接加载到前端html页面直接使用
自己去做
urls.py
from views import * url = [ ("/login", login) ]
views.py
def login(): with open("login.html", 'r')as f: data = f.read() return data.replace("@@name@@", "lynn")
主文件.py
from urls import * from wsgiref.simple_server import make_server def run(request, response): response("200 OK", [("name", "lynn")]) path = request.get("PATH_INFO") for u in url: if u[0] == path: return [bytes(u[1](), encoding="utf-8")] return [b'404'] if __name__ == '__main__': server = make_server("127.0.0.1", 8080, run) server.serve_forever()
总结:
麻烦不灵活,自己要去匹配,数据类型复杂后,处理起来很麻烦
用jinja2实现
views.py
from jinja2 import Template def login(): with open("login.html", 'r', encoding="utf-8")as f: data = f.read() tem_data = Template(data) return tem_data.render(user_dic={"name": "lynn", "password": 123}) # 固定用法,把字典渲染到前端html上
主文件.py
from urls import * from wsgiref.simple_server import make_server
def run(request, response): response("200 OK", [("name", "lynn")]) path = request.get("PATH_INFO") func = None for u in url: if u[0] == path: func = u[1] break if func: res = func() else: res = '404' return [res.encode('utf-8')] # 所有的数据在最后再编码成bytes if __name__ == '__main__': server = make_server("127.0.0.1", 8080, run) server.serve_forever()
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <p>{{ user_dic.name }}</p> <p>{{ user_dic["password"] }}</p> <p>{{ user_dic.get("name") }}</p> </body> </html>