Typecho 在「后台 → 设置 → 永久链接」里修改过规则以后,只会把「新生成的链接」按照新规则来写,并不会自动去改写「已经发布出去」的那一批旧链接,也不会给旧格式做 301/302 跳转,于是老地址再访问就 404。
解决思路只有一条:
让「按旧规则来的请求」重新能够映射到正确的文章(或者自动跳转到新地址)。做法分两步:
让「按旧规则来的请求」重新能够映射到正确的文章(或者自动跳转到新地址)。做法分两步:
-
让程序/服务器先能“认识”旧格式
-
再决定是“直接显示内容”还是“301 跳转到新地址”
下面给出几种常见服务器环境下的具体写法,挑跟自己一样的照抄即可。
(假设你原来用的是
(假设你原来用的是
/archives/{cid}/
这种数字型,后来改成了 /archives/{slug}/
别名型,目录名或后缀不同同理改正则即可。)一、Nginx 方案(推荐,效率最高)
-
在原有的
location / { try-files … }
之前加一段“旧规则”:
nginx
# 旧数字格式跳转到新别名格式
location ~ ^/archives/(\d+)/?$ {
# 先尝试内部跳转到新地址(返回 301,SEO 无损失)
return 301 /archives/$request_uri;
# 如果你只想“兼容”而不跳转,把上一行改成:
# rewrite ^/archives/(\d+)/?$ /index.php?$1 last;
}
# Typecho 官方伪静态规则(保持不变)
location / {
index index.html index.php;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php$1 last;
}
}
-
重载配置
nginx -t && nginx -s reload
二、Apache 方案(.htaccess) 在网站根目录的
.htaccess
里,把旧规则插到最前面:apache
<IfModule mod_rewrite.c>
RewriteEngine On
# 旧数字格式 301 跳转到新别名格式
RewriteRule ^archives/(\d+)/?$ /archives/$1 [R=301,L]
# 下面照旧是 Typecho 的默认规则
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]
</IfModule>
三、宝塔 / 面板用户
「网站 → 伪静态」里把上面 Nginx 或 Apache 那段粘进去保存即可,不用手动 SSH。
「网站 → 伪静态」里把上面 Nginx 或 Apache 那段粘进去保存即可,不用手动 SSH。
四、只想“兼容”而不想 301 行不行?
可以,把上面
可以,把上面
return 301 …
或 RewriteRule … R=301
去掉,改成内部重写到 index.php?cid=$1
就行(Typecho 自己会认出 cid)。但长远看还是建议做 301,对搜索引擎最友好,权重可以传递。五、批量把数据库里的旧格式改成新格式?
Typecho 的永久链接只是“实时拼装”,数据库里并不保存完整 URL,所以改链接格式后文章/页面表里本身无需变动;你只要按上面把旧地址能跳/能解析即可,不需要跑 SQL。
Typecho 的永久链接只是“实时拼装”,数据库里并不保存完整 URL,所以改链接格式后文章/页面表里本身无需变动;你只要按上面把旧地址能跳/能解析即可,不需要跑 SQL。
一句话总结
“改完规则后旧链接 404”并不是 bug,只是缺少一条重定向/兼容规则。按自己服务器的类型把上面几行配置加进去,保存重载,旧地址就能 301 到新地址(或继续正常解析),404 问题即消失。
“改完规则后旧链接 404”并不是 bug,只是缺少一条重定向/兼容规则。按自己服务器的类型把上面几行配置加进去,保存重载,旧地址就能 301 到新地址(或继续正常解析),404 问题即消失。
学到了,以后改永链就有经验了