本文是《Solo 从设计到实现》的一个章节,该系列文章将介绍 Solo 这款 Java 博客系统是如何从无到有的,希望大家能通过它对 Solo 从设计到实现有个直观地了解、能为想参与贡献的人介绍清楚项目,也希望能为给重复发明重新定义博客系统的人做个参考 ❤️

Markdown 渲染

Markdown 渲染指的是将 Markdown 文本转换成 HTML 的过程。

引擎选择

Solo 默认是通过 flexmark-java 进行 Markdown 渲染的。如果启用了独立进程 http-marked 则优先使用 http-marked 渲染。

如果有可能的话,建议使用 http-marked。因为从我们目前看到的渲染效果以及容错情况上看,marked 是要比 flexmark 好一些的。使用 marked 后,如果出现渲染异常,则会使用内置的 flexmark 进行兜底。

if (MARKED_AVAILABLE) {
    try {
        html = toHtmlByMarked(markdownText);
    } catch (final Exception e) {
        LOGGER.log(Level.WARN, "Failed to use [marked] for markdown [md=" + StringUtils.substring(markdownText, 0, 256) + "]:" + e.getMessage());
        com.vladsch.flexmark.ast.Node document = PARSER.parse(markdownText);
        html = RENDERER.render(document);
    }
} else {
    com.vladsch.flexmark.ast.Node document = PARSER.parse(markdownText);
    html = RENDERER.render(document);
}

超时控制

Solo 的 Markdown 渲染是在一个新建线程中完成的,获取处理结果带超时控制(默认 10s)。这样做是为了防止一些无法预期的问题,比如引擎缺陷或是文本怪异导致渲染太耗时,从而耗尽服务线程。

站外链接处理

Markdown 渲染后得到的 HTML 还会通过 jsoup 解析一次,将其中的 a 标签获取出来,如果发现是站外链接,就将其 target 设置为 _blank,点击时以新页签方式打开。

final Document doc = Jsoup.parse(html);
doc.select("a").forEach(a -> {
    final String src = a.attr("href");
    if (!StringUtils.startsWithIgnoreCase(src, Latkes.getServePath())) {
        a.attr("target", "_blank");
    }
});

结果缓存

每次 Markdown 渲染后的最终 HTML 都会放入缓存,下次进行渲染时先从缓存中获取。缓存键是将原 Markdown 文本进行 MD5 哈希得到的,虽然存在一定碰撞的可能,但是目前的结果来看,这个可能性是非常低的。


回到全文目录:《Solo 从设计到实现》

感谢    关注    收藏    赞同    反对    举报    分享