关于Hugo生成日语浊音假名标题链接导致404的问题

前阵子博客从Hexo迁移到了Hugo。Hugo的各方面体验都很好,具体优点在前篇《Make This Blog Great Again》中有作说明,此篇不再赘述。

由于平时常用博客发表一些涉及日文相关的文章,免不了在标题中使用到一些日语。然而在将生成html部署到服务器上后,这些带了日语的标题经常会出现404 Not Found的情况。

起初我以为是生成的Permalink有问题。因为在复制了服务器上对应的文件名后再手动输入链接地址,居然是能直接访问到目标网页的。于是我比对了一下生成的Permalink和实际能够访问到文章的URL,发现了其中的玄机:

表面上看到的是同一串字符串,浏览器对它们分别进行URL encode出来的结果却一长一短,只有部分相等。尝试复制两串字符串,在控制台中进行全等比较发现看上去相同的两个字符串实际上并不全等。剔除相等部分后可以看到两边不一样的地方。

这个时候就比较尴尬了,为什么同样的一串字符串,Hugo生成出来文件名会和原来的不一样呢?粗略比较了一下正常链接和导致404的链接,几乎可以大胆地猜测导致404的元凶是日语的浊音假名。

根据猜测,这里可以找到一个线索:长的字符串中有一个字重复了两次。单独把重复了两次的%E3%82%99进行一次decode会发现这个“神秘”的字符串正是代表浊音的两个点

再则,同样的问题在Linux系统(elementary OS 0.4 Loki)上无法复现(手边没有Windows系统未进行测试),URL encode的结果和文件名 encode的结果始终保持一致。

基本排查到这个地方,这个问题就有眉目了。Hugo生成文件时依赖于文件系统,那就是我使用的macOS在文件系统的编码上有着异于常人的筋骨体肤了:

Mac OS X操作系统使用正式分解万国码(canonically decomposed Unicode),在文件系统中使用UTF-8编码进行文件命名,这做法通常被称为UTF-8-MAC。正式分解万国码中,预组合字符是被禁止使用的,必须以组合字符替换。

这种方法使分类变得非常简单,但是会搞混那些使用预组合字符为标准、组合字符用来显示特殊字符的软件。Mac系统的这种NFD数据是万国码规范化(Unicode normalization)的一种格式。而其他系统,包括Windows和Linux,使用万国码规范的NFC形式,也是W3C标准使用的形式。所以通常NFD数据必须转换成NFC才能被其他平台或者网络使用。

以上引自 UTF-8 - 维基百科,自由的百科全书

因此问题的根源就在于macOS的文件系统使用NFD,会把浊音假名这类组合字拆开,而浏览器采用的是W3C标准的NFC形式,所以浏览器encode的结果就和macOS下Hugo生成出来的文件名encode的结果不一致了。

Google了一下发现大多数人选择了退而求其次,用纯英数字的slug来代替标题作为链接,以此避免NFD的问题,但是这个做法对SEO貌似不是很友好……这里暂时想到两个除此之外的解决方案,仅供参考:

方案一:在服务端安装并运行convmv,把NFD转回NFC,有条件的可以写个监听,只要文件发生变动就自动跑一遍convmv的脚本

$apt-get install convmv
$convmv -f utf-8 -t utf-8 -r --notest --nfc [需要转码的文件夹]

方案二:如果使用FileZilla的话,把文章所在的文件夹单独上传至服务器,FileZilla似乎会对上传的一级目录进行NFD 2 NFC的转换

PS:其实macOS下也有一个convmv,但并没有什么太大的用处,因为无论在macOS环境下转码多少次,文件系统依旧会雷打不动地使用NFD……

comments powered by Disqus