为 Hugo 站点实现外部链接跳转访问
最近,我为博客增加了一个新功能:外部链接跳转页。现在,点击站外链接会先进入一个中转页,经用户确认点击 继续访问 后才前往目标网站。当然这功能并不少见,多数网站都有此功能。
为何需要跳转页?
- 明确告知:清晰告知访客“您即将离开本站”,避免意外跳转。
- 提升安全:为访客提供一道心理屏障,降低链接被篡改的风险。
- 统一体验:统一站外跳转的设计规范,并同步了主站的深浅色模式。


实现方法
该功能主要依赖 Hugo 的 Render Hook 与 JavaScript 协同工作:
服务端预处理 (Hugo):网站构建时,Hugo 通过 Link Render Hook 为所有外部链接添加
target="_blank"等属性,确保其在新标签页打开,完成基础优化。此时链接的href保持不变。客户端动态改写 (JavaScript):页面加载后,
external-links.js脚本开始运行。它会遍历所有<a>标签,识别出未被排除的外部链接,并将其href属性动态地重写,指向我们自定义的跳转页 (/pages/redirect?target=[原始链接])。脚本还能通过MutationObserver监听动态内容(如评论区),确保所有外部链接都被处理。中转页等待用户确认:用户点击链接后会访问
redirect.html页面。该页面的脚本会解析 URL 参数,并等待用户手动点击“继续访问”按钮后,才会将用户重定向至目标网站。
总之,通过服务端预处理、客户端动态修改方式,将链接重写的逻辑完全放在浏览器端,避免了在 Hugo 构建时对 Markdown 内容的修改,实现方式更为灵活。
如何使用?
若想让特定链接“豁免”跳转,操作非常简单,有两种方式可选:
方法一:URL 标记法 (推荐)
在 Markdown 中,只需在链接 URL 的末尾加上 #no-redirect 即可。
示例:
这是一个普通的外部链接:[GitHub](https://github.com)
这是一个不会跳转的链接:[Gitee](https://gitee.com#no-redirect)
Hugo 的 render-link.html 模板会自动识别这个标记,为链接添加 class="no-redirect",同时在最终生成的 href 属性中将这个标记移除,确保链接地址的整洁与正确。
方法二:HTML class 法
如果你需要在文章中直接编写 HTML,也可以手动为 <a> 标签添加 no-redirect 类。
示例:
<a href="https://example.com" class="no-redirect">这个链接也不会跳转</a>
核心代码
1. Link Render Hook (render-link.html)
这个模板是实现新方案的核心。它会检查 URL 是否包含 #no-redirect,然后动态地添加 class 并清理 URL。
{{ $url_str := .Destination }}
{{ $class := "" }}
{{ $is_external := strings.HasPrefix $url_str "http" }}
{{ if strings.HasSuffix $url_str "#no-redirect" }}
{{ $url_str = strings.TrimSuffix "#no-redirect" $url_str }}
{{ $class = "no-redirect" }}
{{ end }}
<a href="{{ $url_str | safeURL }}"
{{ if $class }}class="{{ $class }}"{{ end }}
{{ if $is_external }}target="_blank" rel="noopener noreferrer"{{ end }}
{{ with .Title }}title="{{ . }}"{{ end }}>
{{ .Text | safeHTML }}
</a>
2. 核心 JS 逻辑 (external-links.js)
function processExternalLinks() {
var links = document.querySelectorAll('a');
var host = window.location.hostname;
// ...
for (var i = 0; i < links.length; i++) {
var link = links[i];
// 如果是外部链接,且不含 'no-redirect' class
if (link.hostname !== host && link.protocol.startsWith('http') && !link.classList.contains('no-redirect')) {
var href = link.getAttribute('href');
// ...
// 重写 href 指向跳转页
link.href = '/pages/redirect?target=' + encodeURIComponent(href) + '&theme=' + currentTheme;
}
}
}
3. 跳转页逻辑 (redirect.html)
(function() {
const params = new URLSearchParams(window.location.search);
const target = params.get('target');
const continueBtn = document.getElementById('continue-btn');
if (target && continueBtn) {
const decodedUrl = decodeURIComponent(target);
document.getElementById('target-url').innerText = decodedUrl;
// 为按钮设置点击事件,手动跳转
continueBtn.onclick = function() {
window.location.href = decodedUrl;
};
}
})();
© 转载需附带本文链接,依据 CC BY-NC-SA 4.0 发布。