前文有说,odoo的http文件在处理请求的时候调用了ir.http模型的_match函数,通过这个函数获取到了该请求对应的路由规则,今天我们来看看其中的细节
#----------------------------------------------------------
# ir_http modular http routing
#----------------------------------------------------------
注释写的很清楚,ir_http 模块就是处理http 路由的。 从IrHttp的_description 也能得到同样的答案。
然后下面的注释有意思了 Routing map,路由表。这玩意应该是核心。
class IrHttp(models.AbstractModel):
_name = 'ir.http'
_description = "HTTP Routing"
#------------------------------------------------------
# Routing map
#------------------------------------------------------
还是先看看_match函数吧
@classmethod
def _match(cls, path_info):
rule, args = request.env['ir.http'].routing_map().bind_to_environ(request.httprequest.environ).match(path_info=path_info, return_rule=True)
return rule, args
这个函数很简单,关键的地方是routing_map()函数
@tools.ormcache('key', cache='routing')
def routing_map(self, key=None):
_logger.info("Generating routing map for key %s", str(key))
registry = Registry(threading.current_thread().dbname)
installed = registry._init_modules.union(odoo.conf.server_wide_modules)
if tools.config['test_enable'] and odoo.modules.module.current_test:
installed.add(odoo.modules.module.current_test)
mods = sorted(installed)
# Note : when routing map is generated, we put it on the class `cls`
# to make it available for all instance. Since `env` create an new instance
# of the model, each instance will regenared its own routing map and thus
# regenerate its EndPoint. The routing map should be static.
routing_map = werkzeug.routing.Map(strict_slashes=False, converters=self._get_converters())
for url, endpoint in self._generate_routing_rules(mods, converters=self._get_converters()):
routing = submap(endpoint.routing, ROUTING_KEYS)
if routing['methods'] is not None and 'OPTIONS' not in routing['methods']:
routing['methods'] = routing['methods'] + ['OPTIONS']
rule = FasterRule(url, endpoint=endpoint, **routing)
rule.merge_slashes = False
routing_map.add(rule)
return routing_map
这是生成路由表的关键函数,而且做了缓存, installed 是所有安装好的模块,然后又做了排序。
然后初始化了routing_map , 最后通过一个for循环来填充routing_map ,而for循环遍历的对象是由
_generate_routing_rules 生成的,这个函数是怎么做的呢?
def _generate_routing_rules(self, modules, converters):
return http._generate_routing_rules(modules, False, converters)
一开始没看懂,以为是递归调用自己,然后仔细看了一下,调用的是http的方法,不过
http._generate_routing_rules 这个函数我读起来有点吃力, 这里就不解读了,基本的原理就是遍历安装过的所有模块的controller, 读取route装饰过的方法,并将其封装成rule,endpoint 放到路由表中。
def _generate_routing_rules(modules, nodb_only, converters=None):
"""
Two-fold algorithm used to (1) determine which method in the
controller inheritance tree should bind to what URL with respect to
the list of installed modules and (2) merge the various @route
arguments of said method with the @route arguments of the method it
overrides.
"""
留点小遗憾,以后弥补。