当前位置:首页 > 文章列表 > Golang > Go问答 > Go Goldmark Markdown 中的原始 HTML 为什么不输出

Go Goldmark Markdown 中的原始 HTML 为什么不输出

来源:17golang原创 2026-10-13 16:23:12 0浏览 收藏

Go Goldmark Markdown 中的原始 HTML 不输出,通常不是 Markdown 写错了,而是 HTML renderer 的默认安全策略在生效。Goldmark 默认不渲染原始 HTML,也不会直接放行潜在危险链接;只有在输入已经可信、并且业务确实需要保留 HTML 标签时,才应通过 html.WithUnsafe() 明确打开这个能力。

官方地址:https://github.com/yuin/goldmark

要点速览
  • 原始 HTML 是否输出由 renderer 控制,单纯调整 Markdown 文本或扩展列表不会改变默认安全边界。
  • html.WithUnsafe() 会让原始 HTML 和潜在危险链接按输入内容输出,不能对陌生用户提交的 Markdown 直接开启。
  • 受信任模板可以在 goldmark.WithRendererOptions 中配置;不可信内容应继续保持默认设置,或先经过专门的 HTML 清洗器。

先确认:消失的是原始 HTML,不是普通 Markdown

我第一次遇到这个问题时,输入里同时放了一个加粗语法和一个原始 标签。转换结果中的加粗仍然存在,只有标签没有出现在 HTML 中,这个现象说明解析器并没有整体失效,问题点更靠近输出阶段。

package main

import (
    "bytes"
    "fmt"

    "github.com/yuin/goldmark"
)

func main() {
    source := []byte("**保留的 Markdown**\n\n原始 HTML")
    var output bytes.Buffer

    // 默认实例保留 Markdown 语法,但不会直接输出原始 HTML 标签。
    if err := goldmark.Convert(source, &output); err != nil {
        // 转换失败要保留错误,避免把空结果误判为 HTML 被过滤。
        panic(err)
    }
    fmt.Print(output.String())
}

这个最小例子适合用来判断问题性质:如果 **保留的 Markdown** 正常变成 ,而 没有按原样出现,就不要先去改输入字符串,也不要误以为必须增加 GFM 扩展。

Goldmark Markdown 输入经过解析器和 HTML renderer 后,普通语法与原始 HTML 处在不同输出边界的静态说明图
图1:Goldmark 解析器、HTML renderer 与原始 HTML 输出边界的结构说明图,不是运行截图。

真正的开关在 HTML renderer 的安全默认值

Goldmark 官方文档把 html.WithUnsafe 定义为 renderer 选项:默认情况下,原始 HTML 和潜在危险链接不会被渲染;启用后才会按输入内容输出。也就是说,extension.GFM 可以补充表格、删除线、任务列表和自动链接等语法,但它不是“允许原始 HTML”的开关。

输入或配置默认表现是否解决原始 HTML 不输出适用判断
普通 Markdown 语法正常渲染不需要解决标题、段落、强调等内容
extension.GFM增加 GFM 语法不是专用开关表格、任务列表等扩展
默认 HTML renderer不输出原始 HTML是问题来源不可信 Markdown 的安全默认值
html.WithUnsafe()按输入输出原始 HTML 和危险链接能解决显示问题仅限已经信任或已清洗的内容

因此,排查时我会先问一句:这段 Markdown 来自代码仓库内的模板,还是来自评论、工单、富文本编辑器或外部接口?前一种情况通常可以考虑打开 renderer 选项;后一种情况不能为了让标签显示就无条件放开。

受信任内容怎样显式开启原始 HTML

如果 Markdown 是随程序发布的文档、内部维护的模板,或者在进入转换流程前已经完成了可信来源控制,可以把选项放在 Goldmark 实例创建处。关键是使用 goldmark.WithRendererOptions 传入 HTML renderer 的选项,而不是给输入字符串加转义。

package main

import (
    "bytes"
    "fmt"

    "github.com/yuin/goldmark"
    "github.com/yuin/goldmark/renderer/html"
)

func main() {
    source := []byte("**标题**\n\n已发布")

    markdown := goldmark.New(
        // 只对已确认可信的 Markdown 实例打开原始 HTML 输出。
        goldmark.WithRendererOptions(html.WithUnsafe()),
    )

    var output bytes.Buffer
    if err := markdown.Convert(source, &output); err != nil {
        // 让上层能够区分转换错误和空内容,不能静默吞掉错误。
        panic(err)
    }
    fmt.Print(output.String())
}

