给博客的所有站外链接添加跳转提示页
2025/4/28...大约 2 分钟
首先,本博客的评论系统和博客主站是两套独立的系统,所以要针对两套系统做分别的处理。
1. 博客主站
我们通过插件的方式来实现博客主站中的外链跳转提示页。
1.1 编写插件
在目录 .vuepress/plugins
中创建文件,external-link-redirect.ts
:
import { Markdown } from "vuepress/markdown";
// 定义插件选项接口
interface ExternalLinkRedirectOptions {
internalDomains?: string[];
redirectPath?: string;
urlParamName?: string;
}
const external_link_redirect = (options: ExternalLinkRedirectOptions = {}) => ({
name: "external-link-redirect",
extendsMarkdown: (md: Markdown) => {
md.core.ruler.after("inline", "external_link_redirect", (state) => {
const tokens = state.tokens;
// 从选项中获取内部域名和重定向路径,提供默认值
const internalDomains = options.internalDomains || [];
const redirectPath = options.redirectPath || "/go.html";
const urlParamName = options.urlParamName || "url";
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
if (token.type === "inline" && token.children) {
token.children.forEach((child) => {
if (child.type === "link_open") {
const hrefIndex = child.attrIndex("href");
if (hrefIndex >= 0 && child.attrs) {
const hrefAttr = child.attrs[hrefIndex];
const href = hrefAttr[1];
if (/^https?:\/\//i.test(href)) {
let isInternalLink = false;
try {
const hrefUrl = new URL(href);
isInternalLink = internalDomains.some(
(domain) =>
hrefUrl.hostname === domain ||
hrefUrl.hostname.endsWith(`.${domain}`)
);
} catch (e) {
console.error("Invalid URL:", href, e);
}
if (!isInternalLink) {
try {
hrefAttr[1] = `${redirectPath}?${urlParamName}=${encodeURIComponent(
href
)}`;
} catch (e) {
console.error("Error encoding URL:", href, e);
hrefAttr[1] = `${redirectPath}?${urlParamName}=${href}`; // 回退到不编码的 URL
} finally {
child.attrSet("target", "_blank");
child.attrSet("rel", "noopener noreferrer");
}
}
}
}
}
});
}
}
});
},
});
export default external_link_redirect;
1.2 使用插件
在 .vuepress/config.ts
中注册该插件
plugins: [
externalLinkRedirect({
internalDomains: ["meowpass.com"],
redirectPath: "https://www.meowpass.com/go.html",
urlParamName: "url",
}),
],
配置项说明:
internalDomains
:不进入外链跳转提示页的域名。redirectPath
:外链跳转提示页的路径,默认是/go.html
。urlParamName
:跳转提示页中接收外链的参数名,默认是url
。
2. 评论系统
本博客使用的是 Waline 评论系统,所以该修改不适用于其它评论系统。
由于我的评论系统是采用的 Docker 部署,所以不能使用官方的 Docker 镜像启动,需要自己写一个 dockerfile
构建自己的镜像,我们参考官方文件稍作修改:
# https://github.com/nodejs/LTS
FROM node:lts AS build
WORKDIR /app
ENV NODE_ENV production
RUN set -eux; \
npm config set registry https://registry.npmmirror.com; \
npm install --production --silent @waline/vercel waline-link-interceptor
FROM node:lts-slim
WORKDIR /app
ENV TZ Asia/Shanghai
ENV NODE_ENV production
COPY --from=build /app .
EXPOSE 8360
CMD ["node", "node_modules/@waline/vercel/vanilla.js"]
在第7行,多安装一个依赖 waline-link-interceptor
然后还要修改 docker compose
文件,添加一行配置:
volumes:
- ./config.js:/app/node_modules/@waline/vercel/config.js:ro
挂载的 config.js
文件内容如下:
const LinkInterceptor = require('waline-link-interceptor');
module.exports = {
plugins: [
LinkInterceptor({
whiteList: [
'meowpass.com'
],
// blackList: [],
// interceptorTemplate: `redirect to __URL__`,
redirectUrl: "https://www.meowpass.com/go.html",
encodeFunc: (url) =>{
try {
return `url=${encodeURIComponent(url)}`;
} catch (error) {
console.error('URL 编码失败:', error);
return `url=${url}`; // 降级处理
}
}
})
]
}
然后,构建镜像并启动容器:
sudo docker compose up -d --build