# Version 21.12

# 介绍(Introduction)

该版本为 21 版本 发布周期 中的最后一个发行版本,目前 21 版本将进入长期维护状态,直至 2023 年 12 月。

# 更新内容(What to know)

更多详情请见 更新记录 (opens new window)。值得注意的新功能或突破性功能,以及要升级的内容...

# 更严格的应用程序和蓝图命名检查(Strict application and blueprint names)

v21.6 中,应用程序或蓝图的名称需要符合新的命名规范,现在该规范将在应用启动时进行强制检查。

名称 必须 符合以下规则:

  1. 只允许使用字母和数字 (a-zA-Z0-9)
  2. 可以包含连接符 (-) 或下划线 (_)
  3. 必须以字母或者下划线开头 (a-zA-Z_)

# 更严格的应用程序和蓝图属性检查(Strict application and blueprint properties)

在以前的版本中,您可以直接将属性挂载到 Sanic 或者 Blueprint 上,现在您必须使用 ctx 来进行属性设置。

app = Sanic("MyApp")
app.ctx.db = Database()

# 功能迁移(Removals)

下面几种不推荐使用的方法已被移除:

  • sanic.exceptions.abort
  • sanic.views.CompositionView
  • sanic.response.StreamingHTTPResponse

# 升级您的流式响应 (如果您尚未准备好弃用)

sanic.response.stream 响应方法已被 弃用 并将在 v22.6 版本中删除。如果您仍在使用旧的流式响应,请将其升级。

旧用法 - 已弃用

async def sample_streaming_fn(response):
    await response.write("foo,")
    await response.write("bar")
@app.route("/")
async def test(request: Request):
    return stream(sample_streaming_fn, content_type="text/csv")

临时替代方案

async def sample_streaming_fn(response):
    await response.write("foo,")
    await response.write("bar")
@app.route("/")
async def test(request: Request):
    response = await request.respond(content_type="text/csv")
    await response.send("foo,")
    await response.send("bar")

# CLI 样式更新及每日消息(MOTD)

Sanic CLI 获得了升级,它增加了非常多的新功能,使其能够与 app.run 一较高下。它还包含了一个全新的 MOTD 显示功能。让您快速的对当前环境配置有一个了解。MOTD 和 TTY 是互相感知的,因此它在您的日志中并不会有更详细的记录,主要目的是为了方便应用程序的开发。

$ sanic --help
usage: sanic [-h] [--version] [--factory] [-s] [-H HOST] [-p PORT] [-u UNIX] [--cert CERT] [--key KEY] [--tls DIR] [--tls-strict-host]
             [-w WORKERS | --fast] [--access-logs | --no-access-logs] [--debug] [-d] [-r] [-R PATH] [--motd | --no-motd] [-v]
             [--noisy-exceptions | --no-noisy-exceptions]
             module
   ▄███ █████ ██      ▄█▄      ██       █   █   ▄██████████
  ██                 █   █     █ ██     █   █  ██
   ▀███████ ███▄    ▀     █    █   ██   ▄   █  ██
               ██  █████████   █     ██ █   █  ▄▄
  ████ ████████▀  █         █  █       ██   █   ▀██ ███████
 To start running a Sanic application, provide a path to the module, where
 app is a Sanic() instance:
     $ sanic path.to.server:app
 Or, a path to a callable that returns a Sanic() instance:
     $ sanic path.to.factory:create_app --factory
 Or, a path to a directory to run as a simple HTTP server:
     $ sanic ./path/to/static --simple
Required
========
  Positional:
    module                         Path to your Sanic app. Example: path.to.server:app
                                   If running a Simple Server, path to directory to serve. Example: ./
Optional
========
  General:
    -h, --help                     show this help message and exit
    --version                      show program's version number and exit
  Application:
    --factory                      Treat app as an application factory, i.e. a () -> <Sanic app> callable
    -s, --simple                   Run Sanic as a Simple Server, and serve the contents of a directory
                                   (module arg should be a path)
  Socket binding:
    -H HOST, --host HOST           Host address [default 127.0.0.1]
    -p PORT, --port PORT           Port to serve on [default 8000]
    -u UNIX, --unix UNIX           location of unix socket
  TLS certificate:
    --cert CERT                    Location of fullchain.pem, bundle.crt or equivalent
    --key KEY                      Location of privkey.pem or equivalent .key file
    --tls DIR                      TLS certificate folder with fullchain.pem and privkey.pem
                                   May be specified multiple times to choose multiple certificates
    --tls-strict-host              Only allow clients that send an SNI matching server certs
  Worker:
    -w WORKERS, --workers WORKERS  Number of worker processes [default 1]
    --fast                         Set the number of workers to max allowed
    --access-logs                  Display access logs
    --no-access-logs               No display access logs
  Development:
    --debug                        Run the server in debug mode
    -d, --dev                      Currently is an alias for --debug. But starting in v22.3,
                                   --debug will no longer automatically trigger auto_restart.
                                   However, --dev will continue, effectively making it the
                                   same as debug + auto_reload.
    -r, --reload, --auto-reload    Watch source directory for file changes and reload on changes
    -R PATH, --reload-dir PATH     Extra directories to watch and reload on changes
  Output:
    --motd                         Show the startup display
    --no-motd                      No show the startup display
    -v, --verbosity                Control logging noise, eg. -vv or --verbosity=2 [default 0]
    --noisy-exceptions             Output stack traces for all exceptions
    --no-noisy-exceptions          No output stack traces for all exceptions

