Python Web Flask源码解读——路由原理!

Python Flask 简明教程(7)--路由使用方法详解 本文目录1. 概述2. 简单路由3. 处理HTTP方法4. 绑定多个URL5. URL参数6. 动态URL7. 小结 1. 概述 路由其实就是URL和Python函数的映射关系,说的再明白点,就是客户端请求哪个路径交给哪个函数处理的问题。 通过给函数添加装饰器@app.route,即可定义路由,装饰器的参数即为对应的URL。 2. 简单路由 编写route.py,代码如下: from flask import Flask app = Flask(__name__) @app.route('/hello') 阅读详情

 接 上一篇 的话题,继续阅读 Flask 的源码,来看一下这个框架 路由原理 。

0x00 路由原理

首先看下 Flask 的简易用法

 

Python资源共享群:484031800

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
    return f'Hello, World!'
if __name__ == '__main__':
    app.run()
复制代码

在 Flask 中是使用 @app.route 这个装饰器来实现 url 和方法之间的映射的。

Flask.route

打开 route 方法

def route(self, rule, **options):
    """这个方法的注释非常详细,为了避免代码篇幅过长,这里省略注释"""
    def decorator(f):
        self.add_url_rule(rule, f.__name__, **options)
        self.view_functions[f.__name__] = f
        return f
    return decorator
复制代码

在 route 方法中有两个参数 rule 和 options 。 rule 是 url 规则, options 参数主要是 werkzeug.routing.Rule 类使用。 方法内部还定义 decorator 方法,将 url 路径规则,和方法名称对应关系保存起来,然后将函数方法名与函数对象也对应的保存到一个字典中。

Flask.add_url_rule

def add_url_rule(self, rule, endpoint, **options):
    options['endpoint'] = endpoint
    options.setdefault('methods', ('GET',))
    self.url_map.add(Rule(rule, **options))
复制代码

这个方法的注释也是很详细的,大概的意思如果定义了一个方法

@app.route('/')
def index():
    pass
复制代码

等价于

def index():
    pass
app.add_url_rule('index', '/')
app.view_functions['index'] = index
复制代码

最后调用 url_map.add 方法将 rule 和 option 构造成 Rule 添加到一个 Map 对象中。

Rule

Rule 表示 url 规则,它是在 werkzeug 函数库中定义的类。

url_map 是一个自定义的 Map 对象。它的目的就是实现 url 与方法之间映射关系。

Map.add

def add(self, rulefactory):
    """Add a new rule or factory to the map and bind it.  Requires that the
    rule is not bound to another map.
    :param rulefactory: a :class:`Rule` or :class:`RuleFactory`
    """
    for rule in rulefactory.get_rules(self):
        rule.bind(self)
        self._rules.append(rule)
        self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
    self._remap = True
复制代码

在 add 方法中就调用了 rule 中的 bind 方法,这里才是 真正实现绑定的逻辑。

Rule.bind

def bind(self, map, rebind=False):
    """Bind the url to a map and create a regular expression based on
    the information from the rule itself and the defaults from the map.
    :internal:
    """
    if self.map is not None and not rebind:
        raise RuntimeError('url rule %r already bound to map %r' %
                           (self, self.map))
    # 将url与map对应起来,即将map保存在rule对象自身的map属性上
    self.map = map
    if self.strict_slashes is None:
        self.strict_slashes = map.strict_slashes
    if self.subdomain is None:
        self.subdomain = map.default_subdomain
    rule = self.subdomain + '|' + (self.is_leaf and self.rule or self.rule.rstrip('/'))
    self._trace = []
    self._converters = {}
    self._weights = []
    regex_parts = []
    for converter, arguments, variable in parse_rule(rule):
        if converter is None:
            regex_parts.append(re.escape(variable))
            self._trace.append((False, variable))
            self._weights.append(len(variable))
        else:
            convobj = get_converter(map, converter, arguments)
            regex_parts.append('(?P<%s>%s)' % (variable, convobj.regex))
            self._converters[variable] = convobj
            self._trace.append((True, variable))
            self._weights.append(convobj.weight)
            self.arguments.add(str(variable))
            if convobj.is_greedy:
                self.greediness += 1
    if not self.is_leaf:
        self._trace.append((False, '/'))
    if not self.build_only:
        regex = r'^%s%s$' % (
            u''.join(regex_parts),
            (not self.is_leaf or not self.strict_slashes) and \
                '(?<!/)(?P<__suffix__>/?)' or ''
        )
        self._regex = re.compile(regex, re.UNICODE)
