路由

Falcon使用基于资源的路由来鼓励REST风格的架构。每个资源都由一个类表示,该类负责处理资源支持的所有HTTP方法。

对于资源支持的每个HTTP方法,该类都会实现相应的Python方法,其名称以 on_ 并且以小写的HTTP方法名结束(例如, on_get()on_patch()on_delete() 等)

备注

Falcon中的资源由配置路由时在应用程序启动时创建的单个类实例表示。这最大限度地减少了路由开销并简化了资源类的实现。对于WSGI应用程序,这也意味着资源类必须以线程安全的方式实现(另请参阅: Falcon线安全吗? )。

Falcon路由传入请求(包括 WebSocket handshakes )到基于一组URI模板的资源。如果客户端请求的路径与给定路由的模板匹配,则会将请求传递到关联的资源进行处理。

下面是一个简单的例子,展示了所有部件是如何组合在一起的:

import json

import falcon


class ImagesResource:

    def on_get(self, req, resp):
        doc = {
            'images': [
                {
                    'href': '/images/1eaf6ef1-7f2d-4ecc-a8d5-6e8adba7cc0e.png'
                }
            ]
        }

        # Create a JSON representation of the resource; this could
        #   also be done automatically by assigning to resp.media
        resp.text = json.dumps(doc, ensure_ascii=False)

        # The following line can be omitted because 200 is the default
        # status returned by the framework, but it is included here to
        # illustrate how this may be overridden as needed.
        resp.status = falcon.HTTP_200


app = falcon.App()

images = ImagesResource()
app.add_route('/images', images)

如果没有与请求匹配的路由,则控制传递给默认响应器,该响应器只是引发 HTTPRouteNotFound 。默认情况下,对于常规HTTP请求,此错误将呈现为404响应,对于 WebSocket 握手。可以通过添加自定义错误处理程序来修改此行为(另请参阅 this FAQ topic )。

另一方面,如果路由匹配,但资源没有为请求的HTTP方法实现响应器,则框架将调用默认响应器,该响应器引发 HTTPMethodNotAllowed 。默认情况下,此类将呈现为常规HTTP请求的405响应和 WebSocket 握手。

Falcon还为OPTIONS请求提供默认响应器,该响应器会考虑为目标资源实现哪些方法。

默认行为

Falcon的默认路由引擎基于一个决策树,该树首先被编译成Python代码,然后由运行时评估。默认情况下,只有当路由器处理第一个请求时才会编译决策树。看到了吗 CompiledRouter 了解更多详细信息。

这个 falcon.App.add_route()falcon.asgi.App.add_route() 方法用于将URI模板与资源相关联。然后Falcon根据这些模板将传入的请求映射到资源。

