python中web框架的自定义创建


Posted in Python onSeptember 08, 2019

一、什么是框架

框架的本质就是一个socket服务,可以完成不同主机之间的通信。它是一个半成品的项目,其中可能已经封装好了基本的功能,比如路由,模型,模板,视图功能都已完善,又可能它只封装好了基本的路由功能,其他的所有都需要程序员来完善。
优点:节省了开发时间,节约了开发人力,提高了开发效率

二、框架的种类

目前python开发市场上最常用的有三大框架,Django,flask与tornado。其中,Django是最常用的,它是一个重量级框架,其中的大部分功能都已经被封装完成,只需小小的逻辑代码,即可上线运行。但也正因为这样,Django框架相比较flask来说,比较臃肿,体态比较庞大,因此在一些小型网站的开发上,Django就显得有些大材小用了。
flask是一种轻量级框架,其中只完成了基本的路由功能,其他的所有都需要程序员去完善,或者借用第三方模块,因此,flask可以轻松应对小型网站的开发,但是对于大型网站,虽然也能实现功能,但是对程序员的程序功底要求的非常高。

区别:

Django使用app进行分模块开发,flask使用蓝图进行模块开发
Django使用的是MTV模式进行解耦合,flask没有很好的完成解耦合
Django有自己的模板和路由和orm,没有服务,使用的是wsgiref。
flask 只有自己的路由,模板使用jinja2。Orm使用的是flask-sqlalchemy 模块。
flask是轻量级框架,只封装了核心功能(路由),使用比较灵活。

注:

Django执行流程:

1.浏览器访问应用
2.通过路由系统找到对应的视图函数
3.对数据库进行操作
4.返回页面给浏览器。

三、框架的自定义

理解框架的底层是如何进行工作的,可以帮助我们更有效率的进行框架的使用。
在下面会进行逐步的说明,直至完成基本功能的实现
框架的本质:首先是基于socket进行服务端与客户端的通信,下面的代码是服务端,浏览器是客户端。

import socket
# 第一个参数代表基于网络,第二个参数表示基于tcp协议
server_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#注意需要是元组对象,两个参数分别是url以及端口
server_sk.bind(('127.0.0.1', 9999))
#监听,并且最多允许128台客户机同时连接
server_sk.listen(128)
while True:
  print('等待客户端的链接:')
  #客户端发送过来的请求,是一个元组对象,将其进行解包
  clinet_sk, addr = server_sk.accept()
  content = clinet_sk.recv(1024) # 默认是二进制内容
  print(content) # 接收的到的内容是请求报文,
  #将接收到的二进制内容解码为字符串
  content = content.decode('utf-8')
  print(content)

  # 向浏览器发送内容
  msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8') # 设置响应首行
  msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8') # 设置响应头
  # 告诉浏览器,返回的是文本类型的html,并且以utf-8编码进行解码
  msg3 = '\r\n'.encode('utf-8') # 响应空行
  msg4 = '你好啊浏览器'.encode('utf-8') # 设置响应体
  client_sk.send(msg1)
  client_sk.send(msg2)
  client_sk.send(msg3)
  client_sk.send(msg4)
  client_sk.close()

在获取浏览器输入的url之后,可以根据不同的路径值给与不同的响应,这就是框架中的路由的作用。

import socket

server_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1', 9999))
server_sk.listen(128)


def index(path):
  msg = 'this is a {} page'.format(path).encode('utf-8')
  return msg


def home(path):
  msg = '这是{}页面'.format(path).encode('utf-8')
  return msg


def error(path):
  msg = 'sorry {} 404 not found ...'.format(path).encode('utf-8')
  return msg


while True:
  client_sk, addrs = server_sk.accept()
  content = client_sk.recv(1024)
  content = content.decode('utf-8')
  print('客户端发来贺电:')
  print(content)
  header_lst = content.split('\r\n') # 按\r\n进行切割
  print(header_lst)
  title_lst = header_lst[0].split(' ') # 获取请求首行并按 空格 切割
  print(title_lst)
  path = title_lst[1] # 获取url中的路径部分
  print(path)
  if path == '/home':
    msg = home(path)
  elif path == '/index':
    msg = index(path)
  else:
    msg = error(path)

  # 向页面返回内容
  msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8')
  msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')
  msg3 = '\r\n'.encode('utf-8')
  client_sk.send(msg1)
  client_sk.send(msg2)
  client_sk.send(msg3)
  client_sk.send(msg)
  client_sk.close()

在实际过程中,给浏览器返回前端页面时,是将HTML文件中的内容读取出来,以二进制的形式将其传递给浏览器,由浏览器解析后进行显示。

import socket

server_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1', 9999))
server_sk.listen(128)

def index(path):
  with open('index.html', mode='rb') as f:
    msg = f.read()
  return msg
def home(path):
  with open('home.html', mode='rb') as f:
    msg = f.read()
  return msg
def error(path):
  with open('error.html', mode='rb') as f:
    msg = f.read()
  return msg
