本文重點

訂閱網址是取得設定的入口;Base64 是文字編碼,分享連結描述節點,原生 JSON 則可能包含整套核心執行設定。本文適合遇到「訂閱能開啟卻無法匯入」或需要移轉節點的使用者:先辨認回應內容,再於本機解碼,最後核對協定欄位。轉換可以移轉節點參數,但不代表 DNS、路由與更新關係也會一併保留。

先分清訂閱網址、回應本文與節點設定

格式如 https://sub.example.com/list?token=demo 的網址,只負責讓用戶端取得內容,不能光看網址就判斷回傳格式。本文中的網域、UUID 與參數皆為結構示例,不提供可用連線。實際訂閱網址中的權杖通常具有存取權限,分享網址可能因此洩漏整組節點。

傳統 V2Ray 訂閱通常會將多條分享連結逐行串接,再對整段文字進行 Base64 編碼。有些服務也會直接回傳未編碼的連結清單,或依用戶端的請求回傳不同內容。因此,瀏覽器開啟的結果不一定與用戶端更新時取得的內容相同。

訂閱網址與連結清單

建議

日常大量管理時,建議保留原訂閱網址。服務端可更新清單,用戶端則依群組取得內容;回應本文可能是 Base64,也可能是明文連結。

適合:需要持續更新節點,並分別在桌面與 Android 裝置匯入

單一節點分享連結

常見開頭為 vmess:// 或 vless://。連結主要包含節點連線參數,不等於完整的執行設定。

適合:暫時分享單一節點,或檢查特定記錄的欄位

核心原生 JSON

可包含入站、出站、DNS 與路由。檔案能否執行取決於目標核心及其設定結構,而不是副檔名是否為 JSON。

適合:明確需要自訂入站、出站與路由的設定管理者

v2rayN 與 v2rayNG 的匯入方式

兩款用戶端都能管理常見的 VMess、VLESS 分享連結及傳統連結訂閱,但「能辨識文字」不代表目標核心一定支援其中所有參數。介面名稱會隨版本改變,以下依功能入口說明,避免把訂閱網址貼到單一節點欄位。

依輸入內容選擇匯入方式
輸入內容v2rayN 桌面版v2rayNG Android 版
HTTPS 訂閱網址「訂閱群組」→「訂閱群組設定」,新增群組並填入網址,再更新該群組在「訂閱群組設定」新增網址,返回清單後選擇「更新訂閱」
明文分享連結複製完整連結,使用「從剪貼簿批次匯入 URL」等功能右上角「+」→「從剪貼簿匯入」
整段 Base64 文字優先使用訂閱更新功能解析;手動移轉時,先解碼再匯入連結清單優先使用訂閱群組;若手動匯入時無法辨識,可先解碼為分享連結
核心原生 JSON使用自訂設定相關入口,並選擇相符的核心;不可當作一般訂閱網址匯入使用自訂設定匯入功能;支援範圍取決於所用的 Xray 核心與用戶端版本

v2rayNG 使用 Xray 核心;v2flyNG 使用 V2Fly 核心。即使 JSON 語法正確,也不能據此認定兩種核心都支援其中的安全機制或設定欄位。尤其使用 VLESS、REALITY 等組合時,應先確認目標核心的支援能力,再進行格式轉換。轉換格式無法增加協定支援。

解碼 Base64 訂閱:先檢查外層,再逐行查看

第一步是確認取得的是回應本文,而不是錯誤頁面。若本文開頭是 <!DOCTYPE html>、登入提示或 API 錯誤訊息,就不是待解碼的訂閱內容。只改副檔名或反覆匯入,無法解決驗證過期或服務端回傳錯誤的問題。

  1. 將回應本文存成文字檔並保留原始檔。刪除複製時一併帶入的說明文字,不要把 URL 當成 Base64 本文。
  2. 若本文已以 vmess:// 或 vless:// 開頭,請先當作明文連結清單處理,不要再解碼整段本文。
  3. 若本文是一長串編碼字元,先進行一次外層 Base64 解碼,再依換行拆分並移除空白行。
  4. 逐行檢查協定前綴。若某行是 vmess://,後面還可能有一層 VMess 分享資訊編碼;這不代表整份訂閱需要不斷重複解碼。