复制代码

在 bind 方法中的 for 循环中调用了 parse_url 方法,这是一个生成器函数,它使用正则进行并 yield 回一个元组。这个方法的细节还是挺多的,但这里我们抓住主脉络,先把整体流程搞清楚。

在 Flask 启动时从装饰器 route 开始就把会把 url 和响应的函数方法对应起来。

调用逻辑为

Flask.route -> Flask.add_url_rule -> Map.add -> Rule.bind
复制代码

0x01 响应请求

当服务启动之后, Flask 会默认开启一个 Web 服务器,便于开发调试,而实际环境中可能会使用 nginx+gunicorn 等工具进行部署。由于部署不是本节主题,我们还是专注于客户端请求是如何响应的。

在上一篇我们知道 Flask 通过 Werkzeug 函数库中的 run_simple 方法将服务启动了。

当客户端发送请求时这个方法会被执行

Flask.wsgi_app

def wsgi_app(self, environ, start_response):
    """The actual WSGI application.  This is not implemented in
    `__call__` so that middlewares can be applied:
        app.wsgi_app = MyMiddleware(app.wsgi_app)
    :param environ: a WSGI environment
    :param start_response: a callable accepting a status code, a list of headers and an optional
    exception context to start the response
    """
    with self.request_context(environ):
        rv = self.preprocess_request()
        if rv is None:
            rv = self.dispatch_request()
        response = self.make_response(rv)
        response = self.process_response(response)
        return response(environ, start_response)
复制代码

environ 是 Web 服务器传递过来的参数, request_context(environ) 会创建一个请求上下文实例,通过预处理 preprocess_request 之后就会进入分发请求 dispatch_request ,然后是执行响应 make_response 和 process_response ,最后返回 response 。

这里我们重点关注 dispatch_request 。

Flask.dispatch_request

def dispatch_request(self):
    """Does the request dispatching.  Matches the URL and returns the
    return value of the view or error handler.  This does not have to
    be a response object.  In order to convert the return value to a
    proper response object, call :func:`make_response`.
    """
    try:
        endpoint, values = self.match_request()
        return self.view_functions[endpoint](**values)
    except HTTPException as e:
        handler = self.error_handlers.get(e.code)
        if handler is None:
            return e
        return handler(e)
    except Exception as e:
        handler = self.error_handlers.get(500)
        if self.debug or handler is None:
            raise
        return handler(e)
复制代码

这个方法的核心就是 match_request ,通过匹配客户端请求的 url 规则找到对应函数方法。

Flask.match_request

def match_request(self):
    """Matches the current request against the URL map and also
    stores the endpoint and view arguments on the request object
    is successful, otherwise the exception is stored.
    """
    rv = _request_ctx_stack.top.url_adapter.match()
    request.endpoint, request.view_args = rv
    return rv
复制代码

匹配完成后就会调用 self.view_functions[endpoint](**values) 来执行对应函数方法,并返回函数的返回值。

如果上述 dispatch_request 没有匹配到 url 规则,则会执行 error_handlers 字典中找到对应的错误码执行 handler 方法。

至此 url 路由规则匹配过程就完成了。

0x02 总结一下

在 Flask 启动后会把 route 装饰器解析后,把 url 规则与函数方法进行对应保存。 在客户端请求时, Flask.wsgi_app 方法会被执行,并开始匹配 url 找到对应的方法,执行后将结果返回。 

flask源码 架构图 基于flask0.1 以长图片的形式 诠释 flask0.1 源代码的主要结构,同时标注其之间的联系。希望对看源码的童鞋有所帮助。 立即下载

相关推荐

Innovus ECO技巧:用setEcoMode+ecoAddRepeater实现批量buffer替换的5个关键步骤

本文详细介绍了在Cadence Innovus工具中,利用setEcoMode与ecoAddRepeater命令实现高效、批量Buffer/Inverter替换的工程化策略。通过启用批处理模式、构建可维护的替换规则、掌握高级定位技巧以及规避布线陷阱等5个关键步骤,帮助芯片设计工程师在ECO阶段大幅提升修改效率与质量,确保设计稳定签核。

