- 后端
- Web框架
【免费下载链接】sanic
Accelerate your web app development | Build fast. Run fast.
本文以 docs/sanic/api/core.rst 为骨架,系统讲解 Sanic 六个核心模块:sanic.cookies、sanic.handlers、sanic.headers、sanic.request、sanic.response与sanic.views。读完本文,你将掌握请求对象(Request)的完整属性体系、响应对象(Response)与便捷构造器、Cookie 的安全默认值与读写 API、异常处理器扩展、HTTP 头解析工具以及类视图(HTTPMethodView)的挂载方式,并能在实际业务中直接复用这些代码片段。
一、core.rst:Sanic 核心 API 参考的组织方式
docs/sanic/api/core.rst是 Sanic 文档体系中 Sphinx 自动生成 API 参考的入口之一,它通过automodule指令把六个模块的公开成员(类、函数、属性)直接"拉取"进文档:
sanic.cookies ------------- .. automodule:: sanic.cookies :members: :show-inheritance:同样的指令还覆盖sanic.handlers、sanic.headers、sanic.request、sanic.response与sanic.views。:members:表示列出模块内所有公开成员,:show-inheritance:则会显示继承关系(例如CookieRequestParameters继承自RequestParameters、Header继承自CIMultiDict)。因此,本文讲解的"内容实体"其实都来自这六个模块的源码,核心文件如下:
| 模块 | 主要源码文件 |
|---|---|
| sanic.cookies | sanic/cookies/request.py、sanic/cookies/response.py |
| sanic.handlers | sanic/handlers/error.py、sanic/handlers/content_range.py、sanic/handlers/directory.py |
| sanic.headers | sanic/headers.py、sanic/compat.py(Header 容器) |
| sanic.request | sanic/request/types.py、sanic/request/parameters.py、sanic/request/form.py |
| sanic.response | sanic/response/types.py、sanic/response/convenience.py |
| sanic.views | sanic/views.py |
二、sanic.cookies:Cookie 的解析与安全写入
sanic.cookies模块同时承担两个方向的工作:解析请求中携带的 Cookie(sanic/cookies/request.py),以及构造响应中要写出的 Cookie(sanic/cookies/response.py)。模块公开导出Cookie与CookieJar两个类(见 sanic/cookies/init.py)。
2.1 请求侧:parse_cookie 与 CookieRequestParameters
HTTP 规范允许同名 Cookie 出现多次,所以 Sanic 没有用普通字典解析,而是先由parse_cookie(raw)把原始Cookie请求头按;拆分,返回dict[str, list[str]]:
raw = 'name1=value1; name2="value2"; name3=value3' cookies = parse_cookie(raw) # {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}解析细节体现在源码中:
- 用
COOKIE_NAME_RESERVED_CHARS(sanic/cookies/request.py)过滤名称中()<>@,;:\"/[]?={}等保留字符,非法名称会被跳过; - 支持
=value这类只有值没有名字的 Cookie(对应 httpwg 讨论的边界情况); - 带引号的值会经过
_unquote处理,支持八进制转义(\052)与\x转义。
CookieRequestParameters继承自RequestParameters,行为上"像字典但允许重复键":request.cookies['key']返回第一个值,request.cookies.getlist('key')返回全部值。它在__getitem__和get中还会优先查找带前缀的 Cookie(见下文__Host-/__Secure-),从而实现请求侧与响应侧前缀机制的对称(sanic/cookies/request.py)。
2.2 响应侧:Cookie 的"智能安全默认值"
Cookie类(sanic/cookies/response.py)是一份"安全优先"的 Cookie 表示,两个默认值尤为关键:
secure=True:默认仅允许通过 HTTPS 传输;samesite="Lax":默认启用 SameSite=Lax 防 CSRF。
完整参数如下(均可在response.add_cookie/CookieJar.add_cookie中使用):
| 参数 | 默认值 | 说明 |
|---|---|---|
path | "/" | Cookie 生效路径 |
domain | None | 生效域名 |
secure | True | 仅 HTTPS 传输 |
max_age | None | 存活秒数;设为0表示让浏览器删除该 Cookie |
expires | None | datetime过期时间;为None表示会话级 Cookie |
httponly | False | 禁止 JavaScript 读取 |
samesite | "Lax" | 可选strict/lax/none(大小写不敏感) |
partitioned | False | CHIPS 分区 Cookie |
comment | None | Cookie 注释 |
host_prefix | False | 键加__Host-前缀 |
secure_prefix | False | 键加__Secure-前缀 |
类的构造器会做严格校验(sanic/cookies/response.py):Cookie 名称不能是保留字(如path、domain等_keys中的属性名),不能包含非法字符;host_prefix必须同时满足secure=True、path="/"、domain=None;partitioned=True必须配合host_prefix=True,否则抛出ServerError。字符串化时,__str__会按固定顺序输出Path、Expires、SameSite、Secure、HttpOnly等属性,例如:
Set-Cookie: __Host-sid=abc123; Path=/; SameSite=Lax; Secure; HttpOnlyCookie.make_key(sanic/cookies/response.py)实现了__Host-与__Secure-前缀拼接,并禁止两者同时使用。
2.3 CookieJar:动态写头
CookieJar(sanic/cookies/response.py)绑定了响应头对象(Header),用Set-Cookie作为键动态写入多个 Cookie:
add_cookie(key, value, **options):创建Cookie并headers.add("Set-Cookie", cookie);delete_cookie(key, ...):不会真正删除头,而是重写为value=""、max_age=0,让浏览器按规范删掉它;get_cookie(...)/has_cookie(...):按 key + path + domain 精确检索。
2.4 在响应上直接使用
BaseHTTPResponse暴露了cookies属性与add_cookie/delete_cookie方法(sanic/response/types.py),因此路由处理器里最常用的写法是:
from sanic.response import json @app.get("/login") async def login(request): response = json({"ok": True}) response.add_cookie( "session", "token-value", httponly=True, samesite="lax", max_age=3600, ) return response相关的行为在 tests/test_cookies.py 中有完整覆盖,包括test_cookie_options、test_cookie_deletion、test_cookie_bad_max_age、test_false_cookies_encoded等用例。更完整的业务化教程可继续阅读 guide/content/en/guide/basics/cookies.md。
三、sanic.handlers:异常、范围请求与目录处理
sanic.handlers模块导出三个处理器(见 sanic/handlers/init.py):ErrorHandler、ContentRangeHandler、DirectoryHandler。
3.1 ErrorHandler:可扩展的异常处理框架
ErrorHandler(sanic/handlers/error.py)处理应用内所有未被捕获的异常。它内部维护cached_handlers字典,键为(异常类型, 路由名),并用"精确匹配 → MRO 祖先匹配"两级查找加速:
add(exception, handler, route_names=None):注册异常处理器,可限定到特定路由;重复注册同名处理函数会抛出ServerError;lookup(exception, route_name):先查精确类型,再沿type.mro()向上找父类处理器,找到后会写入缓存;response(request, exception):执行处理器;若处理器本身抛异常,会在 debug 模式下返回定位信息,否则返回通用 500。
扩展方式非常直观——子类化并覆写default():
from sanic import Sanic, Request from sanic.handlers import ErrorHandler from sanic.response import HTTPResponse, text class CustomErrorHandler(ErrorHandler): def default(self, request: Request, exception: Exception) -> HTTPResponse: # 自定义记录与响应逻辑 return text("custom error", status=500) app = Sanic("MyApp", error_handler=CustomErrorHandler())这是源码 docstring 中给出的官方用法(sanic/handlers/error.py),也是监控类扩展(如上报到 Sentry、Raygun,参见 examples/sentry_example.py 与 examples/raygun_example.py)的底层入口。
3.2 ContentRangeHandler:Range 请求解析
ContentRangeHandler(sanic/handlers/content_range.py)继承Range,用于解析Range请求头,支撑断点续传。它要求单位必须是bytes,按start-end拆解;解析失败或缺失时分别抛出HeaderNotFound、InvalidRangeType、RangeNotSatisfiable。这部分能力与response.file/file_stream的_range参数配合(见第五节)。
3.3 DirectoryHandler:静态目录安全服务
DirectoryHandler(sanic/handlers/directory.py)负责为app.static(...)目录模式提供文件服务,支持:
directory_view:是否展示目录列表;index:请求目录时返回的索引文件名;root_path:安全根路径,配合_is_path_within_root(sanic/handlers/directory.py)做 symlink 越界防护——解析后落在根目录之外的软链接会被隐藏,避免目录穿越;follow_external_symlink_files/follow_external_symlink_dirs:显式控制是否放行指向外部的软链接。
四、sanic.headers:HTTP 头解析工具箱
4.1 Header 容器:大小写不敏感、支持多值
Sanic 请求与响应的headers都是Header对象(sanic/compat.py),它继承自multidict.CIMultiDict:
- 大小写不敏感:
request.headers["Content-Type"]与request.headers["content-type"]等价; - 支持多值:
getall(key)返回同名头的全部值,getone(key)取第一个; - 属性式访问
headers.accept_encoding会自动把下划线转成连字符并拼接多值。
RequestParameters(sanic/request/parameters.py)则是查询串、表单、Cookie 的通用容器:get()返回第一个值,getlist()返回完整列表。
4.2 Accept 头解析:MediaType 与 AcceptList
parse_accept(accept)(sanic/headers.py)按 RFC 7231 §5.3.2 把Accept头解析为AcceptList(一组按优先级排序的MediaType):
MediaType携带type、subtype、q权重与其余参数,match()支持双向通配符(*/*、text/*)匹配;AcceptList.match(*mimes)返回Matched对象:优先 q 值与更具体的类型,其次按参数顺序,最后按 Accept 头中的顺序;Matched可当字符串用,且可判空(没匹配到时为 falsy);- 请求对象上的便捷属性
request.accept(sanic/request/types.py)会惰性解析Accept头,缺省时等价于接受*/*。
if request.accept.match("text/html"): return html(...)4.3 代理头解析:RFC 7239 Forwarded 与传统 X-Forwarded-*
sanic.headers提供两套代理场景解析:
parse_forwarded(headers, config)(sanic/headers.py):解析 RFC 7239Forwarded头,并要求其中by或secret字段等于config.FORWARDED_SECRET才会采信,防止伪造;parse_xforwarded(headers, config)(sanic/headers.py):解析传统代理头,受REAL_IP_HEADER、PROXIES_COUNT、FORWARDED_FOR_HEADER配置控制;- 两者最终都会经
fwd_normalize/fwd_normalize_address归一化(IPv6 加方括号、小写化、unknown值剔除、path 做 URL 解码)。
这些解析器正是request.ip、request.remote_addr、request.client_ip、request.scheme、request.host等属性的数据来源(sanic/request/types.py),相关场景在 tests/test_requests.py 的test_standard_forwarded、test_forwarded_scheme等用例中验证。
4.4 其他实用解析函数
| 函数 | 作用 |
|---|---|
parse_content_header(value) | 解析content-type/content-disposition,如form-data; name=upload; filename="f.txt"→('form-data', {'name': 'upload', 'filename': 'f.txt'});自动解%22与%0D%0A转义(sanic/headers.py) |
parse_host(host) | 把host:port拆成主机名与端口(IPv6 加括号) |
parse_credentials(header) | 从 Authorization 等头中提取凭证前缀与值,默认匹配Basic/Bearer/Token,支持自定义前缀集合 |
format_http1_response(status, headers) | 把状态码与字节头拼装为 HTTP/1.1 响应头块,内部预编译了 0–999 的状态行查找表以提升性能(sanic/headers.py) |
五、sanic.request:请求对象的属性体系
sanic.request模块导出Request、RequestParameters、File与parse_multipart_form(见 sanic/request/init.py)。Request主体位于 sanic/request/types.py,几乎所有数据访问都是惰性解析的:首次访问时解析并缓存,后续直接复用。
5.1 主体数据:json / form / files
request.json:惰性调用load_json()(sanic/request/types.py),解析失败且 body 非空时抛BadRequest;也支持传入自定义loads;request.form/request.files:get_form()(sanic/request/types.py)依据Content-Type分支处理application/x-www-form-urlencoded(用parse_qs)与multipart/form-data(用parse_multipart_form流式拆分字段与上传文件);request.cookies:基于parse_cookie构造CookieRequestParameters(见第二节)。
5.2 查询参数
request.args/request.query_args底层是get_query_args()(sanic/request/types.py),使用urllib.parse.parse_qsl,并提供keep_blank_values、strict_parsing、encoding、errors四个可调参数,用于处理空白值保留、严格解析与编码容错等边界需求。
5.3 地址与 URL
request.ip # 对端 socket 地址 request.remote_addr # 代理解析后的客户端地址(forwarded['for']) request.client_ip # 优先代理地址,否则回退 request.ip(Sanic 23.6 起推荐) request.scheme # http/https/ws/wss,综合 SERVER_NAME、代理头与本地协议 request.host # 主机名:端口 request.server_name # 主机名 request.server_port # 端口 request.path # 路径 request.url # 完整 URLurl_for(view_name, **kwargs)(sanic/request/types.py)会自动推断 scheme 与 netloc(默认端口省略),生成指向指定视图的绝对 URL——这是模板与重定向场景下避免硬编码域名的最佳实践。
5.4 match_info 与 scope
request.match_info(sanic/request/types.py):路由匹配后注入的路径参数字典,如/<name>/<age:int>匹配出的值;request.scope:ASGI 模式下暴露的 ASGI scope,非 ASGI 模式访问会抛NotImplementedError。
完整示例可参考 examples/amending_request_object.py 与 guide/content/en/guide/basics/request.md。
六、sanic.response:响应对象与便捷构造器
sanic.response模块导出三类响应对象(sanic/response/types.py)和一批便捷函数(sanic/response/convenience.py)。
6.1 响应类层级
BaseHTTPResponse:所有响应的基类,持有body、status、headers、content_type、stream,提供send()、cookies属性与add_cookie/delete_cookie(第二节已述);HTTPResponse:普通响应,构造时自动把 str 编码为 bytes,支持async with(__aenter__返回send,__aexit__触发eof);JSONResponse:JSON 专用响应,content_type默认为application/json,支持自定义dumps;提供raw_body属性与set_body、append、extend、update、pop等就地修改原始数据并自动重序列化的方法(对 list 用append/extend/pop,对 dict 用update/pop,类型不符抛SanicException);ResponseStream:StreamingHTTPResponse弃用后的兼容层,包装streaming_fn,通过request.respond()建立流式通道,配合response.write()分块写数据。
6.2 便捷函数速查
| 函数 | 默认值/行为 |
|---|---|
text(body) | 默认text/plain; charset=utf-8,body 必须是 str |
json(body, dumps=None, **kwargs) | 默认application/json,可自定义编码器与 kwargs |
html(body) | text/html; charset=utf-8,支持__html__/_repr_html_协议对象 |
raw(body) | 不做任何编码,默认application/octet-stream |
empty(status=204) | 空 body 响应 |
redirect(to, status=302) | 对 URL 做quote_plus安全编码后写入Location(sanic/response/convenience.py) |
file(location, ...) | 读文件返回;支持If-Modified-Since校验返回 304、Range 返回 206、max_age/no_store缓存策略、filename下载名(sanic/response/convenience.py) |
file_stream(location, chunk_size=4096, ...) | 按块流式读文件,同样支持 Range;避免大文件整读内存 |
validate_file(request_headers, last_modified) | 与If-Modified-Since比较,命中则返回 304 |
file()内部的缓存策略逻辑值得注意:设置max_age时输出public, max-age=N并同步生成expires头;no_store=True时输出no-store;两者皆无则退化为no-cache(sanic/response/convenience.py)。Content-Range与 206 状态码的写入由_range参数驱动,与第三节的ContentRangeHandler解析结果一一对应。
from sanic import Sanic, Request from sanic.response import json, file_stream app = Sanic("demo") @app.get("/download/<name>") async def download(request: Request, name: str): return await file_stream( f"/data/files/{name}", filename=name, _range=request.range, # 断点续传 )七、sanic.views:类视图(Class-Based Views)
sanic.views提供HTTPMethodView(sanic/views.py)——把同一路径下不同 HTTP 方法组织成类方法,替代散落的函数式处理器,便于复用公共逻辑。
7.1 定义与挂载
from sanic import Sanic, Request from sanic.views import HTTPMethodView from sanic.response import text app = Sanic("cbv-demo") class DummyView(HTTPMethodView): def get(self, request: Request): return text("I am get method") def put(self, request: Request, my_param_here: str): return text(f"I am put method with {my_param_here}") # 三种挂载方式等价: app.add_route(DummyView.as_view(), "/<my_param_here>") # DummyView.attach(app, "/<my_param_here>") # class DummyView(HTTPMethodView, attach=app, uri="/<my_param_here>"):7.2 关键机制
- 路由分发:
dispatch_request()(sanic/views.py)把请求方法小写化后getattr取同名方法;HEAD请求自动回退到get;未实现的方法由路由层返回405,dispatch_request中的NotImplementedError仅作为兜底; - as_view()(sanic/views.py):返回路由可用的闭包,支持向类构造器传参(
DummyView.as_view(foo=MyFoo())),并自动套用类级decorators列表; - attach()(sanic/views.py):把视图挂到 app 或 Blueprint 上,参数与
add_route对齐:methods(默认{"GET"})、host、strict_slashes、version、name、stream、version_prefix(默认/v); - stream 标记:
stream(func)装饰器(sanic/views.py)给处理函数打上is_stream = True,配合stream=True参数启用流式视图。
相关行为在 tests/test_views.py 中由test_methods、test_unexisting_methods(验证 405)、test_argument_methods、test_with_bp、test_with_attach等用例覆盖。类视图的完整教程参见 guide/content/en/guide/advanced/class-based-views.md。
八、串联起来:一个最小可运行示例
把上述六个模块串起来,一个典型的 Sanic 应用如下:
from sanic import Sanic, Request from sanic.response import json, text from sanic.views import HTTPMethodView app = Sanic("core-demo") class UserView(HTTPMethodView, attach=app, uri="/user/<uid:int>"): async def get(self, request: Request, uid: int): # request.args / request.json / request.cookies 均为惰性解析 response = json({"uid": uid, "ua": request.headers.user_agent}) response.add_cookie("visited", "1", httponly=True) return response async def post(self, request: Request, uid: int): data = request.json return json({"received": data}, status=201) if __name__ == "__main__": app.run(host="0.0.0.0", port=8000, debug=True)这里用到了:headers(user_agent属性式访问)、request(路径参数、JSON 解析、查询参数)、response(json构造器 + Cookie)、views(HTTPMethodView子类化时直接挂载)、cookies(add_cookie)。异常、代理头解析与静态文件服务则分别由handlers与headers的其余函数按需接入。
九、总结与延伸阅读
docs/sanic/api/core.rst以 Sphinxautomodule的方式把 Sanic 最常用的六个模块沉淀为 API 参考,而它们的实现是理解 Sanic"请求进、响应出"整条链路的钥匙:headers负责原始头解析,request提供惰性数据访问,handlers兜底异常与静态文件,response负责统一出站,cookies横跨请求与响应两侧,views提供组织路由的类视图范式。建议继续阅读仓库中的对应章节以获得完整实战指引:
- guide/content/en/guide/basics/request.md:请求对象完整用法;
- guide/content/en/guide/basics/response.md:响应与流式传输;
- guide/content/en/guide/basics/cookies.md:Cookie 业务场景;
- guide/content/en/guide/advanced/class-based-views.md:类视图进阶;
- examples/ 目录下的
hello_world.py、amending_request_object.py、try_everything.py等示例可直接运行体验; - 对应测试文件 tests/test_cookies.py、tests/test_requests.py、tests/test_views.py、tests/test_response.py 是理解各模块边界行为的最佳参照。
- 后端
- Web框架
【免费下载链接】sanic
Accelerate your web app development | Build fast. Run fast.
相关推荐
Clay-viewer核心功能揭秘:为什么它是3D模型预览与导出的终极工具
Clay viewer核心功能揭秘:为什么它是3D模型预览与导出的终极工具 在当今数字内容创作和3D设计领域,一个优秀的3D模型预览与导出工具至关重要。 Cla
从零开始使用home-assistant-config:10分钟快速安装与基础配置
从零开始使用home assistant config:10分钟快速安装与基础配置 home assistant config是一个功能强大的智能家居配置项目,
后端Web框架Cloudflare Workers Playground API 完全指南:Handler、Request、Response 与边缘运行时核心能力
Cloudflare Workers Playground API 完全指南:Handler、Request、Response 与边缘运行时核心能力 Cloud
人工智能AI 技能AI 插件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考