订阅链接格式科普:base64 订阅、原生 JSON 与分享链接的区别和互转

拆解 base64 订阅、Xray 原生 JSON 与 vmess:// vless:// 分享链接的结构差异,说明各客户端能识别哪种格式,以及如何互相转换。

本文速览

订阅 URL 是获取入口,base64 是文本编码,分享链接通常描述一个节点,Xray 原生 JSON 则描述内核运行配置。本文适合遇到“链接能打开却导入失败”“JSON 不能添加到订阅”等问题的用户,按识别格式、选择导入入口、离线解码和检查字段四个步骤,说明哪些转换可以直接完成,哪些必须补齐配置。

一、先区分订阅地址、响应正文与节点配置

复制到剪贴板的内容,并不一定就是节点。以 https:// 开头的订阅地址指向一个资源;客户端请求这个地址后,才得到实际正文。正文可能是逐行排列的分享链接,也可能是这些行经过 base64 编码后的结果,还可能是另一种配置文档。仅凭地址后缀,不能判定它的格式。

四类内容的识别线索
内容常见外观实际作用
订阅 URLhttps:// 开头,可能带访问令牌用于获取及更新远端列表,不直接说明节点协议
base64 订阅正文长串可打印字符,末尾可能有 =通常封装多行分享链接,需要解码后识别内容
单节点分享链接vmess://、vless://、trojan:// 或 ss://描述服务器、认证及部分传输参数
Xray 原生 JSON常见顶层字段为 inbounds、outbounds、routing定义内核的监听入口、出站及流量处理规则

base64 不提供加密保护。拿到正文的人通常可以还原节点地址与认证字段;订阅 URL 中的令牌也可能具有同等访问能力。排障时不要把完整订阅地址、二维码或节点导出文本发到公开讨论区。截图应同时遮住路径、查询参数和节点认证值。

二、base64 订阅与 VMess 的编码层次

常见的传统订阅做法,是先把多个分享链接用换行符连接,再对整段 UTF-8 文本进行 base64 编码。解码一次后,应看到一行一个节点。行尾可能使用 LF 或 CRLF,导入器通常会忽略空行,但不能依赖所有版本都能处理多余空格或字节顺序标记。

  1. 外层:订阅正文整体的 base64,解码后得到多行 URI。
  2. 节点层:常见 vmess:// 格式的后半部分本身也是 base64,解码后得到节点描述 JSON。
  3. 字段层:VLESS 等 URI 的备注、路径和查询参数可能使用百分号编码,例如 %20 表示空格。

因此,一个 VMess 节点可能涉及两次 base64 解码,但两个层次的对象不同。不能看到长字符串就反复解码到“看起来像文字”为止。遇到 vless:// 后,主体通常应按 URI 解析,而不是把整个后缀继续当作 base64。

常见 VMess 分享 JSON 使用 v、ps、add、port、id、net、tls 等字段。其中 v 常见值 "2" 是这类分享格式的版本标识,不是客户端或内核版本。它也不是可以直接交给 Xray 运行的原生配置。

三、分享链接可以还原哪些字段

下面使用保留示例域名和全零 UUID 展示 VLESS URI。它只用于说明结构,不能建立实际连接。端口 443 是示例远端端口,与客户端本地监听端口不是同一概念。

vless://[email protected]:443?encryption=none&security=tls&type=tcp&sni=node.example.invalid#TLS%20example
VLESS URI 与 Xray 配置字段的对应关系
URI 部分配置位置检查重点
主机与端口settings.vnext[].address、port端口应转换为数值,不要带入备注文字
用户信息中的 UUIDsettings.vnext[].users[].id必须与服务端配置一致
encryption=noneusers[].encryption不表示传输层没有 TLS
security=tlsstreamSettings.security与 TLS、REALITY 等传输安全方式区分
snitlsSettings.serverName用于 TLS 服务名称,不应随意替换
# 后的片段客户端节点备注通常不参与认证或网络连接

