目次
ソースシリーズ:
Flask ソース コードの記事: wsgi、Werkzeug、および Flask 起動ワークフロー
Flask ソースコードの記事: 2 単語で Flask がコンテキスト原則であることを完全に理解
具体的な分析プロセスを読みたくない場合は、概要を直接読むと理解できます。
1 起動時のルーティング関連操作
いわゆるルーティング原理は、Flask が独自のルーティング システムをどのように作成し、リクエストが来たときに、ルーティング システムに従って処理機能を正確に見つけてリクエストに応答するかを示します。
このセクションでは、次のように、最も単純な Flask アプリケーションの例を使用してルーティングの原理を説明します。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
(1) app.route()を解析する
まず、ルートの登録はscaffold (Flask が scaffold を継承) パッケージ配下のroute()
デコレータを通じて実現されており、そのソースコードは次のとおりです。
def route(self, rule: str, **options: t.Any) -> t.Callable:
def decorator(f: t.Callable) -> t.Callable:
# 获取endpoint
endpoint = options.pop("endpoint", None)
# 添加路由,rule就是app.route()传来的路由字符串,及'/'
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
このデコレーターは主に 2 つのことを行うことがわかります: 1. の取得endpoint
、2. ルーティングの追加。
これらの中で最も重要なのは、ルート マッピングを追加するために使用される関数ですadd_url_rule()
。
補充:
- エンドポイントは、後で Flask がルーティングと関数名のマッピングを保存するときに使用されます。指定しない場合、デフォルトは装飾された関数名です。使い方は後で分析します。
- app.route() の本質はやはり add_url_rule() 関数であるため、この関数を直接使用することもできます。使用方法については、記事Flask ルーティングを参照してください。
(2) add_url_rule()を解析する
add_url_rule の動作を見てみましょう。そのコア ソース コードは次のとおりです。
class Flask(Scaffold):
# 这里只有要讨论的主要代码,其他代码省略了
url_rule_class = Rule
url_map_class = Map
def __init__(
self,
import_name: str,
static_url_path: t.Optional[str] = None,
static_folder: t.Optional[t.Union[str, os.PathLike]] = "static",
static_host: t.Optional[str] = None,
host_matching: bool = False,
subdomain_matching: bool = False,
template_folder: t.Optional[str] = "templates",
instance_path: t.Optional[str] = None,
instance_relative_config: bool = False,
root_path: t.Optional[str] = None,
):
super().__init__(
import_name=import_name,
static_folder=static_folder,
static_url_path=static_url_path,
template_folder=template_folder,
root_path=root_path,
)
self.url_map = self.url_map_class()
self.url_map.host_matching = host_matching
self.subdomain_matching = subdomain_matching
def add_url_rule(
self,
rule: str,
endpoint: t.Optional[str] = None,
view_func: t.Optional[t.Callable] = None,
provide_automatic_options: t.Optional[bool] = None,
**options: t.Any,
) -> None:
# 1.如果没提供endpoint,获取默认的endpoint
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func) # type: ignore
options["endpoint"] = endpoint
# 2.获取请求方法,在装饰器@app.route('/index', methods=['POST','GET'])的method参数
# 如果没有指定,则给个默认的元组("GET",)
# 关于provide_automatic_options处理一些暂不看
methods = options.pop("methods", None)
if methods is None:
methods = getattr(view_func, "methods", None) or ("GET",)
if isinstance(methods, str):
raise TypeError(
"Allowed methods must be a list of strings, for"
' example: @app.route(..., methods=["POST"])'
)
methods = {
item.upper() for item in methods}
# Methods that should always be added
required_methods = set(getattr(view_func, "required_methods", ()))
# starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.
if provide_automatic_options is None:
provide_automatic_options = getattr(
view_func, "provide_automatic_options", None
)
if provide_automatic_options is None:
if "OPTIONS" not in methods:
provide_automatic_options = True
required_methods.add("OPTIONS")
else:
provide_automatic_options = False
# Add the required methods now.
methods |= required_methods
# 3.重要的一步:url_rule_class方法实例化Rule对象
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options # type: ignore
# 4.重要的一步:url_map(Map对象)的add方法
self.url_map.add(rule)
# 5.判断endpoint和view_func的映射存不存在,如果已经有其他view_func用了这个endpoint,则报错,否则新的映射加到self.view_functions里
# self.view_functions继承自Scaffold,是一个字典对象
if view_func is not None:
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
raise AssertionError(
"View function mapping is overwriting an existing"
f" endpoint function: {
endpoint}"
)
self.view_functions[endpoint] = view_func
上記のソース コードを分析すると、このメソッドは主に次のことを行います。
- 指定されていない場合は
endpoint
、デフォルトを取得しますendpoint
。 - デコレータ
@app.route('/index', methods=['POST','GET'])
のパラメータでリクエスト メソッドを取得しますmethod
。指定されていない場合は、デフォルトのタプル ("GET",) を指定します。 self.url_rule_class()
:Rule
オブジェクトをインスタンス化します。これについては、Rule クラスで後述します。self.url_map.add()
メソッドを呼び出します。self.url_map はMap
オブジェクトです。これについては後で説明します。self.view_functions[endpoint] = view_func
endpointとview_funcのマッピングを追加します。
このうち、Rule
オブジェクトとサムのインスタンス化self.url_map.add()
は Falsk ルーティングの核心であり、以下ではRule
クラスとMap
クラスを分析します。
(3) Ruleクラスを解析する
Rule
クラスはwerkzeug.routing
モジュールの下にあり、そのソース コードはさらに続きます。ここでは、次のように、使用するメイン コードのみを抽出します。
class Rule(RuleFactory):
def __init__(
self,
string: str,
methods: t.Optional[t.Iterable[str]] = None,
endpoint: t.Optional[str] = None,
# 此处省略了其他参数的代码 ...
) -> None:
if not string.startswith("/"):
raise ValueError("urls must start with a leading slash")
self.rule = string
self.is_leaf = not string.endswith("/")
self.map: "Map" = None # type: ignore
self.methods = methods
self.endpoint: str = endpoint
# 省略了其他初始化的代码
def get_rules(self, map: "Map") -> t.Iterator["Rule"]:
"""获取map对象的rule迭代器"""
yield self
def bind(self, map: "Map", rebind: bool = False) -> None:
"""把map对象绑定到Rule对象上,并且根据rule和map信息创建一个path正则表达式,存储在rule对象的self._regex属性里,路由匹配的时候用"""
if self.map is not None and not rebind:
raise RuntimeError(f"url rule {
self!r} already bound to map {
self.map!r}")
# 把map对象绑定到Rule对象上
self.map = map
if self.strict_slashes is None:
self.strict_slashes = map.strict_slashes
if self.merge_slashes is None:
self.merge_slashes = map.merge_slashes
if self.subdomain is None:
self.subdomain = map.default_subdomain
# 调用compile方法创建一个正则表达式
self.compile()
def compile(self) -> None:
"""编写正则表达式并存储到属性self._regex中"""
# 此处省略了正则的解析过程代码
regex = f"^{
''.join(regex_parts)}{
tail}$"
self._regex = re.compile(regex)
def match(
self, path: str, method: t.Optional[str] = None
) -> t.Optional[t.MutableMapping[str, t.Any]]:
"""这个函数用于校验传进来path参数(路由)是否能够匹配,匹配不上返回None"""
# 省去了部分代码,只摘录了主要代码,看一下大致逻辑即可
if not self.build_only:
require_redirect = False
# 1.根据bind后的正则结果(self._regex正则)去找path的结果集
m = self._regex.search(path)
if m is not None:
groups = m.groupdict()
# 2.编辑匹配到的结果集,加到一个result字典里并返回
result = {
}
for name, value in groups.items():
try:
value = self._converters[name].to_python(value)
except ValidationError:
return None
result[str(name)] = value
if self.defaults:
result.update(self.defaults)
return result
return None
Rule
クラスはRuleFactory
クラスを継承し、主なパラメータは次のとおりです。
string
: ルート文字列methods
: ルートメソッドendpoint
:エンドポイントパラメータ
Rule インスタンスは URL パターンを表し、WSGI アプリケーションはさまざまな URL パターンを処理し、同時に多くの Rule インスタンスを生成し、これらのインスタンスはパラメータとして Map クラスに渡されます。
(4) Mapクラスを解析する
Map
このクラスも werkzeug.routing モジュールの下にあり、多くのソース コードがあります。ここでは使用する主なコードのみを抜粋します。主なソース コードは次のとおりです。
class Map:
def __init__(
self,
rules: t.Optional[t.Iterable[RuleFactory]] = None
# 此处省略了其他参数
) -> None:
# 根据传进来的rules参数维护了一个私有变量self._rules列表
self._rules: t.List[Rule] = []
# endpoint和rule的映射
self._rules_by_endpoint: t.Dict[str, t.List[Rule]] = {
}
# 此处省略了其他初始化操作
def add(self, rulefactory: RuleFactory) -> None:
"""
把Rule对象或一个RuleFactory对象添加到map并且绑定到map,要求rule没被绑定过
"""
for rule in rulefactory.get_rules(self):
# 调用rule对象的bind方法
rule.bind(self)
# 把rule对象添加到self._rules列表里
self._rules.append(rule)
# 把endpoint和rule的映射加到属性self._rules_by_endpoint里
self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
self._remap = True
def bind(
self,
server_name: str,
script_name: t.Optional[str] = None,
subdomain: t.Optional[str] = None,
url_scheme: str = "http",
default_method: str = "GET",
path_info: t.Optional[str] = None,
query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None,
) -> "MapAdapter":
"""
返回一个新的类MapAdapter
"""
server_name = server_name.lower()
if self.host_matching:
if subdomain is not None:
raise RuntimeError("host matching enabled and a subdomain was provided")
elif subdomain is None:
subdomain = self.default_subdomain
if script_name is None:
script_name = "/"
if path_info is None:
path_info = "/"
try:
server_name = _encode_idna(server_name) # type: ignore
except UnicodeError as e:
raise BadHost() from e
return MapAdapter(
self,
server_name,
script_name,
subdomain,
url_scheme,
path_info,
default_method,
query_args,
)
Map
クラスには 2 つの非常に重要な属性があります。
self._rules
、属性は一連の Rule オブジェクトを格納するリストです。self._rules_by_endpoint
:
コアメソッドがありますadd()
。ここでの分析app.add_url_rule()
メソッドはステップ4で呼び出されるメソッドです。詳しくは後述する。
(5) MapAdapterクラスを解析する
Map
クラスでは、MapAdapter
クラスが使用されます。このクラスについて理解しましょう。
class MapAdapter:
"""`Map.bind`或`Map.bind_to_environ` 会返回这个类
主要用来做匹配
"""
def match(
self,
path_info: t.Optional[str] = None,
method: t.Optional[str] = None,
return_rule: bool = False,
query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None,
websocket: t.Optional[bool] = None,
) -> t.Tuple[t.Union[str, Rule], t.Mapping[str, t.Any]]:
"""匹配请求的路由和Rule对象"""
# 只摘摘录了主要代码,省略了大量代码...
# 这里是主要步骤:遍历map对象的rule列表,依次和path进行匹配
for rule in self.map._rules:
try:
# 调用rule对象的match方法返回匹配结果
rv = rule.match(path, method)
except RequestPath as e:
# 下面省略了大量代码...
# 返回rule对象(或endpoint)和匹配的路由结果
if return_rule:
return rule, rv
else:
return rule.endpoint, rv
Map.bind
またはMap.bind_to_environ
メソッドがMapAdapter
オブジェクトを返します。
MapAdapter
オブジェクトのコア メソッドは、主match
なステップがマップ オブジェクトのルール リストを走査し、順にパスと照合することです。もちろん、ルール オブジェクトの match メソッドが呼び出され、照合結果が返されます。
Map
次に、クラスとオブジェクトがどのように結合され、少し独立して使用できるかを見てみましょうRlue
。次の例を参照してください。
from werkzeug.routing import Map, Rule
m = Map([
Rule('/', endpoint='index'),
Rule('/blog', endpoint='blog/index'),
Rule('/blog/<int:id>', endpoint='blog/detail')
])
# 返回一个MapAdapter对象
map_adapter = m.bind("example.com", "/")
# MapAdapter对象的 match方法会返回匹配的结果
print(map_adapter.match("/", "GET"))
# ('index', {})
print(map_adapter.match("/blog/42"))
# ('blog/detail', {'id': 42})
print(map_adapter.match("/blog"))
# ('blog/index', {})
Map
オブジェクトがオブジェクトbind
を返しMapAdapter
、MapAdapter
そのオブジェクトのメソッドがmatch
ルートの一致する結果を見つけることができることがわかります。
(6) url_rule_class()を解析する
add_url_rule
最初の主要なステップは、オブジェクトrule = self.url_rule_class(rule, methods=methods, **options)
を作成することですRule
。
Rlue
クラスを分析すると、Rule オブジェクトには主にstring
(ルーティング文字列)、methods
、およびendpoint
3 つの属性があることがわかりました。以下の具体的な例を使用して、インスタンス化されたRule
オブジェクトがどのように見えるかを確認してください。
引き続き冒頭の最上位の例ですが、@app.route('/')
次のように、コードを渡した後に Rule オブジェクトがインスタンス化されるときのオブジェクトの特定のプロパティをデバッグを通じて見てみましょう。
rule
ルール オブジェクトの属性は渡されたルートであり、endpoint
属性は関数名を通じて取得され、method
属性はサポートされているリクエスト メソッドであり、OPTIONS
デフォルトで「HEAD」が追加されていることがわかります。
(7) 解析map.add(rule)
add_url_rule
2 番目の主要な手順は、オブジェクトの add メソッドself.url_map.add(rule)
を呼び出すことです。Map
ステップ 4 で Map オブジェクトを分析するときに言及しましたが、戻ってこのメソッドの動作を詳しく見てみましょう。
def add(self, rulefactory: RuleFactory) -> None:
"""
把Rule对象或一个RuleFactory对象添加到map并且绑定到map,要求rule没被绑定过
"""
for rule in rulefactory.get_rules(self):
# 调用rule对象的bind方法
rule.bind(self)
# 把rule对象添加到self._rules列表里
self._rules.append(rule)
# 把endpoint和rule的映射加到属性self._rules_by_endpoint里
self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
self._remap = True
実際、主なことは、前の手順でインスタンス化した Rule オブジェクトまたは RuleFactory オブジェクトを Map オブジェクトに追加し、それをマップにバインドすることです。
主に次の 2 つのことを行いました。
- ルール オブジェクトのバインド メソッドを呼び出す
rule.bind(self)
: Rule クラスを分析するときに、このメソッドについて説明しました。その主な機能は、マップ オブジェクトを Rule オブジェクトにバインドし、ルール オブジェクトに基づいて正規表現 (Rule オブジェクトのプロパティ) を作成することです。ルールとマップ情報self._regex
。 - ルール オブジェクトを
Map
オブジェクトのリストに追加しますself._rules
。 endpoint
と のrule
マッピングをMap
オブジェクトのプロパティself._rules_by_endpoint
(辞書)に追加します。
例を使用して、追加後に Map オブジェクトがどのようになるかを確認できます。デバッグを通じて、結果は次のようになります。
と のMap
両方の属性に、新しく追加された '/' ルート (ルートはデフォルトで追加された静的ファイルのロケーション ルート)に対応するデータが含まれていることがわかります。self._rules
self._rules_by_endpoint
/static/<path:filename>
以上でルーティングマップの追加方法の解析は終わりました。
2 リクエスト受信時のルートマッチング処理
(1) wsgi_appを解析する
前のリクエストが来たときに、前のリクエストMap
とオブジェクトに従ってRlue
ルートを一致させる方法を分析してみましょう。
前の章では、__call__
リクエストが届いたときに、wsgi サーバーを介してリクエストを処理した後、Flask アプリを呼び出す方法を分析しました。コードは次のとおりです。
def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app`, which can be
wrapped to apply middleware.
"""
return self.wsgi_app(environ, start_response)
アプリのメソッドが実際に呼び出されていることがわかりますwsgi_app()
。そのコードは次のとおりです。
def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
# 1.获取请求上下文
ctx = self.request_context(environ)
error: t.Optional[BaseException] = None
try:
try:
# 2.调用请求上下文的push方法
ctx.push()
# 3.调用full_dispatch_request()分发请求,获取响应结果
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
それには 3 つの主なステップがあります。
- リクエストコンテキストを取得します。
ctx = self.request_context(environ)
- リクエストコンテキストのプッシュメソッドを呼び出します。
ctx.push()
- full_dispatch_request() を呼び出してリクエストを分散し、応答結果を取得します。
response = self.full_dispatch_request()
各ステップの機能を 1 つずつ分析してみましょう。
(2) request_contextの解析
wsgi_app
このメソッドの最初の主要なステップ。
このメソッドは主にコンテキスト オブジェクトを取得するためのものです。
environ
(環境変数など) をメソッドに渡す必要があります。Flask ではコンテキストも重要な概念です。もちろん、次の章ではコンテキストの分析に焦点を当てます。この章では、必要なことだけに焦点を当てます。
def request_context(self, environ: dict) -> RequestContext:
return RequestContext(self, environ)
このメソッドはRequestContext
オブジェクトを作成することです。RequestContext
クラス部分のソースコードは以下の通りです。
class RequestContext:
def __init__(
self,
app: "Flask",
environ: dict,
request: t.Optional["Request"] = None,
session: t.Optional["SessionMixin"] = None,
) -> None:
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
self.url_adapter = None
try:
# 此处是重点,调用了Falsk对象的create_url_adapter方法获取了MapAdapter对象
self.url_adapter = app.create_url_adapter(self.request)
except HTTPException as e:
self.request.routing_exception = e
self.flashes = None
self.session = session
# 其他代码省略...
# 其他方法的源码省略...
RequestContext
オブジェクトを作成する初期化メソッドにおいて、非常に重要なステップは、MapAdapter
オブジェクトを取得することです。
上記のセクション 4 でその機能を分析しましたが、主にルートを照合するために使用されます。
create_url_adapter
ソースコードを見てみましょう:
def create_url_adapter(
self, request: t.Optional[Request]
) -> t.Optional[MapAdapter]:
if request is not None:
if not self.subdomain_matching:
subdomain = self.url_map.default_subdomain or None
else:
subdomain = None
# 此处是重点,调用了Map对象的bind_to_environ方法
return self.url_map.bind_to_environ(
request.environ,
server_name=self.config["SERVER_NAME"],
subdomain=subdomain,
)
if self.config["SERVER_NAME"] is not None:
# 此处是重点,调用了Map对象的bind方法
return self.url_map.bind(
self.config["SERVER_NAME"],
script_name=self.config["APPLICATION_ROOT"],
url_scheme=self.config["PREFERRED_URL_SCHEME"],
)
return None
ご覧のとおり、このメソッドの主な機能は、Map
オブジェクトのbind_to_environ
メソッドを呼び出すことですbind
。先ほど Map クラスの話をしたときにも分析しましたが、この 2 つのメソッドは主にMapAdapter
オブジェクトを返します。
(3) ctx.pushを解析する
wsgi_app
この方法の 2 番目の主要なステップ。
wsgi メソッドでコンテキスト オブジェクトが取得された後、メソッドが呼び出されpush
、コードは次のようになります (コア コードのみが保持されます)。
class RequestContext:
def __init__(
self,
app: "Flask",
environ: dict,
request: t.Optional["Request"] = None,
session: t.Optional["SessionMixin"] = None,
) -> None:
# 代码省略
pass
def match_request(self) -> None:
try:
# 1.调用了MapAdapter对象的match方法,返回了rule对象和参数对象
result = self.url_adapter.match(return_rule=True)
# 2.把rule对象和参数对象放到请求上下文中
self.request.url_rule, self.request.view_args = result
except HTTPException as e:
self.request.routing_exception = e
def push(self) -> None:
"""Binds the request context to the current context."""
# 此处省略了前置校验处理代码(上下文、session等处理)
if self.url_adapter is not None:
# 调用了match_request方法
self.match_request()
push
このメソッドは主にmatch_request
メソッドを呼び出していることがわかります。このメソッドは主に次の 2 つのことを実行します。
- MapAdapter オブジェクトの match メソッドを呼び出すと、
Map
オブジェクトに格納されているルーティング情報に従って現在のリクエストのルートが照合され、ルール オブジェクトとパラメーター オブジェクトが返されます。 - ルール オブジェクトとパラメーター オブジェクトをリクエスト コンテキストに配置します。
(4) full_dispatch_requestを解析する
wsgi_app
この方法の 3 番目の主要なステップ。
full_dispatch_request
メソッドのソースコードは次のとおりです。
def full_dispatch_request(self) -> Response:
self.try_trigger_before_first_request_functions()
try:
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
# 这里是主要的步骤:分发请求
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
return self.finalize_request(rv)
その中にはdispatch_request()
コアメソッドがあります。
dispatch_request()
メソッドのソースコードは次のとおりです。
def dispatch_request(self) -> ResponseReturnValue:
# 1.获取请求上下文对象
req = _request_ctx_stack.top.request
if req.routing_exception is not None:
self.raise_routing_exception(req)
# 2.从上下文中获取前面存在里面的Rule对象
rule = req.url_rule
# if we provide automatic options for this URL and the
# request came with the OPTIONS method, reply automatically
if (
getattr(rule, "provide_automatic_options", False)
and req.method == "OPTIONS"
):
return self.make_default_options_response()
# 这里是重点:根据rule对象的endpoint属性从self.view_functions属性中获取对应的视图函数,
# 然后把上下文中的参数传到视图函数中并调用视图函数处理请求,返回处理结果
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
この方法の主な手順は次のとおりです。
req = _request_ctx_stack.top.request
: リクエストコンテキストオブジェクトを取得しますrule = req.url_rule
Rule
:コンテキストから既存のオブジェクトを取得します。これはctx.push()
、コンテキストに組み込まれたメソッドです。- ルール オブジェクトの endpoint プロパティに従って、self.view_functions プロパティから対応するビュー関数を取得し、コンテキスト内のパラメーターをビュー関数に渡し、ビュー関数を呼び出してリクエストを処理し、処理結果を返します。
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
この時点で、完全なリクエストが処理されます。
3 まとめ
上記の分析によれば、ルーティング ルールとリクエストのマッチングは次のように要約されます。
アプリの起動時:
app.route()
呼び出しadd_url_rule
メソッド。add_url_rule
メソッド内:self.url_rule_class()
インスタンス化されたRule
オブジェクトを呼び出します。add_url_rule
メソッド内:self.url_map.add()
メソッドを呼び出し、Rule
オブジェクトendpoint
とビュー関数の間のマッピング関係を Map オブジェクトに保存します。add_url_rule
メソッド内:self.view_functions[endpoint] = view_func
endpoint と view_func のマッピングを追加します。
リクエスト照合プロセス:
- リクエストが届くと、
WSGI
サーバーは__call__
Flask アプリのメソッドを処理して呼び出し、その後wsgi_app
そのメソッドを呼び出します。 wsgi_app
メソッドでコンテキスト オブジェクトを作成しますctx = self.request_context(environ)
。次に、オブジェクトはMapAdapter
コンテキスト オブジェクト プロパティとしてインスタンス化されます。wsgi_app
メソッド内でコンテキスト オブジェクトを呼び出すメソッドpush
:ctx.push()
。このメソッドは主にMapAdapter
オブジェクトのメソッドを使用しますmatch
。MapAdapter
オブジェクトのメソッド。オブジェクトのメソッドmatch
を呼び出します。このメソッドは、オブジェクトに格納されているルーティング情報に従って現在のリクエストのルートを照合し、オブジェクトとパラメータ オブジェクトをコンテキスト オブジェクトに取得します。rule
match
Map
rule
wsgi_app
full_dispatch_request
メソッド内のメソッドを呼び出してから、dispatch_request()
そのメソッド内のメソッドを呼び出します。dispatch_request()
メソッド内: リクエスト コンテキスト オブジェクトを取得し、 内のオブジェクトを取得Rule
し、ルール オブジェクトのエンドポイント属性に従って属性から対応するビュー関数を取得しself.view_functions
、コンテキスト内のパラメーターをビュー関数に渡し、ビュー関数を呼び出します。リクエストを処理し、処理結果を返します。
全体のフローチャートは次のとおりです。
プロジェクトの前半では、ルーティング ルールを確立するための使用方法Rule
とMap
オブジェクトの使用方法について説明し、後半では、リクエストが受信されたときに照合するためにルーティング ルールを使用する方法について説明します。