井号路径兼容性
作者:黄冠超 (hi@sghua.ng)
飞跃手册过去使用 Docsify 作为引擎,但因为一些已不能考据的技术原因,网站使用了 hash
模式进行路由(参考 routerMode
)。这意味着所有路径都会以井号开头,如 domain.com/#/path
。
迁移到 VitePress 之后,这个问题已经不复存在,但我们仍然需要保持最大的兼容性,确保过去的链接依然能正常使用。
客户端重定向
最直接的解决方法是在客户端进行重定向:
ts
// .vitepress/theme/index.ts
export default {
enhanceApp({ router }) {
router.onAfterRouteChange = async (to) => {
const hashPath = /^\/#\/(.+)\/?$/.exec(to);
if (hashPath) {
console.warn("Hash path is deprecated, redirecting...");
await router.go(hashPath[1]);
}
};
// ...
},
} satisfies Theme;
尝试:CDN URL 重写
我们始终尝试将更多的复杂度从客户端移动到服务端。由于没有我们采用无服务器模式,网站静态托管在对象存储中,因此只能借助于 CDN 来实现。
阿里云 CDN 提供一些 URL 重写规则,可以利用正则表达式进行简单的匹配和改写。使用 clean url 访问网站,就是基于此实现的。我们自然想要进行尝试。具体而言,需要将 ^/#/(.*)
重写为 /$1
。
然而,这个解决方案并不起效——似乎这个正则表达式并没有匹配到任何内容。
尝试:EdgeScript 规则
阿里云 CDN 还提供通过 EdgeScript 添加规则的选项。我们尝试如下:
php
pcs = capture_re($uri, '^/#/(.+)$')
path = get(pcs, 1)
if path {
dst = concat('/', $path)
rewrite(dst, 'redirect')
}
而这依然不起作用,通过调试,发现这个正则表达式依然没有匹配到任何内容,因此规则也没有被执行。
结论
到这里,终于意识到,$uri
只包含了路径本身,而不包含路径后的其他参数以及 anchor!
在普通的 CDN 之外,阿里云还提供了 边缘加速 ESA 服务,其所包含的边缘函数或许可以提供更细粒度的控制,并实现我们所需的功能。不过,其最基础版本一年的价格也「高达」80 余元人民币——这是相对于我们静态部署一个月耗资 1 元左右而言的——因此也作罢了。