以下程式碼僅用於在本機空白頁面的開發人員工具主控台處理已取得的文字,不會向訂閱網址發出請求。先執行函式定義,再以 decodeSubscription(prompt("貼上訂閱回應本文")) 呼叫。請勿在不受信任的網頁主控台處理真實憑證。

function decodeSubscription(input) {
  const raw = String(input ?? "").trim();
  if (!raw) throw new Error("本文為空");
  if (/^(vmess|vless):\/\//i.test(raw)) return raw;

  let encoded = raw.replace(/\s/g, "")
    .replace(/-/g, "+").replace(/_/g, "/");
  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {
    throw new Error("內容不符合 Base64 字元規則");
  }
  encoded = encoded.replace(/=+$/, "");
  if (encoded.length % 4 === 1) {
    throw new Error("編碼長度異常,請確認是否複製完整");
  }
  encoded += "=".repeat((4 - encoded.length % 4) % 4);
  const bytes = Uint8Array.from(atob(encoded), c => c.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

將分享連結轉成 Base64:逐行串接後編碼

若要將明文清單轉成傳統 Base64 訂閱本文,順序是「每行一條連結 → UTF-8 位元組 → Base64」。這只會產生靜態本文,不會自動建立可更新的訂閱服務。將結果存成本機檔案,也不代表用戶端已取得可存取的訂閱 URL。

const link = "vless://[email protected]:443?encryption=none&security=tls&type=tcp&sni=node.example.com#Example-TLS";

function encodeSubscription(links) {
  const text = links.map(item => item.trim()).filter(Boolean).join("\n");
  const bytes = new TextEncoder().encode(text);
  let binary = "";
  for (const byte of bytes) binary += String.fromCharCode(byte);
  return btoa(binary);
}

const encoded = encodeSubscription([link]);
console.log(encoded);
console.log(decodeSubscription(encoded) === link);

中文備註也會納入編碼內容,因此不宜直接對含中文的字串呼叫 btoa。先使用 TextEncoder 轉成 UTF-8 位元組,可避免字元超出範圍。最後一行的往返比較結果應為 true;這只能確認編碼過程未改變示例文字,無法驗證節點是否可連線。

443
示例遠端 TLS 連接埠
10808
後文假設的本機 SOCKS 連接埠
3 → 4
Base64 每 3 個位元組編碼為 4 個字元

以上數字是協定編碼規則與設定示例,不是測速結果,也不是所有用戶端版本的預設值。Base64 並非壓縮;忽略尾端填充時,編碼後長度約為原始位元組數的四分之三的倒數,也就是增加約三分之一。

分享連結與原生 JSON:欄位對應不等於完整移轉

以剛才的 VLESS 連結為例,主機與連接埠會填入出站伺服器設定,UUID 會填入使用者設定,security=tls 對應 TLS,sni 對應 TLS 的伺服器名稱。以下是 Xray 格式的單一出站物件,不是可直接執行的完整設定檔,必須放入完整設定的 outbounds 陣列。

{
  "tag": "proxy",
  "protocol": "vless",
  "settings": {
    "vnext": [
      {
        "address": "node.example.com",
        "port": 443,
        "users": [
          {
            "id": "11111111-1111-4111-8111-111111111111",
            "encryption": "none"
          }
        ]
      }
    ]
  },
  "streamSettings": {
    "network": "tcp",
    "security": "tls",
    "tlsSettings": {
      "serverName": "node.example.com"
    }
  }
}

若要組成可執行的設定,還須明確設定本機入站、出站選擇及必要的路由。例如,假設本機 SOCKS 監聽位址為 127.0.0.1:10808,使用該代理的應用程式也必須填入這個位址與連接埠。遠端的 443 不能填成本機代理連接埠;兩者分別位於連線的兩端。

轉換時需要逐項核對的欄位
分享連結內容原生設定中的對應位置容易遺漏的事項
主機、連接埠、UUIDsettings.vnext 中的伺服器與使用者連接埠須為數字,UUID 前後不可有空格
type、傳輸參數streamSettingsWebSocket 的路徑與 Host 不可只移轉其中一項
security、sniTLS 或相應的安全設定伺服器位址與 SNI 可以不同,不可擅自設為相同
flow 與 REALITY 參數使用者欄位及相應的安全設定須保留服務端要求的 flow、公鑰、short ID 等資訊
# 後的備註用戶端顯示名稱或自行管理的標記備註不是驗證資訊,也不會自動成為路由規則

VMess 常見的分享格式,是在 vmess:// 後接上以 Base64 編碼的分享物件。物件中的 add、port、id、net、path 等欄位屬於分享格式約定,並非核心原生設定的頂層欄位。將解碼後的物件直接存成執行設定,通常會因結構不符而失敗。

分開處理兩種移轉目標:節點參數與完整設定

只移轉節點
  • 建議先從用戶端匯出分享連結,再匯入目標用戶端。
  • 核對 UUID、傳輸方式、TLS、SNI 與路徑等連線欄位。
  • 在目標用戶端重新設定系統代理、DNS 與路由。
保留完整執行設定
  • 保留 JSON 中的入站、出站標籤與路由參照關係。
  • 確認目標核心支援所有欄位,並檢查本機監聽連接埠是否衝突。
  • 透過自訂設定匯入功能匯入,不要硬轉成單一節點連結。

原生 JSON 轉回分享連結時,通常只能擷取部分出站設定;多出站連線、DNS 與路由規則沒有通用的單一連結格式可無損表達。

轉換後驗證:分別確認更新成功與連線成功

訂閱更新成功只代表用戶端取得並解析部分或全部內容,不代表所有節點都能使用。建議保留原訂閱群組,將轉換結果匯入獨立的測試群組;先驗證一個節點,再批次處理。手動匯出的靜態連結也不會保留原訂閱的更新關係。

  1. 核對記錄:比較轉換前後的節點數量,檢查是否有空白行、重複記錄或不支援的協定遭到略過。
  2. 核對欄位:開啟節點編輯介面,檢查位址、連接埠、UUID、傳輸方式、路徑、SNI 與安全機制;不要只確認備註是否相同。
  3. 核對執行狀況:選取測試節點並查看核心記錄。設定解析錯誤、驗證失敗與連線逾時應分別排查。
  4. 核對應用程式連線:確認系統代理或應用程式代理指向實際的本機監聽連接埠,再檢查路由是否將測試請求送往預期的出站。

解碼後還是一長串字元,還要再解碼一次嗎?

先確認是否已出現 vmess://。若有,只需依 VMess 分享格式處理該行後半段,不要繼續解碼整份清單。若沒有協定前綴,也沒有可辨識的 JSON 結構,請先確認原始回應是否完整,以及服務端實際回傳的格式。

JSON 可以開啟,為什麼用戶端仍顯示匯入失敗?

檢查頂層欄位。只有 add、id 等欄位的物件,可能是 VMess 分享資訊;含有 inbounds、outbounds 的物件,才可能是核心執行設定。後者應透過自訂設定匯入功能處理,並進一步核對目標核心支援的欄位。

同一份訂閱在桌面版能更新,Android 卻匯入空白?

先在兩端核對訂閱網址是否完整,再檢查回應內容是否會依用戶端請求而不同。若回應有效,請比較協定與傳輸方式的支援情形;可透過「+」→「從剪貼簿匯入」單獨測試一條明文連結,找出問題記錄,不必反覆轉換整份訂閱。

可以將整份 JSON 轉成一條 VLESS 連結嗎?

只有在目標是可用 VLESS 表達的單一出站時,才適合擷取相應欄位產生連結。先找出 protocol 為 vless 的出站,並保留其連線參數;入站、DNS、路由與其他出站仍須另外保存,無法保證一次轉換就能完整保留。