当前位置:网站首页>Flask1.1.4 werkzeug1.0.1 source code analysis: Routing
Flask1.1.4 werkzeug1.0.1 source code analysis: Routing
2022-07-07 20:23:00 【An engineer$】
Routing is roughly divided into two parts :
- Routing binding : take url_rule and view_func Bound to the falsk In the example , This is in the previous article Start process I've already talked about it in
- Route resolution : When the actual request comes , according to environ To match to the corresponding Rule, And from environ The parameters are resolved from , And then according to Rule.endpoint Go to view_functions Find the corresponding view_function To call
This article focuses on the second part ,Flask The route matching of is actually based on werkzeug.routing.Map and werkzeug.routing.Rule
We can write a simple demo, Learn how to use these two tools .
# structure map
url_map = Map([Rule("/a", endpoint='a'), Rule("/b", endpoint='b'), Rule("/c/<path_param>", endpoint='c')])
# call Map.bind() return MapAdapter object
urls = url_map.bind('eee.com', '/')
# MapAdapter.match() Make request matching
print(urls.match("/a"))
print(urls.match("/c/123"))
print(urls.match("/dd"))
give the result as follows :
# When matched, it will return (endpoint, view_func_args)
('a', {
})
('c', {
'path_param': '123'})
# It doesn't match Throw exceptions
Traceback (most recent call last):
File "/Users/panc/Documents/projects/PycharmProjects/grpc-client/pycode/flask_demo.py", line 9, in <module>
print(urls.match("/dd"))
File "/usr/local/Caskroom/miniconda/base/envs/python37/lib/python3.7/site-packages/werkzeug/routing.py", line 1945, in match
raise NotFound()
werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
ok, Now let's start to study Flask The routing process of ~
First of all, pay attention ,Flask There is no direct URL and view_func Connect , Instead, it adds endpoint The concept of . In fact, it's easy to understand ,URL Most of the time, it is not fixed , It also includes the parameter part , Not suitable for key. in addition , From the steps of processing the request , First, according to the request url Information to match the registered url_rule, And then find the corresponding view_func Perform logical . This is divided into two steps , take url Information and view_func Separate storage , And then through endpoint It seems appropriate to connect the two .
Start process It has been said in an article ,HTTP Format data to WSGI After formatting data , call flask_app(environ, start_response) Execute specific processing logic
class Flask(_PackageBoundObject):
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def wsgi_app(self, environ, start_response):
# Here we build flask.ctx.RequestContext object
# The build process includes Routing processing logic
ctx = self.request_context(environ)
error = None
try:
try:
# Routing logic is also included here Stack the current request context
# The purpose of stack entry is to pass some information to the following by non parameter transfer view_function
ctx.push()
# RequestContext Object construction and push The routing logic has been handled in the process of
# After that, you only need to get the currently requested RequestContext example , use endpoint Just get and call the method
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# Clean up the current context after the request processing Out of the stack
ctx.auto_pop(error)
def request_context(self, environ):
# Notice that the first parameter is flask example
return RequestContext(self, environ)
def create_url_adapter(self, request):
if request is not None:
subdomain = (
(self.url_map.default_subdomain or None)
if not self.subdomain_matching
else None
)
# Previous demo I've seen this inside bind_to_environ and bind It's the same thing
# Return to one MapAdapter object
return self.url_map.bind_to_environ(
request.environ,
server_name=self.config["SERVER_NAME"],
subdomain=subdomain,
)
def full_dispatch_request(self):
self.try_trigger_before_first_request_functions()
try:
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
# Perform the requested
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
# Here will be view_function Return Convert to Response object
return self.finalize_request(rv)
def dispatch_request(self):
# Take out the current RequestContext object And get it request attribute
req = _request_ctx_stack.top.request
# Route matching failed Throw exceptions
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule
# Final Rule Object's endpoint To find the corresponding view_function And call... With parameters Execute specific logic
return self.view_functions[rule.endpoint](**req.view_args)
Now let's look at the key of routing RequestContext
class RequestContext(object):
def __init__(self, app, environ, request=None, session=None):
# Saved here flask app example
self.app = app
if request is None:
# Use environ Construct a Request object
request = app.request_class(environ)
self.request = request
self.url_adapter = None
try:
# here Is to Map.bind Got a MapAdapter object
self.url_adapter = app.create_url_adapter(self.request)
except HTTPException as e:
self.request.routing_exception = e
self.flashes = None
self.session = session
def match_request(self):
try:
# In fact, that is MapAdapter.match() There is no reference here because it was Map.bind_to_environ()
result = self.url_adapter.match(return_rule=True)
# unpacking url_rule namely Rule Object contains endpoint Information view_args The parameter
# in other words RequestContext object push() when , The route resolution process has been completed
# Bind the parsing result to RequestContext Object's request Attribute
self.request.url_rule, self.request.view_args = result
except HTTPException as e:
self.request.routing_exception = e
def push(self):
"""Binds the request context to the current context."""
# Stack the current request context object Convenient for subsequent delivery
_request_ctx_stack.push(self)
if self.url_adapter is not None:
# The key
self.match_request()
ok, At this point, the route parsing process is over ~
To sum up :
- The core of the core is still werkzeug Of Map、Rule、MapAdapter object
- The binding of route is flask_app.add_url_rule() There are many ways , It can be app.route() Or use blueprint, But the essence is flask_app.add_url_rule()
- Route resolution , Nature is map_adapter = url_map.bind_to_environ() -> rule, view_args = map_adapter.match() -> view_functions[rule.endpoint] (**view_args)
- among url_map.bind_to_environ() stay structure RequestContext Object , match Operation in RequestContext.push() When the . After the context object is ready to be merged into the stack , Just take out the current request context object , And then use endpoint To find the corresponding view_func And execute it .
边栏推荐
- 机器学习笔记 - 使用Streamlit探索对象检测数据集
- Airiot helps the urban pipe gallery project, and smart IOT guards the lifeline of the city
- 写了个 Markdown 命令行小工具,希望能提高园友们发文的效率!
- 想杀死某个端口进程,但在服务列表中却找不到,可以之间通过命令行找到这个进程并杀死该进程,减少重启电脑和找到问题根源。
- Force buckle 459 Duplicate substring
- Try the tuiroom of Tencent cloud (there is an appointment in the evening, which will be continued...)
- Meta Force原力元宇宙系统开发佛萨奇模式
- 大厂经典指针笔试题
- Mrs offline data analysis: process OBS data through Flink job
- TS快速入门-泛型
猜你喜欢

