· 订阅格式 · 约 12 分钟

V2Ray 订阅链接格式解析:Base64、原生 JSON 与 vless:// 分享链接互相转换

讲清 Base64 订阅、原生 JSON 配置与 vmess/vless 分享链接三种格式的结构差异,以及在 v2rayN、v2rayNG 中导入和相互转换的方法。

本文速览

先区分订阅地址、订阅响应和节点分享链接,再用一组 VLESS + WebSocket + TLS 示例对照 URI 与 Xray JSON 字段。本文适合遇到“订阅能打开但无法导入”“Base64 解码后仍不是配置”或需要迁移节点的用户;读完可以判断应使用哪种导入入口,并识别转换时会丢失的路由、DNS 和本地监听设置。

订阅地址、Base64 与 JSON 的层次区别

订阅地址通常是一个 HTTPS URL,客户端访问它后才获得节点数据。URL 本身不是 Base64,也不是节点配置;真正需要识别的是服务器返回的响应正文。同一个订阅地址可能根据请求参数或客户端标识返回不同内容,因此不能只凭地址后缀判断格式。

订阅地址响应正文格式识别节点解析内核运行
内容形式识别线索适用入口与边界
订阅地址https:// 开头,可能含访问令牌添加到订阅设置,保留后续更新能力
Base64 订阅正文解码后常为按行排列的分享链接一般由客户端订阅更新功能解析;不是完整运行配置
单节点分享链接vless:// 或常见的 vmess:// 开头适合从剪贴板导入节点;通常不携带本地路由
内核原生 JSON具有 inbounds、outbounds 等字段使用匹配内核的自定义配置入口,字段受内核支持范围约束

Base64 只是字节编码,不是加密。持有订阅正文的人通常可以还原服务器地址和身份信息。JSON 也只是数据语法:一段以花括号开头的文本,可能是节点描述、接口错误消息,或完整内核配置。必须检查内部字段,不能把“合法 JSON”等同于“可直接运行”。

Base64 订阅解码与重新编码

常见的 Base64 订阅先将多条分享链接以换行符连接,再把整段 UTF-8 文本编码。解码后如果看到多行 vless:// 或 vmess://,外层订阅已经还原;不需要再对每条 VLESS 链接做 Base64 解码。部分服务直接返回明文链接列表,这种情况应跳过外层解码。

  1. 先确认拿到的是响应正文,而不是浏览器登录页、访问限制提示或带状态码的错误信息。
  2. 对疑似 Base64 正文移除空格与换行,兼容 URL 安全变体中的 -、_,再补齐末尾填充。
  3. 将解码后的字节按 UTF-8 读取,逐行检查协议前缀,并保留每条链接内部的参数。
  4. 重新编码前确认客户端确实需要 Base64 列表;本地编码得到的是静态文本,并不会生成可自动更新的 HTTPS 订阅服务。

下面是可在本机浏览器开发者工具中使用的纯 JavaScript 函数。它通过字节数组处理中文备注,避免直接用 btoa 编码中文产生错误。函数只转换传入文本,不发起网络请求;输入应来自你信任的内容。

function decodeSubscription(source) {
  const compact = source.trim().replace(/\s+/g, "")
    .replace(/-/g, "+").replace(/_/g, "/");
  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(compact)) {
    throw new Error("输入不是有效的 Base64 字符序列");
  }
  const padded = compact + "=".repeat((4 - compact.length % 4) % 4);
  const bytes = Uint8Array.from(atob(padded), ch => ch.charCodeAt(0));
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}

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

const sampleText = "示例节点";
console.log(decodeSubscription(encodeSubscription(sampleText)));

解码函数报错时,不要反复套用多层转换。先检查正文是否被截断、是否带有引号或网页标签,再确认它是不是明文列表。即使成功解码,也仍需由客户端验证每条链接的协议、必填字段和传输设置。

vless:// 与 vmess:// 的字段结构

VLESS 分享链接通常采用 URI 结构:用户信息位置放 UUID,主机与端口描述服务器,查询参数描述传输和安全层,井号后面保存节点备注。下例使用文档示例域名与演示 UUID,只用于字段对照,不代表可连接的服务。

vless://[email protected]:443?encryption=none&security=tls&type=ws&host=example.net&path=%2Fws&sni=example.net#WS-TLS-demo
443
本例服务端 TLS 端口
10808
下文配置的本地 SOCKS 端口

path=%2Fws 解码后是 /ws。查询参数里的路径、备注和特殊字符应使用百分号编码;不要把整条 URI 一次性编码,也不要对完整 URI 先解码再手动拆分,否则路径中的 & 等字符可能被误认成参数分隔符。IPv6 地址位于主机位置时还需要使用方括号。

VLESS 分享链接

身份
UUID 位于 @ 之前
传输
type=ws
安全层
security=tls
路径
path=%2Fws

本例使用 WebSocket 与 TLS,不应额外添加 Vision flow。

常见 VMess 分享格式

外层
vmess:// 后接 Base64
服务器
JSON 中的 add、port
身份
JSON 中的 id
传输
JSON 中的 net、path

这是常见客户端分享约定,不是可直接交给内核运行的 JSON。

常见 VMess 分享 JSON 中的 v 表示分享格式版本,不是 VMess 协议版本;ps 通常是备注。它与内核出站中的 settings.vnext 结构不同。VMess 的分享约定还存在变体,迁移时应优先使用两端客户端的导入、导出功能,而不是假设所有 vmess:// 内容都有完全相同的内部结构。

从 VLESS 链接生成 Xray 原生 JSON

