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解析模块(ConfigParser)使用方法
Dec 10 Python
python错误:AttributeError: 'module' object has no attribute 'setdefaultencoding'问题的解决方法
Aug 22 Python
Python中使用异常处理来判断运行的操作系统平台方法
Jan 22 Python
python打开文件并获取文件相关属性的方法
Apr 23 Python
python中循环语句while用法实例
May 16 Python
Python实现的手机号归属地相关信息查询功能示例
Jun 08 Python
Python 从attribute到property详解
Mar 05 Python
关于python 的legend图例,参数使用说明
Apr 17 Python
小结Python的反射机制
Sep 28 Python
详解基于Scrapy的IP代理池搭建
Sep 29 Python
python中K-means算法基础知识点
Jan 25 Python
Python基础之函数嵌套知识总结
May 23 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
从零开始 教你如何搭建Discuz!4.1论坛
2006/07/07 PHP
PHP获取指定函数定义在哪个文件中以及其所在的行号实例
2014/05/08 PHP
PHP实现基于文本的摩斯电码生成器
2016/01/11 PHP
PHP使用ajax的post方式下载excel文件简单示例
2019/08/06 PHP
thinkphp5实现微信扫码支付
2019/12/23 PHP
Alliance vs Liquid BO3 第一场2.13
2021/03/10 DOTA
游戏人文件夹程序 ver 4.03
2006/07/14 Javascript
innertext , insertadjacentelement , insertadjacenthtml , insertadjacenttext 等区别
2007/06/29 Javascript
JavaScript 版本自动生成文章摘要
2008/07/23 Javascript
javascript引导程序
2008/10/26 Javascript
Javascript 表单之间的数据传递代码
2008/12/04 Javascript
JavaScript 面向对象的 私有成员和公开成员
2010/05/13 Javascript
IE6下js通过css隐藏select的一个bug
2010/08/16 Javascript
nodejs的require模块(文件模块/核心模块)及路径介绍
2013/01/14 NodeJs
js中符号转意问题示例探讨
2013/08/19 Javascript
Javascript脚本实现静态网页加密实例代码
2013/11/05 Javascript
谷歌浏览器调试JavaScript小技巧
2014/12/29 Javascript
RGB和YUV 多媒体编程基础详细介绍
2016/11/04 Javascript
Angular.JS实现无限级的联动菜单(使用demo)
2017/02/08 Javascript
JS中实现函数return多个返回值的实例
2017/02/21 Javascript
jquery应用实例分享_实现手风琴特效
2018/02/01 jQuery
小程序和web画三角形实现解析
2019/09/02 Javascript
layui点击左侧导航栏,实现不刷新整个页面,只刷新局部的方法
2019/09/25 Javascript
React Native中ScrollView组件轮播图与ListView渲染列表组件用法实例分析
2020/01/06 Javascript
JS中==、===你分清楚了吗
2020/03/04 Javascript
python基础入门学习笔记(Python环境搭建)
2016/01/13 Python
django定期执行任务(实例讲解)
2017/11/03 Python
python之cv2与图像的载入、显示和保存实例
2018/12/05 Python
keras 简单 lstm实例(基于one-hot编码)
2020/07/02 Python
CSS3实现千变万化的文字阴影text-shadow效果设计
2016/04/26 HTML / CSS
css3媒体查询中device-width和width的区别详解
2020/03/27 HTML / CSS
法国发饰品牌:Alexandre De Paris
2018/12/04 全球购物
Booking.com德国:预订最好的酒店和住宿
2020/02/16 全球购物
Python+Selenium自动化环境搭建与操作基础详解
2022/03/13 Python
python模板入门教程之flask Jinja
2022/04/11 Python
Python使用BeautifulSoup4修改网页内容
2022/05/20 Python