Go Goldmark Markdown解析失败排查
你反馈的问题是Markdown内容没有被 goldmark 解析成HTML,而是直接在浏览器中显示为原始Markdown文本。你排除了CSS问题,这表明后端解析确实未能生效。
尽管 Article.Content 字段类型是 template.HTML,但如果 goldmark.Convert 没有成功将Markdown转换为HTML,并且 ConvertMarkdown 函数在失败时返回了原始Markdown文本(虽然标记为 template.HTML),那么浏览器就会将这些原始文本直接显示出来。也就是说,浏览器看到的是 <p># 我的标题</p> 而不是 <h1>我的标题</h1>。
让我们详细排查并改进你的 ConvertMarkdown 函数以及在handler中的调试方法。
1. ConvertMarkdown 函数改进
goldmark 默认的配置可能比较基础。如果你使用的Markdown包含表格、任务列表等 GitHub Flavored Markdown (GFM) 特性,你需要显式地添加扩展。同时,添加 html.WithUnsafe() 选项可以确保Markdown中嵌入的原始HTML(如果存在)也能正确渲染,尽管这在处理用户输入时需要额外注意安全。
建议的 ConvertMarkdown 函数:
package ai
import (
"bytes"
"fmt"
"html/template"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/renderer/html"
)
func ConvertMarkdown(mdContent string) template.HTML {
var buf bytes.Buffer
// 初始化Goldmark解析器,添加GFM扩展和允许不安全的HTML渲染
// GFM包含了表格、任务列表、删除线等常用Markdown特性
gm := goldmark.New(
goldmark.WithExtensions(
extension.GFM, // GitHub Flavored Markdown扩展
),
goldmark.WithRendererOptions(
html.WithUnsafe(), // 允许渲染Markdown中的原始HTML,注意XSS风险
),
)
// 执行Markdown到HTML的转换
if err := gm.Convert([]byte(mdContent), &buf); err != nil {
// 如果转换失败,记录错误并返回原始Markdown内容,但依然标记为template.HTML以防再次转义
// 在实际应用中,你可能需要一个更健壮的日志系统,例如 fun.WriteLog
fmt.Printf("ERROR: Goldmark Markdown conversion failed: %v
Original Content:
%s
", err, mdContent)
return template.HTML(mdContent) // 返回原始Markdown,但标记为安全HTML
}
// 转换成功,返回生成的HTML内容
return template.HTML(buf.String())
}
2. Baike_detail Handler 中的调试
在 Baike_detail 函数中,你可以在将内容传递给模板之前,打印 a.Content 的值,以确认 ConvertMarkdown 函数的输出是否正确。
修改后的 Baike_detail 局部代码:
// ... (前面的代码保持不变)
a.Content = ConvertMarkdown(contentRaw) // 解析Markdown并转义template.HTML
a.CreatedAt = time.Unix(createdAtInt, 0).Format("2006-01-02 15:04")
// --- 添加调试信息 --- //
// 打印Goldmark转换后的HTML内容到控制台,检查是否已成功转换为HTML标签
fmt.Printf("DEBUG: Article Content (after Markdown conversion):
%s
", a.Content)
// --- 调试信息结束 --- //
// 2. 异步增加浏览量(避免阻塞主渲染)
// ... (其余代码保持不变)
3. 检查模板文件 baike_detail.html
确保在 baike_detail.html 中,你使用 {{.Article.Content}} 的方式来直接输出HTML。 html/template 会识别 template.HTML 类型并直接输出其内容,而不会进行额外的HTML转义。
<div class="prose max-w-none">
{{.Article.Content}}
</div>
如果你在模板中使用了例如 {{html .Article.Content}} 或者其他类似 printf 函数,那反而会导致已经安全的 template.HTML 再次被转义。
4. 总结与排查步骤
- 更新
ConvertMarkdown函数:采用上面建议的更完整的goldmark配置,特别是extension.GFM和html.WithUnsafe()。 - 添加
fmt.Printf调试语句:在Baike_detail函数中,在模板渲染前打印a.Content的值。这是最关键的一步,它会告诉你ConvertMarkdown实际返回的是HTML还是原始Markdown。- 如果打印出来的是HTML标签(如
<h1>),说明goldmark转换成功,问题可能在于模板渲染或浏览器显示上(虽然你排除了CSS,但浏览器默认样式可能很丑,但不会显示原始Markdown)。 - 如果打印出来的仍然是原始Markdown文本(如
# Heading),那么问题出在ConvertMarkdown函数内部,需要检查goldmark.Convert是否报错,以及goldmark的配置是否适合你的Markdown语法。
- 如果打印出来的是HTML标签(如
- 检查浏览器开发者工具:查看页面源码或元素检查器,确认
div.prose内部的实际内容是什么。这能最终确认浏览器接收到的HTML结构。
通过以上步骤,你应该能精确地定位问题所在。