meta refresh 是在 HTML 的 head 里用 meta 标簽做跳轉的老寫法,改版、移動端适配、舊連結收口时仍會用到。它和 301、302 最明顯的区別是:服務器返回的狀態碼通常還是 200,浏览器和蜘蛛都要先拿到並解析 HTML,才知道後面還藏着一個新地址。這個差异會改變抓取路径的形態。
為什么這類跳轉容易被漏掉
在服務器日誌里,請求 /old-page 得到的是 200,响應体完整、字节數也不小,看起来一切正常。只有把 HTML 取出来看,才會發現 head 里躺着一行 refresh。如果巡检只看狀態碼和响應大小,這類入口基本不會暴露。
更麻烦的是,這類頁面往往還带着一套完整的導航和内鏈,蜘蛛抓完正文、顺着連結走一圈,才在解析阶段發現跳轉目标,等于多花了一次抓取成本。
常见的几種表現
狀態碼為 200,抓取路径在原地打轉
舊地址被当成一個正常頁面抓取,随後再根據 refresh 發現新地址。若站内仍有連結指向舊地址,两個地址會長期並存,重复抓取和入口分散同时出現。
跳轉目标與 canonical、内鏈指向不一致
頁面 refresh 指向 B,但 canonical 寫的是 A,站内導航鏈的又是 C。蜘蛛拿到的信号互相矛盾,最终哪個地址被当作主入口,往往取决于抓取顺序,难以稳定。
延时值不是 0
寫成 content="5;url=..." 时,解析和跳轉之間存在等待。對蜘蛛来说,這段等待没有意义,却會让頁面看起来像一個停留時間偏短的正常頁面,進一步模糊判断。
跳轉目标本身又是 refresh 頁面
舊連結改到中間頁,中間頁再 refresh 到新連結,形成两跳以上。每跳都返回 200,鏈路越長,损耗越难在日誌里直接看出来。
排查顺序
- 先從日誌里筛出返回 200、但 URL 带明顯舊路径特征的地址,例如合並前的栏目、带 index_old、带临时後缀的連結。
- 用抓取工具或直接請求,检查响應体中是否存在 meta refresh,记錄 refresh 的目标和延时值。
- 把 refresh 目标、頁面 canonical、站内指向该地址的連結三者放在一起對照,标出不一致的頁面。
- 顺着 refresh 目标再請求一次,確認目标地址返回的是 200 還是又一次 refresh,判断鏈路長度。
- 統計這些舊地址被内鏈引用的情况,確認是否還有頁面在持續把它們重新暴露给蜘蛛。
處理建议
- 能用服務端跳轉的,就換成 301 或 302。狀態碼明确,蜘蛛不需要解析 HTML 就能得到结论,也省下一次正文抓取。
- 确需保留頁面的,把 refresh 延时设為 0,並让 canonical 與跳轉目标保持一致,避免信号冲突。
- 跳轉鏈路尽量压到一跳,中間頁如果能合並就直接合並,减少無意义的入口节点。
- 站内引用统一改成最终地址,让舊地址只承担跳轉职责,不再出現在導航、列表和正文連結里。
- 上线後复抓一批样本,確認舊地址的狀態碼已经變化,且没有新的 200 型 refresh 頁面在产生。
巡检时把“返回 200 就当正常”這個預設假设放一放,很多路径断点並不在狀態碼上,而是藏在响應体的前几十行里。