V2Ray 订阅格式对照:Base64 订阅、原生 JSON 与 vmess:// 分享链接如何互转

拆解三种常见订阅与节点格式的结构差异,讲清解码 Base64、拆分享链接、转成原生 JSON 配置的步骤,以及各客户端能直接识别哪种格式。

本文速览

Base64 是编码,订阅是节点集合的获取方式,原生 JSON 是内核运行配置,三者不是同一层级。本文适合遇到“订阅能打开却无法导入”“解码后仍是一串字符”或“分享链接不能当配置文件使用”的读者。按外层订阅、单条链接、内核字段逐层检查,可判断该解码、导入还是补齐配置。

先分清三种格式:订阅地址不是节点配置

结论:先看拿到的内容,再选导入入口。一个以 https:// 开头的订阅地址只是获取入口;它的响应正文才决定客户端收到的是 Base64 节点列表、明文分享链接,还是其他结构。把地址本身做 Base64 解码,不会得到服务器配置。

订阅地址与节点列表

推荐

常见响应是多条分享链接按行排列,再整体进行 Base64 编码。客户端保存订阅地址,更新时重新获取节点;这适合持续维护节点集合,但不是所有服务都使用这种响应格式。

适合:服务方提供有效订阅地址,需要持续更新节点。

vmess:// 分享链接

本文讨论常见的 v2 分享格式:前缀后面是 Base64 编码的节点 JSON。它主要描述一个 VMess 出站所需的信息,不包含完整的本地监听、DNS 与路由策略。

适合:单节点迁移、剪贴板导入和二维码传递。

内核原生 JSON

通常包含 inbounds、outbounds,并可配置 dns 与 routing。结构和支持字段受内核及版本约束,不能仅凭文件扩展名判断兼容。

适合:自定义入站、路由规则及明确指定内核的配置管理。

Base64 不负责保密。订阅地址中的访问令牌、节点 UUID 和分享二维码都可能提供连接权限。排查时使用本地编辑器,不把真实内容粘贴到在线解码站;向他人提供日志前,也要移除这些身份信息。

Base64 订阅解码:外层列表与内层节点分别处理

常见的两层结构是:外层 Base64 解码得到若干条 vmess:// 链接;取其中一条,移除前缀后再次解码,才得到节点 JSON。不能对所有输入固定解码两次。若订阅正文已经以分享链接开头,外层就不需要解码。

  1. 取得响应正文

    用本地工具查看订阅返回内容。若看到登录页、验证码或错误页,先处理访问问题;HTML 页面不是节点列表,即使请求返回成功也不代表订阅可用。

  2. 识别外层

    正文直接出现 vmess:// 或 vless:// 时,按行读取。若是连续编码文本,再尝试 Base64 解码;以 { 或 [ 开头的内容先按 JSON 检查。

  3. 分离节点行

    把解码结果按换行拆开,清除每行首尾空白并过滤空行。不要把多条链接拼成一条,也不要破坏链接内部的字符。

  4. 解析单条链接

    对本文所述的 VMess v2 格式,去掉 vmess:// 后解码并解析 JSON。若内容不是该结构,应确认分享格式来源,而不是强行套用字段。

以下函数用于本地浏览器控制台,兼容标准 Base64 与常见的 URL 安全字符,补齐省略的尾部填充,并按 UTF-8 还原中文备注。先阅读代码再执行。函数不会发送网络请求,也不会自动读取剪贴板。

function decodeBase64Utf8(input) {
  let value = input.trim().replace(/\s+/g, "");
  value = value.replace(/-/g, "+").replace(/_/g, "/");

  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
    throw new Error("输入含有非 Base64 字符");
  }

  value = value.replace(/=+$/, "");
  if (value.length % 4 === 1) {
    throw new Error("Base64 长度不完整");
  }

  value += "=".repeat((4 - value.length % 4) % 4);
  const binary = atob(value);
  const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

function readSubscription(body) {
  const text = body.trim();
  const decoded = /^(vmess|vless):\/\//i.test(text)
    ? text
    : decodeBase64Utf8(text);

  return decoded.split(/\r?\n/)
    .map(line => line.trim())
    .filter(Boolean);
}

