Wagtail 1.13.4 版本发布说明:Beautiful Soup 依赖版本锁定与富文本 HTML 清理机制解析
Wagtail 1.13.4 版本发布说明Beautiful Soup 依赖版本锁定与富文本 HTML 清理机制解析【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail本文以 Wagtail 1.13.42018 年 8 月 13 日发布的官方发布说明为骨架聚焦该版本唯一的修复项——将 Beautiful Soup 锁定为 4.6.0并回溯 1.13.3 中标记 4.6.1 不兼容的背景深入剖析 Wagtail 依赖 Beautiful Soup 进行富文本 HTML 白名单清理的实现细节帮助读者理解依赖版本锁定背后真实的技术动因。版本概况Wagtail 1.13.4 是 1.13 系列的第 4 个补丁版本于2018 年 8 月 13 日发布与 1.13.3 同日发布两者均为当天维护周期的产物。整个发布说明非常精简仅包含一个修复项将 Beautiful Soup 固定Pin到 4.6.0原因是 4.6.1 在格式化空元素formatting empty elements方面存在进一步回归Bug fixes修复人Matt Westcott。说明本篇文章围绕该 release notes 展开文中关于后续小版本1.13.x 之后的内容仅用于佐证该修复在维护分支中的一致性核心分析对象为 1.13.4。该修复记录同样存在于仓库根目录的 CHANGELOG.txt 中1.13.4 (13.08.2018)一节并且后续维护分支的变更日志中也有对应条目说明这是当时各维护线同步合入的修复。为什么一个依赖版本锁定值得一个补丁版本1.13.3 与 1.13.4同一天发布的两个补丁要理解 1.13.4 的修复必须先看它的前一个补丁 1.13.3。根据 docs/releases/1.13.3.rst 与 CHANGELOG.txt1.13.3 的修复内容为将 django-taggit 固定到0.23以恢复对 Django 1.8 的兼容性Matt Westcott将 Beautiful Soup 4.6.1 标记为不兼容原因是其在格式化空元素时存在 bugMatt Westcott。也就是说1.13.3 已经发现了 Beautiful Soup 4.6.1 的空元素格式化问题并声明其不兼容但当时尚未指定替代版本。1.13.4 则进一步把版本正向锁定到 4.6.0从而给出明确的、可用的依赖版本。之所以说进一步回归further regressions是因为 Beautiful Soup 在 4.6.x 这一系列中反复出现空元素格式化问题导致 Wagtail 不得不在相邻的补丁版本里连续跟进处理。空元素格式化问题为何会波及 WagtailWagtail 的富文本编辑与存储并不直接保存 HTML而是保存一种自定义的db-HTML中间格式再在渲染时转换为真正的 HTML。这个过程依赖 HTML 解析与序列化而 Beautiful Soup 正是 Wagtail 在此环节使用的解析器。当 Beautiful Soup 在序列化空元素如img、br、hr时行为不一致例如输出成/img、错误地闭合或转义属性引号会直接影响 Wagtail 白名单清理后产出的 HTML 结构进而破坏 db-HTML 到真实 HTML 的转换。因此这一看似上游库的 bug对 Wagtail 是必须立即修复的阻断性问题。Beautiful Soup 在 Wagtail 源码中的真实角色1. 白名单清理引擎whitelist.pyWagtail 的核心依赖点位于 wagtail/whitelist.py这是一个通用 HTML 白名单引擎专为通过子类化来覆盖特定规则而设计from bs4 import BeautifulSoup, Comment, NavigableString, Tag from django.utils.html import escape ALLOWED_URL_SCHEMES [http, https, ftp, mailto, tel] PROTOCOL_RE re.compile(^[a-z0-9][-.a-z0-9]*:)其核心类Whitelister的clean方法将任意 HTML 字符串解析进 Beautiful Soup 文档树就地清理后再序列化def clean(self, html): Clean up an HTML string to contain just the allowed elements / attributes doc BeautifulSoup(html, html.parser) self.clean_node(doc, doc) # Pass strings through django.utils.html.escape when generating the final HTML. # This differs from BeautifulSoups default EntitySubstitution.substitute_html formatter # in that it escapes to quot; as well as escaping - if we dont do this, then # BeautifulSoup will try to be clever and use single-quotes to wrap attribute values, # which confuses our regexp-based db-HTML-to-real-HTML conversion. return doc.decode(formatterescape)这段代码的注释直接点出了空元素/属性格式化问题对 Wagtail 的杀伤力Beautiful Soup 默认的substitute_html格式化器会用单引号包裹属性值这会混淆 Wagtail 基于正则的 db-HTML→真实 HTML 转换因此 Wagtail 必须显式传入formatterescape。一旦 Beautiful Soup 4.6.1 在序列化空元素时发生回归decode()输出的 HTML 就可能不符合 Wagtail 的后续解析预期。2. db-HTML 转换器db_html.py另一个依赖点在 wagtail/admin/rich_text/converters/db_html.pyfrom bs4 import BeautifulSoup ... doc BeautifulSoup(html, html.parser)该转换器负责把富文本编辑器Hallo产生的 db-HTML 解析为可渲染的 HTML同样依赖 Beautiful Soup 的解析与序列化行为。可以看到Wagtail 全部使用内置的html.parser解析器而非依赖外部 C 扩展如 lxml这也让纯 Python 解析器的格式化行为成为整个链条中不可忽视的变量。3. 文本提取text.py在 wagtail/utils/text.py 中Beautiful Soup 还被用于从富文本中提取纯文本from bs4 import BeautifulSoup def text_from_html(val): return BeautifulSoup(force_str(val), html.parser).getText().strip()这一函数用于诸如搜索索引、摘要生成等场景同样受上游序列化行为影响。默认白名单规则被空元素格式化直接影响的部分在 wagtail/whitelist.py 的DEFAULT_ELEMENT_RULES中可以看到大量典型的空元素void elements与内联元素DEFAULT_ELEMENT_RULES { [document]: allow_without_attributes, a: attribute_rule({href: check_url}), b: allow_without_attributes, br: allow_without_attributes, div: allow_without_attributes, em: allow_without_attributes, h1: allow_without_attributes, h2: allow_without_attributes, h3: allow_without_attributes, h4: allow_without_attributes, h5: allow_without_attributes, h6: allow_without_attributes, hr: allow_without_attributes, i: allow_without_attributes, img: attribute_rule( {src: check_url, width: True, height: True, alt: True} ), li: allow_without_attributes, ol: allow_without_attributes, p: allow_without_attributes, strong: allow_without_attributes, sub: allow_without_attributes, sup: allow_without_attributes, ul: allow_without_attributes, }其中的br、hr、img正是 HTML 规范中的空元素void elements它们在 XHTML 与 HTML 5 之间的序列化方式差异恰是 Beautiful Soup 4.6.1 回归的重灾区。Wagtail 的白名单清理会将这些标签解析、校验属性后重新序列化——一旦上游序列化器对空元素处理出错例如多输出斜杠、错误闭合、属性引号风格变化最终写入数据库或渲染输出的 HTML 就会与预期不一致。URL 安全检查与属性规则白名单不仅过滤标签还通过attribute_rule与check_url对属性做二次校验例如img只允许src、width、height、alt四个属性且src必须通过 URL 检查。check_url会剥离控制字符、HTML 实体并校验协议必须属于ALLOWED_URL_SCHEMEShttp、https、ftp、mailto、tel用于防止javascript:等危险协议注入——这与 1.13.2 修复的URL 中的空字符不再使重定向中间件崩溃等安全相关修复一脉相承。依赖锁定与安全补丁版本背后的工程实践从 1.13.2、1.13.3 到 1.13.4 的连续补丁可以看出 Wagtail 维护者对依赖版本的严谨态度版本发布时间依赖相关修复1.13.22018-07-04修复 ElasticsearchATOMIC_REBUILD、URL 空字符崩溃等1.13.32018-08-13固定 django-taggit0.23恢复 Django 1.8 兼容标记 Beautiful Soup 4.6.1 不兼容1.13.42018-08-13将 Beautiful Soup 固定到 4.6.0解决空元素格式化进一步回归这种先标记不兼容、再锁定可用版本的两步走策略是开源项目应对上游依赖回归时的典型做法在无法立即修复上游时通过安装约束pinning保证既有用户的确定性同时维护者 Matt Westcott 也持续跟进上游最终通过锁定 4.6.0 让依赖关系恢复稳定。结语Wagtail 1.13.4 虽然只包含一行修复记录但它揭示了一个重要事实像 Beautiful Soup 这样的解析库其序列化细节会直接决定 CMS 富文本存储与渲染的正确性。从 wagtail/whitelist.py 的白名单引擎到 wagtail/admin/rich_text/converters/db_html.py 的 db-HTML 转换再到 wagtail/utils/text.py 的纯文本提取Beautiful Soup 贯穿 Wagtail 富文本处理的关键链路。因此当上游在空元素格式化上出现回归时Wagtail 以最快的速度发布补丁版本、锁定 4.6.0也就不足为奇了。对于使用或研究 Wagtail 的开发者这一版本记录也提供了一个实用的经验在 CMS 类项目中依赖的解析/序列化库版本变动可能比表面看起来影响更大固定关键依赖版本、并在升级前充分验证富文本输出的稳定性是值得纳入发布流程的工程实践。【免费下载链接】wagtailA Django content management system focused on flexibility and user experience项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考