订阅地址负责获取内容,Base64 负责文本编码,分享链接描述单个节点,原生 JSON 描述内核配置。本文适合遇到“订阅为空”“JSON 无法导入”或需要迁移节点的用户:先识别响应格式,再在本地解码,最后核对协议、传输与 TLS 字段。转换只改变表达方式,不会补出缺失的服务端参数,也不保证不同内核之间的功能等价。
一、订阅地址、分享链接与原生 JSON 的区别
“V2Ray 订阅”不是一种统一的文件扩展名。客户端访问一个 HTTPS 地址后,可能得到 Base64 文本、逐行分享链接、JSON,也可能得到登录页面。判断格式要看实际响应正文,不能只凭网址是否以 .txt 或 .json 结尾。
客户端可识别的订阅地址
推荐由 v2rayN、v2rayNG 或 v2flyNG 拉取节点列表。前提是服务商提供的响应格式与当前客户端兼容;更新时仍可保留分组关系,不必每次手工复制节点。
适合:日常更新、多设备分别维护订阅分组
逐行分享链接
每行描述一个节点,常见前缀为 vmess://、vless://。适合单节点排错;批量导入后通常只是一次快照,不会自动继承原订阅更新关系。
适合:离线迁移、核对某个节点的字段
内核原生 JSON
可能同时包含入站、出站、DNS 与路由规则。它不是通用节点列表,通常需要使用客户端的自定义配置入口,并匹配所选内核的配置结构。
适合:保留明确的 DNS、路由和多出站设计
客户端与内核也要分开看:v2rayN 是桌面客户端;v2rayNG 使用 Xray 内核,v2flyNG 使用 V2Fly 内核。能导入某种链接,只代表客户端识别了文本,不代表当前内核支持链接声明的全部能力。尤其涉及 REALITY 或特定流控时,应核对内核,而不是反复做 Base64 编解码。
二、先识别订阅响应,再决定是否解码
在受信任的本地工具中查看响应时,先去掉开头的空白,观察第一段内容。订阅地址里的令牌通常具有账户访问意义,不要把完整网址、响应正文或二维码发给在线转换站点。浏览器若显示验证码、登录表单或错误页面,应先解决访问问题。
| 看到的内容 | 可能的格式 | 下一步 |
|---|---|---|
vmess:// 或 vless:// | 明文分享链接列表 | 按行导入,不要再对整个正文解码 |
| 大段字母、数字及少量符号 | 可能是 Base64 编码列表 | 本地解码一次,再观察是否出现协议前缀 |
{ 或 [ | 可能是 JSON | 先解析结构,区分接口响应、节点对象与完整配置 |
<!DOCTYPE html> 或 <html | 网页或访问拦截响应 | 检查地址、登录状态与订阅有效期 |
HTTP 状态码 200 只说明请求得到正常响应,不保证正文是节点。即使正文是合法 JSON,里面也可能只有错误码与提示信息。先判断内容,再选择导入入口,比不断切换代理或修改端口更有效。
三、Base64 订阅怎样还原成逐行分享链接
常见的传统订阅生成流程是:把多个分享链接用换行连接,再对整段 UTF-8 文本做 Base64 编码。解码时反向执行即可。需要留意标准 Base64 的 +、/ 与 URL 安全变体的 -、_,以及末尾可能省略的 = 填充。
下面是可供本地检查的原生 JavaScript 函数。代码只处理传入字符串,不发起网络请求。可在自行创建的离线 HTML 页面中运行;不要把真实订阅粘贴到不可信网页的控制台。UTF-8 解码很重要,否则带中文的节点名称可能乱码。
function base64ToText(source) {
const normalized = source
.replace(/\s+/g, "")
.replace(/-/g, "+")
.replace(/_/g, "/");
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(normalized)) {
throw new Error("内容不符合 Base64 字符规则");
}
const body = normalized.replace(/=+$/, "");
if (body.length % 4 === 1) {
throw new Error("Base64 长度异常,检查是否复制完整");
}
const padded = body + "=".repeat((4 - body.length % 4) % 4);
const bytes = Uint8Array.from(atob(padded), ch => ch.charCodeAt(0));
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
}
function textToBase64(text) {
const bytes = new TextEncoder().encode(text);
const binary = Array.from(bytes, byte => String.fromCharCode(byte)).join("");
return btoa(binary);
}
// 本地自检,结果为 true。
console.log(base64ToText(textToBase64("订阅格式测试")) === "订阅格式测试");
- 将订阅响应正文传给
base64ToText,不是把 HTTPS 订阅地址传进去。 - 用换行拆分解码结果,去除空行与行首、行尾空白;保留每个链接内部的完整字符。
- 检查每一行的协议前缀,先选一个节点测试导入,再批量处理。
- 需要重新生成传统 Base64 列表时,用
textToBase64(links.join("\n"))编码逐行链接文本;这不会自动生成可访问的订阅网址。
外层列表解码一次后,vmess:// 后面仍可能是一段 Base64,这是单节点自身的编码结构,不是解码失败。不要对整个结果机械地反复解码;应先按协议分支处理。
四、VMess 与 VLESS 分享链接怎样对应 JSON 字段
常见 VMess 分享格式是 vmess:// 加 Base64 编码的节点 JSON,常见键包括 add、port、id、net、host、path 与 tls。它是分享格式,不是可直接交给内核的完整配置;其中 v 表示分享格式版本,不是内核版本。
VLESS 分享链接通常把用户标识、地址、端口放在 URI 主体,把传输参数放在查询串。下面使用保留示例域名和演示 UUID,仅用于展示字段对应,不能作为实际节点连接。
vless://[email protected]:443?encryption=none&security=tls&type=tcp&sni=edge.example.com#TLS-demo
| 分享信息 | 常见原生配置位置 | 检查重点 |
|---|---|---|
| 地址与端口 | settings.vnext[].address / port | 远端端口不是本地监听端口 |
| 用户 UUID | settings.vnext[].users[].id | 完整保留,不把备注当作用户标识 |
type=tcp | streamSettings.network | 采用当前内核支持的传输名称 |
security=tls | streamSettings.security | 与协议认证、传输类型分别核对 |
sni | tlsSettings.serverName | 与服务端证书及配置要求匹配 |
WebSocket 的 host / path | wsSettings.headers.Host / path | 不能直接用 SNI 替代 Host |
上述 VLESS 示例可对应为下面的 Xray 出站片段。它没有入站、DNS 与路由,不是完整可运行配置。复制到完整配置时应放入合适的 outbounds 数组位置,并按当前内核文档核对字段。
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "node.example.com",
"port": 443,
"users": [
{
"id": "00000000-0000-4000-8000-000000000001",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "edge.example.com",
"allowInsecure": false
}
}
}
encryption=none不等于关闭 TLS:前者属于 VLESS 用户参数,后者由传输安全层决定。- 不要凭空添加
flow。流控值要与服务端及传输组合匹配,不是所有 VLESS 节点都应填写。 - 生成 URI 查询参数时逐项使用
encodeURIComponent;解析时可使用URL与URLSearchParams,避免对已经解码的值再次解码。 - IPv6 地址在 URI 中需要方括号;节点名称中的空格、中文与
#也应按 URI 规则编码。
五、原生 JSON 为什么不能总是无损转回订阅
单个分享链接主要表达一个远端连接。完整原生 JSON 还可能包含多个出站、规则匹配、DNS 服务器、流量嗅探及本地监听。即使能从某个出站提取出一条 VLESS 链接,也不能靠这条链接恢复全部路由策略。因此“JSON 转订阅”必须先说明是提取节点,还是保留整个运行环境。
转换方案:区分节点迁移与完整配置迁移
只迁移节点
- 从
outbounds找到实际代理出站,而不是直连或阻断出站。 - 提取协议、地址、端口、认证、传输和 TLS 参数。
- 生成当前客户端能识别的分享链接,逐个试导入。
- 在目标客户端单独配置 DNS、系统代理与分流规则。
保留完整配置
- 备份原 JSON,记录对应内核与实际版本。
- 检查文件路径、监听地址和端口占用。
- 使用客户端提供的自定义配置入口,不当作普通订阅导入。
- 启动后检查日志,并确认 DNS 与路由是否按预期执行。
结论:分享链接便于交换节点;原生 JSON 适合保留配置结构。外层重新编码不会弥补两者的信息差。
同样,Xray 与 V2Fly 的 JSON 也不是只改文件名就能通用。特定协议扩展、传输字段与 DNS 选项存在差异。把不支持的字段删掉,可能让配置通过解析,却改变连接行为;应先确认服务端要求,再决定是否迁移。
六、在 v2rayN 与安卓客户端中选择正确入口
界面文字会随版本变化,下面按常见中文菜单说明操作目的;若本机名称不同,找“订阅分组”“剪贴板导入”或“自定义配置”对应功能。不要把订阅网址粘贴到只接受单节点分享链接的编辑框,也不要把一整份 JSON 填进服务器地址栏。
- v2rayN 添加长期订阅:进入「订阅分组」→「订阅分组设置」,新增分组并填写订阅地址。保存后在订阅菜单选择「更新订阅(不通过代理)」或相应更新项;网络确实需要代理时,再选择「更新订阅(通过代理)」。
- v2rayN 导入一次性链接:复制完整的逐行分享链接,在「服务器」菜单选择「从剪贴板导入批量 URL」。先检查导入后的传输类型、TLS 与 SNI,再设为活动服务器。
- v2rayNG 更新订阅:进入「订阅分组设置」,新建分组、填写 URL 并保存,然后返回列表执行「更新订阅」。剪贴板节点应使用添加菜单中的「从剪贴板导入」,两种入口不要混用。
- v2flyNG 检查兼容性:使用其订阅或分享链接导入入口前,先确认节点配置适用于 V2Fly 内核。遇到需要 Xray 专有能力的节点,应向服务方获取适配配置,不能靠编码转换解决。
七、订阅转换与导入失败的常见问题
解码后还是 vmess:// 加一长串,是不是没解完?
外层订阅列表已解码完成。先按换行拆成节点,再单独取某条 vmess:// 后的载荷解码并解析 JSON。不要把整个列表再次送进 Base64 解码器,也不要把 VMess 分享对象直接当作内核配置。
JSON 能打开,客户端为什么显示零个节点?
先检查顶层键。如果是 inbounds、outbounds,它可能是完整内核配置,应使用自定义配置入口;如果是错误码与说明,应先修复订阅访问。JSON 语法正确和订阅格式受支持是两件事。
复制后导入失败,应该先检查哪里?
检查链接是否被聊天工具截断、查询串中的 & 是否被替换成字面量 HTML 实体、是否混入全角冒号或引号。先用一条完整链接测试,确认节点详情正常,再导入其余内容。
节点导入成功却连不上,还要换一种订阅格式吗?
先核对地址、443 等实际服务端端口、UUID、传输路径、SNI 与内核支持情况,再看连接日志。10808 这类本地监听端口不能填到远端端口位置。字段已正确导入时,重新编码通常不会修复连接故障。
能把订阅发给在线工具,让它转换成 JSON 吗?
优先使用本地工具和客户端导出功能。订阅 URL 与节点认证信息都应视作敏感数据;如果已泄露,应在服务方管理页重置订阅令牌,并按其规则更换节点凭据,之后更新各端保存的地址。
最终检查顺序可以压缩为四步:看响应正文,辨认格式层级,核对节点字段,验证内核运行。需要了解 TLS、出站与路由术语时,可查阅术语手册;已经完成导入但仍无法联网时,再按技术参考检查日志与网络设置。