关于Markdig
Markdig 是.NET平台一款兼容性质很好的 .NET Markdown 解析器,它不仅支持标准的Markdown语法支持,还提供了许多扩展功能,让开发者能够灵活地定制 Markdown 文本的解析与渲染。
2.Markdown的超链接
Markdown的超链接语法相较于标准的html标签更加优雅,但也存在局限性,比如HTML的<a rel=nofollow>超链接</a>标签是支持添加 rel=nofollow 、 target=_blank 的属性的(设置这个属性是seo里的常用操作),然而Markdown的语法里默认是不支持这个属性的,很多时候都是直接Markdown和HTML混着用来满足这类特殊属性的编辑需求,虽然效果上没啥问题但总感觉混着用不是很优雅。
2.1 rel=nofollow的作用
nofollow是一个HTML标签的属性值,随着搜索引擎优化(SEO)的兴起,这个标签的意思是告诉搜索引擎不要此网页上的链接或不要追踪此特定链接。如果A网页上有一个链接指向B网页,但A网页给这个链接加上了 rel=”nofollow” 标注,则搜索引擎不把A网页计算入B网页的反向链接。搜索引擎看到这个标签就可能减少或完全取消链接的投票权重。
3. Markdig扩展站外链接添加 rel=nofollow
实现代码的功能简述:
当Markdown渲染解析LinkInline时,通过扩展验证一下标签的url地址是否是站内链接,一般相对链接(没有主机域名)可以直接认为是内部链接,如果是外部地址则判断一下主机域名是否是指定的域名,如果匹配则认为是内部链接,否之就添加rel属性,顺带的给所有超链接添加了target=_blank 属性(也就是新页面打开地址)
3.1 定义一个自定义渲染类
private class CustomLinkRenderer : LinkInlineRenderer
{
private readonly string _relValue;
public CustomLinkRenderer(string relValue)
{
_relValue = relValue;
}
protected override void Write(HtmlRenderer renderer, LinkInline link)
{
if (link is null) return;
var originalAttributes = link.GetAttributes();
var newAttributes = new HtmlAttributes();
if (originalAttributes.Properties.HasItems())
{
// 复制现有属性
foreach (var attr in originalAttributes.Properties)
{
newAttributes.AddPropertyIfNotExist(attr.Key, attr.Value);
}
}
if (Uri.TryCreate(link.Url, UriKind.Absolute, out Uri uri))
{
// 检查是否为外部链接
bool isExternal = !uri.Host.EndsWith("yuantk.com", StringComparison.InvariantCultureIgnoreCase);
if (isExternal)
{
newAttributes.AddPropertyIfNotExist("rel", _relValue);//站外链接标记不输出权重
}
}
newAttributes.AddPropertyIfNotExist("target", "_blank");
link.SetAttributes(newAttributes);
base.Write(renderer, link);// 渲染链接
}
}
3.2 定义一个IMarkdownExtension扩展类
public class ExternalLinkRelExtension : IMarkdownExtension
{
private readonly string _relValue;
public ExternalLinkRelExtension(string relValue = "noopener noreferrer external nofollow")
{
_relValue = relValue;
}
public void Setup(MarkdownPipelineBuilder pipeline)
{
// 确保链接扩展已启用
if (!pipeline.Extensions.Contains<Markdig.Extensions.ReferralLinks.ReferralLinksExtension>())
{
pipeline.UseAdvancedExtensions();
}
}
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
if (renderer is HtmlRenderer htmlRenderer)
{
// 替换默认的链接渲染器
var originalRenderer = htmlRenderer.ObjectRenderers.FindExact<LinkInlineRenderer>();
if (originalRenderer != null)
{
htmlRenderer.ObjectRenderers.Remove(originalRenderer);
}
htmlRenderer.ObjectRenderers.Add(new CustomLinkRenderer(_relValue));
}
}
}
3.3 应用自定义扩展功能
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
//这里将自定义扩展类应用到Markdig内,解析markdown的时候将pipeline传入即可
pipeline.Extensions.Add(new ExternalLinkRelExtension());