路由定义

前面Flask和Starlette已经比较完整描述过路由的概念了,Sanic中的路由采用了与Flask比较相像的使用方法。Sanic类提供了.add_route()方法和.route()修饰器来定义路由。其中.route()修饰器会更加常用一些。

.route()修饰器的调用格式为:.route(uri, methods, host, strict_slashes, stream, version, name),其常用参数含义如下:

  • uri,要绑定到的URL。
  • methods,列表类型,同于指示路由可以响应的请求方法。
  • strict_slashes,确定是否精确匹配尾部的斜线。
  • host,设定处理函数只响应来自指定Host的请求。
  • stream,设定以流的方式处理请求和响应。
  • version,设定当前处理过程的版本。
  • name,设定路由名称,用于.url_for()方法拼合URL。

.route()可以响应GET、POST、PUT、DELETE等所有请求方法,如果只需要响应特定的请求方法,Sanic还提供了.get().post().put().delete().head()等修饰器来修饰特定请求方法的响应函数,这些修饰器的使用与.route()基本一致。如果不使用特定的修饰器来定义请求方法,则需要使用.route()修饰器中的methods参数来设定。

.add_route()方法可以以普通语句方式向应用中添加路由,这对于应用与路由处理函数不在一个文件中定义的项目来说十分有用。.add_route()方法的调用格式为:.add_route(handler, uri, methods, host, strict_slashes, version, name, stream),除参数handler以外,都与修饰器版本可接受的参数一样。.add_route()方法的参数hander可以接受一个函数或者一个类实例用于相应URL的处理。

由于Sanic是基于异步的,所以所有的处理函数都需要是使用async关键字修饰的,这一点与Flask不同,要尤其注意。处理函数一般都接受一个sanic.request.Request类型的参数,其中保存了请求的全部数据,并返回一个来自sanic.response包中的响应类型实例。

路径参数

Sanic的路由也是可以接受参数的,其参数定义与Flask稍微不同,格式为<参数名:参数类型>。处理函数中需要在sanic.request.Request类型参数之后继续书写与路径参数名同名的参数来收取通过URL路径传入的值。

例如:

@app.route("/tag/<tag>", methods=["POST"])
async def add_tag(request, tag)
	return json({"tag": tag})

Sanic的参数类型支持stringintnumberalphapathuuid和正则表达式几种,选择不同的参数类型可以使路由匹配到不同的URL内容。

定义子路由

Sanic中的子路由也是通过蓝图(Blueprint)来设定的。蓝图在定义后需要注册到Web应用中即可。以下给出一个简单示例来说明。

from sanic.response import json
from sanic import Blueprint


bp = Blueprint('a_subroute')

@bp.route("/")
async def bp_root(request):
	return json({"hello": "world"})

在Web应用文件中需要用以下示例中的方式来将蓝图绑定进应用。

from sanic import Sanic
from sub_route import bp


app = Sanic(__name__)
app.blueprint(bp)

app.run(host="0.0.0.0", port=8000)

蓝图中的路由与Sanic应用实例中的路由定义完全相同。蓝图可以被挂载到应用的一个子路径下,自路径可以通过Blueprint类构造函数中的url_prefix参数来指定,在未指定时,蓝图会默认挂载到/下。

挂载到同一路径下的蓝图可以成组来设置,并且蓝图组可以嵌套。具体可参考以下示例。

from sanic import Sanic
from sanic import Blueprint

bp1 = Blueprint("the_first", url_prefix="/first")
bp2 = Blueprint("the_second", url_prefix="/second")

bp3_1 = Blueprint("the_third_sub_1", url_prefix="/t1")
bp3_2 = Blueprint("the_third_sub_2", url_prefix="/t2")
bp3 = Blueprint.group(bp3_1, bp3_2, url_prefix="/third")

api = Blueprint.group(bp1, bp2, bp3, url_prefix="/api")

# 在实际应用时可拆为多个文件
app = Sanic(__name__)
app.blueprint(api)

输出静态文件

对于静态文件的输出是依靠Sanic类和Blueprint类中提供的.static()方法实现的。.static()方法主要用于实现URL与磁盘文件之间的映射。例如:app.static("/static", "./resources")

.static()方法的常用的各个参数用途如下:

  • uri,静态资源要挂载到的URL。
  • path,要向外提供的静态资源所在路径或文件名。
  • pattern,用于过滤所提供的静态文件名的正则表达式。
  • use_modified_since,是否发送文件的修改时间。
  • use_content_range,是否支持发送指定的文件段。
  • stream_large_files,自动采用流发送大文件,设定True将自动采用1KB作为大文件判定依据,可以设置为具体字节数来自定义判定依据。
  • name,用于.url_for()的路由名称。
  • host,指定路由要匹配的Host。
  • strict_slashes,确定是否精确匹配尾部的斜线。
  • content_type,自定义Content-Type。

版本路由

版本路由是Sanic提供的一个比较有特色的路由功能。通过给Sanic类实例和Blueprint类实例提供的.route()修饰器或者.add_route()方法中使用version参数赋予整形值,Sanic可以自动向指定路由前添加v{version}来区分相同路由的不同版本。

具体可参考以下示例。

from sanic import response

# 通过 http://localhost/v1/greeting 访问
@app.route("/greeting", version=1)
def handle_request(request):
	return response.text("The first version")

# 通过 http://localhost/v2/greeting 访问
@app.route("/greeting", version=2)
def handle_request(request):
	return response.text("The second version")

如果在创建蓝图时设定了蓝图的版本,那么版本号将添加到蓝图内的所有URL前。