Hugo 外部链接跳转提示页面

前言#

这两天看到「秦大叔」的博客文章《网站重启》提到，因为博客评论中别人留下的域名过期被黄网注册链接到了黄网，从而导致因涉黄问题而喝茶。可见在大陆目前的网络环境下，这种可大可小的口袋罪收得越来越紧。

为了合规和自我审查，我对博客做了 2 件事，一是把评论系统迁移到了 Giscus，这提高了一定的评论门槛，让评论处于半关闭状态；二是清理了一些博客中的链接，让剩下的链接通过跳转页面跳转。刚好看到「空白」大佬更新了博客《HUGO 外链跳转到中间页》，直接把样式抄过来，算是完成了一件 Todo list。

PS：我觉得正经的个人网站可以备案。但如果你想做不正经的，那你要做的是完全的身份隔离，而不是仅仅不备案却暴露很多关联的交叉实名信息。没有爹味，爱听不听。

定义#

外链：全称为外部链接，又称导入链接。就是指从互联网上别的网站导入到自己网站的链接。以下简称「外链」。

3 个文件创建跳转页面#

我的设计思路与「空白」的第一版 JS 的方式不太一样，我利用 Hugo 内置模板 _markup 的 render-link.html ，在 Hugo 构建时就把外链用 Hugo 内置的 base64Encode 命令进行 base64 编码，充分利用了 SSG 的特性。

1. 新建或者修改 render-link.html#

_markup/render-link.html 是 Hugo 渲染链接的内置模板。
如果博客选用的主题没有自定义 render-link.html，那需要自己新建一个此文件，如果主题已经自定义过链接渲染的，那就可以直接修改此文件。
文件位于 Hugo 项目根目录的 layouts 目录 ：

Copy
layouts/
└── _default/
└── _markup/
├── render-codeblock-bash.html
├── render-codeblock.html
├── render-heading.html
├── render-image.html
├── render-image.rss.xml
└── render-link.html # < --- 此文件

我用的文件内容：

$domainList 相当于一个白名单。

Copy
{{- $domainList := slice "www.eallion.com" "github.com" "twitter.com" -}}
{{- $parsedDestination := urls.Parse .Destination -}}
{{- $host := $parsedDestination.Host -}}
{{- $matched := false -}}
{{- range $domainList -}}
{{- if strings.HasSuffix $host . -}}
{{- $matched = true -}}
{{- break -}}
{{- end -}}
{{- end -}}
{{- if $matched -}}
{{ .Text | safeHTML}}
{{- else -}}
{{ .Text | safeHTML}}
{{- end -}}

PS：DoIt 主题只需要修改 layouts/partials/plugin/link.html 文件。

Tips：利用 render-link.html 可以让博客实现新窗口打开，即 taget="_blank" 。很多亚洲用户都在搜索这个技巧呢。

2. 新建 layout 模板 go.html#

新建一个页面模板，如：go.html，位于 Hugo 项目根目录的 layouts/_default/go.html。
一个最简单的办法是复制 single.html 并重命名为 go.html

Copy
layouts/
└── _default/
└── go.html # < --- 此文件

下面是我的内容，把 HTML CSS 和 JS 放置到了同一个页面中，方便维护。除了需要注意 元素位于自己的模板的位置，基本上是开箱即用。

Copy
{{- define "title" }}{{ .Title }} - {{ .Site.Title }}{{ end -}}

{{- define "content" -}}
{{- $params := .Scratch.Get "params" -}}

.redirect-all {
position: relative;
box-shadow: rgba(0, 0, 0, 0.25) 0px 25px 50px -12px;
border-radius: 10px;
color: #666;
word-break: break-all;
max-width: 800px;
height: 400px;
text-align: center;
font-size: 0.85rem;
overflow: hidden;
margin: 100px auto 0;
background: #fff url(/assets/images/redirect/redirect-light.webp) no-repeat center center / cover;
@include breakpoint('small') {
aspect-ratio: 2 / 1;
height: auto;
}
}

.redirect-nrong {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 1.5rem 1rem
}

.redirect-title {
font-size: 1.25rem;
font-weight: bold;
color: #222;
margin-bottom: 0.5rem;
}

.redirect-info {
margin-top: 6px;
}

.redirect-tis {
display: flex;
align-items: center;
justify-content: center;
gap: 20px;
margin-top: 1rem;
margin-bottom: 2px;
flex-wrap: wrap;
}

.redirect-button {
display: flex;
align-items: center;
border-radius: 3px;
border: none;
background: #006bee;
height: 32px;
padding: 0 14px;
cursor: pointer;
outline: 0;
}

.redirect-button a {
color: #fff !important;
}

[theme=dark] .redirect-all {
background: #fff url(/assets/images/redirect/redirect-dark.webp) no-repeat center center / cover;
color: #999;
}

[theme=dark] .redirect-title {
color: #ddd;
}




{{- /* Content */ -}}



即将离开{{ .Site.Title }}，跳转到以下外部链接
未指定重定向目标。
请自行识别该链接是否安全，请注意您的帐号和财产安全。

立即前往







const params = new URLSearchParams(window.location.search);
const encodedTarget = params.get('target');
const target = atob(encodedTarget); // 使用 atob 进行 Base64 解码

if (target) {

const decodedTarget = decodeURIComponent(target);

document.getElementById('direct-link').href = decodedTarget;
document.getElementById('redirect-link').textContent = '' + decodedTarget; // 在新增的元素中显示原地址
document.getElementById('redirect-link').href = decodedTarget;

} else {
const redirectMessageElement = document.getElementById('redirect-link');
redirectMessageElement.textContent = '未指定重定向目标。';
}

{{- end -}}

3. 新建 go.md 调用模板#

在 Hugo 项目的 content 目录新建一个文件，名为 go.md，go 就会是中转页面的链接 path。
go.md 文件的 Front matter 要选择刚才新建的对应模板，如果模板名称是go.html 那 layout 或者 type 都要选择 go。

Copy
---
title: "Redirect"
layout: "go"
type: "go"
... ...
---

4. 背景图#

背景图放在 static 的目录下：
或者自己能正确引用的位置，如 CDN，并修改 中的 background url。
另外需要适配自己主题的 Dark mode。

static/assets/images/redirect/redirect-light.webp

static/assets/images/redirect/redirect-dark.webp

其他注意事项#

这个方法，只能渲染本博客所有 Markdown 内容文档，即 content 目录下在的 .md 文件。
如果习惯用 {{ Shortcodes }} 发文，或者页面有自定义的 html 链接，需要自己做链接 path 的 base64 兼容，这个模板能解析 href="/go/?target={{ base64Encode }}" 博客内这一类链接，白名单除外。