这个配置改变的是 renderer 的输出策略:输入中的 已发布 会保留为 HTML。若还需要 GFM 语法,应把 extension.GFM 放进 goldmark.WithExtensions;它和 html.WithUnsafe 负责的是两类不同问题。

Goldmark 受信任模板与不可信 Markdown 在 WithUnsafe 配置前后的输入边界和清洗责任关系说明图
图2:受信任模板、不可信输入、renderer 配置和清洗责任的边界说明图,不是运行截图。

不可信 Markdown 不要用 WithUnsafe 硬修

公开评论、用户昵称、工单描述和第三方同步内容都不能默认当作可信模板。WithUnsafe 的语义不是“只让安全的 span 显示”,而是把 renderer 的这层保护交给调用方承担。官方文档也建议对不可信内容使用 HTML sanitizer,例如 Bluemonday 一类的清洗方案。

更稳妥的分层方式是:

  1. 先按来源给 Markdown 标注可信级别,不要让所有请求共享一个全局开启了 WithUnsafe 的 renderer。
  2. 确实需要保留少量标签时,先使用允许列表清洗,再将清洗后的结果交给转换流程。
  3. 把“原始 HTML 是否显示”和“HTML 是否允许哪些标签、属性、协议”拆成两个责任,不要用一个布尔配置代替策略。
  4. 对不可信内容继续使用默认 renderer;如果产品需要富文本,优先采用明确的受限语法或专用渲染方案。
// renderTrustedTemplate 只接收应用内维护的模板,不接收用户评论或外部同步内容。
func renderTrustedTemplate(source []byte) (string, error) {
    markdown := goldmark.New(
        // 可信模板允许保留必要的 HTML 标签;调用方必须保证输入来源受控。
        goldmark.WithRendererOptions(html.WithUnsafe()),
    )

    var output bytes.Buffer
    if err := markdown.Convert(source, &output); err != nil {
        // 将转换错误返回给上层,由上层决定是否记录和回退。
        return "", err
    }
    return output.String(), nil
}

这个函数名故意把 TrustedTemplate 写进边界里。它不是安全过滤器,也不能拿来处理用户输入;这样做的价值是让调用点更容易接受代码审查,避免未来把同一个 renderer 复用到评论接口。

发布前按三项边界检查配置

我会把最后的判断压缩成三项,而不是只检查页面上有没有显示标签:

  • 配置边界:只有确实需要原始 HTML 的实例才传入 html.WithUnsafe(),默认实例保持默认值。
  • 输入边界:确认内容来自版本化模板、内部文档或经过清洗的来源;评论、表单和外部同步内容不能直接归为可信。
  • 输出边界:明确最终 HTML 会被谁消费;如果会进入浏览器页面,必须继续考虑标签、属性和 URL 协议的清洗责任。

如果只是想让 Markdown 里的链接、表格或删除线生效,优先配置对应的 Goldmark 扩展,不要直接打开 WithUnsafe。只有在“原始 HTML 本身就是模板能力”的需求成立,并且输入来源受控时,才使用上面的显式配置。

常见问题

为什么加了 extension.GFM,HTML 还是不显示?

因为 GFM 扩展负责一组 Markdown 语法,原始 HTML 的放行由 HTML renderer 的 WithUnsafe 选项负责,两者不是同一个开关。

WithUnsafe 只允许 span 和 class 吗?

不是。它代表按输入内容渲染原始 HTML 和潜在危险链接,不是针对某一个标签的允许列表。需要精细控制时,应在转换前使用 HTML 清洗策略。

把 HTML 标签写成 Markdown 转义形式可以吗?

转义只能让标签以文字显示,不能达到保留 HTML 结构的目的。如果目标只是展示标签文本,转义是正确选择;如果目标是渲染标签,则需要重新评估输入信任级别和 renderer 配置。

应不应该全局复用开启 WithUnsafe 的 Goldmark 实例?

不建议把它作为所有入口的默认实例。更清楚的做法是为可信模板单独封装实例,普通用户输入继续使用默认 renderer,并在代码层面让两条路径有明显名称差异。

一句话总结:Goldmark 原始 HTML 不输出是默认安全边界,不是解析失败;用 html.WithUnsafe() 可以解决受信任模板的显示问题,但不应跳过输入来源和最终 HTML 消费场景的判断。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go Goldmark 怎么遍历 AST 提取标题目录Go Goldmark 怎么遍历 AST 提取标题目录
上一篇
Go Goldmark 怎么遍历 AST 提取标题目录
Go Goldmark 怎么为自定义节点实现 HTML 渲染
下一篇
Go Goldmark 怎么为自定义节点实现 HTML 渲染
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    460次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    522次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    540次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    488次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    307次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码