為什麼要用 Mihomo API 自動切換節點?

在日常使用 Clash 或 Mihomo 時,最容易被忽略的問題不是「有沒有節點」,而是目前選中的節點是否仍然可用。訂閱裡可能有數十個節點,但實際連線時常遇到延遲突然升高、TLS 握手逾時、封包遺失,或某個出口在尖峰時段暫時不可用。手動打開 Clash Verge Rev、Mihomo Party 或其他客戶端,再進入代理頁面逐一測速,確實可以解決一次性的故障,但不適合長時間無人值守的下載、CI 工作流程、家庭路由器或遠端伺服器。

Mihomo External Controller API 提供了一個較穩定的自動化入口。腳本可以讀取目前的代理群組、呼叫指定節點的延遲測試介面,依據多次測試結果判斷節點狀態,再透過 API 把策略組切換到新的代理。這個流程不會修改訂閱來源,也不會憑空產生節點;它只是把原本需要在圖形介面完成的「測試、判斷、選擇」工作交給一個可記錄、可排程的程式。

本文使用的情境是:設定檔中已有一個名為 PROXY 的選擇型策略組,裡面包含多個合法來源的代理節點。腳本會優先測試候選節點,只有在目前節點連續失敗或明顯超過延遲門檻時才切換,避免因為一次偶發的測速抖動而頻繁跳點。這個「有條件切換」比單純每分鐘選最低延遲節點更適合長連線與實際工作環境。

使用前提:Mihomo API 是本機管理介面,不提供遠端節點,也不會替你取得訂閱。請只在合法授權的設定檔與網路環境中使用,並妥善保管訂閱連結、API 密鑰與節點資訊。

先確認 API、策略組與節點名稱

自動切換能否成功,第一個關鍵是確認客戶端真的開啟了 external controller。不同版本的 Clash Verge Rev、Mihomo Party 或純 Mihomo 設定檔,欄位名稱可能略有差異,但常見設定如下:

YAMLexternal-controller: 127.0.0.1:9090
secret: "change-this-secret"

建議只監聽 127.0.0.1,不要直接寫成 0.0.0.0:9090。後者會讓區域網路甚至其他可達介面有機會接觸管理 API;若確實需要從另一台管理機器操作,應先透過防火牆、VPN 或 SSH 隧道限制來源,再搭配密鑰驗證,而不是把控制器直接暴露在公網。

啟用後,可以先以瀏覽器、curl 或 API 工具讀取代理清單。若設定了密鑰,請在請求標頭加入 Authorization: Bearer,不要把密鑰放進 URL,因為 URL 可能出現在 shell 歷史、反向代理日誌或監控系統中。

Shellcurl -s \
  -H "Authorization: Bearer change-this-secret" \
  http://127.0.0.1:9090/proxies

回應通常是一個 JSON 物件,proxies 裡會包含策略組與單獨節點。你需要先找出三種資訊:實際的策略組名稱、該策略組目前選中的節點,以及可供切換的候選名稱。名稱必須與 API 回應完全一致,包含大小寫、空格、地區標記與特殊符號。不要只憑設定檔裡的印象手動拼接名稱,因為訂閱更新後節點名稱可能已經改變。

假設策略組名稱是 PROXY,切換請求通常使用:

HTTPPUT /proxies/PROXY
Content-Type: application/json
Authorization: Bearer change-this-secret

{"name":"JP-Tokyo-01"}

實際操作時,策略組名稱需要經過 URL 編碼;若名稱含有空格、斜線或非 ASCII 字元,不能直接把原字串拼進路徑。腳本使用 curl --data-urlencode、Python 的 URL 編碼函式或相應 HTTP 函式庫會比較安全。完成切換後,再次讀取該策略組的狀態,確認 now 欄位已變成預期節點。

用延遲測試與故障門檻建立切換腳本

Mihomo 通常可以透過代理群組或節點的 delay API 測試指定 URL。測速網址應選擇你真正關心的服務,例如公司 API、套件註冊站或穩定的 HTTPS 健康檢查端點,不建議只測一個與實際工作毫無關係的網站。測速成功只代表該次請求在指定逾時內完成,不等於節點能長時間承受所有協議與流量,因此腳本仍需要失敗次數、延遲上限與冷卻時間。

下面是一個簡化的 Bash 骨架。它使用 jq 解析 JSON,先檢查一組候選節點,再把第一個通過門檻的節點寫回策略組:

Shell#!/usr/bin/env bash
set -u

API="http://127.0.0.1:9090"
SECRET="${MIHOMO_SECRET:?missing MIHOMO_SECRET}"
GROUP="PROXY"
TEST_URL="https://www.example.com/generate_204"
TIMEOUT=5000
MAX_DELAY=800

auth=(-H "Authorization: Bearer ${SECRET}")

