纯手撸web框架
纯手撸web框架
一、Web应用的组成
接下来我们学习的目的是为了开发一个Web应用程序,而Web应用程序是基于B/S架构的,其中B指的是浏览器,负责向S端发送请求信息,而S端会根据接收到的请求信息返回相应的数据给浏览器,需要强调的一点是:S端由server和application两大部分构成,如图所示:
上图:Web应用组成

二、手鲁web应用
2.1 基本版
import socket
"""
@author RansySun
@create 2019-10-18-11:59
"""
# 创建服务端
server = socket.socket()
server.bind(("127.0.0.1", 8080))
server.listen(5)
while True:
# 等待连接
conn, addr = server.accept()
# 接收浏览器发送的消息
data = conn.recv(1024)
print(data)
# 请求行 请求头 空行 请求体, 返回响应首行
conn.send(b'HTTP/1.1 200 OK \r\n\r\n Hello web')
conn.close()

2.2 根据请求地址,返回请求内容
import socket
"""
@author RansySun
@create 2019-10-18-11:59
"""
# 创建服务端
server = socket.socket()
server.bind(("127.0.0.1", 8080))
server.listen(5)
while True:
# 等待连接
conn, addr = server.accept()
# 接收服务端发送消息
data = conn.recv(1024)
# 获取请求内容
data = str(data, encoding="utf8").split(" ")[1]
# 发送请求头
conn.send(b'HTTP/1.1 200 OK \r\n\r\n ')
print(data)
data = bytes(data, encoding="utf8")
# 响应客户端
conn.send(data)


2.3 根据请求地址返回响应html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎来到鸡公煲, baby</h1>
</body>
</html>
import socket
"""
@author RansySun
@create 2019-10-19-9:54
"""
# 创建连接对象
server = socket.socket()
server.bind(("127.0.0.1", 8080))
server.listen(4)
while True:
# 等待连接
conn, addr = server.accept()
data = conn.recv(1024)
# 接收客户端请求
data = str(data, encoding="utf8").split(" ")[1]
print(data)
# 发送请求头
conn.send(b"HTTP//1.1 200 OK \r\n\r\n")
# 判断请求对象
if data == '/index':
# 返回页面请求
with open("index.html", "rb") as fr:
conn.send(fr.read())
elif data == '/login':
with open("login.html", "rb") as fr:
conn.send(fr.read())
else:
conn.send(b"<h1 style='color:red'>404 error</h1>")



到此为止.....

三、Web框架的由来
综上案例我们可以发现一个规律,在开发S端时,server的功能是复杂且固定的(处理socket消息的收发和http协议的处理),而业务逻辑却各不相同(不同的软件就应该有不同的业务逻辑),重复开发复杂且固定的server是毫无意义的,有一个wsgiref模块帮我们写好了server的功能,这样我们便只需要专注于功能的编写
3.1 简易版
from wsgiref.simple_server import make_server
"""
@author RansySun
@create 2019-10-19-10:20
"""
def run(env, response):
"""
:param env: 请求相关的所有数据
:param response: 对页面做出相关响应
:return:
"""
# 发送请求
response("200 OK \r\n\r\n", [])
# 响应页面
res = 'hello web'
print(env.get("PATH_INFO"))
return [res.encode('utf8')]
if __name__ == '__main__':
server = make_server("127.0.0.1", 8080, run)
# 实时监听地址,只要有客户端来连接, 统一交给run函数处理
server.serve_forever()