# 服务运行模式和 debug 的更改

目前拥有的两个运行模式是:开发(DEV) 和 生产(PRODUCTION) Sanic 服务在生产模式下运行,这是为部署而设计的。

目前,DEV 模式的运行方式与旧版本 Sanic 中的 debug=True 非常相似。但是,在 v22.3 中,debug=True不再 启用自动重载功能。如果您想要调试和自动重载,您应该启用 开发(dev) 模式。

开发模式

$ sanic server:app --dev
app.run(debug=True, auto_reload=True)

生产模式

$ sanic server:app
app.run()

从 v22.3 版本开始,生产模式下将不再默认启用访问日志。

变化摘要如下:

标志 模式 错误追溯 日志 访问日志 自动重载 最大 works
--debug DEBUG yes DEBUG yes ^1
PROD no INFO ^2 ^3
--dev DEBUG yes DEBUG yes yes
--fast yes
  • ^1 --debug 参数将在 v22.3 版本中移除自动重载功能
  • ^2 在 v22.3 版本后将日志级别变更为 WARNING
  • ^3 在 v22.3 版本后将被关闭

# 最大线程数(Max allowed workers)

现在您可以通过 --fast 参数来轻松以最大线程数运行您的应用程序了。

$ sanic server:app --fast
app.run(fast=True)

# 一流的 Sanic 拓展支持(First-class Sanic Extensions support)

Sanic 拓展 提供了许多专门针对 API 开发者的拓展功能,现在只要您在 python 环境中安装了 Sanic 拓展 就能够轻松地使用其所有功能,无需进行额外的设置,这些功能包括:

  • 能够自动创建 HEADOPTIONS,和 TRACE 响应程序
  • 具有跨域保护
  • 具有内置于指定响应程序的响应序列化器
  • 允许进行路由参数的注入
  • 完美适配 Redoc 和 Swagger
  • 能够对请求参数和请求体进行验证
$ pip install sanic[ext]
$ pip install sanic sanic-ext
$ pip install sanic[ext]
$ pip install sanic sanic-ext

最好的安装方式就是在安装 Sanic 的同时一并安装 Sanic 拓展,当然,您也可以独立安装:

$ pip install sanic[ext]
$ pip install sanic sanic-ext

之后,不需要额外的配置。Sanic 拓展将自动附加到您的应用程序,并提供所有拓展功能。

如果你想改变其工作方式,或者提供额外的配置,你可以使用 app.extend 来改变 Sanic 拓展。Config 对象是为 ide 开发提供有用的类型注释。

# This is optional, not required
app = Sanic("MyApp")
app.extend(config={"oas_url_prefix": "/apidocs"})
# This is optional, not required
app = Sanic("MyApp")
app.config.OAS_URL_PREFIX = "/apidocs"
# This is optional, not required
from sanic_ext import Config
app = Sanic("MyApp")
app.extend(config=Config(oas_url_prefix="/apidocs"))

# 上下文异常(Contextual exceptions)

v21.9 版本中,我们向异常添加了默认消息,简化了在整个应用程序中一致引发异常的能力。

class TeapotError(SanicException):
    status_code = 418
    message = "Sorry, I cannot brew coffee"
raise TeapotError

但这样会忽视两个非常重要的问题:

  1. 如何设置动态且可预测的消息格式
  2. 如何向错误消息中添加额外上下文内容

当前版本允许任何 Sanic 异常在引发时具有附加信息,以便在编写错误消息时提供上下文:

class TeapotError(SanicException):
    status_code = 418
    @property
    def message(self):
        return f"Sorry {self.extra['name']}, I cannot make you coffee"
raise TeapotError(extra={"name": "Adam"})

新特性允许您向异常传递额外的信息,在生产模式下,该信息将不会被输出,但是在开发模式下它将进行显示。

生产模式

image

开发模式

image

回到我们刚才提到的第二个问题:如何向错误消息中添加额外上下文内容

这在创建微服务或 API 时特别有用,因为您希望以 JSON 格式传回错误消息。在这个用例中,我们希望有一些关于异常的上下文,而不仅仅是一个可解析的错误消息,以便向客户端返回详细信息。

raise TeapotError(context={"foo": "bar"})

这是我们希望 始终在错误中传递的信息(如果可用)。它应该是这样的:

生产模式

{
  "description": "I'm a teapot",
  "status": 418,
  "message": "Sorry Adam, I cannot make you coffee",
  "context": {
    "foo": "bar"
  }
}

开发模式

