有些系統是為了特定的人建造的,它對那些人運作得很順;對其他人,它就像一扇沒有把手的門——你知道應該能進去,但怎麼推都沒有反應。
我在計劃烏茲別克旅行時遇到了這樣的門。
目的地是布哈拉,從塔什干出發。我找到了烏茲別克鐵路的官方訂票網站 eticket.railway.uz,帳號也註冊好了,選好了班次(06:10 發車、10:16 抵達)、選好了車廂、選好了靠窗的座位。但每當我按下確認,系統就把訂單取消,把我踢回首頁。
沒有錯誤訊息。只有一個乾淨的重導向,像什麼都沒發生過。
旅行社的報價是一面鏡子
我先去問了旅行社。三張票,塔什干到布哈拉,140 歐元。
那個數字讓我想了一下。不是貴不貴的問題,而是:如果我就這樣接受了,我其實根本不知道「票的真實價格是多少」。旅行社的存在有它的意義,有些事情確實需要有人代勞;但這次,我想先弄清楚自己是不是真的沒有辦法自己買。
無法使用,和沒有嘗試,是兩件不同的事。
系統自己取消了那筆訂單
網頁打不開不是技術問題,至少不是「你沒辦法解決」的那種。我打開瀏覽器的開發者工具(DevTools → Network),重新走了一次訂票流程,看著每一個 API 請求進出。
訂單建立了。系統拿到了一個 orderId。然後,在我被重導向回首頁的同時,我看到一個 POST 請求打向:
/api/v1/universal-orders/cancel/{orderId}
不是我取消的。是系統自己取消的。
接著我去查訂單的有效期限 API:
GET /api/v1/universal-orders/process/end-time/{orderId}
它回傳了:
{
"response": {
"endLifeTime": "2026-04-12T13:04:31.226000615"
}
}
看起來正常。但這個時間字串少了一個東西。
一個少掉的符號
"2026-04-12T13:04:31.226000615"
這串時間沒有時區資訊。沒有 Z,沒有 +05:00,什麼都沒有。
在 JavaScript 裡,new Date("2026-04-12T13:04:31") 的行為取決於瀏覽器所在的時區。對烏茲別克當地人(UTC+5)來說,這個時間被解讀為當地時間 13:04,剛好是正確的;對台灣使用者(UTC+8)來說,瀏覽器把它解讀為台灣時間 13:04,換算回 UTC 是 05:04,整整比烏茲別克時間早了三個小時。
系統給你 15 分鐘完成付款。但你的瀏覽器一打開頁面,就認為這個訂單已經過期三個小時了。
計時器立刻歸零,取消訂單,送你回首頁。
這不是一個複雜的 Bug,但它精準地把所有時區不同的人擋在門外——不是因為系統不歡迎你,而是因為系統從來沒有想到你的存在。
在瀏覽器裡動手術
找到問題之後,解法反而簡單。
我需要在 API 回傳的那個瞬間攔截回應,把缺少的時區資訊加回去。因為烏茲別克用的是 UTC+5(塔什干時間),只要在字串後面補上 +05:00,瀏覽器就能正確解析。
做法是在 DevTools 的 Console 貼上以下這段代碼,在進入訂票頁面之前執行:
const _JSONparse = JSON.parse;
JSON.parse = function(text) {
const result = _JSONparse.call(this, text);
if (
result?.response?.endLifeTime &&
typeof result.response.endLifeTime === 'string'
) {
const str = result.response.endLifeTime;
if (
/^\d{4}-\d{2}-\d{2}T/.test(str) &&
!str.endsWith('Z') &&
!/[+\-]\d{2}:\d{2}$/.test(str)
) {
result.response.endLifeTime = str + '+05:00';
console.log('✓ endLifeTime 已修正:', result.response.endLifeTime);
}
}
return result;
};
console.log('✓ 時區修正已啟用,現在可以繼續訂票。');
這段代碼接管了瀏覽器的 JSON.parse,每次 API 回應被解析時,檢查 endLifeTime 欄位是否缺少時區,若是,就補上 +05:00。其他所有資料完全不受影響。
執行之後,重新走一次訂票流程:選車次、選車廂、選座位、按確認。計時器這次正確地從 15 分鐘開始倒數,訂單停在確認頁面,不再被踢走。

操作步驟整理:
- 開啟 eticket.railway.uz 並登入帳號
- 按 F12(或右鍵 → 檢查)開啟 DevTools,切換到 Console 分頁
- 貼上上方代碼並按 Enter,確認看到「✓ 時區修正已啟用」
- 在同一個分頁繼續選票、選座位、確認訂單
- 進入付款頁面,選擇 VISA 完成付款
你點下去,但不知道會到哪裡
付款這一步有一個需要特別說明的地方。
進入付款頁面後,你會看到幾個付款方式的選項。其中有 VISA 圖示,理論上應該導向 Stripe 的付款流程,這對持有台灣或其他國際信用卡的旅客來說是最直接的選擇。
但實際操作時,行為並不穩定。有時點下去確實進入 Stripe 頁面,可以用一般 VISA 刷卡;有時點下去卻跳轉到另一個系統:OCTO Bank(Octobank)。

OCTO Bank 是烏茲別克的本地銀行,它的付款頁面顯示為繁體中文介面,從視覺設計來判斷,比較偏向支援中國的支付管道。對一般國際旅客來說,這條路可能走不通。

如果點下去進入的是 OCTO Bank,建議取消並重試。多試幾次,通常能進入 Stripe 的正規流程。這個行為背後的原因目前不確定,可能是前端的路由隨機分配,也可能和瀏覽器狀態有關。只要沒有被帶到 Stripe,就不要在 OCTO Bank 那端輸入任何資料,重新來一次就好。
三張票,2,600 元
最後,三張從塔什干到布哈拉的票,折合台幣大約 2,600 元。
旅行社的報價是 140 歐元,換算下來大概是票價的兩倍。
我沒有特別算計省了多少。我更在意的是:如果當初沒有想去查,這筆差額就這樣消失了,而我不會知道它的存在。不是說旅行社的服務沒有價值,只是這次它的價值是「幫你繞過一個本來可以解決的問題」,而那個問題,本質上只是一個少了幾個字元的時間字串。
有些時候,系統的「不相容」不是惡意的排除,只是粗心的遺忘。
遺忘了世界上還有時區不同的人。遺忘了 UTC+8 不是全球預設值。遺忘了日期字串少了符號時會發生什麼。
這種遺忘是可以被修補的,不一定要等官方。有時候只需要一段幾十行的代碼、一個 DevTools 的 Console 視窗,和一點點不願意直接放棄的耐心。