结论:数据库批量替换只清掉了内容字段里的绝对 URL,硬编码链接还留在模板文件、配置文件、静态资源、序列化数据和缓存里,必须按「全站搜索定位 → 分类替换 → 清缓存 → 301 兜底 → 链接验证」五步补齐,否则迁移后仍会有一批 404 和跳回旧域名的死链。
数据库替换完了,还有哪些地方藏着旧域名?
结论:最常见的漏网位置是模板与配置文件里的写死地址、序列化字段、附件表里的全 URL、缓存及第三方后台配置,这五类占漏链的绝大多数。
硬编码指直接把 https://old.com/xxx 写死在文件或字段里,而不是通过配置项动态生成。典型落点:模板文件(.html/.tpl/.blade.php/.vue)里的 logo、导航、CDN 引用;.env、config.php、database.php 里的站点 URL;robots.txt 里的 Sitemap 行和 sitemap.xml 里的 loc;邮件/短信模板、支付回调 notify_url、OAuth 的 redirect_uri、微信 JS 安全域名、小程序 request 合法域名——这几项在后台上,数据库替换根本碰不到。
怎么用命令行一次性找出所有硬编码旧域名?
结论:先备份再搜索,用 grep -rIl 列出含旧域名的文件清单,按文件类型分组统计后再动手改。
执行前先留退路:cp -a /www/wwwroot/site /www/backup/site-$(date +%F)。然后定位:
grep -rIl --exclude-dir={.git,node_modules,uploads,runtime,storage} "old\.com" /www/wwwroot/site
grep -rIo "https\?://old\.com[^\"' )<]*" /www/wwwroot/site | awk -F: '{print $1}' | sort | uniq -c | sort -rn | head -30
-I 跳过二进制文件避免误报,-l 只输出文件名便于人工过一遍。确认清单后批量替换:grep -rIl "old\.com" ./ | xargs sed -i 's#https\?://old\.com#https://new.com#g',用 # 作分隔符可以省掉转义斜杠。替换完再跑一次第一条命令,返回空才算干净。
序列化字段能直接用 REPLACE 替换吗?
结论:不能。PHP 序列化字符串带长度前缀(如 s:22:"https://old.com/a.png"),字符串一改长度,长度前缀不跟着变,unserialize 就会失败,整条配置变空。
如果是 WordPress,用 wp search-replace 'old.com' 'new.com' --all-tables --precise --dry-run 先看影响行数,去掉 --dry-run 再执行,它会自动修正序列化长度。其他系统要么写个 PHP 脚本 unserialize → 替换 → serialize 回写,要么定位到具体字段手工改。JSON 字段和 base64 编码过的配置同理,需要用对应的解码方式处理,不能一把 SQL REPLACE 全库扫。
已经替换完,怎么防止漏网链接变 404?
结论:加一层 301 跳转兜底,任何指向 old.com 的硬编码链接都会被打到新域名对应路径上,同时把站内绝对链接尽量改成相对路径。
Nginx 配置:server { listen 80; listen 443 ssl; server_name old.com www.old.com; return 301 https://new.com$request_uri; }。注意这只是兜底,不是修复——页面里残留旧域名会额外多一跳,SEO 上还会产生 canonical 混乱,所以正文里的链接仍然要改成 /path 这种相对写法,下次再迁移就不用重来一遍。
替换完记得清缓存:systemctl reload php-fpm 让 OPcache 失效,Redis 里带站点前缀的 key 删掉,文件缓存目录 runtime/cache、storage/framework/cache 清空,CDN 控制台提交全量刷新。缓存不清,改了文件前台看到的还是旧域名。
迁移是否彻底,跑哪几条命令验证?
结论:拿 sitemap 全量跑一遍状态码,只要出现 301 或 404 就说明还有残留。
curl -s https://new.com/sitemap.xml | grep -o '<loc>[^<]*' | sed 's/<loc>//' | while read u; do
echo "$(curl -o /dev/null -s -w '%{http_code}' "$u") $u"; done | grep -v '^200'
另外单独查两处:curl -s https://new.com | grep -c old.com 应为 0;提交一条测试订单/测试邮件,确认回调地址和邮件里的链接都指向新域名。整个流程在 GJ 站长论坛的运维交流里也常被讨论,遇到特定 CMS 的坑可以直接发帖贴出 grep 结果求定位。
收束:数据库替换只是第一步,真正的迁移完整性取决于文件层搜索是否穷尽、序列化字段是否安全处理、缓存是否清干净、301 是否兜住、状态码验证是否跑完。五步走完,旧域名才算真正下线。