d6e7f8的博客 1117

深入理解Flask路由的实现机制

本篇介绍 Flask 路由的基本用法,并且通过部分源代码深入浅出阐述 Flask 路由的实现机制。

王敏的专栏 2925

淘宝x-mini-wua生成机制与硬件信息关联性深度解析

本文深度解析了淘宝x-mini-wua的生成机制与硬件信息的关联性,详细介绍了其作为设备指纹令牌的核心作用及技术实现细节。通过分析基础硬件层、环境特征层和行为特征层的数据采集,揭示了淘宝如何利用AES加密和分级加密策略防止破解,并探讨了其安全防护与对抗策略。

weixin_29243279的博客 230

python flask源码解析_flask 源码解析:路由

3.flask 源码解析:路由构建路由规则一个 web 应用不同的路径会有不同的处理函数,路由就是根据请求的 URL 找到对应处理函数的过程。在执行查找之前,需要有一个规则列表,它存储了 url 和处理函数的对应关系。最容易想到的解决方案就是定义一个字典,key 是 url,value 是对应的处理函数。如果 url 都是静态的(url 路径都是实现确定的,没有变量和正则匹配),那么路由的过程就是...

weixin_31716637的博客 302

单细胞空间转录组分析流程学习python版(三)

空转python版学习

zfyyzhys的博客 2085

一文读懂AI大模型时代的RAG技术

RAG(Retrieval-Augmented Generation,检索增强生成) 是一种结合检索技术与生成模型的技术架构,旨在通过动态引入外部知识库增强大语言模型(LLM)的生成能力。其核心思想是通过检索系统从外部数据源(如企业知识库、实时文档等)获取相关信息,并将检索结果作为上下文输入生成模型,以提高生成答案的准确性、时效性和专业性

awei0916的专栏 2119

Flask和@app.route(1)

本文我们先来说说Flask,深入探讨Flask如何实现在函数上方写“@app.route()”就能在因特网上输出函数的执行结果。下面是Flask主页给我们的第一个例子,我们现在就由它入手,深入理解“@app.route()”是如何工作的。 app = Flask(__name__)@app.route("/") def hello(): return "Hello World!"@app.r

晓 7840

LLaMA Factory添加新模型template的实战解析

本文主要介绍了LLaMA Factory添加新模型template的实战解析,希望对使用大语言模型的同学们有所帮助。 文章目录 1. 前言 2. 实战解析 2.1 检查代码 2.2 修改代码

herosunly的博客 19万+

Python进阶(五十)浅析Flask运行原理

在学习Python Web开发过程中,掌握了Flask的开发方法。经过一段时间的视频学习,回过头来对Flask的运行原理做一简要解析,以增强自己对Flask的了解。

IT全栈 华强工作室 2万+

WS2812和homeassistant握手

本文学习了WS2812和homeassistant握手,后期会分享更多有趣物联网的操作从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。...

vor234的博客 811

2.1 直流无刷电机(BLDC):机械结构与组件

本文详细解析了直流无刷电机(BLDC)的机械结构与核心组件。BLDC电机通过电子换向取代传统机械电刷,主要包含定子、转子、位置传感器和电子换向器四大组件。定子采用硅钢片叠压结构,配有三相绕组;转子采用永磁体材料,结构设计影响转矩特性;位置传感器(霍尔、编码器、旋转变压器)实现精准换向;电子换向器通过功率逆变拓扑完成电流控制。文章还对比了不同绕组类型、永磁材料及传感器技术的性能特点,为BLDC电机的设计与应用提供了理论基础。

技术工作者 391

flask的路由实现原理(/hello和/hello/的区别)

咱们以路由/hello和/hello/的区别为例 下面我们在浏览器的地址栏中访问/hello,注意不是/hello/ 可以看出有两次的请求,因为这种写法在flask的内部是经过了转发的,怎么看出来是经过了转发,通过http的headers中的Location可以看出是转发到了这个地址。 不管你在url中写的是/hello还是/hello/,在浏览器的地址栏中看到的都是/h...

Null的博客 2614

