路由

Falcon根据一组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.body = 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)
import json

import falcon
import falcon.asgi


class ImagesResource:

    async 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.body = 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.asgi.App()

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

如果没有与请求匹配的路由,则控件将传递给只引发 HTTPRouteNotFound . 默认情况下,此错误将呈现为404响应,但可以通过添加自定义错误处理程序来修改此行为(另请参见 this FAQ topic

另一方面,如果路由匹配,但资源没有为请求的HTTP方法实现响应程序,则框架将调用一个默认响应程序,该响应程序将引发 HTTPMethodNotAllowed .

默认行为

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
# Template fields correspond to named arguments or keyword
#   arguments, following the usual req and resp args.
async 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
)

内置转换器

标识符

等级

例子

int

IntConverter

/teams/{tid:int(8)}

uuid

UUIDConverter

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

dt

DateTimeConverter

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


class falcon.routing.IntConverter(num_digits=None, min=None, max=None)

将字段值转换为int。

标识符: int

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

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

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

class falcon.routing.UUIDConverter

将字段值转换为uuid.uuid。

标识符: uuid

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

class falcon.routing.DateTimeConverter(format_string='%Y-%m-%dT%H:%M:%SZ')

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

标识符: dt

关键字参数

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

自定义转换器

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

class falcon.routing.BaseConverter

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

abstract convert(value)

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

参数

value (str) -- 要转换的原始字符串。

返回

已转换的字段值,或 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.

        """

默认路由器

class falcon.routing.CompiledRouter

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

通常,您不需要直接使用这个路由器类,因为当falcon.api类初始化时,默认情况下会创建一个实例。

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

add_route(uri_template, resource, **kwargs)

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

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

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

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

关键字参数

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

find(uri, req=None)

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

参数

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

关键字参数

req (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)

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

参数

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

falcon.routing.compile_uri_template(template)

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

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

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

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

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

另外,请注意,如果模板包含一个尾随斜杠字符,那么为了规范化路由逻辑,它将被剥离。

参数

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

返回

(模板名称,模板名称)

返回类型

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
# Handle the custom FOO method
async def on_foo(self, req, resp):
    pass