Flask中endpoint的理解

在flask框架中,我们经常会遇到endpoint这个东西,最开始也没法理解这个到底是做什么的。最近正好在研究Flask的源码,也就顺带了解了一下这个endpoint

首先,我们看一个例子:

@app.route('/user/')defuser(name):return'Hello,%s'%name

这个是我们在用flask框架写网站中最常用的。

通过看源码,我们可以发现:

函数等效于

defuser(name)return'Hello,%s'%nameapp.add_url_rule('/user/','user', user)

这个add_url_rule函数在文档中是这样解释的:

add_url_rule(*args, **kwargs)

Connects a URL rule. Works exactly like the route() decorator. If a view_func is provided it will be registered with the endpoint.

add_url_rule有如下参数:

rule– the URL rule as string

endpoint– the endpoint for the registered URL rule. Flask itself assumes the name of the view function as endpoint

view_func– the function to call when serving a request to the provided endpoint

options– the options to be forwarded to the underlying Rule object. A change to Werkzeug is handling of method options. methods is a list of methods this rule should be limited to (GET, POST etc.). By default a rule just listens for GET (and implicitly HEAD). Starting with Flask 0.6, OPTIONS is implicitly added and handled by the standard request handling.

抛开options这个参数不谈,我们看看前三个参数。

rule:这个参数很简单,就是匹配的路由地址

view_func:这个参数就是我们写的视图函数

endpoint:这个参数就是我今天重点要讲的,endpoint

很多人认为:假设用户访问http://www.example.com/user/eric,flask会找到该函数,并传递name='eric',执行这个函数并返回值。

但是实际中,Flask真的是直接根据路由查询视图函数么?

在源码中我们可以发现:

每个应用程序app都有一个view_functions,这是一个字典,存储endpoint-view_func键值对。add_url_rule的第一个作用就是向view_functions中添加键值对(这件事在应用程序run之前就做好了)

每个应用程序app都有一个url_map,它是一个Map类(具体实现在werkzeug/routing.py中),里面包含了一个列表,列表元素是Role的实例(werkzeug/routing.py中)。add_url_rule的第二个作用就是向url_map中添加Role的实例(它也是在应用程序run之前就做好了)

我们可以通过一个例子来看:

app=Flask(__name__)@app.route('/test', endpoint='Test')deftest():pass@app.route('/', endpoint='index')defhello_world():return'Hello World!'if__name__=='__main__':print(app.view_functions)print(app.url_map)    app.run()

运行这个程序,结果是:

{'static': >, 'Test': , 'index': }Map([ Test>,

index>,

' (HEAD, OPTIONS, GET) -> static>]) * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

所以我们可以看出:这个url_map存储的是url与endpoint的映射!

回到flask接受用户请求地址并查询函数的问题。实际上,当请求传来一个url的时候,会先通过rule找到endpoint(url_map),然后再根据endpoint再找到对应的view_func(view_functions)。通常,endpoint的名字都和视图函数名一样。

这时候,这个endpoint也就好理解了:

实际上这个endpoint就是一个Identifier,每个视图函数都有一个endpoint,

当有请求来到的时候,用它来知道到底使用哪一个视图函数

在实际应用中,当我们需要在一个视图中跳转到另一个视图中的时候,我们经常会使用url_for(endpoint)去查询视图,而不是把地址硬编码到函数中。

这个时候,我们就不能使用视图函数名当endpoint去查询了

我们举个例子来说明。比如:

app=Flask(__name__)app.register_blueprint(user, url_prefix='user')app.register_blueprint(file, url_prefix='file')

我们注册了2个蓝图。

在user中(省略初始化过程):

@user.route('/article')defarticle():pass

在file中(省略初始化过程):

@file.route('/article')defarticle():pass

这时候,我们发现,/article这个路由对应了两个函数名一样的函数,分别在两个蓝图中。当我们使用url_for(article)调用的时候(注意,url_for是通过endpoint查询url地址,然后找视图函数),flask无法知道到底使用哪个蓝图下的endpoint,所以我们需要这样:

url_for('user.article')

推荐阅读更多精彩内容

  • 19年6月更新:该篇翻译已经被移到 TangYefei's Blog,相较于简书阅读体验会更好,如果喜欢请点个 ❤...
    tangyefei阅读 32,159评论 22 257
  • [TOC]一直想做源码阅读这件事,总感觉难度太高时间太少,可望不可见。最近正好时间充裕,决定试试做一下,并记录一下...
    何柯君阅读 4,636评论 3 92
  • 可以翻译成“视图入口”,就是个名字。url_for可以用到,其他方面也可以用到(比如导航条确定当前页面),因为en...
    卡萨诺瓦_阅读 151评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 105,028评论 12 126
  • 去年11月的一天,只因在校招网上多看了你一眼,所以才有了现在坐在麦迪斯顿的总部大楼里写着这篇文章,一切皆为缘分使然...
    逆旅少年jump阅读 415评论 0 0