function readVmess(link) {
  const value = link.trim();
  if (!value.startsWith("vmess://")) {
    throw new Error("需要 vmess:// 链接");
  }
  return JSON.parse(decodeBase64Utf8(value.slice(8)));
}

readSubscription 只演示“明文链接列表或其 Base64 编码”这一种订阅约定,不是通用订阅解析器。遇到其他结构时应停止,检查服务方给出的格式说明。Base64 解码成功也只说明编码可读,不代表节点有效或账号仍有权限。

拆开 vmess://:分享字段怎样映射到原生配置

下面是一个用于结构演示的 VMess v2 节点对象。example.com 是文档示例域名,UUID 也仅用于示例,不能据此连接代理服务。字段 v 的值 "2" 表示分享格式版本,不是客户端或内核版本。

{
  "v": "2",
  "ps": "文档示例",
  "add": "example.com",
  "port": "443",
  "id": "00000000-0000-4000-8000-000000000001",
  "aid": "0",
  "scy": "auto",
  "net": "ws",
  "type": "none",
  "host": "example.com",
  "path": "/ws",
  "tls": "tls",
  "sni": "example.com"
}
分享字段原生出站位置转换注意点
add、portsettings.vnext[].address、port地址为字符串;原生端口使用数字。
id、aidsettings.vnext[].users[].id、alterId本例 aid 为 0,对应现代 VMess AEAD 用法。
scysettings.vnext[].users[].security这是 VMess 用户加密设置,不是 TLS 开关。
netstreamSettings.network本例为 ws;不同传输不能只改一个字段。
host、pathwsSettings.headers.Host、wsSettings.path这里按 WebSocket 解释,路径中的查询参数也需保留。
tls、snistreamSettings.security、tlsSettings.serverNameTLS 服务器名与 WebSocket Host 分属不同层。
ps、v备注与分享格式信息不是内核连接所需字段,不应原样塞进出站设置。

转换判断:先保留传输语义,再调整字段类型

逐项核对地址、端口、UUID、传输、TLS、SNI、Host 与路径。不要把分享字段 type: "none" 当作关闭 TLS 的依据,也不要用地址字段自动覆盖服务方明确提供的 SNI。

VMess 与 VLESS 是不同协议。vless:// 常见结构是带用户信息、主机、端口和查询参数的 URI,不能照搬“移除前缀后 Base64 解码 JSON”的流程。把链接前缀从 VMess 改成 VLESS,也不会完成协议转换;服务端必须支持对应协议与身份配置。

转成原生 JSON:节点之外还要补齐入站

原生配置不是把解码后的节点 JSON 换一个文件名。下面给出 Xray 常见 VMess、WebSocket、TLS 结构的完整示例:本地提供 SOCKS 入站,出站使用上面的演示节点。具体字段仍应以实际安装的内核版本为准;不能把它视为所有 V2Fly 版本都接受的统一配置。

10808
本例本地 SOCKS 监听端口
443
本例远端 TLS 连接端口
0
本例 VMess alterId 数值
{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "local-socks",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "example.com",
            "port": 443,
            "users": [
              {
                "id": "00000000-0000-4000-8000-000000000001",
                "alterId": 0,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "serverName": "example.com",
          "allowInsecure": false
        },
        "wsSettings": {
          "path": "/ws",
          "headers": {
            "Host": "example.com"
          }
        }
      }
    }
  ]
}

这个示例没有添加分流规则,默认流量交给首个出站。它也不会自动设置系统代理;应用需要明确使用 127.0.0.1:10808 的 SOCKS 服务。127.0.0.1 限制监听于本机,不应为了排错直接改成面向所有网卡的地址。

反向转换:分享链接只能带走部分配置

由单个 VMess 出站生成分享链接,需要先从原生配置提取服务器、用户及传输字段,组装为前文的 v2 分享对象,再按 UTF-8 编码成 Base64,最后加上 vmess:// 前缀。不能把整个原生配置直接编码后加此前缀,那样得到的结构不符合常见节点导入约定。

function encodeBase64Utf8(text) {
  const bytes = new TextEncoder().encode(text);
  let binary = "";
  for (const byte of bytes) {
    binary += String.fromCharCode(byte);
  }
  return btoa(binary);
}

