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操作日期和时间的方法
Mar 11 Python
Python实现在线暴力破解邮箱账号密码功能示例【测试可用】
Sep 06 Python
python Socket之客户端和服务端握手详解
Sep 18 Python
Python将多个excel表格合并为一个表格
Feb 22 Python
Python 多线程不加锁分块读取文件的方法
Dec 11 Python
python实现学员管理系统
Feb 26 Python
Django 中间键和上下文处理器的使用
Mar 17 Python
Python爬虫实现爬取百度百科词条功能实例
Apr 05 Python
Python 实现数组相减示例
Dec 27 Python
Python 模拟生成动态产生验证码图片的方法
Feb 01 Python
Pytest mark使用实例及原理解析
Feb 22 Python
详解OpenCV获取高动态范围(HDR)成像
Apr 29 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 文件上传源码分析(RFC1867)
2009/10/30 PHP
php中利用post传递字符串重定向的实现代码
2011/04/21 PHP
PHP中echo和print的区别
2014/08/28 PHP
PHP实现登录注册之BootStrap表单功能
2017/09/03 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
2020/02/21 PHP
JavaScript 面向对象的之私有成员和公开成员
2010/05/04 Javascript
使用jQuery.Validate进行客户端验证(初级篇) 不使用微软验证控件的理由
2010/06/28 Javascript
在javascript中对于DOM的加强
2013/04/11 Javascript
jquery获取复选框被选中的值
2014/04/10 Javascript
Highcharts入门之基本属性
2016/08/02 Javascript
微信小程序 ES6Promise.all批量上传文件实现代码
2017/04/14 Javascript
linux 后台运行node服务指令方法
2018/05/23 Javascript
Angularjs之如何在跨域请求中传输Cookie的方法
2018/06/01 Javascript
JS中判断字符串存在和非空的方法
2018/09/12 Javascript
webpack dll打包重复问题优化的解决
2018/10/10 Javascript
微信小程序 腾讯地图SDK 获取当前地址实现解析
2019/08/12 Javascript
Vue3 实现双盒子定位Overlay的示例
2020/12/22 Vue.js
[00:17]天涯墨客一技能展示
2018/08/25 DOTA
利用Python绘制数据的瀑布图的教程
2015/04/07 Python
教大家玩转Python字符串处理的七种技巧
2017/03/31 Python
Django rest framework基本介绍与代码示例
2018/01/26 Python
Python 字符串与二进制串的相互转换示例
2018/07/23 Python
python 实现对文件夹中的图像连续重命名方法
2018/10/25 Python
Python任意字符串转16, 32, 64进制的方法
2019/06/12 Python
基于Python爬虫采集天气网实时信息
2020/06/05 Python
python之语音识别speech模块
2020/09/09 Python
丝绸和人造花卉、植物和树木:Nearly Natural
2018/11/28 全球购物
学前教育毕业生自荐信范文
2013/12/24 职场文书
四风问题查摆材料
2014/08/25 职场文书
领导干部四风问题自我剖析材料
2014/09/25 职场文书
保卫工作个人总结
2015/03/03 职场文书
同学聚会感言一句话
2015/07/30 职场文书
《狮子和鹿》教学反思
2016/02/16 职场文书
详解redis分布式锁的这些坑
2021/05/19 Redis
微信小程序实现聊天室功能
2021/06/14 Javascript
MYSQL 的10大经典优化案例场景实战
2021/09/14 MySQL