用重定向去掉博文的 .html 后缀

谷月姐最近有一个需求,就是用重定向(准确地说是 301 跳转)去掉博文的 .html 后缀,例如,把形如 https://blog.kukmoon.com/834aa795.html 的 URL 转变成 https://blog.kukmoon.com/834aa795/ (注意最后的斜杠)的形式。
01 S 场景
虚拟主机快到期了,我不想再续费了,想把博客部署到一个免费的托管平台。
找来找去,找到了 Cloudflare Pages (下文简称 CF Pages)。CF Pages 不用花钱,可以与 GitHub 无缝对接,在墙内外都有节点,非常适合我部署 本博。
02 C 冲突
CF Pages 会强行忽略 URL 中的 .html 后缀,例如,让形如 https://blog.kukmoon.com/834aa795.html 的网址 302 重定向到形如 https://blog.kukmoon.com/834aa795 (注意最后没有斜杠)的网址。官方称之为 Route Matching (路由匹配)[1]。经测试,它无法手动关闭。
这个问题产生了两个负面影响:
- 
这个功能影响了评论的加载[2]。本博 的评论系统是 Valine,它是根据静态页面的文件名来储存评论数据的,比方说,它会把 https://example.tld/file123.html这个页面的所有评论放在数据库的file123.html表中。所以 本博 不同镜像的同一篇文章会共享同样的评论。但是 Route matching 去掉了.html后缀,导致 Valine 评论系统会在数据库新建一个 file123 表,从而使得部署在 CF Pages 上的 本博镜像 不能与其他的镜像共享评论。
- 
这个功能影响了搜索引擎的收录与检索。搜索引擎收录的 URL 是含有 .html后缀的,如果去掉了这个后缀,就势必会影响搜索引擎的收录与检索。
所以,我要是把博客从虚拟主机迁移到 CF Pages,就需要妥善地处理 Route Matching 带来的这两个负面影响。
03 Q 问题:301 跳转
我的解决方案是,在虚拟主机和 CF Pages 两边都配置 301 跳转,去掉 .html 后缀,让两边的 URL 保持一致。这样,一方面可以共享评论,另一方面也不影响搜索引擎的收录和检索。
现在问题来了,如何配置 301 跳转呢?
不同的服务端,配置 301 跳转的方法不同。
我的虚拟主机用的服务端是 Apache (CPanel 面板用的是 Apache)。CF Pages 也有自己的方法。本文只介绍这两种方法。
04 A 解决:配置 301 跳转的方法
4.1 在虚拟主机上配置 301 跳转
我的虚拟主机用的是 CPanel 面板,它是用 Apache 作为 Web 服务端,需要编写 .htaccess 文件配置 301 跳转。
新建一个名为 .htaccess 的文件(如何新建以点开头的文件,请自行谷歌搜索),填入内容如下:
| 1 |  | 
说明:
- 第 10 行打开改写功能。
- 第 12 行是改写规则。它查找匹配正则表达式 ^/?([a-z0-9]+)\.html$的字符串,并将它替换成/$1/,$1表示前面的正则表达式中用圆括号括起来的部分所匹配到的内容,R=301 表示 301 (永久)重定项,L 表示执行完此条规则后不再执行下面的改写规则。
- 此处的正则表达式详解:
- ^表示从这里开始
- /就是左斜杠本身,它不是转义字符
- ?表示它前面的字符出现 0 次或 1 次,经测试此处必须有这个半角问号,否则匹配失败
- ()用圆括号把正则表达式的一部分括起来,可以用- $n(n为从1开始的数字)表示圆括号里的正则表达式匹配到的内容
- [a-z0-9]用方括号把一组字符括起来,表示匹配之里面任意一个字符,此处的意思是任意一个小写字母(a-z)或者数字(0-9)
- +表示它前面的字符出现 1 次或多次
- [a-z0-9]+表示至少1个小写字母或数字
- \.反斜杠和句点都是转义字符,因此如果要匹配句点,需要在它前面加一个反斜杠,所以说- \.匹配- .
- html就匹配- html这四个小写字母
- $表示从这里结束
 
注意:
- 把 .htaccess文件保存到blog/sources/目录(此处假设我的博客源文件保存在blog/目录里)。
- 在 macOS 系统中,默认把以句点开头的文件当作隐藏文件,所以需要按 Shift + Cmd + .快捷键,让“访达”显示隐藏文件。
4.2 在 CF Pages 上配置 301 跳转
CF Pages 提供了文档[3],按照文档写一个重定向规则文件 _redirects 就可以啦。不过,比起 CPanel(Apache),CF Pages 几乎不支持正则表达式。
文件内容如下(只有一行)
| 1 |  | 
说明:
- *号代表任意数量的任意字符,- :splat代表前文中的- *号匹配到的内容。
- 301 代表 301 跳转。
注意:把 .htaccess 文件保存到 blog/sources/ 目录(此处假设我的博客源文件保存在 blog/ 目录里)。
4.3 配置 Hexo 使上述两个文件生效

我虽然把 .htaccess 和 _redirects 这两个文件放到了 blog/sources/ 目录,但是,如果不配置一下 Hexo,这两个文件是不会部署到远程主机的,也就不会生效[4]。
用文本编辑器打开 _config.yml。
- 
找到 # URL节,将permalink:的值改成:abbrlink/(注意前面的半角冒号和后面的半角斜杠)。让 Hexo 渲染生成的博客 URL 为不带.html后缀的 URL。 
- 
找到 # Include / Exclude file(s)节,在include:下方添加上述两个文件名。让 Hexo 在渲染时将这两个文件也复制到public/目录中。 
- 
找到 # Deploy节,为每个远程主机添加一个新参数:ignore_hidden: false。让 Hexo 在部署时将作为隐藏文件的.htaccess也一并上传到远程主机。 
5 结语
搞定,301 跳转测试通过。
图片版权:
题图:"File:Symbol redirect vote2.svg" by Benoit Rochon is licensed under CC BY 3.0 . 
头图:Image by Jose Antonio Alba from Pixabay
参考文献