3.2 根据请求做出响应
<!-- index -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>
<!-- login -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎来到鸡公煲, baby</h1>
</body>
</html>
<!-- get_time -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
time
<body>
</body>
</html>
<!-- get_user -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>{{ user }}</p>
<p>{{ user.name }}</p>
<p>{{ user['pwd'] }}</p>
<p>{{ user.get('hobby') }}</p>
<h1></h1>
<h1></h1>
</body>
</html>
<!-- get_db -->
<!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-6 col-md-offset-2">
<h1 class="text-center"></h1>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>id</th>
<th>x</th>
<th>y</th>
</tr>
</thead>
<tbody>
<tbody>
{% for user_dict in user %}
<tr>
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.x }}</td>
<td>{{ user_dict.y }}</td>
</tr>
{% endfor %}
</tbody>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
# url.py
from views import *
"""
@author RansySun
@create 2019-10-19-10:49
"""
urls = [
('/index', index),
('/login', login),
('/xxx', xxx),
('/get_time', get_time),
('/get_user', get_user),
('/get_db', get_db),
]
# views.py
from datetime import datetime
"""
@author RansySun
@create 2019-10-19-10:49
"""
def index():
return "index"
def login():
return "login"
def xxx():
return "xxx"
def error(env):
return '404 error'
def get_time():
"""
获取时间
:return:
"""
data_time = datetime.now().strftime('%Y-%m-%d %X')
with open(r"templates\time.html", 'r', encoding='utf8') as fr:
data = fr.read()
data = data.replace("time", data_time)
return data
from jinja2 import Template
def get_user():
"""
前端通过字典获取用户信息
:return:
"""
dic = {'name': 'randy', 'pwd': '123123', 'hobby': ['read', 'running', 'music']}
with open(r'templates/user.html', 'r', encoding="utf-8") as fr:
data = fr.read()
temp = Template(data)
# 将字典dic传递给前端页面 页面上通过变量名user就能够获取到该字典
res = temp.render(user=dic)
return res
import pymysql
def get_db():
mysql = pymysql.connect(
host="127.0.0.1",
user="root",
password="root",
charset="utf8",
db="db1",
autocommit=True
)
sql = "select * from a1"
cursor = mysql.cursor(pymysql.cursors.DictCursor)
cursor.execute(sql)
res = cursor.fetchall()
with open("templates/get_db.html", "r", encoding='utf8') as fr:
data = fr.read()
# print(res)
temp = Template(data)
data = temp.render(user=res)
return data
# wsgiref.py
from wsgiref.simple_server import make_server
from url import *
from views import *
"""
@author RansySun
@create 2019-10-19-10:20
"""
def run(env, response):
"""
:param env: 请求相关的所有数据
:param response: 对页面做出相关响应
:return:
"""
# 发送请求
response("200 OK", [])
# 获取连接请求后缀
resp = env.get("PATH_INFO")
# 用来存储后续匹配到的函数名
func = None
# 查找匹配的后缀函数
for url in urls:
if resp == url[0]:
func = url[1]
break
# 判断func是否有值
if func:
res = func()
else:
res = error(env)
return [res.encode('utf8')]
if __name__ == '__main__':
server = make_server("127.0.0.1", 8080, run)
# 实时监听地址,只要有客户端来连接, 统一交给run函数处理
server.serve_forever()
至此,我们就针对web开发的开发自定义了一个框架,所以说框架的本质就是一系列功能的集合体、不同的功能放到不同的文件中。有了该框架,可以让我们专注于业务逻辑的编写,极大的提高了开发web应用的效率(开发web应用的框架可以简称为web框架),比如我们新增一个业务逻辑,要求为:浏览器输入http://127.0.0.1:8011/home 就能访问到home.html页面,在框架的基础上具体开发步骤如下:
步骤一:在templates文件夹下新增home.html
步骤二:在url.py的urls中新增一条映射关系
urls = [
('/index', index),
('/timer', timer),
('/home', home), # 新增的映射关系
]
步骤三:在views.py中新增一个名为home的函数
def home(environ):
with open('templates/home.html', 'r',encoding='utf-8') as f:
data = f.read()
return data.encode('utf-8')
我们自定义的框架功能有限,在Python中我们可以使用别人开发的、功能更强大的Django框架




