Sanic 核心 API 完全指南:cookies、handlers、headers、request、response 与 views 模块源码级解析
2026/9/20 15:25:18 网站建设 项目流程
  • 后端
  • Web框架

【免费下载链接】sanic

Accelerate your web app development | Build fast. Run fast.

项目地址:https://gitcode.com/gh_mirrors/sa/sanic
点击查看免费下载

本文以 docs/sanic/api/core.rst 为骨架,系统讲解 Sanic 六个核心模块:sanic.cookiessanic.handlerssanic.headerssanic.requestsanic.responsesanic.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.handlerssanic.headerssanic.requestsanic.responsesanic.views:members:表示列出模块内所有公开成员,:show-inheritance:则会显示继承关系(例如CookieRequestParameters继承自RequestParametersHeader继承自CIMultiDict)。因此,本文讲解的"内容实体"其实都来自这六个模块的源码,核心文件如下:

模块主要源码文件
sanic.cookiessanic/cookies/request.py、sanic/cookies/response.py
sanic.handlerssanic/handlers/error.py、sanic/handlers/content_range.py、sanic/handlers/directory.py
sanic.headerssanic/headers.py、sanic/compat.py(Header 容器)
sanic.requestsanic/request/types.py、sanic/request/parameters.py、sanic/request/form.py
sanic.responsesanic/response/types.py、sanic/response/convenience.py
sanic.viewssanic/views.py

二、sanic.cookies:Cookie 的解析与安全写入

sanic.cookies模块同时承担两个方向的工作:解析请求中携带的 Cookie(sanic/cookies/request.py),以及构造响应中要写出的 Cookie(sanic/cookies/response.py)。模块公开导出CookieCookieJar两个类(见 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 生效路径
domainNone生效域名
secureTrue仅 HTTPS 传输
max_ageNone存活秒数;设为0表示让浏览器删除该 Cookie
expiresNonedatetime过期时间;为None表示会话级 Cookie
httponlyFalse禁止 JavaScript 读取
samesite"Lax"可选strict/lax/none(大小写不敏感)
partitionedFalseCHIPS 分区 Cookie
commentNoneCookie 注释
host_prefixFalse键加__Host-前缀
secure_prefixFalse键加__Secure-前缀

类的构造器会做严格校验(sanic/cookies/response.py):Cookie 名称不能是保留字(如pathdomain_keys中的属性名),不能包含非法字符;host_prefix必须同时满足secure=Truepath="/"domain=Nonepartitioned=True必须配合host_prefix=True,否则抛出ServerError。字符串化时,__str__会按固定顺序输出PathExpiresSameSiteSecureHttpOnly等属性,例如:

Set-Cookie: __Host-sid=abc123; Path=/; SameSite=Lax; Secure; HttpOnly

Cookie.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):创建Cookieheaders.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_optionstest_cookie_deletiontest_cookie_bad_max_agetest_false_cookies_encoded等用例。更完整的业务化教程可继续阅读 guide/content/en/guide/basics/cookies.md。

三、sanic.handlers:异常、范围请求与目录处理

sanic.handlers模块导出三个处理器(见 sanic/handlers/init.py):ErrorHandlerContentRangeHandlerDirectoryHandler

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拆解;解析失败或缺失时分别抛出HeaderNotFoundInvalidRangeTypeRangeNotSatisfiable。这部分能力与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携带typesubtypeq权重与其余参数,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头,并要求其中bysecret字段等于config.FORWARDED_SECRET才会采信,防止伪造;
  • parse_xforwarded(headers, config)(sanic/headers.py):解析传统代理头,受REAL_IP_HEADERPROXIES_COUNTFORWARDED_FOR_HEADER配置控制;
  • 两者最终都会经fwd_normalize/fwd_normalize_address归一化(IPv6 加方括号、小写化、unknown值剔除、path 做 URL 解码)。

这些解析器正是request.iprequest.remote_addrrequest.client_iprequest.schemerequest.host等属性的数据来源(sanic/request/types.py),相关场景在 tests/test_requests.py 的test_standard_forwardedtest_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模块导出RequestRequestParametersFileparse_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.filesget_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_valuesstrict_parsingencodingerrors四个可调参数,用于处理空白值保留、严格解析与编码容错等边界需求。

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 # 完整 URL

url_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:所有响应的基类,持有bodystatusheaderscontent_typestream,提供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_bodyappendextendupdatepop就地修改原始数据并自动重序列化的方法(对 list 用append/extend/pop,对 dict 用update/pop,类型不符抛SanicException);
  • ResponseStreamStreamingHTTPResponse弃用后的兼容层,包装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;未实现的方法由路由层返回405dispatch_request中的NotImplementedError仅作为兜底;
  • as_view()(sanic/views.py):返回路由可用的闭包,支持向类构造器传参(DummyView.as_view(foo=MyFoo())),并自动套用类级decorators列表;
  • attach()(sanic/views.py):把视图挂到 app 或 Blueprint 上,参数与add_route对齐:methods(默认{"GET"})、hoststrict_slashesversionnamestreamversion_prefix(默认/v);
  • stream 标记stream(func)装饰器(sanic/views.py)给处理函数打上is_stream = True,配合stream=True参数启用流式视图。

相关行为在 tests/test_views.py 中由test_methodstest_unexisting_methods(验证 405)、test_argument_methodstest_with_bptest_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)

这里用到了:headersuser_agent属性式访问)、request(路径参数、JSON 解析、查询参数)、responsejson构造器 + Cookie)、viewsHTTPMethodView子类化时直接挂载)、cookiesadd_cookie)。异常、代理头解析与静态文件服务则分别由handlersheaders的其余函数按需接入。

九、总结与延伸阅读

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.pyamending_request_object.pytry_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.

项目地址:https://gitcode.com/gh_mirrors/sa/sanic
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询