当前位置:网站首页>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 .
边栏推荐
- Deep learning model compression and acceleration technology (VII): mixed mode
- 基于深度学习的目标检测的更新迭代总结(持续更新ing)
- Optimization cases of complex factor calculation: deep imbalance, buying and selling pressure index, volatility calculation
- 力扣599. 两个列表的最小索引总和
- Force buckle 2315 Statistical asterisk
- Lingyun going to sea | saihe & Huawei cloud: jointly help the sustainable development of cross-border e-commerce industry
- Mrs offline data analysis: process OBS data through Flink job
- 一文读懂数仓中的pg_stat
- 备份 TiDB 集群到持久卷
- Force buckle 2319 Judge whether the matrix is an X matrix
猜你喜欢
AADL Inspector 故障树安全分析模块
Optimization cases of complex factor calculation: deep imbalance, buying and selling pressure index, volatility calculation
使用高斯Redis实现二级索引
OneSpin 360 DV新版发布,刷新FPGA形式化验证功能体验
使用高斯Redis实现二级索引
php 获取图片信息的方法
Data island is the first danger encountered by enterprises in their digital transformation
Force buckle 599 Minimum index sum of two lists
微服务远程Debug,Nocalhost + Rainbond微服务开发第二弹
I wrote a markdown command line gadget, hoping to improve the efficiency of sending documents by garden friends!
随机推荐
Lingyun going to sea | yidiantianxia & Huawei cloud: promoting the globalization of Chinese e-commerce enterprise brands
Force buckle 459 Duplicate substring
Mongodb learn from simple to deep
一. 基础概念
TS quick start - Generic
Vulnhub tre1
Force buckle 2315 Statistical asterisk
理财产品要怎么选?新手还什么都不懂
图扑数字孪生煤矿开采系统,打造采煤“硬实力”
【Auto.js】自动化脚本
OneSpin 360 DV新版发布,刷新FPGA形式化验证功能体验
ASP. Net learning & ASP's one word
Phoenix JDBC
POJ 1742 Coins ( 单调队列解法 )「建议收藏」
数据孤岛是企业数字化转型遇到的第一道险关
Force buckle 599 Minimum index sum of two lists
ERROR: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your
Solve the problem that the executable file of /bin/sh container is not found
大厂经典指针笔试题
MIT science and technology review article: AgI hype around Gato and other models may make people ignore the really important issues