用真实 gunicorn 与 curl 验证 Range 请求:send_file 的 206 与 Content-Range(起止、后缀、开放区间、超出长度截断);越界、反向、多段、非 bytes 单位都是 416;If-Range;curl -C - 断点续传 SHA-256 一致;生成器响应不支持 Range;自己实现的 206;HEAD + Range。
实测 Flask 的内容协商:Accept 的 q 值、通配符、同 q 值时服务器列表顺序决定、q=0、没有 Accept 头时 best_match 为 None;accept_mimetypes 的接口与 */* 的误判;406 与 Vary: Accept;Accept-Language 匹配;Accept-Encoding;URL 后缀;curl 与 requests 的默认 Accept。
验证 Flask 的 Jinja2 模板加载:DispatchingJinjaLoader 与 FileSystemLoader;get_source 返回 (源码, 文件名, uptodate);DictLoader、ChoiceLoader、PrefixLoader、FunctionLoader;在 Flask 里换加载器;模板被编译成 Python 生成器函数;编译约是渲染的 191 倍。
实测 Flask 模板的搜索路径:先应用的 templates 再按注册顺序的蓝图,同名先找到的赢;render_template 传列表取第一个存在的;.. 与绝对路径的模板名被拒;用 ChoiceLoader 加额外目录;render_template_string 的 include 仍走加载器;list_templates 与同名冲突检查。
实测 Jinja2 模板继承:block 覆盖与 super();多级继承;嵌套 block;循环里的 block 要加 scoped 才能读到循环变量;self.block;动态 extends;extends 前的文字照样输出;include 的 context 选项;继承每多一层约 2.0 µs。
实测 Flask 的上下文处理器:默认注入 g 与 request;自己的处理器合并进每次渲染、后注册覆盖先注册、视图传的最优先;每次渲染执行一次;蓝图的只对蓝图生效、app_ 前缀的全局生效;处理器里放函数实现惰性;10 个各 0.5 ms 的处理器让每次渲染变成约 7889 µs。
实测自定义 Jinja 过滤器:四种注册方式;链式;返回 str 会被转义、Markup 才是 HTML,Markup(f"…{s}…") 会导致 XSS 而 Markup.format 是正确写法;pass_context 与 pass_environment;None 与 Undefined;第一个请求之后不能再注册;内置过滤器共 54 个。
实测 Flask 的模板全局:template_global、add_template_global、jinja_env.globals、蓝图的 app_template_global、pass_context;渲染时传入的同名变量优先;被 import 的宏(不带 context)能看到全局但看不到上下文处理器的变量;全局值只求值一次;未被调用的全局函数执行 0 次。
实测自定义 Jinja 测试:x is name 与 is not;带参数的测试;pass_context;与 select/reject/selectattr 配合;内置测试与 Python 真假值的区别(defined、none、true);错误信息;全部 45 个测试;测试、过滤器、全局函数的耗时对比。
实测 Jinja 自动转义:只看扩展名(.html.j2 与 .jinja 不转义);转义哪五个字符;属性、href、script、style 各上下文下的实际输出;把用户输入拼进模板源码会泄露 SECRET_KEY;|safe 与 autoescape;tojson。
实测 Markup 与 |safe:Markup 是 str 子类,运算会转义另一侧的 str;Markup(f"…{u}…") 与 Markup("…%s…" % u) 会让用户输入未转义;format 与 % 是安全写法;模板里 safe/e/forceescape/striptags;__html__ 协议;大写会弄坏实体。
实测 Jinja2 宏:import 与 from-import;call 块与带参数的 caller();签名里不能写 *args,体内用 varargs 与 kwargs;递归与默认值;作用域(import 默认读不到调用方变量);自动转义;500 行表格里宏调用约为直接写的 3.3 倍。