path_lst = [
  ('/index', index), # 注意写的是函数的地址,不是调用函数
  ('/home', home),
]
while True:
  client_sk, addrs = server_sk.accept()
  content = client_sk.recv(1024)
  content = content.decode('utf-8')
  print('客户端发来贺电:')
  print(content)
  header_lst = content.split('\r\n') # 按\r\n进行切割
  print(header_lst)
  title_lst = header_lst[0].split(' ') # 获取请求首行并按 空格 切割
  print(title_lst)
  path = title_lst[1] # 获取url中的路径部分
  func = None
  for path_tup in path_lst:
    if path_tup[0] == path:
      func = path_tup[1] # 将 对应函数地址赋值给func
      break
  if func:
    msg = func(path)
  else:
    msg = error(path)
  # 向页面返回内容
  msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8')
  msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')
  msg3 = '\r\n'.encode('utf-8')
  client_sk.send(msg1)
  client_sk.send(msg2)
  client_sk.send(msg3)
  client_sk.send(msg)
  client_sk.close()

在上一步向浏览器返回具体页面的同时,可以将其中的某些数据进行替换,然后重新进行编码。这就是框架中{{}}的作用

import socket

server_sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1', 9999))
server_sk.listen(128)

def index(path):
  with open('index.html', mode='r', encoding='utf-8') as f:
    msg = f.read()
    msg = msg.replace('xxoo', path).encode('utf-8')
  return msg
def home(path):
  with open('home.html', mode='rb') as f:
    msg = f.read()
  return msg
def error(path):
  with open('error.html', mode='rb') as f:
    msg = f.read()
  return msg
path_lst = [
  ('/index', index), # 注意写的是函数的地址,不是调用函数
  ('/home', home),
]
while True:
  client_sk, addrs = server_sk.accept()
  content = client_sk.recv(1024)
  content = content.decode('utf-8')
  print('客户端发来贺电:')
  print(content)
  header_lst = content.split('\r\n') # 按\r\n进行切割
  print(header_lst)
  title_lst = header_lst[0].split(' ') # 获取请求首行并按 空格 切割
  print(title_lst)
  path = title_lst[1] # 获取url中的路径部分
  func = None
  for path_tup in path_lst:
    if path_tup[0] == path:
      func = path_tup[1] # 将 对应函数地址赋值给func
      break
  if func:
    msg = func(path)
  else:
    msg = error(path)
  # 向页面返回内容
  msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8')
  msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')
  msg3 = '\r\n'.encode('utf-8')
  client_sk.send(msg1)
  client_sk.send(msg2)
  client_sk.send(msg3)
  client_sk.send(msg)
  client_sk.close()

到这里,框架的基本功能就已经实现了,在此基础上进行优化,将不同的功能分开存储,就可以实现框架的解耦合。就是框架的雏形。

上面写的都比较??拢?旅娓?桓霰冉暇?虻男捶?/p>

"""
框架的本质就是一个socket,完成了基本功能的封装,需要程序员去搞定逻辑部分
"""
import socket
#第一个参数表示基于网络,第二个表示基于tcp
socket_pro = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 设置URL及端口
socket_pro.bind(("127.0.1.1",8888))
# 最多可允许128个客户端同时连接
socket_pro.listen(128)
"""
在实际返回到某个页面的时候,并不是指向了此页面,
而是将页面中的内容以二进制形式读取出来,作为返回值传递到前端进行解析
"""
# 在实际中,我们需要将后台的数据传输到前端进行显示,因此在传输之前,就要将数据替换掉,
# 在传输前有一个读取的过程,在读取时,我们就可以将数据替换,然后重新进行编码为二进制,
# 就可以被客户端所解析,从而显示
def index(path):
  with open('index.html','r',encoding='utf-8') as fie:
    msg = fie.read()
    # fie.read()读取出来的内容为 字符串形式,要将其传到前端页面,就要再次进行编码
    msg = msg.replace('oooo',path).encode('utf-8')
    print(type(fie.read())) # <class 'str'>
  return msg
# 没有替换页面中数据时的读取方式
def home(path):
  with open('home.html','rb')as fie:
    msg = fie.read()
  return msg
def other():
  with open('other.html','rb')as fie:
    msg = fie.read()
  return msg
  