BI的边界:BI不适合做什么?主数据、MarTech?该如何扩展?

让这个CRMEB单商户微信商城系统火起来,太好用了!

Airiot helps the urban pipe gallery project, and smart IOT guards the lifeline of the city

Mongodb learn from simple to deep

使用高斯Redis实现二级索引

Vulnhub's funfox2

Nebula Importer 数据导入实践

机械臂速成小指南(十二):逆运动学分析

【论文阅读】MAPS: Multi-agent Reinforcement Learning-based Portfolio Management System

MRS离线数据分析:通过Flink作业处理OBS数据
随机推荐
【mysql篇-基础篇】事务
Jenkins 用户权限管理
一文读懂数仓中的pg_stat
力扣674. 最长连续递增序列
MRS离线数据分析:通过Flink作业处理OBS数据
PHP method of obtaining image information
【解决】package ‘xxxx‘ is not in GOROOT
使用 BR 备份 TiDB 集群数据到 Azure Blob Storage
微服务远程Debug,Nocalhost + Rainbond微服务开发第二弹
Mongodb learn from simple to deep
【Auto.js】自动化脚本
深度学习模型压缩与加速技术(七):混合方式
Useful win11 tips
《数字图像处理原理与实践(MATLAB版)》一书之代码Part2[通俗易懂]
如何满足医疗设备对安全性和保密性的双重需求?
Prometheus remote_write InfluxDB,unable to parse authentication credentials,authorization failed
使用camunda做工作流设计,驳回操作
浅尝不辄止系列之试试腾讯云的TUIRoom(晚上有约,未完待续...)
Phoenix JDBC
Implement secondary index with Gaussian redis