# Version 21.12
- 介绍(Introduction)
- 更新内容(What to know)
- 更严格的应用程序和蓝图命名检查(Strict application and blueprint names)
- 更严格的应用程序和蓝图属性检查(Strict application and blueprint properties)
- 功能迁移(Removals)
- 升级您的流式响应 (如果您尚未准备好弃用)
- CLI 样式更新及每日消息(MOTD)
- 服务运行模式和 debug 的更改
- 最大线程数(Max allowed workers)
- 一流的 Sanic 拓展支持(First-class Sanic Extensions support)
- 上下文异常(Contextual exceptions)
- 后台任务管理(Background task management)
- 定义路由中的上下文参数(Route context kwargs in definitions)
- 蓝图可以在任意时刻注册
- 通知异常 (将所有的异常输出到日志中)
- 可枚举的信号事件
- 自定义环境变量的类型转换
- 通过配置项禁用 uvloop
- 使用多个 TLS 证书运行 Sanic 服务
- 新闻(News)
- 鸣谢(Thank you)
# 介绍(Introduction)
该版本为 21 版本 发布周期 中的最后一个发行版本,目前 21 版本将进入长期维护状态,直至 2023 年 12 月。
# 更新内容(What to know)
更多详情请见 更新记录 (opens new window)。值得注意的新功能或突破性功能,以及要升级的内容...
# 更严格的应用程序和蓝图命名检查(Strict application and blueprint names)
在 v21.6 中,应用程序或蓝图的名称需要符合新的命名规范,现在该规范将在应用启动时进行强制检查。
名称 必须 符合以下规则:
- 只允许使用字母和数字 (
a-zA-Z0-9
) - 可以包含连接符 (
-
) 或下划线 (_
) - 必须以字母或者下划线开头 (
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 拓展 就能够轻松地使用其所有功能,无需进行额外的设置,这些功能包括:
- 能够自动创建
HEAD
,OPTIONS
,和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
但这样会忽视两个非常重要的问题:
- 如何设置动态且可预测的消息格式
- 如何向错误消息中添加额外上下文内容
当前版本允许任何 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"})
新特性允许您向异常传递额外的信息,在生产模式下,该信息将不会被输出,但是在开发模式下它将进行显示。
生产模式
开发模式
回到我们刚才提到的第二个问题:如何向错误消息中添加额外上下文内容
这在创建微服务或 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)。