这个文件是我手写的。二十来条,每条三行。
先说清楚:它读起来一点也不聪明。全站二十页,写脚本生成省事得多,我试过,跑了一遍就删了。
文件时间不等于内容时间
脚本的思路是扫一遍目录,按每个文件的修改时间填 lastmod。听起来天经地义,直到我做了一次全站重新上传:所有文件的修改时间变成了同一分钟。脚本生成的 sitemap 于是在告诉搜索引擎 —— 今天这二十页全都更新了。
这句是假话。那天我只改了一个错别字。
根子在于,文件时间记录的是「这个文件最后一次被写过」,不是「这页内容最后一次变化」。对我来说这两个时间只在理想情况下重合。上传、备份、批量替换字符,都能让前者变、后者不变。
把日期写诚实,比想象中费事
所以我现在手动改。改完一篇,先在正文里改,再打开 sitemap.xml,找到那一行,改掉。顺序固定,漏的概率小一点。
照样漏过两次。一次是改了个错别字,当时觉得不值得动 sitemap。后来想通了:内容变了就是变了,我不该替搜索引擎判断哪次改动算数。另一次纯粹是忘了,隔了快一周才发现某个日期不对。
我确实被诱惑过。把所有条目的 lastmod 都刷成当天,整个站看起来一直在更新,多体面。我没做。二十条日期一模一样,是最明显的自动生成痕迹;更要紧的是,那还是一句假话。这种地方写对了没人夸你,写错了是会被翻出来看的。
robots.txt 我第一条就写错了
第一版里我写了一条 Disallow: /404.html,理由很直白:错误页不该出现在搜索结果里。
我把它理解成「别收这一页」。它实际的含义是「别来抓这一页」。这两件事差得远。一个地址被挡在门外,搜索引擎照样可能把它列进结果,只要有别处链接过去,只不过拿不到摘要,结果里显示的是一行光秃秃的网址,比收录了还难看。真想让它不出现,反倒得让页面能被抓,然后在页面里说明不要收录。
这条我最后整个删掉了。二十页的站,坏链本来就少,为它多写一行不如不写。现在文件里只剩两行有用的:全站放行,和一行指向 sitemap 的完整地址。
那个地址我最早写的是 /sitemap.xml,相对路径。它必须是完整网址,从站点根写起的简称在这里没有意义 —— 这行字是给站外的程序看的,它不知道「本站」是谁。改完我用浏览器直接访问了一次,确认返回的是 XML,不是那个自定义错误页。
nginx 上跟着改了两个地方
原来我把 xml 塞在静态资源的长缓存那一组里。后来反应过来:sitemap 是内容,不是资源。我加一篇文章它就该变,而一个月的缓存会让搜索引擎整整一个月拿到旧的那份。现在 html、xml、txt 一律不走长缓存。
robots.txt 我也照这个处理。它一天被读不了几次,为省那点流量去冒「拿到旧文件」的风险不划算。顺手加了 charset utf-8;,因为本地检查工具抱怨过编码 —— 文件本身是纯 ASCII,加不加大概都行,一行的事。
location = /robots.txt {
charset utf-8;
expires -1;
add_header Cache-Control "no-cache";
}
location = /sitemap.xml {
charset utf-8;
expires -1;
add_header Cache-Control "no-cache";
}
两处我到现在也不确定
一、robots.txt 里那行 Sitemap 指针到底起没起作用,我说不清。日志里能看到抓取,但看不出对方是先读了 robots.txt 再顺着过来的,还是从别的地方知道的地址。
二、changefreq 和 priority 这两项,我读到过「早就被忽略」的说法,也读到过「仍然参考」的说法,两边都没找到站得住的出处。我现在还写着 —— 写了不亏 —— 但它到底有没有产生过任何作用,我不知道。
现在的样子
二十来条,六十行左右。没有插件,没有构建。加一篇文章要改四处:分类列表、归档、标签页、sitemap。
麻烦是真的。但每次手动改的时候,我至少清楚自己在改什么、为什么改。这个站总共二十页,麻烦的规模和站的规模勉强配得上 —— 等它有一百页,我大概就得换个做法了。