092、Python在芯片验证中的应用:从脚本小子到验证架构师

Python在芯片验证中的高效应用 本文通过实际案例展示了Python在芯片验证中的关键作用。凌晨三点的调试场景揭示了传统方法的局限,Python脚本能在20分钟内分析80GB波形数据定位FIFO指针问题。文章重点介绍了两个核心工具: 智能日志分析系统:通过正则表达式和上下文分析,自动分类百万行验证日志中的错误,生成可视化报告,效率远超传统grep方法。 寄存器模型生成器:将Excel表格自动转换为UVM寄存器模型代码,将原本需要两周的手工工作缩短至两小时,同时保证零错误。 文章还展示了Python与Sys

z534437748的博客 72

Python Web Flask源码解读(二)——路由原理

继续阅读Flask的源码

终身开发者 172

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

python flask源码解析_Python Web Flask源码解读(二)——路由原理

关于我一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。Github:https://github.com/hylinux1024微信公众号:终身开发者(angrycode)接上一篇的话题,继续阅读Flask的源码,来看一下这个框架路由原理。0x00 路由原理首先看下Flask的简易用法...

weixin_39539761的博客 148

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Python Web Flask源码解读!启动流程!

0x00 什么是WSGI Web Server Gateway Interface 它由Python标准定义的一套Web Server与Web Application的接口交互规范。 WSGI不是一个应用、框架、模块或者库,而是规范。、 Python资源共享群:626017123 那什么是Web Server(Web服务器)和什么是Web Applicati...

Pythoncxy的博客 185

Python Web Flask源码解读!模板渲染过程!

关于我 编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。 Github: github.com/hylinux1024 微信公众号:angrycode Python资源共享群:484031800 前面对 Flask 启动流程 和路由原理都进行了源码走读。今天我们看看 模板渲染 的过程。 ...

Pythoncxy的博客 375

python web 模版_Python Web Flask源码解读!模板渲染过程!

关于我编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。微信公众号:angrycodePython资源共享群:484031800前面对 Flask 启动流程 和路由原理都进行了源码走读。今天我们看看 模板渲染 的过程。0x00 使用模板首先看一个来自官方文档使用模板渲染的例子from flask...

weixin_39637589的博客 245

Python Web Flask源码解读(三)——模板渲染过程

关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。 Github:https://github.com/hylinux1024 微信公众号:终身开发者(angrycode) 前面对Flask启动流程和路由原理都进行了源码走读。今天我们看看模板渲染的过程。 0x00 ...

weixin_30364147的博客 274

python模板过程_Python Web Flask源码解读(三)——模板渲染过程

关于我一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。Github:https://github.com/hylinux1024微信公众号:终身开发者(angrycode)前面对Flask启动流程和路由原理都进行了源码走读。今天我们看看模板渲染的过程。0x00 使用模板首先看一个来自官...

weixin_39674028的博客 258

Python明星web框架Flask

Flask简介Flask是一个相对于Django而言轻量级的Web框架。和Django大包大揽不同,Flask建立于一系列的开源软件包之上,这其中 最主要的是WSGI应用开发库Werkzeug和模板引擎Jinja,werkzeug和Jinja这两个库和Flask一样,都是pocoo团队开发的。

Dimikart的博客 2290

python的flask框架的使用的详细步骤

2018.05.16********************************************************** author: wills 阅读以下内容默认掌握的知识:: 1. python基础 2. 会使用pip工具 3. 能熟练使用pycharm工具 4. 掌握virtualenv工具,能够自己安装python的虚拟环境并且使用虚拟环...

星河灿烂的博客 6万+

python之django框架(路由列表)

前言 Python常用的web框架有django,flask,tornado,bottle等,这些Python框架,用来帮助你更轻松的创建web应用。这些框架把相应的模块组织起来,使得构建应用的时候可以更快捷,也不用去关注一些细节(例如socket和协议),所以需要的都在框架里了。 django 框架是python开发的常用web框架 深度解析下来,django其中一个的重要特性就是使用了路由的...

weixin_43178103的博客 650
上一篇: 资深程序员经典总结:MySQL的并发控制原理!
下一篇: Python学习的必备法宝,随查随用,太方便了吧!
普通网友
博客等级 码龄7年 438粉丝 263原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值