for node in "JP-Tokyo-01" "SG-Home-02" "US-West-01"; do
  encoded=$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$node")
  result=$(curl -fsS --max-time 8 "${auth[@]}" \
    "$API/proxies/${encoded}/delay?url=$(python3 -c 'import urllib.parse; print(urllib.parse.quote("'"$TEST_URL"'"))')&timeout=$TIMEOUT" \
    || true)
  delay=$(printf '%s' "$result" | jq -r '.delay // 99999')

  if [ "$delay" -le "$MAX_DELAY" ]; then
    curl -fsS -X PUT "${auth[@]}" \
      -H "Content-Type: application/json" \
      --data "{\"name\":\"$node\"}" \
      "$API/proxies/$(python3 -c 'import urllib.parse; print(urllib.parse.quote("'"$GROUP"'", safe=""))')" \
      && printf '%s selected delay=%s\n' "$node" "$delay"
    exit 0
  fi
done

printf '%s\n' "no healthy node found" >&2
exit 1

這段程式適合用來理解 API 互動順序,但正式使用前仍應補上目前節點判斷、重試與日誌。若每次排程都直接切到測得最低的節點,可能造成瀏覽器連線、下載工作或 WebSocket 在短時間內反覆中斷。因此較穩妥的策略是先保留目前節點:只有當目前節點連續兩至三次失敗,或延遲超過例如 800 毫秒並持續一段時間,才搜尋替代節點。

  1. 取得目前狀態:讀取 /proxies,確認策略組存在,並記錄目前的 now 節點。
  2. 測試目前節點:使用與實際需求接近的 HTTPS 網址,設定合理的連線逾時,不要把一次失敗立即視為永久故障。
  3. 套用故障門檻:用狀態檔保存連續失敗次數、上次切換時間與目前節點,讓腳本在多次執行之間保留判斷依據。
  4. 選擇替代節點:只在候選節點成功且延遲低於門檻時切換;若所有候選都失敗,保留原狀並記錄警告。
  5. 驗證切換結果:重新讀取策略組,確認實際選擇已更新,再把節點名稱、延遲與時間寫入日誌。

候選節點最好來自 API 即時回應,而不是永久硬編碼。你可以先以設定檔中的固定白名單限制範圍,再由腳本檢查這些名稱是否仍存在。這樣既能避免把故障節點以外的特殊策略組誤當成普通節點,也能降低訂閱更新後名稱變動造成的錯誤。

保護密鑰、設定排程與處理異常

自動化腳本最常見的安全問題不是 API 本身,而是密鑰被不小心寫進公開儲存庫、終端歷史或錯誤日誌。建議將密鑰放在只有目前使用者可讀的環境檔,並設定檔案權限;不要把完整的 Authorization 標頭用 set -x 印出,也不要在失敗訊息中輸出整個請求環境。若使用 Windows,可透過使用者層級環境變數或系統認證儲存機制管理;macOS 與 Linux 則可使用權限受限的環境檔、鑰匙圈或 Secret Service。

不要直接暴露控制器:若 API 綁定在區域網路介面,僅有密鑰仍不足以抵禦所有風險。控制器具備切換代理、讀取連線資訊甚至進行管理操作的能力,請優先限制監聽位址與防火牆來源,並定期更換密鑰。

排程方面,Linux 可以先用 systemd timer 或 cron,每五至十五分鐘執行一次;Windows 可使用工作排程器;macOS 則可使用 launchd。排程頻率不要盲目設得太短,因為每次測試都會消耗節點資源,也可能觸發服務端的頻率限制。對長連線用途而言,五分鐘檢查一次通常比每三十秒切換更容易維持穩定。

腳本應區分幾種退出結果:API 無法連線代表 Mihomo 未啟動或控制器設定錯誤;HTTP 401 或 403 多半代表密鑰不符;HTTP 404 可能是節點名稱未經編碼或 API 路徑不適用;延遲 API 回傳錯誤則可能是測試網址、DNS 或候選節點本身有問題。把這些情況分開記錄,之後才能知道究竟是客戶端故障、規則問題,還是節點品質下降。

建議日誌至少包含時間、策略組、原節點、目標節點、測試網址、延遲、失敗原因與腳本版本。例如只寫「已切換」並不足以追蹤問題;若使用者隔天發現 Git、瀏覽器與影音服務都曾中斷,卻沒有切換前後資料,就很難判斷是頻繁切換、DNS 變更還是出口本身不穩。當日誌累積到一定量後,可再依節點統計成功率與中位延遲,淘汰長期表現不佳的候選項。

最後要注意 API 切換與策略組類型的關係。select 類群組通常適合由腳本明確指定節點;url-testfallback 或巢狀策略組則可能已經包含自己的自動選擇邏輯。不要讓外部腳本與核心內建機制同時頻繁改寫同一個群組,否則日誌會出現互相覆蓋的選擇結果。比較穩妥的做法是:由 Mihomo 負責一般健康檢查,外部腳本只在連續故障、特定服務需要獨立出口,或需要把結果送入監控系統時介入。

相較於許多只提供單一測速按鈕、卻沒有 API 文件與錯誤觀測能力的同類工具,手動操作在節點數量增加後很快會變得繁瑣,跨平台排程與密鑰管理也常需要自行拼湊。Clash 官網 的優勢在於以 Mihomo API、策略組狀態、延遲門檻和日誌設計出一套可逐步驗證的流程,Windows、macOS、Linux 都能依相同思路調整,不必把每次故障都變成手動點選。如果你想先取得適合測試與配置的 Clash 客戶端,不妨前往下載,再按照本文的 API 安全與故障轉移步驟建立自己的自動切換架構。