当前位置:网站首页>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 .
边栏推荐
- 备份 TiDB 集群到持久卷
- [MySQL - Basic] transactions
- 一文读懂数仓中的pg_stat
- Dachang classic pointer written test questions
- 一. 基础概念
- Get webkitformboundary post login
- 实战:sqlserver 2008 扩展事件-XML转换为标准的table格式[通俗易懂]
- 基于深度学习的目标检测的更新迭代总结(持续更新ing)
- With st7008, the Bluetooth test is completely grasped
- Force buckle 88 Merge two ordered arrays
猜你喜欢
随机推荐
Force buckle 674 Longest continuous increasing sequence
AIRIOT助力城市管廊工程,智慧物联守护城市生命线
Dachang classic pointer written test questions
ASP.NET学习& asp‘s one word
Force buckle 912 Sort array
Update iteration summary of target detection based on deep learning (continuous update ing)
Oracle 存储过程之遍历
php 获取图片信息的方法
School 1 of vulnhub
AADL Inspector 故障树安全分析模块
【奖励公示】第22期 2022年6月奖励名单公示:社区明星评选 | 新人奖 | 博客同步 | 推荐奖
Cuda版本不一致,编译apex报错
有了ST7008, 蓝牙测试完全拿捏住了
机器学习笔记 - 使用Streamlit探索对象检测数据集
使用高斯Redis实现二级索引
ERROR: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your
Traversal of Oracle stored procedures
解决/bin/sh进去的容器运行可执行文件报not found的问题
Gorilla official: sample code for golang to open websocket client
With st7008, the Bluetooth test is completely grasped