Sanic 处理程序简介#

处理程序(handlers) 也被称为视图(view)。在 Sanic 中,处理程序是至少接受 sanic.request.Request 实例作为参数并返回 sanic.response.HTTPResponse 实例或执行相同操作的协程的任何可调用程序。

它是一个同步或异步函数。

def i_am_a_handler(request):
    return HTTPResponse()

async def i_am_ALSO_a_handler(request):
    return HTTPResponse()

处理程序的工作是响应端点并做一些事情。这是您的大部分业务逻辑的去处。

重要

  1. 您几乎永远不会想要直接使用 sanic.response.HTTPresponse。使用其中一种便利方法要简单得多。

  2. 正如我们将在流部分看到的,您并不总是需要返回对象。如果使用这个低级 API,则可以在处理程序中控制响应流,并且不使用返回对象。

简单的基于函数的处理程序#

创建路由处理程序最常用的方法是修饰该函数。它创建了视觉上简单的路由定义标识。

from sanic import text, Sanic

app = Sanic("Demo")
@app.get("/foo")
async def foo_handler(request):
    return text("I said foo!")

下面的处理器的名字是:"foo_handler"

@app.get("/foo")
async def foo_handler(request):
    return text("I said foo!")
---------------------------------------------------------------------------
RouteExists                               Traceback (most recent call last)
Cell In[2], line 2
      1 @app.get("/foo")
----> 2 async def foo_handler(request):
      3     return text("I said foo!")

File /opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/sanic/mixins/routes.py:209, in RouteMixin.route.<locals>.decorator(handler)
    206     handler.is_stream = stream
    208 if apply:
--> 209     self._apply_route(route, overwrite=overwrite)
    211 if static:
    212     return route, handler

File /opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/sanic/app.py:618, in Sanic._apply_route(self, route, overwrite)
    615 ctx = params.pop("route_context")
    617 with self.amend():
--> 618     routes = self.router.add(**params)
    619     if isinstance(routes, Route):
    620         routes = [routes]

File /opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/sanic/router.py:148, in Router.add(self, uri, methods, handler, host, strict_slashes, stream, ignore_body, version, name, unquote, static, version_prefix, overwrite, error_format)
    141 if len(hosts) > 1:
    142     ident = (
    143         f"{name}_{host.replace('.', '_')}"
    144         if name
    145         else "__unnamed__"
    146     )
--> 148 route = super().add(**params)  # type: ignore
    149 route.extra.ident = ident
    150 route.extra.ignore_body = ignore_body

File /opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/sanic_routing/router.py:252, in BaseRouter.add(self, path, handler, methods, name, requirements, strict, unquote, overwrite, append, priority)
    250     if route.segments in routes:
    251         existing_group = routes[route.segments]
--> 252         group.merge(existing_group, overwrite, append)
    254     routes[route.segments] = group
    256 if name:

File /opt/hostedtoolcache/Python/3.10.13/x64/lib/python3.10/site-packages/sanic_routing/group.py:168, in RouteGroup.merge(self, group, overwrite, append)
    156 if (
    157     current_route == other_route
    158     or (
   (...)
    165     )
    166 ) and not append:
    167     if not overwrite:
--> 168         raise RouteExists(
    169             f"Route already registered: {self.raw_path} "
    170             f"[{','.join(self.methods)}]"
    171         )
    172 else:
    173     _routes.append(other_route)

RouteExists: Route already registered: foo [GET]

但是,您可以通过将 name 参数传递给装饰器来覆盖这一点。

# 处理器名字改为 "foo"
@app.get("/foo", name="foo")
async def foo_handler(request):
    return text("I said foo!")

事实上,有时您必须提供名称。例如,如果在同一个函数上使用两个装饰器,则需要为其中至少一个提供名称。

如果你不这样做,你会得到一个错误,你的应用程序将无法启动。名称在应用程序中必须是唯一的。

# Two handlers, same function,
# different names:
# - "foo_arg"
# - "foo"
@app.get("/foo/<arg>", name="foo_arg")
@app.get("/foo")
async def foo(request, arg=None):
    return text("I said foo!")