{
  "description": "I'm a teapot",
  "status": 418,
  "message": "Sorry Adam, I cannot make you coffee",
  "context": {
    "foo": "bar"
  },
  "extra": {
    "name": "Adam",
    "more": "lines",
    "complex": {
      "one": "two"
    }
  },
  "path": "/",
  "args": {},
  "exceptions": [
    {
      "type": "TeapotError",
      "exception": "Sorry Adam, I cannot make you coffee",
      "frames": [
        {
          "file": "handle_request",
          "line": 83,
          "name": "handle_request",
          "src": ""
        },
        {
          "file": "/tmp/p.py",
          "line": 17,
          "name": "handler",
          "src": "raise TeapotError("
        }
      ]
    }
  ]
}

# 后台任务管理(Background task management)

当使用 app.add_task 方法创建后台任务时,可以额外的设置一个 name 参数,方便后续获取或取消任务。

app.add_task(dummy, name="dummy_task")
task = app.get_task("dummy_task")
app.cancel_task("dummy_task")

# 定义路由中的上下文参数(Route context kwargs in definitions)

定义路由时,您可以添加任意数量的带有' ctx_ '前缀的关键字参数。这些值将被注入到路由“ctx”对象中。

@app.get("/1", ctx_label="something")
async def handler1(request):
    ...
@app.get("/2", ctx_label="something")
async def handler2(request):
    ...
@app.get("/99")
async def handler99(request):
    ...
@app.on_request
async def do_something(request):
    if request.route.ctx.label == "something":
        ...

# 蓝图可以在任意时刻注册

在以前的 Sanic 版本中,蓝图的注册顺序有着严格的限制,如果您在响应函数注册到蓝图之前将蓝图注册到应用程序中,这些对象将会丢失。

现在,您可以随时注册一个蓝图,所有被注册到蓝图上的响应函数都将在启动时被包含。

# 通知异常 (将所有的异常输出到日志中)

新增了一个 NOISY_EXCEPTIONS 配置项,该配置项默认为 False。 Sanic 支持任何静默异常,这意味着如果您在捕获异常后设置了 quiet=False 参数,该异常将不会在日志中输出。

但是当您设置了 NOISY_EXCEPTIONS 为 True 时,无论 quiet 如何进行设置,都将被记录。

这在调试时极为有用。

app.config.NOISY_EXCEPTIONS = True

# 可枚举的信号事件

为了方便,我们内置了一个能够枚举所有信号的事件

from sanic.signals import Event
@app.signal(Event.HTTP_LIFECYCLE_BEGIN)
async def connection_opened(conn_info):
    ...

# 自定义环境变量的类型转换

默认情况下,在环境变量中加载 config 配置的时候,Sanic 将主动转换配置为可能的类型,您可以通过配置转换器来进行控制:

app = Sanic(..., config=Config(converters=[UUID]))

# 通过配置项禁用 uvloop

现在 uvloop 的使用可由配置值进行控制:

app.config.USE_UVLOOP = False

# 使用多个 TLS 证书运行 Sanic 服务

现在 Sanic 支持使用多个不同的 TLS 证书运行:

app.run(
    ssl=[
        "/etc/letsencrypt/live/example.com/",
        "/etc/letsencrypt/live/mysite.example/",
    ]
)

# 新闻(News)

# 即将发布:《Sanic web 开发》

由 Sanic 核心开发人员 @ahopkins (opens new window) 主笔的新书即将发布,访问 sanicbook.com (opens new window) 了解更多信息。

掌握使用 Sanic 的实用知识,以提高 web 应用程序的性能和可伸缩性。除此之外,我们将提高您的开发技能,让您学会定制您的应用程序,以满足不断变化的业务需求,而不必对应用程序进行重大的过度设计。

该书的收入将按照一定的比例捐赠给 SCO ,用于 Sanic 的进一步发展。因此购买此书是你支持 Sanic 发展的另一种方式。

# 文档的深色模式(Dark mode for the docs)

如果您还没有注意到,该网站现在支持原生在深色模式和浅色模式之间进行切换,您可以通过页面的右上角来进行手动切换。

# 鸣谢(Thank you)

感谢每一位参与本次发布的人:👏

@adarsharegmi (opens new window) @ahopkins (opens new window) @ashleysommer (opens new window) @ChihweiLHBird (opens new window) @cnicodeme (opens new window) @kianmeng (opens new window) @meysam81 (opens new window) @nuxion (opens new window) @prryplatypus (opens new window) @realDragonium (opens new window) @SaidBySolo (opens new window) @sjsadowski (opens new window) @Tronic (opens new window) @Varriount (opens new window) @vltr (opens new window) @whos4n3 (opens new window)

并且,特别感谢 @ConnorZhang (opens new window)@ZinkLu (opens new window),他们在同步翻译最新中文文档上付出了巨大精力。


如果您喜欢本项目,请考虑参与建设本项目。我们欢迎您提交代码,也欢迎您以任何其他方式来参与本项目的建设。比如撰写文档,分享使用心得,参与社区讨论,当然,如果经济允许,您也可以考虑经济资助 (opens new window)

MIT Licensed
Copyright © 2018-present Sanic Community Organization

~ Made with ❤️ and ☕️ ~