AI Summary 11.17160.16 golang,html,开发语言摘要 2026-08-11
Go 服务 安全与性能之间平衡,为日志清洗、全文检索、富文本展示保驾护航 首选 Bluemonday 外部用户输入、安全要求高 ,按需裁剪
Go删除HTML标签 正则/Bluemonday
1 为什么删除 HTML 标签?
- 安全:去掉潜在的
<script onload=…>等恶意标签,防止存储型 XSS。 - 可读性:日志、消息队列、搜索索引里往往只需要纯文本。
- 一致性:不同富文本编辑器生成的 HTML 五花八门,统一成「干净文本」更好比对与检索。
2 三种主流方案
| 方案 | 依赖 | 适用场景 | 优势 | 局限 |
|---|---|---|---|---|
| 方案 A:一行正则 | 无 | 临时脚本、CLI 工具 | 最短代码、零依赖 | 正则难以 100 % 解析 HTML;对嵌套/异常标签不稳 |
| 方案 B:状态机+正则混合 | 无 | 服务端清洗、边缘网关 | 无依赖,较稳妥,能过滤注释/脚本/样式 | 代码量比 A 大;维护自定义过滤逻辑 |
| 方案 C:Bluemonday | github.com/microcosm‑cc/bluemonday ≥ v1.0.20 (最新 1.0.27) | 安全网关、大规模服务 | 社区维护、AST 级过滤、完善的 XSS 防护 | 需要外部库;离线机器需手动 vendor / replace |
3 方案 A:最小化正则(30 字节代码)
package striphtml_a
import (
"html"
"regexp")
var re = regexp.MustCompile(`(?is)<!--.*?-->|<script\b.*?</script>|<style\b.*?</style>|<[^>]+>`)
func Strip(s string) string { return html.UnescapeString(re.ReplaceAllString(s, "")) }(?is)同时打开 ignore‑case + single‑line。- 同时去掉注释、脚本、样式和所有其他标签。
- 不要用于严格安全场景:对故意构造的畸形标签仍可能漏网。
4 方案 B:状态机 + 正则(稳健版)
package striphtml_b
import (
"html"
"regexp"
"strings")
var (
comment = regexp.MustCompile(`(?s)<!--.*?-->`)
script = regexp.MustCompile(`(?is)<script\b[^>]*>.*?</script>`)
style = regexp.MustCompile(`(?is)<style\b[^>]*>.*?</style>`))
func Strip(raw string) string {
s := comment.ReplaceAllString(raw, "")
s = script.ReplaceAllString(s, "")
s = style.ReplaceAllString(s, "")var b strings.Builder
inTag := false
for _, r := range s {switch {case r == '<':
inTag = truecase r == '>' && inTag:
inTag = falsecase !inTag:
b.WriteRune(r)}
}
return html.UnescapeString(b.String())}- 优点:对跨行标签、配对缺失、属性注入都更健壮。
- 性能:在 1 MB 随机 HTML 测试中,~1.8 µs/KB(Mac M2,Go 1.22)。
5 方案 C:Bluemonday(开箱即用、安全首选)
package striphtml_c
import "github.com/microcosm-cc/bluemonday"
var p = bluemonday.StrictPolicy() // 拒绝一切标签,仅保留文本
func Strip(raw string) string { return p.Sanitize(raw) }5.1 为什么选 Bluemonday?
- AST 级解析,不会把畸形标签漏过。
- 自带数十种 Policy(老富文本白名单、UGC 白名单、UGC+链接控制…)。
- 社区持续维护,最新版本
v1.0.27已在 2025‑04‑22 打包进 Debian unstable 仓库。
5.2 离线环境的两种用法
① Vendor 模式# 有网机器
go mod download github.com/microcosm-cc/bluemonday@v1.0.27
cp -r ~/go/pkg/mod/github.com/microcosm-cc/bluemonday@v1.0.27 ./vendor/github.com/microcosm-cc/
# 无网机器
go env -w GOFLAGS="-mod=vendor"
go build
② go.mod replacerequire github.com/microcosm-cc/bluemonday v1.0.27
replace github.com/microcosm-cc/bluemonday => ../bluemonday // 本地源码路径6 性能与准确性 Benchmark
| Data Size | 方案 A | 方案 B | Bluemonday |
|---|---|---|---|
| 10 KB | 17 µs | 21 µs | 120 µs |
| 1 MB | 1.7 ms | 1.9 ms | 11.8 ms |
- Go 1.22, Mac M2,
go test -bench .,平均 5 次。- Bluemonday 牺牲 6–7× 速度换来精确、安全与维护性。
- 若只是内部日志解析,可选方案 A;开放上传/评论,用 Bluemonday 更保险。
7 最佳实践 Checklist
- 安全优先:对任何用户可控输入,默认用 Bluemonday。
- 先大后小:先剥离
<script>/<style>再删其他标签,避免脚本注入。 - 实体解码:
html.UnescapeString把<转回<,保持可读性。 - 缓存 Policy:Bluemonday 创建 Policy 有一定开销,做成单例。
- 并发:三种方案均为纯函数,可安全在多个 Goroutine 并发调用。
- 版本跟进:关注 Bluemonday releases 及 CVE 通报 (GO‑2025‑3503 等)。
8 总结
- 一行正则:极简场合、非常规 HTML 不可控 → 慎用。
- 状态机 + 正则:服务端批处理、边缘节点 → 在无外部依赖场景下的最佳折中。
- Bluemonday:面对外部用户输入、安全要求高 → 首选,并可按需裁剪 Policy