go只需专注接收markdown、安全转html并返回,前端用轻量编辑器即可;goldmark需配置html.withunsafe()和自定义sanitizer白名单防xss;接口须设json content-type、限流校验,前端防抖调用并直接渲染html。

为什么不用现成的前端编辑器(如 CodeMirror、Toast ui)?
因为你要的是「golang 实现」——重点在后端能力,不是前端渲染。真正需要 Go 做的只有三件事:接收 Markdown 文本、安全转为 HTML、返回给前端。前端编辑器用 textarea 或轻量级库(比如 simplemde)就够了,Go 只管「接、转、吐」。
常见错误是把整个编辑器逻辑塞进 Go:比如想用 Go 渲染实时预览、处理键盘快捷键、做语法高亮……这些该由浏览器完成,Go 做只会卡顿、难调试、跨域麻烦。
- Go 不该处理 dom 操作或用户输入事件
- 所有 HTML 转换必须在服务端完成,不能信前端传来的
__html字段 - 若用
blackfriday(已归档),注意它不维护了;推荐goldmark,默认禁用 XSS,更省心
goldmark 渲染 Markdown 时怎么防 XSS?
goldmark 默认不开 HTML 标签,但如果你允许用户粘贴含 <script></script> 的内容,又没配好选项,照样中招。关键不是“关不关 HTML”,而是「明确声明哪些标签/属性可保留」。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
goldmark.WithExtensions()启用基础扩展(表格、脚注等),但别加goldmark.Extender自定义危险节点 - 必须显式配置
html.WithUnsafe()—— 听起来反直觉,但这是「启用 HTML 解析」的开关;没它,<div> 会被原样转义 <li>真正防 XSS 靠 <code>html.WithSanitizer(),传入自定义函数,只放行<p></p>、<pre class="brush:php;toolbar:false;"></code>、<code><code></code>、<code><strong></code> 等白名单标签</li> <li>别用 <code>bluemonday</code> 二次过滤——goldmark 自带 sanitizer 更轻、更可控</li> </ul> <p>示例关键片段:</p> <pre class='brush:php;toolbar:false;'>md := goldmark.New( goldmark.WithExtensions(extension.GFM), goldmark.WithRendererOptions( html.WithUnsafe(), // 允许解析原始 HTML html.WithSanitizer(func(tag string, attrs []html.Attribute) bool { allowed := map[string]bool{"p": true, "code": true, "pre": true, "strong": true, "em": true} return allowed[tag] }), ), )</pre> <h3>POST 接口接收 Markdown 内容要注意什么?</h3> <p>很多人写 <code>http.HandleFunc("/render", ...),直接读r.Body,结果中文乱码、换行丢失、超长文本截断——根本原因是没设 Content-Type 和读取方式。正确做法:
- 前端必须发
Content-Type: application/json,字段名统一用content(别用markdown或text,易和 Form 表单混淆) - Go 后端用
json.NewDecoder(r.Body).Decode(&req),而不是r.FormValue("content")—— 后者只适用于application/x-www-form-urlencoded - 加
http.MaxBytesReader限制请求体大小,比如 1MB:http.MaxBytesReader(w, r, 1024*1024),否则恶意大文件会耗尽内存 - 别在 handler 里做复杂渲染——先校验长度(如
len(req.Content) ),再交给 <code>goldmark处理
前端怎么和 Go 渲染接口配合最省事?
别写一堆 ajax 状态管理。一个
textarea+ 一个div#preview+ 一个防抖提交就够了。要点:
- 用
input或keyup事件监听编辑区,但加 300ms 防抖,避免每敲字都发请求 - 请求用
fetch("/render", { method: "POST", body: JSON.stringify({content: text}) }),别漏headers: {"Content-Type": "application/json"} - 响应直接赋值给
preview.innerHTML—— 因为 goldmark 输出的是安全 HTML,不用再DOMPurify.sanitize() - 如果预览区样式错乱(比如代码块没高亮),说明你漏了 CSS:goldmark 不生成 class,要自己加
<pre class="brush:php;toolbar:false;"><code class="go"></code>,然后靠 <code>highlight.js</code> 渲染</pre>
容易被忽略的一点:Go 返回的 JSON 必须是
{"html": "..."}结构,前端别去拆response.text()再手动 parse —— 直接response.json()取html字段。 - 前端必须发