# 定义路由列表,类似于Django中url.py文件中的urlpatterns
urlpatterns = [
  ('/index',index),
  ('/home',home)
]
while True:
  print('等待客户端连接中')
  print('-----'*24)
  print(socket_pro.accept())
  print('*******'*24)
  # socket_pro.accept()返回的是一个元组
  socket_min,addr = socket_pro.accept()
  # 可接收1024个字节
  contents = socket_min.recv(1024)
  print(contents)
  print('========' * 24)
  contents = contents.decode('utf-8')
  print(contents)
  print('#########'*24)
  # 按\r\n进行分割
  header_lst = contents.split('\r\n')
  print('header:{}'.format(header_lst))
  print('+'*100)
  # 按空格进行分割,获取请求首行
  url_lst = header_lst[0].split(' ')
  print(url_lst)
  print('___----___'*24)
  # 获取用户输入的url路径
  url = url_lst[1]
  print(url)
  print('=+=+=+='*24)
  func = None
  # 循环获取urlpatterns列表中的元组对象
  for url_real in urlpatterns:
    # 如果从地址栏中获取的url与列表中的子子元素相同,说明该路径存在
    if url_real[0] == url:
      # 将urlpatterns中的视图函数名赋值给一个对象
      func = url_real[1]
      # 退出循环
      break
  if func:
    # 调用视图函数
    msg = func(url)
  else:
    msg = other()

  #响应,给客户端返回响应
  socket_min.send('http/1.2 200 error\r\n'.encode('utf-8'))
  socket_min.send('Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8'))#设置响应头信息
  socket_min.send('\r\n'.encode('utf-8'))
  # 浏览器默认解码方式为gbk,可以使用响应头告诉浏览器解码方式
  # 返回给客户端一段响应
  socket_min.send(msg)
  # 关闭
  socket_min.close()

嗯,就到这里。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python  pip安装lxml出错的问题解决办法
Feb 10 Python
python发送邮件实例分享
Jul 28 Python
Python 旋转打印各种矩形的方法
Jul 09 Python
Python实现Selenium自动化Page模式
Jul 14 Python
Flask框架学习笔记之表单基础介绍与表单提交方式
Aug 12 Python
Numpy将二维数组添加到空数组的实现
Dec 05 Python
使用python3 实现插入数据到mysql
Mar 02 Python
pycharm中导入模块错误时提示Try to run this command from the system terminal
Mar 26 Python
pyinstaller将含有多个py文件的python程序做成exe
Apr 29 Python
关于keras中keras.layers.merge的用法说明
May 23 Python
如何一键升级Python所有包
Nov 05 Python
python 从list中随机取值的方法
Nov 16 Python
python web框架中实现原生分页
Sep 08 #Python
python中open函数的基本用法示例
Sep 07 #Python
Python3显示当前时间、计算时间差及时间加减法示例代码
Sep 07 #Python
利用python计算时间差(返回天数)
Sep 07 #Python
Django配置MySQL数据库的完整步骤
Sep 07 #Python
Django项目创建到启动详解(最全最详细)
Sep 07 #Python
Python笔试面试题小结
Sep 07 #Python
You might like
PHP中使用GD库创建圆形饼图的例子
2014/11/19 PHP
Ubuntu上安装yaf扩展的方法
2018/01/29 PHP
动态标签 悬停效果 延迟加载示例代码
2013/11/21 Javascript
验证控件与Button的OnClientClick事件详细解析
2013/12/04 Javascript
Javascript实现Array和String互转换的方法
2015/12/21 Javascript
jquery自定义右键菜单、全选、不连续选择
2016/03/01 Javascript
基于jquery编写的放大镜插件
2016/03/23 Javascript
js自定义select下拉框美化特效
2016/05/12 Javascript
理解 javascript 中的函数表达式与函数声明
2017/07/07 Javascript
React-Native之定时器Timer的实现代码
2017/10/04 Javascript
Vue2 SSR渲染根据不同页面修改 meta
2017/11/20 Javascript
webpack打包js文件及部署的实现方法
2017/12/18 Javascript
老生常谈JS中的继承及实现代码
2018/07/06 Javascript
详解JavaScript事件循环机制
2018/09/07 Javascript
详解小程序不同页面之间通讯的解决方案
2018/11/23 Javascript
JS二级菜单不同实现方法分析【4种方法】
2018/12/21 Javascript
js 计算图片内点个数的示例代码
2019/04/04 Javascript
JS数组Object.keys()方法的使用示例
2019/06/05 Javascript
layui实现图片虚拟路径上传,预览和删除的例子
2019/09/25 Javascript
vue实现的多页面项目如何优化打包的步骤详解
2020/07/19 Javascript
vue中如何添加百度统计代码
2020/12/19 Vue.js
原生js实现放大镜组件
2021/01/22 Javascript
基于Python打造账号共享浏览器功能
2019/05/30 Python
python实现爬取百度图片的方法示例
2019/07/06 Python
Python高并发和多线程有什么关系
2020/11/14 Python
彻底弄明白CSS3的Media Queries(跨平台设计)
2010/07/27 HTML / CSS
html5与css3小应用
2013/04/03 HTML / CSS
data:image data url 文件转为Blob上传后端的方法
2019/07/16 HTML / CSS
英国时尚饰品和发饰购物网站:Claire’s
2017/07/04 全球购物
美国女士内衣在线折扣商店:One Hanes Place
2019/03/24 全球购物
节省高达65%的城市景点费用:Go City
2019/07/06 全球购物
党员学习中共十八大报告思想汇报
2014/09/15 职场文书
出资证明书范本(标准版)
2014/09/24 职场文书
2015年园林绿化工作总结
2015/05/23 职场文书
师德师风培训感言
2015/08/03 职场文书
Python实现天气查询软件
2021/06/07 Python