Falcon的默认路由器使用python类来表示资源。实际上,这些类在应用程序中充当控制器。它们将一个传入的请求转换为一个或多个内部操作,然后根据这些操作的结果组合一个对客户机的响应。(另见: Tutorial: Creating Resources

           ┌────────────┐
request  → │            │
           │ Resource   │ ↻ Orchestrate the requested action
           │ Controller │ ↻ Compose the result
response ← │            │
           └────────────┘

每个资源类定义不同的“响应者”方法,资源允许的每个HTTP方法对应一个。响应程序名称以开头 on_ 并根据它们处理的HTTP方法命名,如 on_get()on_post()on_put() 等。

备注

如果您的资源不支持特定的HTTP方法,只需省略相应的响应程序,falcon将使用默认的响应程序,该响应程序将引发 HTTPMethodNotAllowed 当请求该方法时。通常,这会导致向客户机发送405响应。

响应程序必须始终定义至少两个要接收的参数 RequestResponse 对象,分别为:

def on_post(self, req, resp):
    pass

对于ASGI应用程序,响应程序必须是协同程序函数:

async def on_post(self, req, resp):
    pass

这个 Request 对象表示传入的HTTP请求。它公开用于检查头、查询字符串参数和与请求关联的其他元数据的属性和方法。还提供了类似于流对象的文件,用于读取请求主体中包含的任何数据。

这个 Response 对象表示应用程序对上述请求的HTTP响应。它提供设置状态、标题和正文数据的属性和方法。这个 Response 对象还公开类似dict的内容 context 属性,用于将任意数据传递给挂钩和中间件方法。

备注

而不是直接操纵 Response 对象,响应程序可以引发 HTTPErrorHTTPStatus . Falcon将把这些异常转换为适当的HTTP响应。或者,您可以通过 add_error_handler() .

除了标准 reqresp 参数,如果路由的模板包含字段表达式,则任何希望接收该路由请求的响应程序都必须接受以模板中定义的相应字段名命名的参数。

字段表达式由带括号的字段名组成。例如,给定以下模板:

/user/{name}

对的卖出请求 '/user/kgriffs' 会导致框架调用 on_put() 路由资源类上的响应程序方法,传递 'kgriffs' 通过额外的 name 响应程序定义的参数:

# Template fields correspond to named arguments or keyword
#   arguments, following the usual req and resp args.
def on_put(self, req, resp, name):
    pass

因为字段名对应于响应程序方法中的参数名,所以它们必须是有效的Python标识符。

单个路径段可以包含一个或多个字段表达式,字段不需要跨越整个路径段。例如::

/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}
/serviceRoot/People('{name}')

(另请参见 Falcon tutorial 有关在示例应用程序上下文中设置路由的其他示例和演练。)

场转换器

Falcon的默认路由器支持使用字段转换器来转换URI模板字段值。现场转换器也可以执行简单的输入验证。例如,以下URI模板使用 int 转换值的转换器 tid 给 Python int ,但仅当它正好有八位数字时::

/teams/{tid:int(8)}

如果该值格式错误且无法转换,Falcon将拒绝请求,并对客户端作出404响应。

转换器用字段表达式中给出的参数规范进行实例化。这些规范遵循标准的Python语法来传递参数。例如,下面代码中的注释显示了在URI模板中给定不同参数规范的情况下如何实例化转换器:

# IntConverter()
app.add_route(
    '/a/{some_field:int}',
    some_resource
)

# IntConverter(8)
app.add_route(
    '/b/{some_field:int(8)}',
    some_resource
)

# IntConverter(8, min=10000000)
app.add_route(
    '/c/{some_field:int(8, min=10000000)}',
    some_resource
)

(另请参阅如何 UUIDConverter 在Falcon的ASGI教程中使用: 图像资源 。)

内置转换器

标识符

等级

例子

int

IntConverter

/teams/{tid:int(8)}

uuid

UUIDConverter

/diff/{left:uuid}...{right:uuid}

dt

DateTimeConverter

/logs/{day:dt("%Y-%m-%d")}

float

FloatConverter

/python/versions/{version:float(min=3.7)}

path

PathConverter

/prefix/{other:path}


class falcon.routing.IntConverter(num_digits=None, min=None, max=None)[源代码]

将字段值转换为int。

标识符: int

关键字参数:
  • num_digits (int) -- 要求值具有给定的位数。

  • min (int) -- 如果该值小于此数字,则拒绝该值。

  • max (int) -- 如果该值大于此数字,则拒绝该值。

convert(value)[源代码]

将URI模板字段值转换为其他格式或类型。

参数:

value (str or List[str]) -- 要转换的原始字符串。如果 CONSUME_MULTIPLE_SEGMENTS=True 该值是包含转换器匹配的路径段的字符串列表。

返回:

已转换的字段值,或 None 如果无法转换字段。

返回类型:

object

class falcon.routing.FloatConverter(min: Optional[float] = None, max: Optional[float] = None, finite: bool = True)[源代码]

将字段值转换为浮点型。

标识符: float

关键字参数:
  • min (float) -- 如果该值小于此数字,则拒绝该值。

  • max (float) -- 如果该值大于此数字,则拒绝该值。

  • finite (bool) -- 确定是否仅匹配普通有限数(默认: True )。设置为 False 匹配NaN、inf和-inf以及有限个数字。