将分享链接转成完整 JSON,需要补上链接中没有的本地入站与出口标签。下面配置与前面的 VLESS 示例对应,使用 Xray 配置结构;本地只监听 127.0.0.1:10808。实际使用前须替换为已获授权的真实服务器参数,示例域名本身不能提供代理服务。

{
  "log": {
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "example.net",
            "port": 443,
            "users": [
              {
                "id": "9f2a54d1-8bc6-4d71-a903-0be458e623fd",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "serverName": "example.net"
        },
        "wsSettings": {
          "path": "/ws",
          "headers": {
            "Host": "example.net"
          }
        }
      }
    }
  ]
}

在 v2rayN 与 v2rayNG 中选择导入入口

先区分“保留订阅关系”和“导入单个节点”。把订阅解码后逐条导入虽然能生成节点,但通常会失去订阅来源及自动更新关系。若希望以后继续更新服务器列表,应保存原始订阅 URL,而不是只保存当前导出的分享链接。

v2rayN:订阅、剪贴板与自定义配置分开处理

  1. 订阅 URL:打开「订阅分组」→「订阅分组设置」,新增分组,填写备注与 URL,保存后使用「订阅分组」中的更新订阅功能。更新完成后检查新增节点,而不是把 URL 当成单节点地址填写。
  2. 分享链接:复制完整的 vless:// 或 vmess:// 文本,再使用「服务器」→「从剪贴板导入批量 URL」。导入后编辑节点,核对地址、端口、TLS、SNI 与传输路径。
  3. 完整 JSON:使用「服务器」→「添加自定义配置服务器」一类的自定义配置入口,选择与文件匹配的内核,再按界面要求选择配置文件。不要将整份 JSON 粘贴到订阅 URL 输入框。

v2rayNG:先建立订阅分组,再执行更新

  1. 在主界面菜单进入「订阅分组设置」,通过新增按钮填写订阅名称与地址,保存后返回主界面执行「更新订阅」。
  2. 对单条分享链接,复制完整文本,再点主界面「+」→「从剪贴板导入」。确认生成的配置类型与来源一致后再连接。
  3. 对 Xray 原生 JSON,使用「+」菜单里的自定义配置导入入口,按所用版本选择文件或剪贴板方式。不要把常见 VMess 分享 JSON 当成完整自定义配置导入。

不同发行版本的菜单文案可能略有调整,应按“订阅分组”“剪贴板链接”“自定义配置”这三个入口含义寻找。使用 v2flyNG 时,还要单独确认订阅中协议与传输的兼容性;v2rayNG 能识别某条 Xray 节点,不代表另一内核客户端也能运行同样配置。

JSON 反向导出与转换时的信息损失

“互相转换”不意味着三种格式总能完整往返。单节点链接主要描述远端连接,而完整 JSON 可能包含多个入站、多个出站、DNS、路由、策略和日志。把 JSON 导成一条 VLESS 链接,本质上是在选择其中一个出站并提取它的连接参数,其余本地行为通常无法放进链接。

转换方向通常可以保留需要额外处理
链接列表与 Base64 互转原始链接文本与顺序字符编码、换行与 URL 安全变体
VLESS 链接转 JSON地址、身份、常见传输与安全参数补充入站、出口标签及本地路由
JSON 出站转分享链接目标客户端支持的单节点字段选择出站,处理扩展字段,另存 DNS 与分流规则
VMess 转 VLESS仅能参考共用的地址与传输信息服务端必须实际提供 VLESS,不能靠改前缀切换协议

迁移时优先在源客户端选择节点并使用导出分享链接功能,再在目标客户端检查字段。如果手头只有多出站 JSON,先根据 outbounds 中的 tag 与 protocol 确定目标,不能把直连或阻断出站误当成服务器。涉及扩展参数时,应保留原 JSON 备份,并在目标端查看实际生成的配置。

订阅解码与导入常见问题

订阅地址在浏览器能打开,为什么客户端更新失败?

先看返回内容是否真的是节点列表,而不是登录网页或接口错误 JSON。再核对完整 URL 是否遗漏令牌与查询参数。若当前网络无法直接访问该地址,可在已有可用节点的前提下选择通过代理更新;不要用同一个尚未导入的节点作为更新所需的唯一网络出口。

Base64 解码成功,却提示没有可导入的服务器?

检查解码结果每一行的协议前缀。外层 Base64 成功只证明编码可还原,不证明内容受客户端支持。若得到的是 JSON,继续判断它是分享字段对象还是完整配置;若是 HTML,就回到订阅请求本身排查,不要继续编码。

分享链接能导入,但连接仍然超时怎么办?

打开节点编辑界面,对照来源检查端口、传输路径、TLS 和 SNI。本文示例的远端端口是 443,本地 10808 只是 SOCKS 监听端口,不能互换。再查看核心日志,区分域名解析、连接超时和 TLS 握手错误;“导入成功”仅说明解析器接受了字段。

为什么转换后国内直连规则消失了?

节点分享链接一般不承载整套本地路由。请在目标客户端单独恢复路由设置;若使用自定义 JSON,检查 routing.rules 与出口标签是否对应。需要设置 domainStrategy 时,应放在 routing 层级,而不是塞进单条规则。

最后验证时,每次只改变一个层次:先保证内容格式正确,再确认字段完整,最后检查网络与内核运行。这样可以把“订阅获取失败”“链接解析失败”和“节点连接失败”分开处理,避免在编码工具与代理设置之间反复试错。

客户端下载v2rayN / v2rayNG