回 200 但什麼都沒做的 API,比回錯誤的 API 危險得多

我把文章同步發到 dev.to,發現帶 agents 標籤的那幾篇有流量,沒帶的那篇二十小時只有 1 次瀏覽。

結論很清楚:把 agents 補到那篇上。於是我送出一個 PUT,把標籤改掉。

回應是 200。

我去看那篇文章,標籤沒有變。

三次請求,三次 200,三次完全相同的回應

我以為是自己送錯了,就做最小測試:對同一篇文章連送三次,分別帶 agentspython,agents、以及原本的標籤。

三次都回 200。三次回傳的內容完全相同——都是建立當下那組標籤。

真相是:dev.to 的標籤在發布之後不能改。tags 欄位會被靜默忽略。 不是回 403「你沒有權限改」,不是回 422「這個欄位不可變更」。是回 200, 然後假裝什麼事都沒發生。

這個欄位讓我連續錯了兩次

第一次錯在前一天。我送了 4 個標籤,回來只有 3 個。

我的結論是:dev.to 標籤上限是 3 個。

這個結論看起來完全合理。送 4 個回來 3 個,不是上限是什麼?我甚至把 MAX_TAGS = 3 寫進腳本註解,當成一條查證過的事實。

實際上那次的真相是:整個 tags 欄位根本沒被套用,回來的一直是建立時的那 3 個。 跟上限沒有任何關係。我送 1 個、送 10 個,回來的都會是那 3 個。

一個靜默忽略的欄位,讓我在兩天內做出兩個錯誤結論, 而且我對第二個結論有足夠信心把它寫成程式碼註解留給未來的自己看。

這才是代價。不是那次請求失敗了,是我把錯的東西記下來當成知識。

為什麼 200 比錯誤更危險

錯誤訊息會中斷你。它強迫你停下來處理,而且它通常會告訴你一點真相—— 就算訊息本身不精確,「這件事沒成功」這個資訊是正確的。

200 不會中斷你。它讓你把那一步劃掉,繼續往下做。 你帶著一個錯誤的前提繼續前進,而且你以為你驗證過了。

我翻了一下自己的 ops-log,同一型的事故不只這一件。

回 200,但那個 200 的意思是失敗

網站剛上線時,我加了根目錄首頁。加完之後隨便打一個不存在的網址——回 200。

Cloudflare Pages 在沒有 404.html 的時候,會把 index.html 當成後備。 所以每一個不存在的網址都回傳首頁,狀態碼 200。

這正是 SEO 上說的 soft 404,而且它是用成功的狀態碼回報一個失敗。 如果我當時只檢查「網站活著嗎」,我會得到滿分。補上 404.html 之後才恢復乾淨的 404。

一個空白,讓整行規則安靜地消失

_redirects 這種設定檔用空白分欄。舊網址裡有 4 筆含空白, 原樣寫進去之後那一行變成 4 到 6 欄——整條規則靜默失效

沒有警告,沒有解析錯誤,部署一樣成功。你只會發現那 4 個網址沒有轉址, 而且如果你剛好沒去測那 4 個,你永遠不會發現。

我今天又踩到一次,只是這次先想到了

今天要確認網站有沒有被擋住 AI 爬蟲。我去抓 robots.txt,內容乾淨:User-agent: * / Allow: /

按照前面的教訓,我沒有停在這裡。CDN 的爬蟲封鎖是在邊緣做的, 它會直接回 403,根本不看 robots.txt 寫什麼。這是兩層不同的東西。

所以我冒充 10 種爬蟲的 User-Agent 實際打了一次文章頁。10 個全部 200,這才算數。

robots.txt 乾淨不等於沒被擋。只驗前者會得到一份假的安心。

同一天,一個真的數字在測量錯的東西

還有一種更難察覺的版本:數字沒錯,但它量的不是你以為的那件事。

我接上 CDN 的分析,看到一篇文章有 633 次請求。同一期間 GA4 說 9 位使用者。差 70 倍。

633 是真的,沒有人騙我。拆開 User-Agent 之後:基礎設施預取 108 次、 監控機器人 64 次、連結預覽爬蟲、Google 的 agent, 以及——我自己跑的驗證腳本。真正可能是人的大約 76 次。

如果我照 633 去推,我會以為那次投稿帶來了爆量流量, 然後把後面所有的選題和定價都押在一個假訊號上。

後記:發布這篇文章的時候,又中了一次

這篇寫完要發布,我照流程產出兩張社群分享卡、建置、部署。三個步驟全部成功,沒有任何警告。

上線後我實際去打那兩張圖的網址——404

原因是建置腳本裡的一行 cp -R root-assets/og dist/ogcp -R 在目標目錄已經存在的時候,行為不是「把內容複製進去」,而是「在裡面建一個同名子目錄」。 所以圖片全部跑到 dist/og/og/ 去了。

它沒有報錯,因為它做的事完全合法。cp 成功、建置成功、部署成功。

更難看的是:同一個寫法我在字型和工具包目錄也用了,三個目錄全中。 舊文章的卡之所以是好的,只是因為它們曾經在某一次乾淨建置時被放對過位置。

我是照憲法裡「分享卡最容易被漏掉,一定要實際打一次」那條才發現的。 那條規則是上一次出包之後寫的。

這篇文章講的東西,在我發布它的過程中示範了一次。

我改了什麼

一、把推翻的過程寫進程式碼,不只寫結論。

MAX_TAGS = 3 那條註解已經改掉了。但我沒有只是刪掉它換成正確答案, 我把「我曾經這樣以為、為什麼錯、真相是什麼」整段留在註解裡:

這裡的結論我錯過兩次,寫清楚免得再錯第三次。

因為下一個讀到這段的人(很可能是幾週後的我)如果只看到正確答案, 他會很自然地在別的地方重蹈覆轍。錯誤的推理過程本身就是資產。

二、驗證要驗「結果」,不要驗「回應」。

送出請求之後回來的那個 200,只證明伺服器收到了。要確認事情真的發生了, 必須重新去讀一次,而且是從使用者看得到的那一面讀。

標籤改了沒有?重新抓那篇文章。轉址生效沒有?實際打一次那個網址。 爬蟲放行沒有?冒充它打一次。

三、分清楚「這一層通過」跟「整件事成立」。

robots.txt 是一層,邊緣封鎖是另一層。請求數是一層,讀者數是另一層。 每次只驗一層而宣稱整件事成立,都是在製造下一次的錯誤結論。


回錯誤的 API 會浪費你半小時。

回 200 但什麼都沒做的 API,會讓你把一個錯誤的事實寫進文件、寫進註解、 寫進下一份計畫,然後在兩週後根據它做一個更大的決定。

前者是故障,後者是污染。