convert(value: str)[源代码]

将URI模板字段值转换为其他格式或类型。

参数:

value (str or List[str]) -- 要转换的原始字符串。如果 CONSUME_MULTIPLE_SEGMENTS=True 该值是包含转换器匹配的路径段的字符串列表。

返回:

已转换的字段值,或 None 如果无法转换字段。

返回类型:

object

class falcon.routing.UUIDConverter[源代码]

将字段值转换为uuid.uuid。

标识符: uuid

为了进行转换,字段值必须由32个十六进制数字组成的字符串,如中所定义。 RFC 4122, Section 3. 但是,请注意,连字符和urn前缀是可选的。

convert(value)[源代码]

将URI模板字段值转换为其他格式或类型。

参数:

value (str or List[str]) -- 要转换的原始字符串。如果 CONSUME_MULTIPLE_SEGMENTS=True 该值是包含转换器匹配的路径段的字符串列表。

返回:

已转换的字段值,或 None 如果无法转换字段。

返回类型:

object

class falcon.routing.DateTimeConverter(format_string='%Y-%m-%dT%H:%M:%SZ')[源代码]

将字段值转换为日期时间。

标识符: dt

关键字参数:

format_string (str) -- 用于将字段值解析为日期时间的字符串。支持strptime()识别的任何格式(默认 '%Y-%m-%dT%H:%M:%SZ'

convert(value)[源代码]

将URI模板字段值转换为其他格式或类型。

参数:

value (str or List[str]) -- 要转换的原始字符串。如果 CONSUME_MULTIPLE_SEGMENTS=True 该值是包含转换器匹配的路径段的字符串列表。

返回:

已转换的字段值,或 None 如果无法转换字段。

返回类型:

object

class falcon.routing.PathConverter[源代码]

用于匹配路径其余部分的已转换字段。

此字段转换器匹配URL路径的其余部分,将其作为字符串返回。

当前仅当在URL模板的末尾使用时才支持此转换器。

Falcon的经典路由规则也适用于此转换器:考虑模板 '/foo/bar/{matched_path:path}' ,这条路 '/foo/bar' 将要 not 匹配路线; '/foo/bar/' 将会匹配,制作 matched_path='' ,何时 strip_url_path_trailing_slashFalse (默认设置),虽然它将 not 当该选项为 True

(另请参阅: Falcon如何处理请求路径中的尾随斜杠? )

CONSUME_MULTIPLE_SEGMENTS = True

当设置为时 True 它表明该转换器将使用多个URL路径段。目前使用的转换器具有 CONSUME_MULTIPLE_SEGMENTS=True 必须位于URL模板的末尾,这意味着它将消耗所有剩余的URL路径段。

convert(value)[源代码]

将URI模板字段值转换为其他格式或类型。

参数:

value (str or List[str]) -- 要转换的原始字符串。如果 CONSUME_MULTIPLE_SEGMENTS=True 该值是包含转换器匹配的路径段的字符串列表。

返回:

已转换的字段值,或 None 如果无法转换字段。

返回类型:

object

自定义转换器

自定义转换器可以通过 converters 路由器选项。转换器只是一个实现 BaseConverter 接口:

class falcon.routing.BaseConverter[源代码]

URI模板字段转换器的抽象基类。

CONSUME_MULTIPLE_SEGMENTS = False

当设置为时 True 它表明该转换器将使用多个URL路径段。目前使用的转换器具有 CONSUME_MULTIPLE_SEGMENTS=True 必须位于URL模板的末尾,这意味着它将消耗所有剩余的URL路径段。

abstract convert(value)[源代码]

将URI模板字段值转换为其他格式或类型。

参数:

value (str or List[str]) -- 要转换的原始字符串。如果 CONSUME_MULTIPLE_SEGMENTS=True 该值是包含转换器匹配的路径段的字符串列表。

返回:

已转换的字段值,或 None 如果无法转换字段。

返回类型:

object

自定义路由器

在实例化时可以指定自定义路由引擎 falcon.App()falcon.asgi.App() . 例如:

router = MyRouter()
app = App(router=router)

自定义路由器可以从默认值派生 CompiledRouter 引擎,或实现完全不同的路由策略(如基于对象的路由)。

自定义路由器是实现以下接口的任何类:

class MyRouter:
    def add_route(self, uri_template, resource, **kwargs):
        """Adds a route between URI path template and resource.

        Args:
            uri_template (str): A URI template to use for the route
            resource (object): The resource instance to associate with
                the URI template.

        Keyword Args:
            suffix (str): Optional responder name suffix for this
                route. If a suffix is provided, Falcon will map GET
                requests to ``on_get_{suffix}()``, POST requests to
                ``on_post_{suffix}()``, etc. In this way, multiple
                closely-related routes can be mapped to the same
                resource. For example, a single resource class can
                use suffixed responders to distinguish requests for
                a single item vs. a collection of those same items.
                Another class might use a suffixed responder to handle
                a shortlink route in addition to the regular route for
                the resource.

            **kwargs (dict): Accepts any additional keyword arguments
                that were originally passed to the falcon.App.add_route()
                method. These arguments MUST be accepted via the
                double-star variadic pattern (**kwargs), and ignore any
                unrecognized or unsupported arguments.
        """

    def find(self, uri, req=None):
        """Search for a route that matches the given partial URI.

        Args:
            uri(str): The requested path to route.

        Keyword Args:
             req(Request): The Request object that will be passed to
                the routed responder. The router may use `req` to
                further differentiate the requested route. For
                example, a header may be used to determine the
                desired API version and route the request
                accordingly.

                Note:
                    The `req` keyword argument was added in version
                    1.2. To ensure backwards-compatibility, routers
                    that do not implement this argument are still
                    supported.

        Returns:
            tuple: A 4-member tuple composed of (resource, method_map,
                params, uri_template), or ``None`` if no route matches
                the requested path.

        """

带后缀的响应器

虽然Falcon鼓励REST架构风格,但它足够灵活,可以适应其他范例。考虑一下为计算器构建API的任务,该计算器可以加减两个数字。您可以实现以下内容:

class Add():
    def on_get(self, req, resp):
        resp.text = str(req.get_param_as_int('x') + req.get_param_as_int('y'))
        resp.status = falcon.HTTP_200


class Subtract():
    def on_get(self, req, resp):
        resp.text = str(req.get_param_as_int('x') - req.get_param_as_int('y'))
        resp.status = falcon.HTTP_200


add = Add()
subtract = Subtract()
app = falcon.App()
app.add_route('/add', add)
app.add_route('/subtract', subtract)

但是,这种方法突出了这样一种情况,即按资源分组对于您的域可能没有意义。在此上下文中,加法和减法似乎在概念上没有映射到两个独立的资源集合。我们可能希望根据它们的函数属性(即,接受两个数字,对它们做一些操作,然后返回结果)来对它们进行分组,而不是基于从每个数据中“获取”不同资源的想法来将它们分开。

有了带后缀的Responders,我们就可以做到这一点,以更过程化的风格重写上面的示例:

class Calculator():
    def on_get_add(self, req, resp):
        resp.text = str(req.get_param_as_int('x') + req.get_param_as_int('y'))
        resp.status = falcon.HTTP_200

    def on_get_subtract(self, req, resp):
        resp.text = str(req.get_param_as_int('x') - req.get_param_as_int('y'))
        resp.status = falcon.HTTP_200


calc = Calculator()
app = falcon.App()
app.add_route('/add', calc, suffix='add')
app.add_route('/subtract', calc, suffix='subtract')

在第二次迭代中,使用带后缀的Responder,我们能够根据响应者的操作而不是他们表示的数据对响应者进行分组。这为我们提供了额外的灵活性,以适应纯粹的RESTful方法根本不适合的情况。

默认路由器

class falcon.routing.CompiledRouter[源代码]

将其路由逻辑编译为python代码的快速uri路由器。

一般情况下,您不需要直接使用该路由器类,因为在初始化Falcon.App类时,默认情况下会创建一个实例。

路由器将URI路径视为一个URI段树,并通过一次检查一个URI段进行搜索。它不会为每次查找解释路由树,而是生成内联的定制python代码来执行搜索,然后编译该代码。这使得路由处理相当快。

编译过程延迟到第一次使用路由器(针对第一个路由的请求),以减少启动应用程序所需的时间。当添加了大量路由时,这可能会显著延迟应用程序的第一次响应。将最后一条路由添加到应用程序时 compile 可以提供标志以强制路由器立即编译,从而避免第一次响应的任何延迟。

备注

使用多线程Web服务器托管应用程序时,可能会在启动时同时路由多个请求。因此,该框架使用锁来确保只执行决策树的一次编译。

另请参阅 CompiledRouter.add_route()

add_route(uri_template, resource, **kwargs)[源代码]

在URI路径模板和资源之间添加路由。

可以重写此方法以自定义添加路由的方式。

参数:
  • uri_template (str) -- 用于路由的URI模板

  • resource (object) -- 要与URI模板关联的资源实例。

关键字参数:
  • suffix (str) -- 此路由的可选响应程序名称后缀。如果提供了后缀,falcon将把get请求映射到 on_get_{{suffix}}() ,将请求发布到 on_post_{{suffix}}() 等等。通过这种方式,可以将多个密切相关的路由映射到同一个资源。例如,单个资源类可以使用后缀响应器来区分单个项目的请求与那些相同项目的集合。另一个类可能使用后缀响应器来处理短链接路由以及资源的常规路由。

  • compile (bool) -- 可用于编译此呼叫的路由逻辑的可选标志。默认情况下, CompiledRouter 延迟编译,直到路由第一个请求。这可能会在处理第一个请求时引入明显的延迟,特别是当应用程序实现大量路由时。设置 compileTrue 添加最后一个路由时,可确保第一个请求在这种情况下不会延迟(默认为 False )。。。注意::始终将此标志设置为 True 当一次添加数百条新路由时,可能会减慢添加新路由的速度。建议仅将此标志设置为 True 在添加最终路线时。

find(uri, req=None)[源代码]

搜索与给定的部分URI匹配的路由。

参数:

uri (str) -- 请求的路由路径。

关键字参数:

req -- 这个 falcon.Requestfalcon.asgi.Request 对象,该对象将传递给路由的响应方。当前,此参数的值被忽略 CompiledRouter 。路由完全基于路径。

返回:

由(resource,method_map,params,uri_template)或 None 如果没有与请求的路径匹配的路由。

返回类型:

tuple

map_http_methods(resource, **kwargs)[源代码]

将HTTP方法(例如get、post)映射到资源对象的方法。

此方法是从 add_route() 可以重写以提供自定义映射策略。

参数:

resource (instance) -- 表示休息资源的对象。默认映射HTTP方法 GETon_get()POSTon_post() 等等。如果您的资源不支持任何HTTP方法,只需不定义相应的请求处理程序,Falcon就会做正确的事情。

关键字参数:

suffix (str) -- 此路由的可选响应程序名称后缀。如果提供了后缀,falcon将把get请求映射到 on_get_{{suffix}}() ,将请求发布到 on_post_{{suffix}}() 等等。通过这种方式,可以将多个密切相关的路由映射到同一个资源。例如,单个资源类可以使用后缀响应器来区分单个项目的请求与那些相同项目的集合。另一个类可能使用后缀响应器来处理短链接路由以及资源的常规路由。

路由实用程序

这个 falcon.routing 模块包含以下可由自定义路由引擎使用的实用程序。

falcon.routing.map_http_methods(resource, suffix=None)[源代码]

将HTTP方法(例如get、post)映射到资源对象的方法。

参数:

resource -- 带有的对象 应答器 方法,遵循命名约定 *on_* *,对应于资源支持的每个方法。例如,如果一个资源支持GET和POST,那么它应该定义 on_get(self, req, resp)on_post(self, req, resp) .

关键字参数:

suffix (str) -- 此路由的可选响应程序名称后缀。如果提供了后缀,falcon将把get请求映射到 on_get_{{suffix}}() ,将请求发布到 on_post_{{suffix}}() 等。

返回:

HTTP方法到显式定义的资源响应程序的映射。

返回类型:

dict

falcon.routing.set_default_responders(method_map, asgi=False)[源代码]

将资源上未显式定义的HTTP方法映射到默认响应器。

参数:
  • method_map -- 将HTTP方法映射到资源中显式定义的响应程序的dict。

  • asgi (bool) -- True 如果使用ASGI应用程序, False 否则(默认 False )。

falcon.routing.compile_uri_template(template)[源代码]

将给定的URI模板字符串编译为模式匹配器。

此函数可用于构造自定义路由引擎,该引擎迭代可能的路由列表,尝试根据每个路由的已编译正则表达式匹配传入请求。

每个字段都转换为一个命名组,这样当找到匹配项时,可以使用 re.MatchObject.groupdict() .

此函数不支持默认路由器中使用的更灵活的模板语法。只能识别带括号字段表达式的简单路径。例如::

/
/books
/books/{isbn}
/books/{isbn}/characters
/books/{isbn}/characters/{name}

警告

如果模板包含尾随斜杠字符,则会将其删除。

请注意,这是 不同 从… the default behavioradd_route() 与默认设置一起使用 CompiledRouter

这个 strip_url_path_trailing_slash 未考虑请求选项 compile_uri_template()

参数:

template (str) -- 要编译的模板。请注意,字段名仅限于ASCII A-Z、A-Z和下划线字符。

返回:

(模板名称,模板名称)

返回类型:

tuple

自 3.1 版本弃用.

falcon.app_helpers.prepare_middleware(middleware: Iterable, independent_middleware: bool = False, asgi: bool = False) Tuple[tuple, tuple, tuple][源代码]

检查中间件接口并准备请求处理的方法。

备注

此方法仅适用于WSGI应用程序。

参数:

middleware (iterable) -- 中间件对象的可迭代。

关键字参数:
  • independent_middleware (bool) -- True 请求和响应中间件方法是否应单独处理(默认 False )

  • asgi (bool) -- True 如果ASGI应用程序, False 否则(默认 False )

返回:

准备好的中间件方法元组的元组

返回类型:

tuple

falcon.app_helpers.prepare_middleware_ws(middleware: Iterable) Tuple[list, list][源代码]

检查中间件接口并为请求处理准备WebSocket方法。

备注

此方法仅适用于ASGI应用程序。

参数:

middleware (iterable) -- 中间件对象的可迭代。

返回:

A两件装的 (request_mw, resource_mw) 元组,其中 request_mw 是一个有序的列表,该列表包含 process_request_ws() 方法,以及 resource_mw 是一个有序的列表,该列表包含 process_resource_ws() 方法。

返回类型:

tuple

自定义HTTP方法

虽然通常不建议这样做,但除了GET和PUT等标准HTTP方法之外,有些应用程序可能还需要支持非标准HTTP方法。要支持自定义HTTP方法,请使用以下方法之一:

  • 理想情况下,如果在应用程序中不使用钩子,则可以通过重写 falcon.constants.COMBINED_METHODS . 例如::

    import falcon.constants
    falcon.constants.COMBINED_METHODS += ['FOO', 'BAR']
    
  • 由于钩子的性质,如果确实使用钩子,则需要将falcon_custom_http_methods环境变量定义为自定义方法的逗号分隔列表。例如::

    $ export FALCON_CUSTOM_HTTP_METHODS=FOO,BAR
    

一旦您使用了适当的方法,您的自定义方法应该是活动的。然后,您可以像任何其他HTTP方法一样定义请求方法:

# Handle the custom FOO method
def on_foo(self, req, resp):
    pass