徒手撸出一个类flask微框架根据业务进行路由分组

author author     2022-10-16     156

关键词:

所谓分组就是按照前缀分布映射

如:

/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 = prefix
        self.__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 handler
    return 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__扫描的时候没有获取到则直接404
    if not request.path.startswith(self.prefix):
        return
    for 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,如果全部执行完没有路由,则直接404
        if response:
            return response
    raise 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 = prefix
        self.__routetable = []
    def route(self,pattern,*methods):
        def wapper(handler):
            uri = (methods,re.compile(pattern),handler)
            print('uri:',uri)
            self.__routetable.append(uri)
            return handler
        return wapper
    def 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 None
        for 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 = []
    @classmethod
    def register(cls,router:Router):
        cls.ROUTERS.append(router)
    @dec.wsgify
    def __call__(self, request:Request):
        for router in self.ROUTERS:
            response = router.match(request)
            return response
        raise 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 = 9999
    server = make_server(ip,port,App())
    server.serve_forever()
    server.server_close()


徒手撸出一个类flask微框架理解http请求request和response

environ环境参数考虑到后期的事宜,引入第三方库webobhttps://docs.pylonsproject.org/projects/webob/en/stable/index.html  一、webob.request对象将环境参数解析并封装成request对象使用方法: GET 发送的数据是URL的查询字符串,在request... 查看详情

徒手生撸一个验证框架,api参数校验不再怕!

 你们之中大概率早已练就了代码的拷贝、粘贴,无敌的码农神功,其实做久了业务功能开发,练就这两个无敌神功,那是迟早的事儿。今天先抛一个小问题,来打通你的任督二脉,就是很好奇的问一下:业务功能开发中,输... 查看详情

徒手搭建python单元测试框架

参考技术A稍微具有一定规模的企业对于软件开发一般都会要求写单元测试,虽然各自标准不同,有的可能要求覆盖率达到50即可,而像我司这种竟然要求行覆盖率和分支覆盖率都要到95%以上。本文会手把手教你如何在项目初期搭... 查看详情

从零实现web框架geo教程-分组控制-04(代码片段)

...指路由的分组。如果没有路由分组,我们需要针对每一个路由进行控制。但是真实的业务场景中,往往某一组路由需要相似的处理。例如 查看详情

flask编写restfulapi

...'等方法发送请求到服务器,改变相应的资源状态。Flask是一个基于Python开发的微型web框架,其中Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进... 查看详情

如何在 Flask API 路由系统中定义基本路由

...em【发布时间】:2015-01-2505:18:00【问题描述】:在像slimphp框架这样的框架中,您可以定义在所有路由中都相同的基本路由,例如/api/v1。所以在slim中,我们可以对路由进行分组,而不是在每条路由中添加/api/v1:$app->group(\'/api/v1... 查看详情

flask框架基础功能(代码片段)

...大基础功能,包括:路由系统模板数据库几种常用Flask库一个简单的Flask事例Flask是一个基于Python,依赖Jinja2模板和WSGI服务的框架。当我们访问一个URL时,浏览器发出HTTP请求,WSGI接收到我们的请求,交给Flask框架提供的一系列功... 查看详情

3.2路由分发应用(代码片段)

...么微前端主要借鉴后端微服务的概念。简单地说,就是将一个巨无霸(Monolith)的前端工程拆分成一个一个的小工程。它们完全具备独立的开发、运行能力。整个系统就将由这些小工程协同合作,实现所有页面的展示与交互。可... 查看详情

python的flask介绍(代码片段)

...的使用根据URL返回特定网页实验步骤1.什么是Flask?Flask是一个web框架。也就是说Flask为你提供工具,库和技术来允许你构建一个web应用程序。这个wdb应用程序可以使一些web页面、博客、wiki、基于web的日历应用或商业网站。Flask属于... 查看详情

如何像实体框架一样在Core Data的一个类文件中对属于一个实体的方法进行分组?

】如何像实体框架一样在CoreData的一个类文件中对属于一个实体的方法进行分组?【英文标题】:HowtogroupmethodsbelongtooneentityinoneclassfileinCoreDatalikeinEntityFramework?【发布时间】:2010-06-0517:31:44【问题描述】:如何在像EntityFramework这... 查看详情

flask框架——flask简介(代码片段)

...例——flask实现用户登录Flask框架介绍一、Flask简介Flask是一个基于Python开发并且依赖jinja2模板和WerkzeugWSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人... 查看详情

flask的路由

...服务器route装饰器:可以使用Flask应用实例的route装饰器将一个URL规则绑定到一个视图函数上结果可以看到,由于hello2函数路径和请求方式和hello1一样,会被hello1覆盖掉,所以在访问的时候只会执行hello1,并不会执行hello2修改两个... 查看详情

django

...用  注:特别喜欢Django的Admin,给人的感觉非常棒,是一个很完美的自动化的管理界面。 Django框架的设计模式用的是MTV,借鉴了MVC框架的思想,MTV对应的也就是三个部分,Model(模型)、Template(模板)和View(视图)。  Mode... 查看详情

11.1flask框架介绍(代码片段)

FLASK框架框架介绍Flask是一个基于Python开发并且依赖jinja2模板和WerkzeugWSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求... 查看详情

微服务架构案例(01):项目技术选型简介,架构图解说明(代码片段)

...业务中比较常见,场景模式就是单个应用、单个数据库。一个程序包(例如war格式或者Jar格式)包含所有业务需求功能,这是一种比较传统的架构风格。单体架构的缺陷复杂性高,整个项目包含的模块多,依赖模糊,修改程序容... 查看详情

微服务架构案例(01):项目技术选型简介,架构图解说明(代码片段)

...业务中比较常见,场景模式就是单个应用、单个数据库。一个程序包(例如war格式或者Jar格式)包含所有业务需求功能,这是一种比较传统的架构风格。单体架构的缺陷复杂性高,整个项目包含的模块多,依赖模糊,修改程序容... 查看详情

微服务方式实现双重网关

参考技术A最近在做一个多项目整合的工作,因为每个项目都有自己的一套网关,每个网关都有自己的加解密算法,整合到一起要求对外提供统一的用户鉴权,而且不对原有系统做大规模的重构,基于这些现实考虑使用两重API网... 查看详情

微服务核心组件zuul网关原理剖析

...务服务的看门神,相比具体实现业务的系统服务来说它是一个边缘服务,主要提供动态路由,监控,弹性,安全性等功能。在分布式的微服务系统中,系统被拆为了多套系统,通过zuul网关来对用户的请求进行路由,转发到具体... 查看详情