徒手撸出一个类Flask微框架(三)根据业务进行路由分组
所谓分组就是按照前缀分布映射
如:
/product/(\w+)/(?P<id>\d+ # 匹配/product/123123 的前缀
比如什么类别,类别下的什么产品 等,
用request path进行正则匹配,所以需要用到正则分组
分析我们当前代码,只有__call__方法才是真正在做处理,也就是说得在这个方法获取分组
通过动态属性
通过动态属性,将匹配到的命名分组域当前request对象,因为一个请求对应不同的request实例
这里是一个实例只能对应一个request
@dec.wsgify
def __call__(self, request:Request):for methods, pattern, handler in self.ROUTE:print(self.ROUTE)if not methods or request.method in methods:if request.method.upper() in methods:matcher = pattern.match(request.path)if matcher:request.args = matcher.group() #所有的分组request.kwargs = matcher.groupdict() #所有的命名分组return handler(request)raise exc.HTTPNotFound('no')
对我们而言命名后的分组才有价值,动态增加属性之后,增加了属性,为了获取分组信息
打印这两个如下:
>>>>>> /
>>>>>> {
每一个前缀所对应的字段我们认为是不同的路由实例,每个实例保存自己的前缀,在内部实现Application,这一就将Application变为多个实例
思路:通过request的前缀名来判断不同的业务,通过不同的前缀名来调用不同的方法
比上一节多了一级
需求:
URL 为/product/12345,那么需要将产品id 12345取出,用分组包装,一旦分离出来前缀product,那么这就是一个一级路由分组,通过第一级判断交给谁来做
再通过Applicaction 判断前缀扔给不同的对象,而对象内又对应不同的pattern(正则)再交给不同的handler
例:
p = Router('/product') 直接转化前缀
p.get(pattern正则) 匹配路径,replice之后换为空,切分后再判断
提交的模式
/product/(\w+)/(?P<id>\d+)
可以理解为每一个前缀都是一个不同的路由实例,每个实例保留的是业务分组
前缀必须以/根开始
前缀不能在后面加/ ,用户不认这个,只能strip掉
建立隶属关系
一个prefix下有若干个url,建立了某种关系,比如/xxx/xx 这里URL属于xxx的管理范围;只要符合格式就属于prefix的管辖范围
一个Router类 通过每一个类都管理一个prefix
之前所有方法都是在Application类方法中,现在要将其拆开
现在路由表方式应该如何处理?
不同前缀对应不同的router实例,那么这些方法就不是类方法了,而是对应一个实例方法
我们现在想让每个业务分开,各管各的,独立负责自己的路由信息对应不同的实例;
如果是一个实例的话那么可以独立管理,那么如果是类属性则不适用,因为类属性是共享的,所以要由实例自己管理独立的路由表
定义Application类,只保存所有注册的路由对象,__call__依然是回调的入口,一切从这里开始
在这里需要遍历所有的Rtouer实例,这里是Router实例不是类属性
找到实例之后返回response即可
路由分组
按照前缀分别映射
分析:
application是作为入口的东西是单一的,所以需要固定
大多数server 需要传递一个单一的对象,会找到入口wsgi的入口,也就是__call__
首先知道每一个前缀的管理是不同的对象,这个类为Router
将注册的方法移到Router类,实现一个实例管理当前业务的url,实际上还是meatch方法
原则:只找一个route
代码如下:
解决前缀问题
# /product/tv/1234 /product/tv/abc
# /python/student/16
# /product/(\w+)/(?<id>\d+)
找到定义初始化,一个实例独立管理,路由要在初始化的时候定义好
prefix 是前缀,默认为空;
每个实例自行管理自己的路由表;
class Router:def __init__(self,prefix:str=''):self.__prefix = prefixself.__routetable = []
定义route
@property
def prefix(self):return self.__routetable
def route(self, pattern, *methods): # 传入正则和路径def wapper(handler):uri = (methods,re.compile(pattern),handler)self.__routetable.append(uri)return handlerreturn wapper
定义请求方法
@property
def prefix(self):return self.__prefix
def get(self,pattern):return self.route('GET', pattern)
def post(self,pattern):return self.route('POST', pattern)
定义maetch **
·判断是否属于自己实例管理的prefix
·如果不是以它为前缀的直接return None
·如果归属自己管理所有循环作完没有匹配到直接默认return None 或者404
·并修改前缀 通过replace,因为传递url是带的,但是在处理的时候是
def match(self,request:Request):# 如果不是以某为前缀则直接return空,那么则没有注册,当__call__扫描的时候没有获取到则直接404if not request.path.startswith(self.prefix):returnfor methods, pattern, handler in self.__routetable:if not methods or request.method.upper() in methods:# 我们写的pattern是/produ ct/(\w+)/(?<id>\d+),匹配的是后半部分,那匹配也是后半部分,所以要去掉前缀matcher = pattern.match(request.path.replace(self.prefix))if matcher:request.kwargs = matcher.groupdict()return handler
定义Application
定义Application
·定义ROUTERS列表用于管理实例对象
·如果是外界可以注册进来,那肯定不是实例,所以还需要类方法
注册的方式:
p = Router('/product') 直接转化前缀
p.get(pattern正则) 匹配路径,replice之后换为空,切分后再判断
没有必要实例化,注册的东西都需要在这之上
class Application:ROUTERS = []
#将Router注册进来
@classmethod
def register(cls,router:Router):cls.ROUTERS.append(router)
定义__call__方法
查找每个ROUTERS 返回response,前提是找到request之后
如果能处理则必须返回数据,判断是否有数据要么None要么非None
@dec.wsgify
def __call__(self, request:Request):# 获取response,问每一个router进行询问,调用实例化的router进行match方法,将request传递过去for router in self.ROUTERS:response = router.match(request)# 一旦有数据获取那么直接返回response,如果全部执行完没有路由,则直接404if response:return responseraise exc.HTTPNotFound('no')
如果没有思路的话先定义application最后再定义match方法
注册
idx = Router()
py = Router('/py')
这样一写,肯定是由注册方法进行注册,所以还需要调用注册方法
Application.register(idx)
Application.register(py)
只要application能够调用,那么就直接到__call__中遍历
这样通过业务的分级进行分别管理
完整如下:
class Router:def __init__(self,prefix:str=''):# /product/tv/1234 /product/tv/abc# /python/student/16# /produ ct/(\w+)/(?<id>\d+)self.__prefix = prefixself.__routetable = []def route(self,pattern,*methods):def wapper(handler):uri = (methods,re.compile(pattern),handler)print('uri:',uri)self.__routetable.append(uri)return handlerreturn wapperdef get(self,pattern):return self.route(pattern,'GET')def post(self,pattern):return self.route(pattern,'POST')def match(self,request:Request):if not request.path.startswith(self.__prefix):return Nonefor methods,pattern,handler in self.__routetable:if not methods or request.method.upper() in methods:matcher = pattern.match(request.path.replace(self.__prefix,'',1))if matcher:request.kwargs = matcher.groupdict()return handler(request)
class App:ROUTERS = []@classmethoddef register(cls,router:Router):cls.ROUTERS.append(router)@dec.wsgifydef __call__(self, request:Request):for router in self.ROUTERS:response = router.match(request)return responseraise exc.HTTPNotFound('no')
idx = Router()
App.register(idx)
@idx.get('^/$')
def index(request:Request):res = Response()res.body = 'aa'.encode()return res
if __name__ == "__main__":ip = '127.0.0.1'port = 9999server = make_server(ip,port,App())server.serve_forever()server.server_close()
转载于:https://blog.51cto.com/yijiu/2071939
相关文章:

TCP编程函数和步骤
TCP编程的服务器端一般步骤是1、 创建一个socket,用函数socket();2、 设置socket属性,用函数setsockopt(); * 可选3、 绑定IP地址、端口等信息到socket上,用函数bind();4、 开启监听,用函数listen();5、 接…

OSD的主要实现方法和类型(转)
源:OSD的主要实现方法和类型 目前有两种主要的OSD实现方法:外部OSD发生器与视频处理器间的叠加合成;视频处理器内部 支持OSD,直接在视频缓存内部叠加OSD信息。 外部OSD发生器与视频处理器间的叠加合成的实现原理是:由一个MCU内建的…

为什么要研究游戏 AI 呢?
作者 | 叶鑫来源 | DatawhaleAI作为时下计算机算法的超级巨星,在例如CV、NLP、语音、机器人等诸多领域都有广泛的应用。而在游戏领域,AI的应用往往被认为只是把游戏角色拟人化,算法的第一印象也通常是强化学习。但实际当中,AI在游…

oracle 工具:tkprof
https://docs.oracle.com/cd/B10501_01/server.920/a96533/ex_plan.htm http://blog.csdn.net/dba_waterbin/article/details/8010629 oracle sql执行计划怎么看 https://zhidao.baidu.com/question/1178766860347033659.html

Linux环境编程--文件基本操作
Linux 下目录是/这样的 而windows是\怎么记呢?\和w是不是一样的反向?所以Linux的目录就是反的反向,好记了。 一:open函数名称:open目标:打开一个文件。头文件:#include <sys/types.h>#in…

Firefox插件
为什么80%的码农都做不了架构师?>>> 网站优化必备的9个Firefox插件 在网页设计制作中经常使用到的火狐浏览器插件工具: 1. Firebug Firebug是开发人员们钟爱火狐浏览器的一个重要原因,Firebug是火狐浏览器上一个集成式的强大调试…

马斯克公开支持“上班摸鱼”:让工作更愉快!
整理 | 王晓曼出品 | 程序人生 (ID:coder _life)11月16日,在国美集团批评员工上班摸鱼的通报中,一名员工在网易云音乐上使用了22.5G的流量格外显眼。11月18日,网易云音乐也紧跟热点上线了摸鱼计算器活动&am…

瀚思首发三款产品 推动大数据安全战略布局
安全已成为了当下社会最为关注的几个问题之一,随着大数据时代的来临,如今的安全问题也变得严峻和复杂。近日,HanSight瀚思在北京召开了产品战略暨融资发布会,推出了瀚思用户行为分析系统(HanSight UBA)、瀚…

Linux环境编程--编辑器基本操作
vim使用 新建文件 #vim hello.c 插入模式 按下I键,底下出现- - 插入- - 换行:按下Enter 删除字符:普通模式下按x 删除整行:按dd 恢复删除:按u 取消命令: CtrlR 对U后果弥补 复制:y y2w复制2个…

2021 IDEA大会开启AI思想盛宴,用“创业精神”做科研
11月22日上午10时许,由深圳市福田区人民政府、深圳市福田区科技创新局和粤港澳大湾区数字经济研究院(International Digital Economy Academy, 简称“IDEA”)联合举办的2021 IDEA大会在深圳福田开幕。大会以“The World Needs a Few Good IDE…

Android不同分辨率和不同密度适配
官方原文地址:http://developer.android.com/training/multiscreen/screendensities.html 本文主要介绍: 1.dip dp sp 简单用法 2.适配不同分辨率屏幕图片的处理方法 支持不同的密度或分辨率 本课介绍如何通过提供不同的资源和使用的测量分辨率独立单元支…

网络工程师成长日记333-某城市政府项目
网络工程师成长日记333-某城市政府项目 这是我的第333篇原创文章,记录网络工程师行业的点点滴滴,结交IT行业有缘之人 直接上干货,拓扑图: 工程目的:排除故障配置如下:LinWei#show running-configBuilding c…

linux环境编程-- ftok()函数
系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。 ftok原型如下: key_t ftok( char * fname, int id )fname就时你指定的文件名(该文件必须是存在而且可以访问的),id是…

使用 ChatterBot 库制作一个聊天机器人
作者 | 周萝卜来源 | 萝卜大杂烩我们学习一些如何使用 ChatterBot 库在 Python 中创建聊天机器人,该库实现了各种机器学习算法来生成响应对话,还是挺不错的1什么是聊天机器人聊天机器人也称为聊天机器人、机器人、人工代理等,基本上是由人工智…

powerDesign设计随笔
PowerDesigner的Table视图同时显示Code和Name的方法 实现方法:Tools-Display Preference powerDesigner设置 name不自动等于code 从数据库里抽取了数据模型,为了理清思路,需要将name改为中文名称,但是pd自动将name填充为code&…

Apache Kylin在绿城客户画像系统中的实践
前言\\作为国内知名的房地产开发商,绿城经过24年的发展,已为全国25万户、80万人营造了美丽家园,并将以“理想生活综合服务提供商”为目标,持续为客户营造高品质的房产品和生活服务。\\2017年,绿城理想生活集团成立&…

linux环境编程--IPC 之 msg queue
消息队列在UNIX的SystemV版本,AT&T引进了三种新形式的IPC功能(消息队列、信号量、以及共享内存)。但BSD版本的UNIX使用套接口作为主要的IPC形式。Linux系统同时支持这两个版本。系统调用msgget() 如果希望创建一个新的消息队列࿰…

2021 IDEA大会圆满落幕,一文回顾大会精彩看点
11月23日,为期两天的2021 IDEA大会在深圳福田圆满落幕。2021 IDEA大会由深圳市福田区人民政府、深圳市福田区科技创新局和粤港澳大湾区数字经济研究院(International Digital Economy Academy,简称“IDEA”)联合举办。深圳市科创委…

【转】Android下编译jni库的二种方法(含示例) -- 不错
原文网址:http://blog.sina.com.cn/s/blog_3e3fcadd01011384.html 总结如下:两种方法是:1)使用Android源码中的Make系统2)使用NDK(从NDK r5开始)---------------------------------源码要求&…

linux下如何修改系统时间
我们一般使用“date -s”命令来修改系统时间。比如将系统时间设定成2018年2月23日的命令如下。 #date -s 02/23/2018 将系统时间设定成下午11点12分0秒的命令如下。 #date -s 11:12:00 注意,这里说的是系统时间,是linux由操作系统维…

thttpd服务器
1 引言随着微处理器技术、计算机网络技术的进步,基于嵌入式WEB的网络数字视频监控系统逐渐得到了人们的广泛关注。把图像采集、视频压缩和WEB功能集中到一个体积很小的设备内,可以直接连入局域网和Internet,达到即插即用,省掉多种…

链接产业 聚变未来 | 移动云区块链开发者论坛来了
有人认为,如果说蒸汽机释放了人们的生产力,电力解决了人们基本的生活需求,互联网改变了信息传递的方式,那么区块链作为构造信任的机器,将可能改变整个人类社会价值传递的方式。区块链已走进大众视野,成为社…

Bzoj4016: [FJOI2014]最短路径树问题
题面 传送门 Sol 先\(SPFA\)求出单源最短路,\(Bfs\)建出树,字典序可以用堆解决 然后就是点分治的一眼题 开桶记录到当前根经过边长度相同的最长路,记录它的长度 自己强行\(yy\)了一个这种类型的点分丑陋写法 # include <bits/stdc.h> #…

libevent源码深度剖析
原文地址:http://blog.csdn.net/sparkliang/article/details/4957667libevent源码深度剖析一——序幕张亮1 前言 Libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少。写这一系列文章的用意在于&#…

元宇宙中可跨语种交流!Meta 发布新语音模型,支持128种语言无障碍对话
编译 | 禾木木出品 | AI科技大本营(ID:rgznai100)语言交流是人类互动一种自然的方式,随着语音技术的发展,我们可以与设备以及未来的虚拟世界进行互动,由此虚拟体验将于我们的现实世界融为一体。然而,语音技…

前端面试官,我为什么讨厌你。
近两年来,参加过的前端面试不下二十场了,吐槽一下。我所经历的,都是小公司,大公司的同学请无视。 招聘信息能否不要装逼?写一大堆你项目根本用不上的,来给谁看?我曾遇到上面写了一堆对js如何要求…

【ASP.NET Core】解决“The required antiforgery cookie xxx is not present”的错误
当你在页面上用 form post 内容时,可能会遇到以下异常: The required antiforgery cookie "????????" is not present. 咱们来重现一下错误。新建一个 ASP.NET Core 项目,模板选【空】就行了,这是老周最喜欢的项…

linux系统级别的能够打开的文件句柄的数file-max命令
简单的说, max-file表示系统级别的能够打开的文件句柄的数量, 而ulimit -n控制进程级别能够打开的文件句柄的数量.man 5 proc, 找到file-max的解释:file-max中指定了系统范围内所有进程可打开的文件句柄的数量限制(系统级别, kernel-level). (The value …

这封以数字构写的蓝图,正在实现笔尖所触即世界
作者 | 贾凯强出品 | AI科技大本营(ID:rgznai100)一撇一捺,一勾一抹,笔走龙蛇,可见真意。笔者小时候字迹潦草,便总是抱怨为什么一定要写字好看?而如今计算机统治了世界,键盘和鼠标早…

Svn 笔记—— Hooks
pre-commit 钩子功能:[rootDa hooks]# cat /application/svndata/sadoc/hooks/pre-commit#!/bin/bash#Check message lenth ---更新版本时强制输入信息小于5个字符会退出REPOS"$1"TXN"$2"logmsgsvnlook log -t $TXN $REPOS |grep &q…