纯手撸web框架的更多相关文章
- 使用wsgiref手撸web框架
模板 前言 要说到应用程序,就不得不提的就是cs架构和BS架构 所谓的cs架构就是client端和server端,就像我们的电脑上的qq,微信等应用程序 bs架构就是浏览器端和server端,我们不需 ...
- 2022年整理最详细的java面试题、掌握这一套八股文、面试基础不成问题[吐血整理、纯手撸]
这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.面向对象 2.JDK.JRE.JVM区别和联系 3.==和equals 4.final 5.String .Strin ...
- 纯手写Myatis框架
1.接口层-和数据库交互的方式 MyBatis和数据库的交互有两种方式: 使用传统的MyBatis提供的API: 使用Mapper接口: 2.使用Mapper接口 MyBatis 将配置文件中的每一个 ...
- 手撸Spring框架,设计与实现资源加载器,从Spring.xml解析和注册Bean对象
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你写的代码,能接的住产品加需求吗? 接,是能接的,接几次也行,哪怕就一个类一片的 i ...
- 手写web框架之加载Controller,初始化框架
1,加载Controller 我们需要创建 一个ControllerHelper类,让它来处理下面的逻辑: 通过ClassHelper我们可以获取所有定义了Controller注解的 ...
- 手写web框架之实现依赖注入功能
我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...
- 手写web框架之实现Bean容器
实现Bean容器 使用ClassHelper可以获取所加载的类,但无法通过类来实例化对象,因此我们需要提供一个反射工具类,让它封装java反射相关的API,对外提供更好用的工具方法.将该类命名为 ...
- 手写web框架之加载配置项目
一 定义框架配置项 在项目的src/main/resources目录下创建一个名为smart.propertiesd的文件,文件的内容如下: smart.framework.jdbc.driver= ...
- 纯手写SpringMVC框架,用注解实现springmvc过程
闲话不多说,直接上代码! 1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping ...
随机推荐
- php条件判断(9.29 第十五天)
超级全局变量:$GLOBALS //包含全部变量的全局组合数组$_SERVER //包含请求头中的信息,用户的IP.用户的UA.头信息$_REQUEST //包含用户提交的所有数据(POST/GET ...
- 执行 composer update 命令的时候报 Your requirements could not be resolved to an installable set of packages. 错误
Your requirements could not be resolved to an installable set of packages. 以上原因:不匹配composer.json要求的版 ...
- 【Vue中的坑】Vue中的@mouseenter没反应?
在开发中想实现鼠标悬浮,然后发现事件不由被出发,查找资料,发现并不是所有情况都不能用 下面就简单的说一下如何避免这种情况 如果你的悬浮事件是在 a 标签上,那么你直接使用就会出问题,你需要加一个nat ...
- Egret Engine 2D - 显示容器
DisplayObjectContainer 所有容器的父类 1 添加 删除 子对象 2 访问子对象 3 检测子对象 4 设置叠放次序 Sprite 继承自DisplayObjectContain ...
- SublimeText3和插件的安装
SublimeText3和插件的安装 步骤一:进入官网下载SublimeText3(http://www.sublimetext.com/3),安装并打开SublimeText3 步骤二:进入Su ...
- float 格式化到TCHAR 数组
<span style="white-space:pre"> </span>float lCount = 123.3; TCHAR tcBalance[MA ...
- HTTP协议(四):首部
前言 作者说:上一节中介绍了HTTP报文中的状态码,这一节同样是对报文的补充,介绍的是HTTP首部字段.不过,你如果是第一次见到这个东西,肯定会特别疑惑,什么是HTTP首部? <图解HTTP&g ...
- Keras + Flask 提供接口服务的坑~~~
最近在搞Keras,训练完的模型要提供个预测服务出来.就想了个办法,通过Flask提供一个http服务,后来发现也能正常跑,但是每次预测都需要加载模型,效率非常低. 然后就把模型加载到全局,每次要用的 ...
- CSS 宽,高,背景设置
width 宽,height 高,background 背景:背景色 background-color:颜色值--英文单词/十六进制/rgb:背景图 background-image:url(‘图片路 ...
- setoolkit+花生壳 制作钓鱼网站
国家法律一定要遵守,知识要用在对的地方. 本贴只为了和大家交流学习,请勿用在其他地方,损害任何人的利益. 今天我,来说一下钓鱼网站 (在kali) 我们选择 1 回车 再选择 2 回车 再选择3 ...