转换复杂传输时,至少还要核对 flow、alpn、传输路径、HTTP Host 和相应安全参数。不同分享格式与客户端版本对参数名的约定可能不同。不能因为地址、端口和 UUID 相同,就认为两个配置等价。

转换判断:导入后先核对传输参数

将原链接与节点编辑页逐项对照,先检查传输类型、TLS 服务名称和 flow,再做连接测试;缺失这些字段时,重新编码订阅正文不能修复连接。

四、Xray 原生 JSON 不是节点列表

Xray 原生 JSON 描述的是运行环境。inbounds 决定本地接收流量的方式,outbounds 定义连接远端的方式,routing 可以把不同请求送往不同出站。下面的最小示例对应上一节的 VLESS 节点,设置本地 SOCKS 监听为 127.0.0.1:10808;所有远端参数仍为不可连接的演示值。

{
  "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": "vless",
      "settings": {
        "vnext": [
          {
            "address": "node.example.invalid",
            "port": 443,
            "users": [
              {
                "id": "00000000-0000-0000-0000-000000000000",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "tlsSettings": {
          "serverName": "node.example.invalid"
        }
      }
    }
  ]
}

这个示例没有显式配置 routing 和 dns,只展示单入口、单出站的结构。监听地址限制为回环地址,不向局域网开放;udp: true 只是允许该 SOCKS 入站处理相应请求,并不保证应用、远端和网络路径都具备可用的 UDP 通路。

转换边界:提取节点与保留运行配置

分享链接转原生 JSON
  • 解析地址、端口、认证和传输参数。
  • 补充本地入站与监听端口。
  • 按实际需求配置 DNS、日志与路由。
原生 JSON 转分享链接
  • 选择一个能够表达为 URI 的代理出站。
  • 核对当前分享格式能否承载全部传输字段。
  • 另行保留入站、路由和 DNS 配置备份。

单节点 URI 通常无法承载整份运行配置;多出站、链式连接和路由规则不能默认随节点一起迁移。

五、v2rayN、v2rayNG 与 v2flyNG 的导入选择

格式能够被解析,与所用内核能够运行该协议,是两项独立条件。v2rayN 是桌面客户端,v2rayNG 使用 Xray 内核,v2flyNG 使用 v2fly 内核。导入前应同时确认客户端入口、内核类型和所需传输能力,不要把某个客户端能保存的配置,直接视为另一个客户端也能运行。

订阅地址:用于持续维护节点列表

推荐

在 v2rayN 的「订阅分组」→「订阅分组设置」中添加地址,再执行「更新全部订阅(不通过代理)」或对应的通过代理更新操作。菜单文案随版本可能略有调整,应以实际界面为准。

适合:节点会变更,需要保留后续更新入口。

分享链接:用于导入单个节点

在 v2rayN 中可使用「服务器」→「从剪贴板导入批量 URL」,常见快捷键为 Ctrl+V。v2rayNG 的新增菜单提供「从剪贴板导入」;v2flyNG 应使用其分享链接导入入口,并确认内核支持对应协议及传输。

适合:临时测试、单节点迁移、逐项核对参数。

原生 JSON:用于保留完整运行设置

使用客户端提供的自定义配置导入入口,而不是订阅地址输入框。v2rayNG 可使用自定义配置导入功能;v2rayN 应通过自定义配置服务器入口处理。v2flyNG 需要与其 v2fly 内核兼容的配置,不能直接套用 Xray 专用字段。

适合:需要固定入站、DNS 或复杂路由,且能自行维护配置。

把订阅内容解码后再手工导入,通常只是生成节点快照,不会自动保留原订阅的更新关系。自定义 JSON 也不等同于界面管理的普通节点:系统代理开关指向的端口,必须与实际入站一致。上例只监听 SOCKS 10808,不能假定另有 HTTP 10809 可用。

六、离线解码与重新编码的具体步骤

如果只是检查编码,可在本地空白页面的浏览器开发者工具控制台中处理,不必把订阅提交到在线转换服务。下面仅使用浏览器内置 API,不发送网络请求。先用固定文本测试,确认环境支持 TextEncoder 和 TextDecoder,再在可信本地环境处理已获取的正文;不要在不熟悉的网页控制台粘贴真实订阅。

function decodeBase64Text(input) {
  const normalized = input.trim()
    .replace(/\s+/g, "")
    .replace(/-/g, "+")
    .replace(/_/g, "/");
  if (normalized.length % 4 === 1) {
    throw new Error("base64 长度无效");
  }
  const padded = normalized
    + "=".repeat((4 - normalized.length % 4) % 4);
  const bytes = Uint8Array.from(
    atob(padded),
    character => character.charCodeAt(0)
  );
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

function encodeBase64Text(text) {
  const bytes = new TextEncoder().encode(text);
  const parts = [];
  for (const byte of bytes) {
    parts.push(String.fromCharCode(byte));
  }
  return btoa(parts.join(""));
}

decodeBase64Text("5rWL6K+V"); // 测试
encodeBase64Text("测试");     // 5rWL6K+V
  1. 先识别:若正文已是逐行 URI,不需要外层解码;若开头是 JSON 对象,先检查字段结构。
  2. 只解一层:对确认属于 base64 的正文调用解码函数,检查结果是否为节点行,而不是错误页面。
  3. 保留节点原文:不要对整条 URI 反复调用百分号解码。路径中的保留字符可能因此改变含义。
  4. 按行整理:移除纯空行,保留每条分享链接内部字符;重新编码时使用换行符连接各节点。
  5. 验证导入:先用单个节点测试,再处理整个列表。只有编码错误时,重新编码才是对应修复方法。

上述函数只完成编码和解码,不会把 VMess 转成 VLESS,也不会把原生 JSON 自动变成订阅。协议转换涉及服务端是否提供相应入口,无法靠修改字符串前缀完成。同样,base64 包裹一份原生 JSON 后,它仍然不是常见的“逐行节点 URI”订阅。

七、导入失败与转换丢字段的排查

订阅地址能打开,为什么客户端说没有节点?

检查实际响应正文,而不是只看状态码。若内容是登录表单、访问限制说明或 HTML 页面,应先修复订阅访问权限。若是原生 JSON,则改用自定义配置入口,不要继续在订阅框中重复添加。

解码后还是 vmess://,是不是解码失败?

这通常说明外层订阅已经正确解开。先把整条 VMess 链接交给客户端导入。只有需要检查字段时,才单独解码它后面的节点描述,且不要把得到的分享 JSON 当成完整内核配置。

节点导入成功,为什么仍然连接不上?

进入节点编辑页核对远端端口、UUID、传输类型、TLS 服务名称及 flow,再查看内核日志。导入成功只能说明解析器接受了数据,不能证明远端可达、认证有效或本地代理已被应用使用。

转换后分流规则和 DNS 怎么不见了?

单节点分享通常只包含代理出站参数。回到原始 JSON 备份,分别迁移 routing、dns 和所需入站。不要通过增加节点备注来携带这些运行规则,客户端不会据此恢复完整配置。

通过代理更新订阅也超时,要先改格式吗?

先判断请求是否真正完成。已有可用节点时,可在 v2rayN「订阅分组」中尝试对应的通过代理更新操作;没有可用连接时,应先检查本地网络与订阅地址权限。请求超时发生在解析正文之前,改 base64 编码不能解决。

最终验收要分三步:订阅是否成功获取、节点参数是否被完整解析、流量是否进入预期出站。修改格式后先保留原始备份;对于自定义 JSON,尤其要确认监听地址和端口没有发生变化,再验证应用的代理设置。

下载v2rayN