纯手撸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框架的更多相关文章

  1. 使用wsgiref手撸web框架

    模板 前言 要说到应用程序,就不得不提的就是cs架构和BS架构 所谓的cs架构就是client端和server端,就像我们的电脑上的qq,微信等应用程序 bs架构就是浏览器端和server端,我们不需 ...

  2. 2022年整理最详细的java面试题、掌握这一套八股文、面试基础不成问题[吐血整理、纯手撸]

    这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.面向对象 2.JDK.JRE.JVM区别和联系 3.==和equals 4.final 5.String .Strin ...

  3. 纯手写Myatis框架

    1.接口层-和数据库交互的方式 MyBatis和数据库的交互有两种方式: 使用传统的MyBatis提供的API: 使用Mapper接口: 2.使用Mapper接口 MyBatis 将配置文件中的每一个 ...

  4. 手撸Spring框架,设计与实现资源加载器,从Spring.xml解析和注册Bean对象

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你写的代码,能接的住产品加需求吗? 接,是能接的,接几次也行,哪怕就一个类一片的 i ...

  5. 手写web框架之加载Controller,初始化框架

    1,加载Controller     我们需要创建 一个ControllerHelper类,让它来处理下面的逻辑:      通过ClassHelper我们可以获取所有定义了Controller注解的 ...

  6. 手写web框架之实现依赖注入功能

    我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...

  7. 手写web框架之实现Bean容器

    实现Bean容器    使用ClassHelper可以获取所加载的类,但无法通过类来实例化对象,因此我们需要提供一个反射工具类,让它封装java反射相关的API,对外提供更好用的工具方法.将该类命名为 ...

  8. 手写web框架之加载配置项目

    一  定义框架配置项 在项目的src/main/resources目录下创建一个名为smart.propertiesd的文件,文件的内容如下: smart.framework.jdbc.driver= ...

  9. 纯手写SpringMVC框架,用注解实现springmvc过程

    闲话不多说,直接上代码! 1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping ...

随机推荐

  1. php条件判断(9.29 第十五天)

    超级全局变量:$GLOBALS //包含全部变量的全局组合数组$_SERVER //包含请求头中的信息,用户的IP.用户的UA.头信息$_REQUEST //包含用户提交的所有数据(POST/GET ...

  2. 执行 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要求的版 ...

  3. 【Vue中的坑】Vue中的@mouseenter没反应?

    在开发中想实现鼠标悬浮,然后发现事件不由被出发,查找资料,发现并不是所有情况都不能用 下面就简单的说一下如何避免这种情况 如果你的悬浮事件是在 a 标签上,那么你直接使用就会出问题,你需要加一个nat ...

  4. Egret Engine 2D - 显示容器

      DisplayObjectContainer 所有容器的父类 1 添加 删除 子对象 2 访问子对象 3 检测子对象 4 设置叠放次序 Sprite 继承自DisplayObjectContain ...

  5. SublimeText3和插件的安装

    SublimeText3和插件的安装 步骤一:进入官网下载SublimeText3(http://www.sublimetext.com/3),安装并打开SublimeText3   步骤二:进入Su ...

  6. float 格式化到TCHAR 数组

    <span style="white-space:pre"> </span>float lCount = 123.3; TCHAR tcBalance[MA ...

  7. HTTP协议(四):首部

    前言 作者说:上一节中介绍了HTTP报文中的状态码,这一节同样是对报文的补充,介绍的是HTTP首部字段.不过,你如果是第一次见到这个东西,肯定会特别疑惑,什么是HTTP首部? <图解HTTP&g ...

  8. Keras + Flask 提供接口服务的坑~~~

    最近在搞Keras,训练完的模型要提供个预测服务出来.就想了个办法,通过Flask提供一个http服务,后来发现也能正常跑,但是每次预测都需要加载模型,效率非常低. 然后就把模型加载到全局,每次要用的 ...

  9. CSS 宽,高,背景设置

    width 宽,height 高,background 背景:背景色 background-color:颜色值--英文单词/十六进制/rgb:背景图 background-image:url(‘图片路 ...

  10. setoolkit+花生壳 制作钓鱼网站

    国家法律一定要遵守,知识要用在对的地方. 本贴只为了和大家交流学习,请勿用在其他地方,损害任何人的利益. 今天我,来说一下钓鱼网站 (在kali) 我们选择  1  回车 再选择 2 回车 再选择3 ...