varchar(255) 陷阱:帳密正確,卻從 in-app 瀏覽器登入回 500
前言:帳密明明正確,卻回 500 某天收到回報:使用者從手機點開官網登入,帳號密碼都對,卻跳出 Internal Server Error。換其他瀏覽器再登入就成功了。 「帳密正確卻 500」這種錯誤特別惱人,因為它不是身分驗證的問題,而是驗證通過之後才出事。本文記錄怎麼從一行日誌追到根因,以及背後三個值得每個後端工程師記住的設計教訓。 從日誌追根因:三條線索 先分清楚登入失敗的兩種回應:帳密錯誤會回 400 Invalid identifier or password;而這次是 500。光這一點就暗示——帳密其實是對的,問題出在登入流程的後半段。 線索一:500 只在帳密正確時出現 撈出該帳號當天的登入紀錄,發現 500 全部集中在某個時段,之後突然出現一次成功,再之後才是幾筆「帳密錯誤」的 400。換句話說,那串 500 本身就證明了帳密一直是對的——錯的不是驗證。 線索二:那行 PostgreSQL 錯誤訊息 日誌裡每筆 500 都附帶同一句資料庫錯誤: insert into "refresh_tokens" (..., "user_agent") values (...) - value too long for type character varying(255) 真相浮現:登入驗證通過後,後端要寫一筆 refresh token 進資料庫,其中 user_agent 欄位是 varchar(255),而這次要寫入的值超過 255 字元,PostgreSQL 直接拒絕,未被攔截的例外往上冒成了 500。 線索三:為什麼有時成功、有時失敗 成功那次寫進資料庫的 user_agent 長度是 128;失敗那幾次的值都超過 255。差別就在 User-Agent 字串的長度——而它由「使用者用什麼瀏覽器」決定。 根本原因:varchar(255) 塞不下 in-app 瀏覽器的 UA 寫入 refresh_tokens 的欄位中,token 是固定長度的隨機字串、expires_at 是時間、device_type 是短列舉、ip_address 也很短。唯一長度會劇烈變動、且可能爆掉的,只有 user_agent。 ...