function createVmessLink(share) {
  return "vmess://" + encodeBase64Utf8(JSON.stringify(share));
}

function createBase64Subscription(links) {
  return encodeBase64Utf8(links.join("\n"));
}

createVmessLink 接收的是已按字段表整理好的分享对象,不负责自动提取复杂配置,也不验证节点参数。createBase64Subscription 接收分享链接数组,生成常见订阅正文;它并不会创建一个可更新的订阅地址,后者还需要由受控服务提供响应。

迁移判断:节点用链接,策略用备份

仅迁移服务器连接信息时使用分享链接;需要保留路由、DNS 与本地监听设置时使用经过检查的配置备份。转换后逐项对照关键字段,不以“导入成功”作为无损迁移的证明。

客户端导入:订阅、剪贴板与自定义配置分开使用

客户端能识别某种外层格式,不等于其内核支持里面的所有协议与传输。v2rayN 是桌面客户端;v2rayNG 使用 Xray 内核;v2flyNG 使用 V2Fly 内核。先匹配连接参数与内核能力,再选择导入入口。以下菜单以常见中文界面为参照,不同发布版本可能调整名称和位置。

输入内容v2rayN安卓客户端
订阅地址「订阅分组」→「订阅分组设置」,添加地址后更新分组。v2rayNG 在侧边栏「订阅分组设置」添加,再用主界面菜单「更新订阅」。v2flyNG 按当前版本订阅入口操作。
单条分享链接复制完整链接,使用「服务器」→「从剪贴板导入批量 URL」。v2rayNG 在主界面右上角「+」→「从剪贴板导入」。v2flyNG 使用其分享链接导入入口。
原生 JSON 文件使用「服务器」菜单中的「添加自定义配置服务器」,并核对使用的内核。使用当前版本的自定义配置导入功能;不要粘贴到订阅地址栏,跨内核迁移先检查字段。

v2rayN 常见订阅更新操作位于「订阅分组」→「更新当前订阅(不通过代理)」。这一项控制获取订阅时是否经过代理,不会把节点的连接方式改成直连。若订阅站点必须经代理访问,应选择对应的通过代理更新方式,并先确认现有代理链路可用。

  1. 更新失败先看响应。地址过期、访问令牌失效或返回网页时,不应继续做节点格式转换。先检查更新日志与订阅权限。
  2. 导入失败先看结构。检查是否多复制了引号、缺少前缀,或把完整 JSON 错当成分享链接。中文备注乱码时检查 UTF-8 编解码。
  3. 连接失败再看参数。节点已出现在列表却无法连接,应核对 UUID、端口、WebSocket 路径、Host、TLS 与 SNI,而不是反复重做 Base64 编码。
  4. 手工修改单独保存。订阅更新可能重建节点条目。临时修改的节点宜复制到独立分组,并记录与订阅原值的差异。

常见问题:解码成功为什么仍然不能使用

解码后还是 vmess://,是否说明解码失败?

不是。外层订阅装的是分享链接列表,看到 vmess:// 通常说明已取得节点行。若要查看节点 JSON,再对单条链接的前缀后内容解码;若只是导入客户端,通常可以直接使用整条分享链接。

任何 JSON 都可以作为 V2Ray 原生配置吗?

不可以。VMess 分享对象、客户端设置备份和内核配置都可能采用 JSON,但字段语义不同。先检查是否具有该内核要求的入站、出站结构,再检查协议与传输字段。JSON 语法正确只代表文本能被解析。

把本地节点列表编码后,就有可自动更新的订阅了吗?

只有订阅正文,没有订阅服务。自动更新还需要一个稳定、受访问控制的获取地址。把正文保存到本地不会让其他设备自动收到变更;只传递一次节点时,分享链接更直接。

客户端导入成功,是否意味着连接参数完整?

不一定。解析器可能接受基础字段,却忽略未支持的扩展参数。导入后应打开节点编辑界面,对照传输类型、路径、Host 与 TLS 服务器名,再进行实际连接测试。二维码也只是文本载体,不会补齐缺失参数。

下载v2rayN查看平台与安装选项