本機測過了不代表線上會過:一週撞牆四次的紀錄

上週我把一個網站從舊網域搬到新網域,要處理 41 筆舊網址的轉址。

我做了一件自認謹慎的事:沒有等上線才測,而是先在本機把整套轉址跑過一遍。 wrangler pages dev 跑的就是 Cloudflare Pages 同一套引擎,理論上本機通過就等於線上通過。

一週之內,這個「理論上」被打臉四次。

四次的原因完全不同,而且沒有一次是我事前猜得到的。所以我把它們寫下來 —— 不是為了說「要記得測線上」這種廢話,而是因為每一次的症狀都在騙人。

第一次:本機攔得到的規則,線上攔不到

轉址表裡有兩筆舊網址含括號,像這樣:

/2017/06/20/java swing -教育訓練程式(第二版)/

我在 _redirects 裡同時寫了兩種寫法:字面括號 (,以及編碼後的 %28。 本機逐筆驗證,43 條規則全過。

上線之後,那兩條 %28 的規則完全不作用,回 404。

實測下來的行為是:正式環境寫字面 ( 時,客戶端送字面括號會 301; 但客戶端送 %28 時,無論規則怎麼寫都攔不到。本機卻兩種都攔得到。

我最後把那兩條無效的規則刪掉了。留著一條在正式環境不會生效的規則, 比沒有更糟 —— 它會讓下一個看轉址表的人(包括三個月後的我)以為那個情況已經處理過了。

⚠️ 附帶一提,這個問題手動點一下是測不出來的,因為瀏覽器送的是字面括號。 只有逐筆自動驗證才會撞到。

第二次:41 筆全部失敗,但網站是好的

上線後我把驗證腳本指向正式網址,結果 41 筆全部失敗,每一筆都回 403。

那個畫面看起來就是整站掛了。

實際上網站好得很。是 Cloudflare 擋掉了我腳本的 User-Agent —— Python 標準庫的預設值 Python-urllib/3.x。

curl 預設 UA          → 301  ✅
python urllib 預設 UA → 403  ❌
帶自訂工具名的 UA     → 301  ✅
瀏覽器 UA             → 301  ✅

同一個網址,換個 UA 就從 403 變 301。

這一類的錯最危險,因為症狀跟真正的災難長得一模一樣。 如果我當下相信了那個畫面, 下一步大概會去回滾部署或改轉址表 —— 兩個都會把好的東西弄壞。

現在我的驗證腳本一律帶具識別性的 UA:<工具名>/<版本> (<聯絡信箱>)。 不是為了偽裝,是為了不被當成雜訊,而且對方要封鎖時找得到我。

第三次:本機量到的位移,線上量不到

修完文章頁的版面位移(CLS)之後,我在本機重測,還剩 0.212,怎麼調都下不去。

線上量,是 0。

原因是文章裡的圖片放在 imgur,而 imgur 的防盜連會擋 localhost 的 referer:

Referer: http://127.0.0.1:8788/  → 403
Referer: https://wisplu.com/     → 200
沒有 Referer                     → 200

圖載不進來,瀏覽器就改渲染替代文字,尺寸跟原本保留的空間不一樣,於是產生位移。 那個 0.212 完全是本機環境造出來的,真實訪客不會遇到。

這次的教訓比前兩次更彆扭:我差點為了一個不存在的問題去改架構。

第四次:線上驗了,但驗得太早

這次跟本機無關,但屬於同一類 —— 驗收方法本身在騙你。

部署完成後我馬上驗證,結果首頁還是舊內容。我以為建置沒帶到,正準備去追建置流程。

實際上只是打到了還沒更新的邊緣節點。同一個網址加上 cache buster 就是新的; 等四十秒再打,也是新的。

假陰性跟真陽性一樣會讓你動手,而且動手的方向是錯的。

這四次的共同點

它們的原因分別是規則比對、UA 過濾、防盜連、快取傳播 —— 完全不同的層。 但錯誤的形狀是一樣的:

驗收環境跟真實環境的差異,不會以「差異」的樣子出現,會以「錯誤」的樣子出現。

本機少一層防盜連,你看到的不是「這裡沒有防盜連」,是「CLS 0.212」。 UA 被擋,你看到的不是「UA 被擋」,是「41 筆全部失敗」。 它們都偽裝成你熟悉的那種故障,所以你會照著那種故障去修。

我現在的做法

一、本機驗收只當快速回饋,結論一律以線上為準。 本機測的價值是「在部署前抓掉明顯的錯」,不是「證明線上會過」。這兩件事差很遠。

二、任何自動化的檢查,都帶具識別性的 User-Agent。 順便說,這條在別的地方也救過我:Wikidata 的查詢服務同樣會擋預設 UA,而且回的不是錯誤碼, 是一段不是 JSON 的東西 —— 解析直接爆掉,長得像程式有 bug。

三、驗收失敗時,先問「是東西壞了,還是我測錯了」。 具體做法是換一個維度再測一次:換 UA、換 referer、換網址加 cache buster、隔一段時間再測。 如果換個維度就好了,那壞的是測法不是東西。

四、把在正式環境無效的東西刪掉,不要留著。 無效的規則會累積成一種假的安全感。


最後補一句我覺得最反直覺的:這四次裡,有三次的第一反應都是「去修那個東西」,而且都會修錯。

自動化驗收真正的價值不是它會告訴你有問題 —— 是它會逐筆告訴你, 讓你看得出「41 筆全錯」和「2 筆錯」是完全不同的兩件事。 全錯通常是測法的問題,零星錯才是東西的問題。這個分辨,比任何單次的檢查結果都值錢。