<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>周润发博客</title>
  
  <subtitle>收录开源，好用的互联网项目</subtitle>
  <link href="https://blog.zrf.me/atom.xml" rel="self"/>
  
  <link href="https://blog.zrf.me/"/>
  <updated>2026-04-14T16:03:51.000Z</updated>
  <id>https://blog.zrf.me/</id>
  
  <author>
    <name>周润发</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>NodeWarden 部署教程：在 Cloudflare 零成本搭建私有 Bitwarden，无需服务器</title>
    <link href="https://blog.zrf.me/p/NodeWarden-Bitwarden/"/>
    <id>https://blog.zrf.me/p/NodeWarden-Bitwarden/</id>
    <published>2026-03-28T02:00:00.000Z</published>
    <updated>2026-04-14T16:03:51.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="NodeWarden"><a href="#NodeWarden" class="headerlink" title="NodeWarden"></a>NodeWarden</h1><p>想找免费的 Bitwarden 自建方案？这篇文章会手把手教你如何部署使用 NodeWarden，在 Cloudflare Workers 上 <strong>零成本搭建一个属于自己的密码管理器</strong> ，全程无需 VPS 服务器。</p><p>相比传统部署方式，这套方案不仅完全免费，还支持官方客户端同步、自动填充、云端备份以及 TOTP 双重验证，几乎可以替代官方付费功能，非常适合个人长期使用。</p><p>我们都知道，Bitwarden 是目前最受欢迎的开源密码管理器之一，但过去自建往往需要一台长期运行的 VPS 服务器，既麻烦又有成本。</p><p>而现在大佬更进一步用 NodeWarden 直接把 Bitwarden 服务端搬到了 “赛博大善人” Cloudflare 的 Workers 上，让我们可以用 <strong>零服务器成本实现完整功能</strong> 。</p><p>部署 NodeWarden 完成后，你就可以在手机、电脑、浏览器插件中无缝使用 Bitwarden，实现密码同步、自动填充等功能，在这里统统 <strong>直接白嫖</strong> 爽翻～</p><blockquote><p><strong>为什么选择 NodeWarden？</strong></p><ul><li><strong>费用：</strong> 0元（利用 Cloudflare Workers 免费额度）</li><li><strong>性能：</strong> 极速（部署在 CF 全球边缘节点）</li><li><strong>安全：</strong> 私有化部署，数据存储在自己的 CF D1&#x2F;KV 数据库</li><li><strong>兼容性：</strong> 支持所有 Bitwarden 官方客户端（iOS&#x2F;Android&#x2F;Chrome&#x2F;桌面端）</li><li><strong>核心优势：</strong> 比 Vaultwarden 更轻量，完全不需要购买 VPS 服务器。</li></ul></blockquote><h2 id="NodeWarden-与-Bitwarden-官方服务端能力对比"><a href="#NodeWarden-与-Bitwarden-官方服务端能力对比" class="headerlink" title="NodeWarden 与 Bitwarden 官方服务端能力对比"></a>NodeWarden 与 Bitwarden 官方服务端能力对比</h2><p>在开搞之前，我们先看看这个 NodeWarden 版本，和官方版有什么区别。简单总结：<strong>个人单用户使用完美，企业&#x2F;多人协作功能精简。</strong></p><table><thead><tr><th>能力</th><th>Bitwarden</th><th>NodeWarden</th><th>说明</th></tr></thead><tbody><tr><td>网页密码库</td><td>✅</td><td>✅</td><td><strong>原创Web Vault界面</strong></td></tr><tr><td>全量同步 <code>/api/sync</code></td><td>✅</td><td>✅</td><td>已针对官方客户端做兼容优化</td></tr><tr><td>附件上传 &#x2F; 下载</td><td>✅</td><td>✅</td><td>Cloudflare R2 或 KV</td></tr><tr><td>Send</td><td>✅</td><td>✅</td><td>支持文本与文件 Send</td></tr><tr><td>导入 &#x2F; 导出</td><td>✅</td><td>✅</td><td>支持 Bitwarden JSON &#x2F; CSV &#x2F; <strong>ZIP 导入（包括附件）</strong></td></tr><tr><td><strong>云端备份中心</strong></td><td>❌</td><td>✅</td><td><strong>支持 WebDAV &#x2F; E3 定时备份</strong></td></tr><tr><td>密码提示（网页端）</td><td>⚠️ 有限</td><td>✅</td><td><strong>无需发送邮件</strong></td></tr><tr><td>TOTP &#x2F; Steam TOTP</td><td>✅</td><td>✅</td><td>含 <code>steam://</code> 支持</td></tr><tr><td>多用户</td><td>✅</td><td>✅</td><td>支持邀请码注册</td></tr><tr><td>组织 &#x2F; 集合 &#x2F; 成员权限</td><td>✅</td><td>❌</td><td>未实现</td></tr><tr><td>登录 2FA</td><td>✅</td><td>⚠️ 部分支持</td><td>当前仅支持用户级 TOTP</td></tr><tr><td>SSO &#x2F; SCIM &#x2F; 企业目录</td><td>✅</td><td>❌</td><td>未实现</td></tr></tbody></table><p>可以看出，对于咱们个人日常使用，NodeWarden 的功能已经完全绰绰有余了！我甚至更喜欢这个，免费且能使用 <strong>云端备份</strong> 去掉了我之前的焦虑。</p><h2 id="NodeWarden-部署前准备"><a href="#NodeWarden-部署前准备" class="headerlink" title="NodeWarden 部署前准备"></a>NodeWarden 部署前准备</h2><ol><li><strong>一个 Cloudflare 账号</strong><ul><li>需要拥有一个托管在 CF 上的 <strong>域名</strong>，没有域名可以查看 <a href="https://blog.zrf.me/p/Free-Domains/">最新免费域名资源汇总</a>（因为 CF 默认的 <code>workers.dev</code> 域名在国内访问是被阻断的）。</li><li>需要绑定信用卡或 PayPal（开通 R2储存桶 服务，免费额度对个人绝对够用，不会扣费）。</li></ul></li><li><strong>一个 GitHub 账号</strong><ul><li>用于 Fork 源码并授权一键部署。</li></ul></li></ol><h2 id="NodeWarden-部署教程"><a href="#NodeWarden-部署教程" class="headerlink" title="NodeWarden 部署教程"></a>NodeWarden 部署教程</h2><h3 id="第一步：Fork-项目源码"><a href="#第一步：Fork-项目源码" class="headerlink" title="第一步：Fork 项目源码"></a>第一步：Fork 项目源码</h3><p>首先，我们需要把大佬的源码复刻到咱们自己的 GitHub 仓库里。</p><ol><li><p>打开 NodeWarden 的 GitHub 开源地址：<a href="https://github.com/shuaiplus/NodeWarden">https://github.com/shuaiplus/NodeWarden</a></p></li><li><p>来到页面右上角，可以给大佬点个 <strong>Star</strong> ，然后 <strong>Fork</strong> 按钮，将项目复制到你自己的账号下。<br><img src="https://img.zrf.me/20260328035657529.webp" alt="NodeWarden GitHub 源码 Fork 步骤"> </p></li><li><p>项目同步更新（可选）</p><ul><li>本来我这里写的是建议开启，但是由于自动同步更新，导致我创建的二十多个号通行密钥全部失效，我全部转移到此项目上，费了我老半天劲呢，我很难受！！！原由：<a href="https://github.com/shuaiplus/nodewarden/commit/76623d72014efb994d390e9bcab019088fb219e3">重构：移除与密码相关的功能和类型</a> <strong>最新现已修复数据还在的，不难受了</strong></li><li>自动：进入你的 Fork 仓库 ➜ <code>Actions</code> ➜ <code>Sync upstream</code> ➜ <code>Enable workflow</code>，会在每天凌晨 3 点自动同步上游。<br><img src="https://img.zrf.me/20260328040648270.webp" alt="NodeWarden GitHub 源码 项目同步更新1"><br><img src="https://img.zrf.me/20260328040846436.webp" alt="NodeWarden GitHub 源码 项目同步更新2"></li></ul></li></ol><h3 id="第二步：一键部署到-Cloudflare"><a href="#第二步：一键部署到-Cloudflare" class="headerlink" title="第二步：一键部署到 Cloudflare"></a>第二步：一键部署到 Cloudflare</h3><p>这步非常丝滑，不需要你敲任何代码。但是要明确你的 Cloudflare 是否开通 R2 存储功能。没有就先去开通一下，需要绑卡，功能是免费的，如开通过一直下一步就可以了。</p><table><thead><tr><th>储存</th><th>是否需绑卡</th><th>单个附件&#x2F;Send文件上限</th><th>免费额度</th></tr></thead><tbody><tr><td>R2</td><td>需要</td><td>100 MB（软限制可更改）</td><td>10 GB</td></tr><tr><td>KV</td><td>不需要</td><td>25 MiB（Cloudflare限制）</td><td>1 GB</td></tr></tbody></table><ol><li>打开 <a href="https://dash.cloudflare.com/?to=/:account/workers-and-pages/create">Workers</a> ➜ <code>Continue with GitHub</code> ➜ 选择你 Fork 后的仓库（<code>NodeWarden</code>）➜ 下一步 ➜ （默认使用 R2 存储；若未开通，可用 KV 来代替，将<strong>部署命令</strong>改为 <code>npm run deploy:kv</code>）➜ 部署 ➜ 打开生成的链接</li></ol><p><img src="https://img.zrf.me/20260328043332698.webp" alt="Cloudflare Workers 部署 NodeWarden 部署设置1"><br><img src="https://img.zrf.me/20260328043419975.webp" alt="Cloudflare Workers 部署 NodeWarden 部署设置2"><br><img src="https://img.zrf.me/20260328043458144.webp" alt="Cloudflare Workers 部署 NodeWarden 部署设置3"></p><h3 id="第三步：初始化设置与绑定域名"><a href="#第三步：初始化设置与绑定域名" class="headerlink" title="第三步：初始化设置与绑定域名"></a>第三步：初始化设置与绑定域名</h3><ol><li><p>部署成功后，Cloudflare 会为你分配一个类似 <code>nodewarden.xxx.workers.dev</code> 的域名地址。</p><blockquote><p><strong>注意：</strong><br>由于国内网络环境，<code>.workers.dev</code> 通常是打不开的。来到设置，找到 <strong>域和路由</strong> ➜  <strong>自定义域</strong> ，绑定一个你自己的二级域名（例如 <code>nodewarden.zrf.me</code>）。我就使用默认的来教程，自用建议绑定。</p></blockquote><p> <img src="https://img.zrf.me/20260328044419790.webp" alt="设置自定义域名"></p></li><li><p>绑定好自定义域名后，用浏览器打开这个域名，你就会看到 NodeWarden 的页面。提示你 <strong>设置 JWT_SECRET</strong>：这是用于加密你的会话 Token 的密钥，系统会随机生成，复制下来我们按照页面中的提示去添加这个变量。<br><img src="https://img.zrf.me/20260328045053658.webp" alt="Cloudflare Workers 部署 NodeWarden 部署 设置 JWT_SECRET 环境变量 1"></p></li><li><p>回到 Cloudflare 面板刚刚的 <code>nodewarden</code> 项目页面，点击顶部的 <strong>设置</strong>，找到 <strong>变量和机密</strong>，点击添加。按照下图所示填写：</p><ul><li><strong>类型</strong>：下拉选择 <strong>密钥</strong>（必须选 <strong>密钥</strong> 不然后期项目同步更新，变量：JWT_SECRET 会失效，别问我怎么知道）。</li><li><strong>变量名称</strong>：填入 <code>JWT_SECRET</code>。</li><li><strong>值</strong>：<strong>粘贴</strong>你刚才在第 2 步网页上复制的那串密钥。</li><li>填写完成后，点击<strong>部署</strong>保存即可。<br><img src="https://img.zrf.me/20260328045828090.webp" alt="Cloudflare Workers 部署 NodeWarden 部署 设置 JWT_SECRET 环境变量 2"></li></ul></li><li><p>刷新域名地址，我们就来到项目首页了，去创建 <strong>主账号密码</strong>：<strong>关键！</strong> 这是你以后登录 Bitwarden 客户端的唯一账号和主密码，千万别忘了！创建完登录即可。<br><img src="https://img.zrf.me/20260328052039316.webp" alt="NodeWarden 项目中 创建账户"></p></li><li><p>到这里项目部署就全部完成了，非常的简单。</p></li></ol><h2 id="NodeWarden-简单使用教程"><a href="#NodeWarden-简单使用教程" class="headerlink" title="NodeWarden 简单使用教程"></a>NodeWarden 简单使用教程</h2><h3 id="1-设置二次验证"><a href="#1-设置二次验证" class="headerlink" title="1. 设置二次验证"></a>1. 设置二次验证</h3><ol><li><p>来到项目 <strong>账户设置</strong> ➜  <strong>设置二次验证 (TOTP)</strong> ：强烈建议开启！有些小伙伴可能对 TOTP 不太熟，其实它就是咱们常说的 <strong>2FA 双重身份验证</strong>，支持 <strong>Google Authenticator (谷歌验证器)</strong> 或微软验证器。赶紧绑定一下，或者使用本项目去保存，稍后会教，这里就不写了。</p><ul><li>不知道为啥我扫码添加失败了，如果你也遇到这情况，直接使用 <strong>输入设置密钥</strong> 就可以成功绑定了！</li></ul></li><li><p>保存 <strong>恢复代码</strong> ：千万别漏了这一步！ 顺手生成一下，找个安全的地方保存好。 万一哪天你手机丢了、或者验证器没法用进不去账号，这就是你登入账号的最后一把救命钥匙！<br><img src="https://img.zrf.me/20260328055519187.webp" alt="NodeWarden 项目中 设置二次验证"></p></li></ol><h3 id="2-连接Bitwarden客户端"><a href="#2-连接Bitwarden客户端" class="headerlink" title="2. 连接Bitwarden客户端"></a>2. 连接Bitwarden客户端</h3><p>项目服务端搞定了，接下来就是连接 Bitwarden 客户端！</p><ol><li><p>来到官方下载页面 <a href="https://bitwarden.com/download/">Bitwarden-点击前往</a> 下载好的 <strong>Bitwarden 客户端</strong> ，我一般喜欢用浏览器插件，我以 Chrome 为例 <a href="https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb?browser=chrome">Chrome-Bitwarden 密码管理器-点击前往</a> 安装完成后，在浏览器的右上角 <strong>扩展程序</strong> 找到Bitwarden，点击图钉图标来固定Bitwarden扩展。<br><img src="https://img.zrf.me/20260328063716060.webp" alt="安装 Bitwarden 扩展程序"></p></li><li><p>我发现这个插件页面登录UI有问题还是怎么，反正我这里是异常显示，可以点右上角的 <strong>弹出新窗口</strong> ，弹出后就可以自由拖动大小了，在登录界面，不要急着输入账号，点击最下方的 <strong>“bitwarden.com”</strong> 选择 <strong>自托管</strong> 选项，弹出的 <strong>服务器URL</strong> 中填写你的项目域名地址，如你设置了自定义域名就写自定义的。然后输入你的账户密码进行登录就行了，如果刚才开启了二次验证，系统会要求你输入 6 位动态验证码。<br><img src="https://img.zrf.me/20260328064648613.webp" alt="登录 Bitwarden 程序1"><br><img src="https://img.zrf.me/20260328065225096.webp" alt="登录 Bitwarden 程序2"></p></li></ol><h3 id="3-从浏览器导出密码"><a href="#3-从浏览器导出密码" class="headerlink" title="3. 从浏览器导出密码"></a>3. 从浏览器导出密码</h3><ol><li><p>从 Chrome 或 Edge 浏览器导出密码：</p><ul><li>打开浏览器的设置，然后导航到密码设置，例如 <code>chrome://password-manager/settings</code> 或 <code>edge://wallet/passwords</code></li><li>找到“导出密码”并点击“下载文件”。系统可能会提示您输入计算机密码进行验证。对于 Microsoft Edge 浏览器，此选项可能隐藏在“已保存密码”部分的菜单下。</li><li>指定导出文件的保存位置，并确认格式为逗号分隔值( CSV )。</li><li>选择“保存”完成导出。<br><img src="https://img.zrf.me/20260328132513507.webp" alt="从 Chrome 或 Edge 浏览器导出密码"></li></ul></li><li><p>将数据导入密码库：拿到导出的 CSV 文件后，你可以直接你部署的 NodeWarden 网页端导入，也可以在 Bitwarden 浏览器扩展插件进行导入。随便选一个就行，两边的数据都是云端实时同步的。<br><img src="https://img.zrf.me/20260328134232628.webp" alt="导入数据到 NodeWarden 或 Bitwarden"></p></li><li><p>拿我自己来说，平时习惯把 Chrome 当主力大号用，Edge 当备用小号，结果两边浏览器存了大量重复或者交叉的账号密码。现在哪怕你导入了多个浏览器的多份数据，直接在网页端左侧菜单点击 「重复项」，项目就会自动帮你找出所有重复的账号密码。点击上方的「选择重复项」即可智能勾选，然后一键「删除」，这下整个密码库清爽了， <strong>强迫症狂喜</strong><br><img src="https://img.zrf.me/20260328135604084.webp" alt="NodeWarden 项目中 去重复项"></p></li></ol><h3 id="4-云端备份（推荐）"><a href="#4-云端备份（推荐）" class="headerlink" title="4. 云端备份（推荐）"></a>4. 云端备份（推荐）</h3><ol><li><p>InfiniCLOUD：是日本的云存储服务，支持 WebDAV，只需邮箱即可注册免费 20 GB；填写推荐码后总计 25 GB，还不错我用了蛮久的了，当时搞了 45G 空间只用来存储数据根本用不完。</p></li><li><p>你在<a href="https://infini-cloud.net/en/">InfiniCLOUD-点击前往</a>注册后，在<a href="https://infini-cloud.net/en/modules/mypage/usage/">My Page-点击前往</a>里输入邀请码: <code>DYZYJ</code>，就能额外再获得 5GB 永久免费空间，总共可到 25GB。<br><img src="https://img.zrf.me/20260328145642528.webp" alt="InfiniCLOUD"></p></li><li><p>在左侧导航栏点击 「云端备份」，然后在「备份地点」区域点击 「+ 新增地点」，选择 WebDAV 类型。</p><ul><li>WebDAV 服务地址：输入 InfiniCLOUD 地址 <a href="https://miya.teracloud.jp/dav">https://miya.teracloud.jp/dav</a>  （替换为你的实际地址）</li><li>WebDAV 用户名：输入你的 InfiniCLOUD 账号（如 zrfme）</li><li>WebDAV 密码：输入你的 InfiniCLOUD 应用密码（不是登录密码）</li><li>远程目录：输入备份存放目录（如 nodewarden，会自动创建）</li><li>配置完成后，先点击「启用」开启自动备份计划,再点击「保存设置」；你也可以按需点击「手动执行」立即触发一次备份测试，或点击「删除」来移除该备份地点。</li></ul></li></ol><p><img src="https://img.zrf.me/20260328150759898.webp" alt="NodeWarden 项目中 设置云端备份"></p><h3 id="5-使用-NodeWarden-为-账号-开启通行密钥-Passkeys-与-TOTP"><a href="#5-使用-NodeWarden-为-账号-开启通行密钥-Passkeys-与-TOTP" class="headerlink" title="5. 使用 NodeWarden 为 账号 开启通行密钥 (Passkeys) 与 TOTP"></a>5. 使用 NodeWarden 为 账号 开启通行密钥 (Passkeys) 与 TOTP</h3><p>接下来的操作才是 <strong>NodeWarden</strong> 的真正魅力所在：我们要直接“白嫖”官方 Bitwarden 只有高级会员（Premium）才能享有的 <strong>内置 TOTP 验证器</strong> 和 <strong>通行密钥 (Passkeys)</strong> 功能。</p><p>很多大佬可能还习惯在手机上装个 Google Authenticator，每次登录都要翻手机找验证码，简直是“反人类”操作。（当然我把这个 NodeWarden 项目的 TOTP 在谷歌验证器与此项目都绑定了，以防这个项目出现了什么问题。导致后续验证出现问题。）</p><p>用了 NodeWarden 之后，咱们直接把这些全部集成到插件软件里面，电脑用插件手机端用客户端也是一样使用。</p><h4 id="5-1-配置-Passkeys（通行密钥）"><a href="#5-1-配置-Passkeys（通行密钥）" class="headerlink" title="5.1 配置 Passkeys（通行密钥）"></a>5.1 配置 Passkeys（通行密钥）</h4><p>Passkeys 是未来的趋势，不用背密码，安全性还爆表。下面我以 GitHub 为例，带大家感受一下什么叫真正的“丝滑”。</p><ol><li><strong>进入 GitHub 设置：</strong> 登录你的 GitHub，点头像进入 <code>Settings</code> ➜ <code>Password and authentication</code>。</li><li><strong>点击添加：</strong> 在 <strong>Passkeys</strong> 栏目找到 <code>Add a passkey</code>，新添加需要收验证码验证身份。验证完成添加既可，然后叫你命名你就随便写，你知道这个用于哪里就行，方便后续记忆。<br> <img src="https://img.zrf.me/20260414173952252.webp" alt="配置 Passkeys（通行密钥）"></li><li><strong>插件接管：</strong> 此时浏览器会进入等待界面，只要你安装并登录了 Bitwarden 插件，它会 <strong>自动跳出</strong> “保存通行密钥”的窗口。如我下面的截图所示，插件非常智能，它会自动匹配你库里现有的 GitHub 账号。</li><li><strong>一键关联保存：</strong> 在插件弹窗中，直接点击你那个 <strong>对应的登录账号</strong>（就是图中红框标出的账号）。如果你想存成一个新项目，也可以点右上角的 <code>+ 新增</code>。点完之后，这个 Passkey 就稳稳地存进你的 NodeWarden 数据库了。<br> <img src="https://img.zrf.me/20260414174838023.webp" alt="谷歌插件接管 Passkeys 保存界面"></li></ol><ul><li><strong>爽点：</strong> 下次你登录 GitHub 电脑端只要点一下“使用通行密钥”，手机端指纹或面容一刷，瞬间进后台，连账号密码都不用输入，安全又快捷！<br> <img src="https://img.zrf.me/20260414183701046.webp" alt="Bitwarden 程序中 使用通行密钥 登录"></li></ul><h4 id="5-2-开启内置-TOTP"><a href="#5-2-开启内置-TOTP" class="headerlink" title="5.2 开启内置 TOTP"></a>5.2 开启内置 TOTP</h4><p>大家注意，官方 Bitwarden 的内置 TOTP（就是那个 30 秒一变的 6 位验证码）是 <strong>收费功能</strong> 。但使用 NodeWarden ，<strong>直接免费了！</strong></p><ol><li><strong>获取密钥：</strong> 在 GitHub 的双因素认证（2FA）页面，选择 <code>Enable two-factor authentication</code>。你会看到一个 <strong>二维码</strong> 。<br> <img src="https://img.zrf.me/20260414192347503.webp" alt="开启 Enable two-factor authentication"></li><li><strong>编辑条目：</strong> 打开 Bitwarden 插件，找到你的 GitHub 账号，点右侧的三个点，再点 <code>编辑</code>。</li><li><strong>注入灵魂：</strong> 找到 <code>验证器密钥 (TOTP)</code> 这一行：<ul><li>你可以点右边的 <strong>相机图标</strong> 直接对着屏幕扫。</li><li>或者直接点击把二维码下方 <strong>Setup Key</strong> 的那一串字符，粘贴进去。<br> <img src="https://img.zrf.me/20260414192129164.webp" alt="验证器密钥 (TOTP) 导入密钥 到 Bitwarden 程序中"></li></ul></li><li><strong>保存即用：</strong> 保存后，使用 TOTP 进行验证一下。你会发现条目里出现了一个不断刷新的 6 位数字。<br> <img src="https://img.zrf.me/20260414191933373.webp" alt="保存密钥 并 TOTP 验证"></li><li><strong>附件保存：非常重要，如果丢失会导致你的账号无法登录</strong> 我们可以把这些恢复代码直接保存到项目中，下载下来添加在<code>附件</code>中 或 添加复制到 <code>字段</code> 去保存，项目有自动备份功能。我并不担心数据丢失。<br> <img src="https://img.zrf.me/20260414194437285.webp" alt="恢复代码 备份 很重要"></li></ol><ul><li><strong>强迫症狂喜：</strong> 以后登录需要验证码，插件会自动帮你填充，或者点一下直接复制，再也不用满世界找手机了！</li></ul><h2 id="完结撒花！发哥小提示！"><a href="#完结撒花！发哥小提示！" class="headerlink" title="完结撒花！发哥小提示！"></a>完结撒花！发哥小提示！</h2><p>至此，你拥有了一个完全属于自己、无需维护服务器、基于 Cloudflare 全球边缘节点加速，并且支持密码同步、自动填充、云端备份以及 TOTP 功能的满血版密码管理器！。</p><p>相比传统自建方案，这种基于 Cloudflare 的无服务器部署方式，不仅成本为 0，还兼顾了性能与可用性，可以说是目前个人用户最优雅的 Bitwarden 自建方案之一。</p><p>虽然“白嫖”很爽，但因为我们把“鸡蛋都放进了一个篮子”（账号密码、Passkey、TOTP）都集中在同一个 NodeWarden 系统中。因此，有两件事情你<strong>必须认真对待</strong>：</p><ol><li><p><strong>主账号必须稳：</strong><br>一定要确认 NodeWarden 主账号已开启 TOTP 双重验证。建议同时在第三方验证器（如 Google Authenticator）中备份一份，避免一些问题导致无法登录。</p></li><li><p><strong>备份恢复代码：</strong><br>虽然 NodeWarden 已支持定时云端备份（如 WebDAV），在大多数情况下数据是安全的，但恢复代码依然建议保留一份离线备份。比如说 Cloudflare 崩了，刚好你这个时候要使用（小概率但是会发生）</p><p>因为一旦出现设备丢失、TOTP 无法使用等情况，恢复代码可能是你重新访问账号的唯一方式。</p></li></ol><p>最后记住一句话：<br><strong>你可以忘记密码，但绝不能丢掉恢复代码。</strong></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;NodeWarden&quot;&gt;&lt;a href=&quot;#NodeWarden&quot; class=&quot;headerlink&quot; title=&quot;NodeWarden&quot;&gt;&lt;/a&gt;NodeWarden&lt;/h1&gt;&lt;p&gt;想找免费的 Bitwarden 自建方案？这篇文章会手把手教你如何部署使用 </summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="隐私" scheme="https://blog.zrf.me/tags/%E9%9A%90%E7%A7%81/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    <category term="密码管理" scheme="https://blog.zrf.me/tags/%E5%AF%86%E7%A0%81%E7%AE%A1%E7%90%86/"/>
    
    <category term="Bitwarden" scheme="https://blog.zrf.me/tags/Bitwarden/"/>
    
    <category term="NodeWarden" scheme="https://blog.zrf.me/tags/NodeWarden/"/>
    
  </entry>
  
  <entry>
    <title>免费域名升级玩法：用VPS8让根域名支持CNAME等高级解析</title>
    <link href="https://blog.zrf.me/p/VPS8-Domains/"/>
    <id>https://blog.zrf.me/p/VPS8-Domains/</id>
    <published>2026-03-07T00:17:27.000Z</published>
    <updated>2026-03-13T18:06:56.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="简单介绍"><a href="#简单介绍" class="headerlink" title="简单介绍"></a>简单介绍</h1><p>之前我发过一篇<a href="https://blog.zrf.me/p/Free-Domains/">最新免费域名资源汇总：实测免费渠道与超值付费方案</a>。里面汇总了超多免费域名，而域名的使用来说，大多数免费域名平台都只能用「A记录」指向IP，像CNAME、MX、NS这些高级记录类型基本都不支持（当然能托管到Cloudflare的除外）。比如 IDC.LC、9v4.net、Loc.cc 这些服务，大家用过就知道，功能很有限。</p><p>这次我来简单聊聊怎么用 VPS8（vps8.zz.cd）这个自带PowerDNS管理的免费域名平台，让你的免费域名也能用上专业DNS托管功能。</p><p>不同于那些免费域名平台，VPS8 解决了免费域名平台解析弱的痛点，VPS8 允许你直接配置 <strong>“根域名 CNAME”</strong> ，这对想要绑定 Vercel、GitHub Pages 或者 Cloudflare Pages 的小伙伴来说简直是刚需！</p><h2 id="第一步：注册VPS8账号"><a href="#第一步：注册VPS8账号" class="headerlink" title="第一步：注册VPS8账号"></a>第一步：注册VPS8账号</h2><ol><li><p>先打开这个链接：<a href="https://vps8.zz.cd/signup">https://vps8.zz.cd/signup</a> ，注册一个自己的账号。<br><img src="https://img.zrf.me/20260307121252562.webp" alt="这是VPS8的注册页面，填好信息就能注册。"></p></li><li><p>注册完之后，回到首页，点击订阅，选择DNS服务。<br><img src="https://img.zrf.me/20260307121642604.webp" alt="这里是订阅DNS服务的界面，选DNS就行。"></p></li><li><p>在页面上方输入框里填你的域名，然后去你的域名注册商那里，把域名服务器（NS）改成下面这两个：<br><code>ns1.vps8.zz.cd</code><br><code>ns2.vps8.zz.cd</code><br><img src="https://img.zrf.me/20260307125617696.webp" alt="在这里输入你的域名，准备修改NS记录。"></p></li></ol><h2 id="第二步：修改域名名称服务器"><a href="#第二步：修改域名名称服务器" class="headerlink" title="第二步：修改域名名称服务器"></a>第二步：修改域名名称服务器</h2><ul><li>我这里使用 IDC.LC 家的 nn.kg 后缀的免费域名为例子。</li></ul><ol><li>登录你的域名注册平台，把NS服务器地址改成刚才那两个，然后点更新保存。<br><img src="https://img.zrf.me/20260307125720954.webp" alt="域名平台修改NS服务器的操作界面。"></li></ol><h2 id="第三步：在Cloudflare绑定域名"><a href="#第三步：在Cloudflare绑定域名" class="headerlink" title="第三步：在Cloudflare绑定域名"></a>第三步：在Cloudflare绑定域名</h2><ol><li><p>登录Cloudflare，来到你需要绑定域名的项目，添加你的域名，选择“自定义域名”设置。<br><img src="https://img.zrf.me/20260307130716120.webp" alt="Cloudflare添加自定义域名的界面。"></p></li><li><p>输入你的域名地址，然后点击继续。<br><img src="https://img.zrf.me/20260307131106500.webp" alt="输入域名后，Cloudflare会让你继续下一步。"></p></li><li><p>选择“我的DNS提供商”，意思是你继续用当前的DNS服务商。接下来设置CNAME记录，把你的域名指向Cloudflare，开始配置。<br><img src="https://img.zrf.me/20260307131356963.webp" alt="这里是设置CNAME记录的界面。"></p></li><li><p>复制Cloudflare给你的记录值，比如我的是<code>zrfweb.pages.dev</code>，你会拿到属于你自己的。<br><img src="https://img.zrf.me/20260307131556881.webp" alt="复制你自己的CNAME记录值。"></p></li><li><p>回到VPS8平台，添加解析记录，名称填@，意思是根域名。<br><img src="https://img.zrf.me/20260307132141378.webp" alt="VPS8平台添加解析记录的界面，名称用@代表根域名。"></p></li><li><p>等几分钟，你就可以看到域名设置完成，绑定成功，显示活动状态。<br><img src="https://img.zrf.me/20260307133621278.webp" alt="域名绑定完成"></p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;简单介绍&quot;&gt;&lt;a href=&quot;#简单介绍&quot; class=&quot;headerlink&quot; title=&quot;简单介绍&quot;&gt;&lt;/a&gt;简单介绍&lt;/h1&gt;&lt;p&gt;之前我发过一篇&lt;a href=&quot;https://blog.zrf.me/p/Free-Domains/&quot;&gt;最新免费域名资源汇</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="DNS" scheme="https://blog.zrf.me/tags/DNS/"/>
    
    <category term="CDN" scheme="https://blog.zrf.me/tags/CDN/"/>
    
    <category term="免费域名" scheme="https://blog.zrf.me/tags/%E5%85%8D%E8%B4%B9%E5%9F%9F%E5%90%8D/"/>
    
    <category term="域名注册" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%B3%A8%E5%86%8C/"/>
    
    <category term="域名托管" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%89%98%E7%AE%A1/"/>
    
    <category term="白嫖域名" scheme="https://blog.zrf.me/tags/%E7%99%BD%E5%AB%96%E5%9F%9F%E5%90%8D/"/>
    
    <category term="资源分享" scheme="https://blog.zrf.me/tags/%E8%B5%84%E6%BA%90%E5%88%86%E4%BA%AB/"/>
    
  </entry>
  
  <entry>
    <title>最新免费域名资源汇总：实测免费渠道与超值付费方案</title>
    <link href="https://blog.zrf.me/p/Free-Domains/"/>
    <id>https://blog.zrf.me/p/Free-Domains/</id>
    <published>2026-01-27T17:17:27.000Z</published>
    <updated>2026-03-18T19:15:49.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="最新域名资源汇总："><a href="#最新域名资源汇总：" class="headerlink" title="最新域名资源汇总："></a>最新域名资源汇总：</h1><p>2026 年开始，今天给兄弟们整理了一波最新、好用的免费域名合集。对于咱们这种爱折腾、没事就搭个站，或者看见域名就想“集邮”的人来说，免费域名肯定是刚需。</p><p>俗话说“免费的才是最贵的”，免费域名的稳定性还是无法与付费域名相比，指不定哪天平台跑路或域名被回收，前车之鉴可以看看我下面提到的 NYC.mn (被回收)</p><p>下面这些域名平台有我近期和我部分长期使用的老牌服务 <strong>全部实测</strong> 整理出来的（当然有门槛无法测试的除外），大家按需自取，且用且珍惜！</p><p><strong>欢迎大家给我投稿，我未收录的域名平台，毕竟一个人的资源收集能力终归有限。</strong></p><h2 id="免费域名"><a href="#免费域名" class="headerlink" title="免费域名"></a>免费域名</h2><h3 id="1-DnShe"><a href="#1-DnShe" class="headerlink" title="1. DnShe"></a>1. DnShe</h3><p>这个是我最近用得比较多的，真是量大管饱，最近还出了新的后缀，托管到 Cloudflare 的速度也很快，刚绑定完基本就生效了。注意：最近新增的 cn.mt 和 bbroot.com 后缀需要单独的专用邀请码才能注册，且一旦违规连坐邀请人，现阶段这两个域名注册永久有效但还暂不支持托管到 Cloudflare。<br><strong>特别注意：</strong> 但是我在使用中遇到了一些问题，这个平台会删 DNS 解析记录，我之前一些域名明明设置了解析，但是后面上去看，发现解析显示是空的状态为未解析，但实际可用，不晓得为啥子。<br><img src="https://img.zrf.me/20260129022251245.webp" alt="DnShe-DNS 解析"></p><p><strong>注册地址：</strong> <a href="https://my.dnshe.com/">DnShe-点击前往</a> （注册额度邀请码：GS4D1788E2）</p><p><strong>可用后缀：(部分域名支持托管到 Cloudflare)</strong></p><ul><li>de5.net、cc.cd、ccwu.cc、us.ci、cn.mt、bbroot.com</li></ul><p><strong>平台规则：</strong></p><ul><li>域名续期：2026 年 1 月 1 号起新注册的改为按年算，系统将在域名到期前 180 天内开启免费续期通道，可在面板或 API 一键续期。</li><li>注册额度：2025年12月1日起实行新规（3+2模式），新用户基础 3 个名额，完成邀请可加 2 个，最高 5 个；老用户权益不变。</li></ul><hr><h3 id="2-DigitalPlat（US-kg）"><a href="#2-DigitalPlat（US-kg）" class="headerlink" title="2. DigitalPlat（US.kg）"></a>2. DigitalPlat（US.kg）</h3><p>因为之前 US.KG 滥用严重导致被注册局暂停解析，现在平台主力免费域名已切换为 DPDNS.ORG。很早注册 US.KG 子域名被切换到 DPDNS.ORG。之前使用 US.KG 的时候经常炸，改成 DPDNS.ORG 后没怎么听说炸了。<br><strong>特别注意：</strong> 这个平台的后缀大部分的地区国内不是很好用。我看我是24年中旬注册的了，我的评价是一般。<br><img src="https://img.zrf.me/20260129021359906.webp" alt="DigitalPlat（US.kg）"></p><p><strong>注册地址：</strong> <a href="https://dash.domain.digitalplat.org/auth/register"> DigitalPlat（US.kg）-点击前往</a></p><p><strong>可用后缀：(支持托管到 Cloudflare)</strong></p><ul><li>qzz.io、dpdns.org</li></ul><p><strong>平台规则：</strong></p><ul><li>域名续期：域名有效期 360 天，到期前 180 天内免费续费。</li><li>注册额度：默认免费 1 个，给 GitHub 项目点赞后再给 1 个，总共能注册 2 个。</li></ul><hr><h3 id="3-EU-CC"><a href="#3-EU-CC" class="headerlink" title="3. EU.CC"></a>3. EU.CC</h3><p>这是 Gname 搞的活动，注册是一年，后期可续（平台这么说的），注册只需要验证使用邮箱验证和MFA验证（谷歌身份验证器 (Authenticator)我用的这个），无需验证手机号。</p><p><strong>注册地址：</strong> <a href="https://www.gname.com/tld-eu-cc.html">EU.CC-点击前往</a></p><p><strong>可用后缀：(支持托管到 Cloudflare)</strong></p><ul><li>eu.cc（标价 1.88 美元的才行）</li></ul><p><strong>平台规则：</strong></p><ul><li>域名续期：必须在到期前 90 天内，去活动页面的“免费续费”列表手动点续费，自动续费不免费。</li><li>注册额度：一个账号限注册 3 个。<br><img src="https://img.zrf.me/20260129020244864.webp" alt="EU.CC-域名续期"></li></ul><hr><h3 id="4-ZoneABC"><a href="#4-ZoneABC" class="headerlink" title="4. ZoneABC"></a>4. ZoneABC</h3><p>这家的特点就是部分免费域名支持 Cloudflare 的 Enterprise Plan 计划，这样的 CDN 线路，肯定是比 Free 计划要好的多，但是其实这个特色功能现在跟没有一样，因为其支持的域名，目前已经无法添加DNS记录。<br>但目前看到社区讨论说好像无管理员在线，发邮件也没人回复，可以玩玩。<a href="https://github.com/ZoneABC/ZoneABC/discussions">ZoneABC GitHub社区</a><br><img src="https://img.zrf.me/20260129022702348.webp" alt="ZoneABC-GitHub社区"><br><strong>特别注意：</strong> </p><ol><li><strong>不要注册使用：</strong>  zabc.net  webn.cc vvvv.ee 这些域名后缀测试，会出现（Cloudflare API错误：记录配额已超出）无法正常使用域名的添加DNS记录功能。<br><img src="https://img.zrf.me/20260129024047034.webp" alt="ZoneABC-Cloudflare API错误：记录配额已超出"></li><li>sylu.net 域名添加DNS记录功能正常，但其提供的 SaaS 功能无法使用。貌似这个域名不支持，其他我自己还没测到（还不够积分注册其他后缀），坑全让我踩上了，哈哈哈。<br><img src="https://img.zrf.me/20260129023359159.webp" alt="ZoneABC-sylu.net-SaaS 功能无法使用"></li></ol><p><strong>注册地址：</strong> <a href="https://d.zrf.me/zoneabc">ZoneABC-点击前往（带AFF介意可去除后缀）</a></p><p><strong>可用后缀：</strong></p><ul><li>webn.cc、zabc.net、sylu.cc、sylu.net、acg.rest、vvvv.ee、ctil.li</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：每人 5 个域名。采用积分制，完善资料可以得20积分（可注册一个普通域名）和邀请人1人能得10积分。</li></ul><hr><h3 id="5-INDEVS-in"><a href="#5-INDEVS-in" class="headerlink" title="5. INDEVS.in"></a>5. INDEVS.in</h3><p>由印度人打造的面向开发者的免费域名。界面看着还蛮好看，目前支持托管到 Cloudflare。这个之前很早发在频道了的，当时不需要验证一些信息，现在明确的要求验证了，如再次看到记得前往验证一下哦，免得被暂停使用。<br><img src="https://img.zrf.me/20260129015624382.webp" alt="INDEVS.in"></p><p><strong>注册地址：</strong> <a href="https://domain.stackryze.com/">INDEVS.in-点击前往</a></p><p><strong>可用后缀：(支持托管到 Cloudflare)</strong></p><ul><li>.indevs.in</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：单用户限 5 个。</li><li>域名续期：有效期 1 年，到期前 60 天左右可发起免费续订。</li></ul><hr><h3 id="6-PublicZone-NYC-mn"><a href="#6-PublicZone-NYC-mn" class="headerlink" title="6. PublicZone (NYC.mn)"></a>6. PublicZone (NYC.mn)</h3><p>2025 年 12 月 1 日 PublicZone 正式收购了 NYC.mn。说来也巧，我之前在老平台申请过一个“永久”的域名，在 2025 年 05 月 27 日 结果被判定 <strong>网络钓鱼</strong> 给回收了，而我确定我没有这样的行为，没想到这次新平台开放，我又成功把在这个域名注册回来了，兜兜转转终究还是回到了我手里。目前我只亲测了 NYC.mn 完美托管 Cloudflare，其他后缀没试过，大家可以自测。<br><img src="https://img.zrf.me/20260129014231053.webp" alt="PublicZone (NYC.mn)1"></p><p><strong>注册地址：</strong> <a href="https://publiczone.org/free">PublicZone (NYC.mn)-点击前往</a></p><p><strong>可用后缀：(部分支持托管到 Cloudflare)</strong></p><ul><li>nyc.mn、fr.cr、int.al、com.cn.st、edu.cn.st、org.cn.st、net.cn.st、ngo.cn.st、dev.cn.st、me.cn.st</li></ul><p><strong>平台规则：</strong></p><ul><li>域名现状：已完成收购交接，老域名保持有效，不会过期。<a href="https://dot.nyc.mn/">NYC.mn 子域名服务 服务转移公告</a></li><li>注册额度：普通新用户注册已暂停。目前仅面向现有用户及通过验证的开源开发者（需 GitHub 项目 100+ Stars），验证后送 50 美元积分（无需实际付款），可用于新注册或续费（足够注册 10 年）。<br><img src="https://img.zrf.me/20260129014720272.webp" alt="PublicZone (NYC.mn)2"></li></ul><hr><h3 id="7-NDJP-NET"><a href="#7-NDJP-NET" class="headerlink" title="7. NDJP.NET"></a>7. NDJP.NET</h3><p>服务器在日本，解析速度蛮快的，支持使用 API 从路由器或脚本更新DDNS，很适合拿来给家里的 NAS 做动态域名。<br><img src="https://img.zrf.me/20260129012346063.webp" alt="NDJP.NET"></p><p><strong>注册地址：</strong> <a href="https://manage.ndjp.net/">NDJP.NET-点击前往</a></p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>.ndjp.net</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：暂时没看到明确限制，测试开了 3 个都可以。</li></ul><hr><h3 id="8-EE-CD"><a href="#8-EE-CD" class="headerlink" title="8. EE.CD"></a>8. EE.CD</h3><p>最省事的一个，直接用 Google 账号一键登录。有个大亮点： 它的底层解析服务商是 DNSPod，那他国内的解析速度和稳定性应该非常不错。虽然不支持托管到 Cloudflare，但自带的解析功能非常全，我体验发证书蛮快的。<br><img src="https://img.zrf.me/20260129011203521.webp" alt="EE.CD"></p><p><strong>注册地址：</strong> <a href="https://eecd.cc/">EE.CD-点击前往</a></p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>ee.cd、my.uy、vps.cd</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：一个号限 1 个域名。</li></ul><hr><h3 id="9-ClouDNS"><a href="#9-ClouDNS" class="headerlink" title="9. ClouDNS"></a>9. ClouDNS</h3><p>ClouDNS 其实是一家非常老牌的 DNS 服务商了，以前的神器，现在限制太多了，IP 不干净不让注册，我是老早以前注册了，现在还托管在 Cloudflare 中，但是现在不能托管了。稳倒是蛮稳定的，当个备选吧。 <strong>这好像是我第一个拥有的免费域名，从此走上了集邮之路。</strong><br><img src="https://img.zrf.me/20260129010210265.webp" alt="ClouDNS"></p><p><strong>注册地址：</strong> <a href="https://www.cloudns.net/">ClouDNS-点击前往</a></p><p><strong>可用后缀：(新注册暂不支持托管到 Cloudflare)</strong></p><ul><li>dns-dynamic.net、cloudns.be、cloudns.ch</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：单号 1 个域名（DNS域），50 条 DNS 解析记录。</li><li>资源限制：每月 50 万次 (500K) DNS 查询，支持 1 个动态 DNS 主机名和 1 个邮件转发。</li></ul><hr><h3 id="10-DeSec"><a href="#10-DeSec" class="headerlink" title="10. DeSec"></a>10. DeSec</h3><p>这个我是体验蛮久的了，主打硬核安全的免费 DNS 托管服务，最大的亮点是原生支持 DNSSEC 自动化管理，还是相当稳定的且注册流程也非常简单。支持的解析记录种类还是蛮多的。<br><img src="https://img.zrf.me/20260129030212569.webp" alt="DeSec-解析记录"></p><p><strong>注册地址：</strong> <a href="https://desec.io/">DeSec-点击前往</a></p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>dedyn.io</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：单账号限 1 个域名，解析记录不限。</li></ul><hr><h3 id="11-Dynu"><a href="#11-Dynu" class="headerlink" title="11. Dynu"></a>11. Dynu</h3><p>这是个老牌的动态域名服务商，域名后缀就是多且还都是主流顶级后缀，适合家庭宽带公网 IP 映射，不支持修改 NS 记录托管到 Cloudflare。我先注册占坑了。<br><strong>特别注意：</strong> 免费用户要注意，新注册的子域名有“30天成熟期”限制。在注册满 30 天之前，无法添加 TXT 记录（刚注册无法立刻通过 DNS 验证申请 SSL 证书）<br><img src="https://img.zrf.me/20260128210243245.webp" alt="Dynu-TXT记录限制"></p><p><strong>注册地址：</strong> <a href="https://www.dynu.com/">Dynu-点击前往</a></p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>accesscam.org、camdvr.org、casacam.net、ddnsfree.com、ddnsgeek.com、freeddns.org、giize.com、gleeze.com、kozow.com、loseyourip.com、mywire.org、ooguy.com、theworkpc.com、webredirect.org 等。</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：免费账户可以创建 4 个免费域名。</li><li>域名续期：主打“永久免费且不过期”，只要账号状态正常，不需要像其他 DDNS 那样每月手动续期，非常省心。</li></ul><hr><h3 id="12-IDC-LC"><a href="#12-IDC-LC" class="headerlink" title="12. IDC.LC"></a>12. IDC.LC</h3><p>这是一个提供 nn.kg 短后缀的平台。虽然走的是下单流程，但使用优惠码后是免费的。<br><strong>特别注意：</strong> 官方对资源利用率要求很高，注册后必须尽快添加 A 或 AAAA 记录指向你的博客或 VPS。系统会定期扫描，一旦判定不活跃会直接删除域名以防资源浪费。<br><img src="https://img.zrf.me/20260128231918180.webp" alt="IDC.LC-删除不活跃的域名，以防止资源浪费"></p><p><strong>注册地址：</strong> <a href="https://www.idc.lc/">IDC.LC-点击前往</a> （优惠码：free）</p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>.nn.kg</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：每位用户限用 1 次优惠码。下单时输入优惠码：free 即可免费注册。</li></ul><hr><h3 id="13-I8-CLOUD-GV-UY"><a href="#13-I8-CLOUD-GV-UY" class="headerlink" title="13. I8 CLOUD (GV.UY)"></a>13. I8 CLOUD (GV.UY)</h3><p>这个平台之前叫 GV.UY，现在改名叫 I8 CLOUD 了。我看 LOGO 还有没有更改。之前老的注册地址也定向为新的地址了，提供了三个挺有意思的后缀。<br>官方于 <strong>2025 年 12 月 3 日</strong> 在系统基本稳定后，正式开放了二级域名注册。<strong>2025 年 12 月 28 日</strong> 就进 PSL（Public Suffix List）了，大佬这也太强啦，除了域名，I8 CLOUD 还提供免费的主机空间、容器和虚拟机，专为开发者、学生和开源项目打造。<br><strong>特别注意：</strong> 目前采用邀请制，需要获取到邀请码才能注册（项目上线还没到90天吧，哈哈哈）项目经历：<a href="https://www.nodeloc.com/t/topic/75011">Nodeloc-关于聊聊GV.UY的项目-您可能不知道的事</a><br><img src="https://img.zrf.me/20260129001711475.webp" alt="CLOUD (GV.UY)-90天我还不到呢"></p><p><strong>注册地址：</strong> <a href="https://nic.i8.al/">I8 CLOUD-点击前往</a> （需要邀请码才能注册，我没有。）</p><p><strong>可用后缀：(部分支持托管到 Cloudflare)</strong></p><ul><li>gv.uy（支持托管到 Cloudflare）、hsk.sk、zz.cd</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度： 默认注册用户可使用优惠码注册 1 个免费域名，如你有更多使用需求，可在「域名促销代码」界面，额外申请最多 2 个优惠码。则每个账户最多可获得 3 个不同后缀的免费域名。<br><img src="https://img.zrf.me/20260131213830339.webp" alt="I8 CLOUD (GV.UY)-域名促销代码"></li><li>激活方式： 下单时输入优惠码 <code>I8CLOUD</code> 即可免费注册域名。</li><li>域名续期：有效期 1 年，到期前 90 天左右可发起免费续订。</li></ul><hr><h3 id="14-Loc-cc-Nodeloc"><a href="#14-Loc-cc-Nodeloc" class="headerlink" title="14. Loc.cc (Nodeloc)"></a>14. Loc.cc (Nodeloc)</h3><p>这是 Nodeloc 社区（一个开放、自由的技术资源讨论社区）提供的免费域名福利。之前是使用  FossBilling 部署的，现在迁移到这个新的程序来使用。如之前已经注册过的小伙伴可以迁移到新程序，项目已经在 Github 开源，有兴趣的小伙伴可以去玩玩。<a href="https://github.com/nodeloc/opendomain">OpenDomain - 免费二级域名分发平台</a></p><p><strong>注册地址：</strong> <a href="https://domain.nodeloc.com/register?ref=5005e7b59ac5821f">Loc.cc-点击前往</a> （优惠码：FREEFOREVER）</p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>loc.cc</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度： 现在可使用优惠码免费申请一个终身免费 loc.cc  域名。限量100个。（限时的）<br><img src="https://img.zrf.me/20260213232256092.webp" alt="Loc.cc (Nodeloc)"></li></ul><hr><h3 id="15-NIC-UA-pp-ua"><a href="#15-NIC-UA-pp-ua" class="headerlink" title="15. NIC.UA (pp.ua)"></a>15. NIC.UA (pp.ua)</h3><p>这是一个非常老牌且极其稳定的免费域名服务，很早之前我也写过一个简单流程：<a href="https://blog.zrf.me/p/notes-pp-ua/">注册永久免费域名pp.ua-点击前往</a> 我到目前为止已经续订一次了，虽然注册门槛相对较高，但稳定性极好。它完美支持修改 NS 记录托管到 Cloudflare，适合长期建站使用。<br><strong>特别注意：</strong></p><ol><li>验证门槛：注册过程需要验证 <strong>外币信用卡</strong>（会预扣 1 乌克兰格里夫纳进行验证，随后立即撤销退回，不实际扣费）以及 <strong>Telegram 账号</strong> （用于接收激活码） <strong>Telegram 绑定的号码与平台购买域名信息需一致</strong> 。</li><li>隐私公开：该域名的 WHOIS 信息是 <strong>强制公开</strong> 的，无法开启隐私保护，注册信息（姓名&#x2F;电话&#x2F;邮箱）均可查询。</li></ol><p><strong>注册地址：</strong> <a href="https://nic.ua/en/signup/tqczmwiu">NIC.UA-点击前往（带AFF介意可去除后缀）</a></p><p><strong>可用后缀：(支持托管到 Cloudflare)</strong></p><ul><li>pp.ua</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度： 单个账号在 30 天内最多可注册 3 个 <code>.pp.ua</code> 域名，后续每个月都能注册。</li><li>域名续期： 有效期为 1 年。支持免费续期，在域名到期前 3-4 个月即可申请免费续订（但是我具体忘了多久续订）能续订的时候最后 <strong>Renew</strong> 按钮可以点击。<br><img src="https://img.zrf.me/20260129044554357.webp" alt="NIC.UA (pp.ua) 域名续期"></li><li>教程笔记：简单流程：<a href="https://blog.zrf.me/p/notes-pp-ua/">注册永久免费域名pp.ua-点击前往</a></li></ul><hr><h3 id="16-ZZ-NIC-zz-ac"><a href="#16-ZZ-NIC-zz-ac" class="headerlink" title="16. ZZ.NIC (zz.ac)"></a>16. ZZ.NIC (zz.ac)</h3><p>这是博主“涛叔”发起的免费域名项目，我看到这个项目也进行了申请，但是申请理由确实很简陋抽象，所以没有通过，然后看到其群组加入进去后，看到其博客内容已将自己的主博客域名从 taoshu.in 迁移到了 tao.zz.ac，以此证明其长期运营的决心。翻看到博主写的一些博文，巨真诚（我就释然了我没有通过，该，哈哈哈）<br>目前网页注册，看起来像是提交一个KYC表单，博主再进行人工审核。 更多关于：<a href="https://tao.zz.ac/dns/zz.html">ZZ.NIC 免费域名计划说明</a><br><img src="https://img.zrf.me/20260129034552857.webp" alt="ZZ.NIC (zz.ac)"></p><p><strong>特别注意：</strong> 域名持有者的姓名、域名含义会直接通过 <a href="https://nic.zz.ac/#whois">WHOIS 页面</a> 公开，不支持匿名持有。<br><strong>注册地址：</strong> <a href="https://nic.zz.ac/">ZZ.NIC-点击前往</a></p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>zz.ac</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：因为其特殊性，既 1 个免费域名。</li><li>域名续期：目前查询根域名有效期至 <strong>2035年04月30日</strong> ，不同于大多数免费域名需依赖维护者每年续费的模式，该博主直接锁定了未来十年的有效期，在长期持有的稳定性上给足了用户安全感。<br><img src="https://img.zrf.me/20260129035848220.webp" alt="ZZ.NIC (zz.ac)-域名有效期"></li></ul><hr><h3 id="17-9v4-net"><a href="#17-9v4-net" class="headerlink" title="17. 9v4.net"></a>17. 9v4.net</h3><p>这个是在逛 Nodeloc 社区 的时候看到的，用户在注册特定后缀域名并完成建站后，可以申请免费的 VPS 资源。适合有实际建站需求且愿意折腾的用户。<br>注册第一个域名先使用优惠码，然后可以注册一个，去添加一个新的域名购物车，但是别支付，去邀请码页面右侧填写邀请码，可再次购买一个域名。<br><strong>特别注意：</strong></p><ol><li>必须持有 94v.net 域名，且该域名已完成网站部署，内容需健康安全。满足条件后方可申请免费 VPS。</li><li>系统会严格检测闲置资源及滥用行为，违规或长期不使用的域名&#x2F;VPS 将会被删除。</li></ol><p><strong>注册地址：</strong> <a href="https://store.9v4.com/">9v4.net-点击前往</a> （优惠码：newuser）</p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>ug.cx、hiv-info.com、ww.fyi、94v.net</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：默认注册用户可使用优惠码：newuser 注册 1 个免费域名，有效期为一年。使用邀请码可再次注册，上限未知。若是想长期使用，需提交工单&#x2F;说明需包含域名、用途、承诺保证等信息。</li><li>域名续期：可在「邀请码」界面，生成邀请码，邀请一个新用户使用此邀请码后，邀请者可使用此邀请码续订域名，<strong>最高邀请名额为五个。</strong> 我已成功通过邀请码续订的方式续订域名到29年了。<br><img src="https://img.zrf.me/20260319030613121.webp" alt="域名邀请续期"></li></ul><hr><h3 id="18-VPS8"><a href="#18-VPS8" class="headerlink" title="18. VPS8"></a>18. VPS8</h3><p>说实话，VPS8 这个平台最吸引我的倒不是它送的那一个免费域名，而是它后台自带的那套 <strong>PowerDNS 管理系统</strong>。</p><p>很多免费域名平台的解析功能都非常简单，通常根域名（@）只能配置 A 记录，但这家的 DNS 托管是真的专业。它最大的亮点是支持 <strong>“根域名 CNAME”</strong> ，这对想要绑定 Vercel、GitHub Pages 或者 Cloudflare Pages 的小伙伴来说简直是刚需！</p><p>我觉得这平台的核心玩法其实是它的 <strong>DNS 托管功能</strong>：如果你手里有其他支持修改 NS 服务器的域名，直接托管到 VPS8 这里，解析体验直接起飞，妥妥的“免费域名顶级待遇”！</p><p><strong>注册地址：</strong> <a href="https://vps8.zz.cd/">VPS8-点击前往</a> （优惠码：VPS8_2026）</p><p><strong>可用后缀：(不支持托管到 Cloudflare)</strong></p><ul><li>com.cfd</li></ul><p><strong>平台规则：</strong></p><ul><li>注册额度：免费注册 1 个免费域名，有效期为一年。</li><li>域名续期：域名到期前90天内，可免费续订。</li><li>教程笔记：简单的使用流程： <a href="https://blog.zrf.me/p/VPS8-Domains/">免费域名升级玩法：用VPS8让根域名支持CNAME等高级解析</a></li></ul><hr><h2 id="超值付费域名"><a href="#超值付费域名" class="headerlink" title="超值付费域名"></a>超值付费域名</h2><ul><li>如果你觉得免费的太折腾，想买个正经域名，下方是目前性价比比较高的国外注册商，部分支持支付宝，价格透明。</li></ul><h3 id="1-Google-Workspace-COM-¥14-年"><a href="#1-Google-Workspace-COM-¥14-年" class="headerlink" title="1. Google Workspace (.COM ¥14&#x2F;年)"></a>1. Google Workspace (.COM ¥14&#x2F;年)</h3><p><a href="https://blog.zrf.me/p/Google-Workspace-Domains">超低价注册.COM域名：Google Workspace土耳其区仅需14元&#x2F;年详细教程</a> 这是目前极低成本注册 .COM 等顶级域名的方法，在 Google Workspace 土耳其区注册域名，折合人民币仅需 <strong>14 元&#x2F;年</strong> (75 TRY)。<br><strong>特别注意：</strong></p><ol><li>IP 环境：注册过程中对 IP 纯净度要求极高，IP 不干净会导致手机号验证失败（无限循环或报错）。建议使用高质量干净的节点。</li><li>支付门槛：必须使用支持外币支付的信用卡。我博文写了一下兄弟成功或失败的一些卡种可参考。<a href="https://blog.zrf.me/p/Google-Workspace-Domains/#%E4%BA%8B%E5%89%8D%E5%87%86%E5%A4%87">卡种查看</a></li><li>核心操作（必看）：注册并购买域名后， <strong>务必去管理后台取消“商业标准版”订阅</strong> ，仅保留“域名注册”订阅，否则会产生高额的 Workspace 套件月租费，<strong>我还真遇到某位群友没有取消！！！</strong></li></ol><p><strong>注册地址：</strong> <a href="https://workspace.google.com/intl/zh-CN/">Google Workspace-点击前往</a></p><p><strong>可用后缀：</strong></p><ul><li>com、net、org（好多呢，自己看到时候）</li></ul><p><strong>平台规则：</strong></p><ul><li>域名续期：目前按年自动扣费（约 14 元&#x2F;年），<strong>不支持</strong> 一次性预付多年。后续需注意谷歌后续可能会调整定价规则。<strong>我还没到续订的时候，有些兄弟等看我能不能自动续订呢</strong></li><li>管理权限：域名实际由 Squarespace 托管，但账单在 Google Admin 管理。支持授权给其他 Squarespace 账号管理。</li><li>邮件服务：取消 Workspace 订阅后无原生邮箱功能，可以使用 <strong>Cloudflare 电子邮件路由</strong> 实现域名邮箱收件。</li></ul><hr><h3 id="2-Spaceship-COM-首年特惠¥20-数字-XYZ-特惠¥4-65-年"><a href="#2-Spaceship-COM-首年特惠¥20-数字-XYZ-特惠¥4-65-年" class="headerlink" title="2. Spaceship (.COM 首年特惠¥20 数字.XYZ 特惠¥4.65&#x2F;年)"></a>2. Spaceship (.COM 首年特惠¥20 数字.XYZ 特惠¥4.65&#x2F;年)</h3><p>现在平台有 .COM 的首年特惠与目前性价比最高的是 <strong>6位纯数字 .xyz 域名</strong>，单年仅需 <strong>¥4.65</strong>。允许一次性买断 10 年，总价不到 50 元人民币，是目前长期持有独立域名最划算的方案之一，支持 <strong>支付宝</strong> 付款。</p><p><strong>特别注意：</strong></p><ol><li>.COM 首年特惠：优惠码 COMPROS 可低至 <strong>约¥20</strong> （注意：使用优惠码时关闭代理，使用本地网络直连）。<br><img src="https://img.zrf.me/20260129055508389.webp" alt=".COM 首年特惠"></li><li>数字.XYZ 特惠：搜索 6 位纯数字（如 123456.xyz），价格会自动显示为 <strong>¥4.65&#x2F;年</strong>。也可以 <strong>直接拉满 10 年</strong>（先注册1年+后续费9年），总成本仅 <strong>¥46.5</strong> 。<br><img src="https://img.zrf.me/20260129055030055.webp" alt="数字.XYZ 特惠价格"></li></ol><p><strong>注册地址：</strong> <a href="https://www.spaceship.com/zh/domains/">Spaceship-点击前往</a> （.COM 首年特惠 优惠码：COMPROS）</p><p><strong>平台规则：</strong></p><ul><li>续费说明：<ul><li>.COM 首年特惠：仅限首年优惠，次年续费恢复原价（约 ¥70&#x2F;年）。</li><li>数字.XYZ 特惠：续费价格稳定在 <strong>¥4.65&#x2F;年</strong>，适合长期持有， <strong>注意：</strong> 看到有兄弟直接买十年，这样的操作是不行的， <strong>先注册1年+后续费9年</strong> 这样才可以啦。</li></ul></li></ul><hr><h3 id="3-NameSilo-top、lol、cyou-首年特惠-1"><a href="#3-NameSilo-top、lol、cyou-首年特惠-1" class="headerlink" title="3. NameSilo (top、lol、cyou 首年特惠$1 )"></a>3. NameSilo (top、lol、cyou 首年特惠$1 )</h3><p>NameSilo 是公认性价比极高的老牌注册商，以价格透明、无隐形消费著称。特别是 top、lol、cyou 等后缀，配合优惠码首年仅需 <strong>$1</strong> 左右，支持 <strong>支付宝</strong> 付款。</p><p><strong>特别注意：</strong></p><ol><li>优惠代码：结账时输入 Appstore ，订单金额可立减 <strong>$1.00</strong>（大部分便宜后缀折后仅需 $1 左右）。<br><img src="https://img.zrf.me/20260129063103506.webp" alt="NameSilo-优惠代码使用"><br><img src="https://img.zrf.me/20260129063113217.webp" alt="NameSilo-购买成功"></li><li>隐私保护：不同于部分平台需付费开启，NameSilo 提供 <strong>永久免费</strong> 的 WHOIS 隐私保护，注册后记得检查开启。</li></ol><p><strong>注册地址：</strong> <a href="https://www.namesilo.com/">NameSilo-点击前往</a> （优惠码：Appstore）</p><p><strong>可用后缀：(完美支持托管到 Cloudflare)</strong></p><ul><li>top、lol、cyou</li></ul><p><strong>平台规则：</strong></p><ul><li>域名续期： top、lol、cyou 等域名属于“首年特惠”，续费价格约 top域名 是 $4.88&#x2F;年，其他后缀域名自测。<br><img src="https://img.zrf.me/20260129065547042.webp" alt="NameSilo-top域名续期"></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;最新域名资源汇总：&quot;&gt;&lt;a href=&quot;#最新域名资源汇总：&quot; class=&quot;headerlink&quot; title=&quot;最新域名资源汇总：&quot;&gt;&lt;/a&gt;最新域名资源汇总：&lt;/h1&gt;&lt;p&gt;2026 年开始，今天给兄弟们整理了一波最新、好用的免费域名合集。对于咱们这种爱折腾</summary>
      
    
    
    
    <category term="资源中心" scheme="https://blog.zrf.me/categories/%E8%B5%84%E6%BA%90%E4%B8%AD%E5%BF%83/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="DNS" scheme="https://blog.zrf.me/tags/DNS/"/>
    
    <category term="CDN" scheme="https://blog.zrf.me/tags/CDN/"/>
    
    <category term="免费域名" scheme="https://blog.zrf.me/tags/%E5%85%8D%E8%B4%B9%E5%9F%9F%E5%90%8D/"/>
    
    <category term="域名注册" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%B3%A8%E5%86%8C/"/>
    
    <category term="域名托管" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%89%98%E7%AE%A1/"/>
    
    <category term="白嫖域名" scheme="https://blog.zrf.me/tags/%E7%99%BD%E5%AB%96%E5%9F%9F%E5%90%8D/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    <category term="Google Workspace" scheme="https://blog.zrf.me/tags/Google-Workspace/"/>
    
    <category term="US.KG" scheme="https://blog.zrf.me/tags/US-KG/"/>
    
    <category term="pp.ua" scheme="https://blog.zrf.me/tags/pp-ua/"/>
    
    <category term="资源分享" scheme="https://blog.zrf.me/tags/%E8%B5%84%E6%BA%90%E5%88%86%E4%BA%AB/"/>
    
  </entry>
  
  <entry>
    <title>用户花400元只为收一条验证码，成功后转头把赎回的域名赞助给我！</title>
    <link href="https://blog.zrf.me/p/Talk-20251211/"/>
    <id>https://blog.zrf.me/p/Talk-20251211/</id>
    <published>2025-12-11T15:55:27.000Z</published>
    <updated>2025-12-11T15:55:27.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="用户花400元只为收一条验证码，成功后转头把赎回的域名赞助给我！"><a href="#用户花400元只为收一条验证码，成功后转头把赎回的域名赞助给我！" class="headerlink" title="用户花400元只为收一条验证码，成功后转头把赎回的域名赞助给我！"></a>用户花400元只为收一条验证码，成功后转头把赎回的域名赞助给我！</h1><p>我一直公益维护着一个临时邮箱项目，不知不觉已经一年多了，大家有需要可以直接跳转使用：<a href="https://mail.zrf.me/">ZRF.ME | 临时邮件</a></p><p>昨天遇到个特别的用户，他之前用项目的邮箱绑定了重要账号，结果对应的域名过期两个月（还在赎回期），现在需要使用，却无法收验证码。了解到赎回要364元后，他二话不说转了400元让我帮忙操作，等顺利收到验证码、问题解决后，转头把赎回的域名赞助给我了！这波操作写下来记录一下～</p><h2 id="故事始末"><a href="#故事始末" class="headerlink" title="故事始末"></a>故事始末</h2><p>昨天晚上突然收到用户的消息：“你好，这个邮箱地址收不到验证码了吗？还有办法可以收到吗，是有点重要，🧧可以解决吗？”</p><p>我一看，瞬间明白，这个邮箱对应的域名已经在两个月前就过期了，自然收不到任何邮件。<br><img src="https://img.zrf.me/20251212031347527.webp" alt="即刻短文：过期时发了公告"></p><p>我如实跟他说明情况：“这个域名已经到期了，现在有两个选择：</p><ol><li>等域名删除后重新注册（70多块，但要等不确定的时间）；</li><li>现在赎回，要花364元（含一年续费），能立刻恢复收件。”</li></ol><p><img src="https://img.zrf.me/20251212031321292.webp" alt="域名赎回费用"></p><p>用户：“我以为200以内可以解决的！”</p><p>转头我问了问，也没人清楚赎回期域名回到域名池子中需要多久。</p><p>犹豫片刻后，用户：“选赎回！我不懂这些，我给你转钱吧，麻烦你操作一下，400就当辛苦费了！毕竟也白嫖你的了” 说完直接转了400元过来（实际我得到的是一个域名（70元）与36元赞赏，加起来是106元）。</p><p>接下来就是我的操作时间：</p><ol><li>支付赎回费：花364元完成域名赎回+一年续费（服务商规定，赎回后有效期按原到期时间续一年，不是从赎回日算）；<br><img src="https://img.zrf.me/20251212031119801.webp" alt="支付凭证"><br><img src="https://img.zrf.me/20251212031219892.webp" alt="域名有效期"></li><li>配置恢复：重新把域名配置到临时邮箱项目，调整MX记录和收件规则，确保能正常接收邮件；</li><li>通知用户：不到半小时就搞定了，告诉用户可以测试收件，他很快就收到了那封“价值400元”的验证码邮件。</li></ol><p>用户测试收件后很快回复“好了 感谢”，还主动提起自己踩坑的原因：“十月份的时候我上了一次，就忘记了”——原来他早就用过，只是后续没留意域名过期的问题，才闹了这场“风波”。</p><h2 id="案例中的解惑"><a href="#案例中的解惑" class="headerlink" title="案例中的解惑"></a>案例中的解惑</h2><p>借这个案例，还顺便解决了我之前一直困惑的两个问题！都是同账号、同域名的场景下：</p><ol><li><p>同Cloudflare账号重新托管域名，DNS名称服务器会变吗？<br><strong>答：会变！</strong><br>之前一直以为同账号重新添加域名，DNS名称服务器会和原来保持一致，结果这次域名赎回后实操发现：在同一个Cloudflare账号里重新托管，分配的DNS名称服务器和之前完全不一样了。<br>查了下相关信息，就算是同账号，重新添加域名时也可能触发名称服务器变动（比如遇到解析冲突、服务商预设规则等）。至于这次是不是因为“域名赎回状态”导致的，我暂时也没搞清楚，只能分享这个实操结论：<br><img src="https://img.zrf.me/20251212031522777.webp" alt="DNS名称服务器"></p></li><li><p>域名过期删除Cloudflare托管后，之前的Snippets资格会保留吗？<br><strong>答：不会保留，会直接消失！</strong><br>我这域名之前有Cloudflare Snippets功能资格，后来因为域名过期，就从Cloudflare里删除了托管。这次赎回域名重新托管回来后，资格直接没了，还挺可惜的～<br><img src="https://img.zrf.me/20251212031451412.webp" alt="Cloudflare Snippets"></p></li></ol><h2 id="临时邮箱的使用相关"><a href="#临时邮箱的使用相关" class="headerlink" title="临时邮箱的使用相关"></a>临时邮箱的使用相关</h2><ol><li>服务状态参考：关于 <strong>ZRF.ME | 临时邮件</strong> 的维护动态和可用情况，可查看 <a href="https://blog.zrf.me/p/65/#%E6%9C%8D%E5%8A%A1%E7%8A%B6%E6%80%81%E5%85%AC%E7%A4%BA">ZRF.ME | 临时邮件 服务状态公示</a>；</li><li>核心定位：<strong>ZRF.ME | 临时邮件</strong> 是“一次性隐私保护工具”，核心用途是避免真实邮箱泄露，仅适用于注册不重要的网站、接收垃圾邮件、测试账号、领取短期优惠券等临时场景；</li><li>绝对禁忌：<strong>切勿绑定支付、社交、工作、银行等重要账号</strong>！一方面，临时邮箱多为短时有效，部分会在几小时到24小时内自动失效，邮件内容可能被清除且无法恢复；另一方面，域名可能因维护成本、遗忘续费等原因过期，后续无法接收验证码；</li></ol><h2 id="认可是项目维护的最大动力"><a href="#认可是项目维护的最大动力" class="headerlink" title="认可是项目维护的最大动力"></a>认可是项目维护的最大动力</h2><p>作为一名非盈利临时邮箱项目的维护者，我做这个项目的初衷很简单：给大家提供一个免费、方便的临时在线工具，解决“不想泄露真实邮箱”的痛点。<a href="https://github.com/dreamhunter2333/cloudflare_temp_email">此项目由 Hunter Dream 开发并开源在 GitHub</a> 再次致谢！</p><p>平时遇到的大多是来问问题的朋友，这次这个用户是真给力！直接用自己的方式支持我——赞赏是认可我的服务，还把赎回的域名赞助给项目，更是给了我挺大的鼓励。</p><p>这个域名我已经重新配置到项目中，现在大家依然可以用这个域名注册临时邮箱，享受免费的收件服务——这也算是这位用户给所有使用者的一份“福利”吧！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;用户花400元只为收一条验证码，成功后转头把赎回的域名赞助给我！&quot;&gt;&lt;a href=&quot;#用户花400元只为收一条验证码，成功后转头把赎回的域名赞助给我！&quot; class=&quot;headerlink&quot; title=&quot;用户花400元只为收一条验证码，成功后转头把赎回的域名赞</summary>
      
    
    
    
    <category term="日常闲聊" scheme="https://blog.zrf.me/categories/%E6%97%A5%E5%B8%B8%E9%97%B2%E8%81%8A/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="日常" scheme="https://blog.zrf.me/tags/%E6%97%A5%E5%B8%B8/"/>
    
    <category term="办公" scheme="https://blog.zrf.me/tags/%E5%8A%9E%E5%85%AC/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="闲聊" scheme="https://blog.zrf.me/tags/%E9%97%B2%E8%81%8A/"/>
    
  </entry>
  
  <entry>
    <title>Cloudflare Snippets + SaaS：让任意域名“白嫖” 使用 Snippets VLESS 节点</title>
    <link href="https://blog.zrf.me/p/Cloudflare-Snippets-SaaS/"/>
    <id>https://blog.zrf.me/p/Cloudflare-Snippets-SaaS/</id>
    <published>2025-12-10T03:17:27.000Z</published>
    <updated>2026-02-25T21:20:37.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Cloudflare-Snippets-SaaS：让任意域名“白嫖”-使用-Snippets-VLESS-节点"><a href="#Cloudflare-Snippets-SaaS：让任意域名“白嫖”-使用-Snippets-VLESS-节点" class="headerlink" title="Cloudflare Snippets + SaaS：让任意域名“白嫖” 使用 Snippets VLESS 节点"></a>Cloudflare Snippets + SaaS：让任意域名“白嫖” 使用 Snippets VLESS 节点</h1><p>简单来说：咱们已经部署好的 Snippets 脚本，不管使用啥域名（不用转入 CF的都可以），都能直接调用它用起来～</p><p>这就意味着，只要你有 Snippets 功能，之前用它部署的 VLESS 不限流量节点或其他脚本，都可以借助 Cloudflare SaaS 功能，将其他域名直接接入使用！相当于一个节点直接变 100 个，爽翻～  （应该不会有人去折腾100个吧）</p><p>对于咱们个人用 Cloudflare 这功能，一般是拿来 <strong>保护源站</strong> （比如防攻击、隐藏真实服务器地址），或者给网站<strong>提速</strong>（靠CF的全球节点缓存资源）~ 都可以学习使用一下。</p><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h2><p>在开始之前，请确认你拥有以下资源：</p><ol><li>开通 SaaS 功能<ul><li>首次开启需绑定，需要验证信用卡或 PayPal（仅用于身份验证，前 100 个域名完全免费，不会扣费）。</li></ul></li><li>一个“工具人”域名（主域名）：<ul><li>本教程使用：<code>azrf.me</code>。拥有 <strong>Snippets</strong> 资格。</li></ul></li><li>一个“业务”域名（没有托管在 Cloudflare 中的域名，使用免费域名演示，已经托管在CF的域名也可以）：<ul><li>本教程使用：<code>cfcf6.cc.cd</code>。 我们将配置子域名 <code>Snippet.cfcf6.cc.cd</code>。通过 SaaS 技术来将他接入到 <strong>Snippets</strong> 中使用。</li></ul></li></ol><h2 id="第一步：配置-Cloudflare-回退源-Origin"><a href="#第一步：配置-Cloudflare-回退源-Origin" class="headerlink" title="第一步：配置 Cloudflare 回退源 (Origin)"></a>第一步：配置 Cloudflare 回退源 (Origin)</h2><p>我们需要在主域名 <code>azrf.me</code> 上配置一个入口，告诉 Cloudflare 流量该往哪里走。</p><ol><li>登录 Cloudflare，进入 <code>azrf.me</code> 的控制面板。</li><li>点击左侧菜单 <strong>DNS</strong> -&gt; <strong>记录</strong>。</li><li>添加一条 <strong>CNAME 记录</strong>：<ul><li><strong>名称</strong>: <code>snippet-origin</code> (完整域名为 <code>snippet-origin.azrf.me</code>)</li><li><strong>目标</strong>: <code>www.example.com</code></li><li><strong>代理状态</strong>: 必须开启 <strong>小黄云</strong></li><li><strong>解释</strong>：这里的 <code>www.example.com</code> 是防止回退源为空的兜底页面，填其他可访问的 HTTP 页面也可以。</li></ul></li></ol><p><img src="https://img.zrf.me/20251210061120267.webp" alt="设置回退源"></p><h2 id="第二步：部署-Snippets-片段规则-核心"><a href="#第二步：部署-Snippets-片段规则-核心" class="headerlink" title="第二步：部署 Snippets 片段规则(核心)"></a>第二步：部署 Snippets 片段规则(核心)</h2><h3 id="1-部署-Snippets-VLESS-项目"><a href="#1-部署-Snippets-VLESS-项目" class="headerlink" title="1. 部署 Snippets VLESS 项目"></a>1. 部署 Snippets VLESS 项目</h3><p>Snippets 是核心逻辑所在，所有的节点或脚本处理都在这里完成。<strong>（我写这默认你已经看过前面的教程，如果看的有点懵，可以回顾，下面也贴了地址。）</strong></p><ol><li><p>打开 <code>azrf.me</code> 面板，在左侧菜单栏找到 <strong>Snippets</strong> 选项并点击。</p></li><li><p>点击页面中的 <strong>创建片段</strong> 按钮，进入配置界面。</p></li><li><p><strong>代码区域</strong>：将你的 VLESS 代码粘贴进来。</p><blockquote><p>代码获取：往期教程已整理好，可跳转查看：<a href="https://blog.zrf.me/p/Cloudflare-Snippets/">Cloudflare Snippets 免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选</a></p></blockquote></li><li><p><strong>片段规则</strong>（设置触发条件）：</p><ul><li>第一栏选择：<strong>主机名</strong></li><li>第二栏选择：<strong>等于</strong></li><li>第三栏填写值：需绑定的 SaaS 域名（如 <code>Snippet.cfcf6.cc.cd</code>，或主域名 <code>snippet.azrf.me</code>）</li><li>解释：当访问请求的主机名匹配你填写的 SaaS 域名（或主域名）时，Cloudflare 会自动执行这段 VLESS 代码；比如填写 <code>Snippet.cfcf6.cc.cd</code> 后，访问该 SaaS 域名就会触发规则生效。<br><img src="https://img.zrf.me/20251211192145110.webp" alt="配置Snippets规则"></li></ul></li><li><p><strong>多SaaS域名批量配置</strong> （按需选择）：</p><ul><li><p><strong>手动添加</strong>（适合1-5个域名，操作直观）<br>重复步骤4的配置，每次在第三栏填写不同的 SaaS 域名，用 <code>or</code> 合并规则；</p></li><li><p><strong>表达式批量配置</strong>（适合5个以上域名，高效快捷）<br>无需重复手动添加，点击规则区域的「编辑表达式」，粘贴以下格式代码：<br><code>(http.host eq &quot;Snippet.xxx.com&quot;) or (http.host eq &quot;Snippet.yyy.com&quot;) or (http.host eq &quot;Snippet.zzz.com&quot;)</code><br>（按需替换域名，用 <code>or</code> 合并规则）<br><img src="https://img.zrf.me/20251211194524925.webp" alt="表达式批量配置"></p></li></ul></li><li><p>确认配置无误后，点击 <strong>保存并部署</strong> 即可生效。</p></li></ol><h3 id="2-部署-ECH-Workers-项目"><a href="#2-部署-ECH-Workers-项目" class="headerlink" title="2. 部署 ECH-Workers 项目"></a>2. 部署 ECH-Workers 项目</h3><p>既然 Cloudflare 提供了 5 个 Snippets 片段规则额度，用完 1 个部署 VLESS 后，剩余额度完全可以用来部署 ECH-Workers 代理（上一期详细讲过的免费不限流量方案），步骤和 VLESS 部署逻辑一致，跟着走就行：</p><ol><li>回到 <code>azrf.me</code> 面板的 <strong>Snippets</strong> 页面，再次点击 <strong>创建片段</strong>（新片段对应 ECH-Workers 服务，与 VLESS 分开独立配置）。</li><li><strong>代码区域</strong>：将你的 ECH-Workers 代码粘贴进来。<blockquote><p>代码获取：往期教程已整理好，可跳转查看：（代码获取：<a href="https://blog.zrf.me/p/Cloudflare-ECH-Workers/">免费不限流量！ECH-Workers 代理部署教程：Workers&#x2F;Snippets 双方案 + PC &#x2F; 安卓多端适配</a></p></blockquote></li><li><strong>片段规则</strong>（关键：触发主机名与 VLESS 区分开）：<ul><li>第一栏选择：<strong>主机名</strong></li><li>第二栏选择：<strong>等于</strong></li><li>第三栏填写值：ECH-Workers 专属的 SaaS 域名（如 <code>ech.cfcf6.cc.cd</code>，或自定义 <code>ech.azrf.me</code>，务必和 VLESS 的 <code>Snippet.xxx.com</code> 区分开）。</li><li>解释：通过不同的主机名触发不同片段，访问 <code>ech.cfcf6.cc.cd</code> 时执行 ECH-Workers 代码，访问 <code>Snippet.cfcf6.cc.cd</code> 时执行 VLESS 代码，互不冲突。（若想给 ECH-Workers 也绑定多个 SaaS 域名，格式参考 VLESS 的配置逻辑）</li></ul></li><li>确认代码和规则无误后，点击 <strong>保存并部署</strong>，ECH-Workers 服务即可独立生效。</li></ol><h2 id="第三步：配置-SaaS-自定义主机名"><a href="#第三步：配置-SaaS-自定义主机名" class="headerlink" title="第三步：配置 SaaS 自定义主机名"></a>第三步：配置 SaaS 自定义主机名</h2><p>这一步是“桥梁”，将你的接入域名连接到主域名上。</p><ol><li><p>在 <code>azrf.me</code> 面板左侧菜单找到 <strong>SSL&#x2F;TLS</strong> -&gt; <strong>自定义主机名</strong>。</p></li><li><p><strong>设置回退源</strong>：</p><ul><li>输入你在第一步设置的完整域名：<code>snippet-origin.azrf.me</code>。</li><li>点击 <strong>添加回退源</strong>，等待状态变为“有效”。</li></ul><p> <img src="https://img.zrf.me/20251210014609461.webp" alt="添加回退源"></p></li><li><p><strong>添加自定义主机名</strong>：</p><ul><li>点击 <strong>添加自定义主机名</strong> 按钮。</li><li><strong>自定义主机名</strong>：填写 <code>Snippet.cfcf6.cc.cd</code> (你的接入完整域名)。</li><li><strong>最低 TLS 版本</strong>：建议选  <strong>默认 (1.2)</strong> 。</li><li><strong>证书验证方法</strong>：选择 <strong>TXT 验证</strong>。</li><li><strong>自定义源服务器</strong>：<strong>关键！</strong> 这里务必填写 <code>snippet-origin.azrf.me</code>。然后点击 <strong>添加自定义主机名</strong></li><li>原理：这告诉 Cloudflare，“虽然用户访问的是 <code>Snippet.cfcf6.cc.cd</code>，但请你把请求转给 <code>snippet-origin.azrf.me</code> 处理”。这样一来，请求就会命中我们在第二步设置的 Snippets 触发规则。</li></ul><p> <img src="https://img.zrf.me/20251210023450981.webp" alt="添加自定义主机名详情"></p></li><li><p><strong>证书主机名状态变为有效</strong></p><ul><li>回到 Cloudflare 面板刷新，直到 <strong>证书状态</strong> 和 <strong>主机名状态</strong> 都变为 <strong>有效</strong>。一般在十分钟之内。之前挺快的可以60秒现在我看是十分钟。但一般要不到。</li><li>此时，访问 <code>https://Snippet.cfcf6.cc.cd</code>，应该能看到你的 Snippets 部署的 VLESS 节点页面的 <code>Hello World!</code> 伪装页面了。<br><img src="https://img.zrf.me/20251210024852254.webp" alt="证书主机名状态变为有效"></li></ul></li></ol><h2 id="第四步：接入域名-DNS-验证"><a href="#第四步：接入域名-DNS-验证" class="headerlink" title="第四步：接入域名 DNS 验证"></a>第四步：接入域名 DNS 验证</h2><p>Cloudflare 需要确认你真的拥有 <code>cfcf6.cc.cd</code> 这个域名。请登录该域名的 DNS 管理后台进行操作：（托管在 Cloudflare 的域名也可以设置 ）</p><h3 id="1-第三方-DNS（未托管在-Cloudflare-的域名-）"><a href="#1-第三方-DNS（未托管在-Cloudflare-的域名-）" class="headerlink" title="1. 第三方 DNS（未托管在 Cloudflare 的域名 ）"></a>1. 第三方 DNS（未托管在 Cloudflare 的域名 ）</h3><p><strong>1. 添加 CNAME 记录</strong></p><ul><li><strong>类型</strong>：<code>CNAME</code></li><li><strong>名称&#x2F;主机</strong>：<code>Snippet</code></li><li><strong>值</strong>：<code>snippet-origin.azrf.me</code></li></ul><p><img src="https://img.zrf.me/20251210024421463.webp" alt="添加 CNAME 记录"></p><p><strong>2. 添加 TXT 记录 (用于证书与主机名验证)</strong></p><ul><li><strong>类型</strong>：<code>TXT</code></li><li><strong>名称&#x2F;主机</strong>：<code>_acme-challenge.Snippet</code><blockquote><p><strong>注意</strong>：请仔细观察截图，不要复制 Cloudflare 给出的完整域名，需要自行删除后缀。通常只需要填写 <code>_acme-challenge.Snippet</code> (取决于你的 DNS 服务商是否自动补全域名后缀)。</p></blockquote></li><li><strong>值</strong>：(复制 CF 给出的长字符串，如图右边这个。)</li></ul><p><img src="https://img.zrf.me/20251210023726178.webp" alt="证书验证值获取"><br><img src="https://img.zrf.me/20251210024247958.webp" alt="DNS添加界面"></p><p><strong>3. 检查 DNS 记录</strong><br>全部设置完成后，你的 DNS 列表中应包含以下三条关键记录（如下图所示）：</p><p><img src="https://img.zrf.me/20251210024644353.webp" alt="DNS设置完成汇总"></p><h3 id="2-托管在-Cloudflare-的域名"><a href="#2-托管在-Cloudflare-的域名" class="headerlink" title="2. 托管在 Cloudflare 的域名"></a>2. 托管在 Cloudflare 的域名</h3><p><strong>1. 添加 CNAME 记录</strong></p><ul><li><strong>类型</strong>：<code>CNAME</code></li><li><strong>名称&#x2F;主机</strong>：<code>填写你的片段主机名前缀</code> 如：Snippet。</li><li><strong>值</strong>：<code>填写你的回退源域名</code></li><li><strong>代理状态</strong>: 开启 <strong>小黄云</strong></li><li><strong>证书与主机名验证</strong>：然后其他步骤与上方一致不再赘述。</li></ul><p><img src="https://img.zrf.me/20251211211105679.webp" alt="托管在 Cloudflare 的域名"></p><p><strong>4. 等待验证生效</strong><br>回到 Cloudflare 面板刷新，直到 <strong>证书状态</strong> 和 <strong>主机名状态</strong> 都变为 <strong>有效</strong>。</p><ul><li>提示：通常很快，几分钟内即可完成，这家免费域名是我见过很快的了～</li></ul><p>关键补充：证书和主机名生效后，一定要回到前面的「Snippets 片段规则配置」步骤（第二步第1点的片段规则&#x2F;第5点多域名配置），把这个新加的主机名（如 <code>Snippet.cfcf6.cc.cd</code>）添加到触发规则中，否则访问该域名无法触发 VLESS 代码！</p><p>完成规则添加后，访问 <code>https://Snippet.cfcf6.cc.cd</code>，你应该能看到 Snippet 部署的 VLESS 节点页面（例如显示 <code>Hello World!</code> 伪装内容）。</p><p><img src="https://img.zrf.me/20251210024852254.webp" alt="验证成功状态"></p><hr><h2 id="第五步：切换优选（可选）"><a href="#第五步：切换优选（可选）" class="headerlink" title="第五步：切换优选（可选）"></a>第五步：切换优选（可选）</h2><p>这是最后一步，将默认的 CF 线路替换为你挑选优选线路。</p><ul><li><p><strong>重要说明：此步骤需要你 SaaS域名 使用非CF上托管的域名才能进行优选</strong></p></li><li><p><strong>其他说明：该操作对咱们 VLESS 节点的部署和使用并无实际作用，纯粹是视觉上的优化（让域名解析看起来更 “绿”），不想折腾的小伙伴直接跳过即可！</strong></p></li></ul><p><strong>为什么不能一开始就填优选？</strong></p><blockquote><p><strong>必须先拿到 SSL 证书！</strong><br>Cloudflare 需要先验证回退源指向正确，才会签发证书。如果直接填优选，验证会失败，导致没有证书，节点无法连接。</p></blockquote><ol><li>回到 <code>cfcf6.cc.cd</code> 的 DNS 管理后台。</li><li><strong>修改刚才那条 CNAME 记录</strong>：<ul><li>找到主机名为 <code>Snippet</code> 的 CNAME 记录。</li><li><strong>将值修改为一个优选域名</strong>。</li><li>例如使用官方优选域名：<code>www.shopify.com</code>,<code>mfa.gov.ua</code>等，如果你有更好用的优选域名或优选 IP，可以自行替换。</li></ul></li><li><strong>保存生效</strong>。</li></ol><p><img src="https://img.zrf.me/20251210025610524.webp" alt="切换优选域名"></p><h2 id="最终效果流程总结"><a href="#最终效果流程总结" class="headerlink" title="最终效果流程总结"></a>最终效果流程总结</h2><ol><li><strong>极速连接</strong>：客户端连接 <code>Snippet.cfcf6.cc.cd</code>。</li><li><strong>优选解析</strong>：DNS 解析到你填写的优选域名（速度飞快）。</li><li><strong>边缘识别</strong>：Cloudflare 边缘节点收到请求，识别 Host 为 <code>Snippet.cfcf6.cc.cd</code>。</li><li><strong>内部路由</strong>：Cloudflare 将其映射到源站 <code>snippet-origin.azrf.me</code>。</li></ol><p>通过这种方式，你既隐藏了真实源站，又能让任意接入域名轻松接入 Cloudflare 的全球网络并享受优选加速！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Cloudflare-Snippets-SaaS：让任意域名“白嫖”-使用-Snippets-VLESS-节点&quot;&gt;&lt;a href=&quot;#Cloudflare-Snippets-SaaS：让任意域名“白嫖”-使用-Snippets-VLESS-节点&quot; class=&quot;h</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="隐私" scheme="https://blog.zrf.me/tags/%E9%9A%90%E7%A7%81/"/>
    
    <category term="科学上网" scheme="https://blog.zrf.me/tags/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="代理工具" scheme="https://blog.zrf.me/tags/%E4%BB%A3%E7%90%86%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Clash" scheme="https://blog.zrf.me/tags/Clash/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
  </entry>
  
  <entry>
    <title>免费不限流量！ECH-Workers 代理部署教程：Workers/Snippets 双方案 + PC / 安卓多端适配</title>
    <link href="https://blog.zrf.me/p/Cloudflare-ECH-Workers/"/>
    <id>https://blog.zrf.me/p/Cloudflare-ECH-Workers/</id>
    <published>2025-12-04T14:17:27.000Z</published>
    <updated>2026-02-25T21:20:37.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="免费不限流量！ECH-Workers-代理部署教程：Workers-Snippets-双方案-PC-安卓多端适配"><a href="#免费不限流量！ECH-Workers-代理部署教程：Workers-Snippets-双方案-PC-安卓多端适配" class="headerlink" title="免费不限流量！ECH-Workers 代理部署教程：Workers&#x2F;Snippets 双方案 + PC &#x2F; 安卓多端适配"></a>免费不限流量！ECH-Workers 代理部署教程：Workers&#x2F;Snippets 双方案 + PC &#x2F; 安卓多端适配</h1><p>在上一篇《<a href="https://blog.zrf.me/p/Cloudflare-Snippets/">Cloudflare Snippets 免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选</a>》中，不少朋友反馈没权限用 Snippets—— 这次直接上全员可用的 Workers 方案！</p><p>这是一个基于WebSocket的安全隧道代理项目，支持TCP转发、SOCKS5&#x2F;HTTP代理，还通过ECH技术隐藏SNI，进一步提升安全性。</p><p>本文教你用 Cloudflare Workers&#x2F;Snippets 部署 ECH-Workers，搭配专用客户端就能实现科学上网，就算 SNI 被墙也能稳定连接。下面简单介绍下核心用到的ECH协议——我也不太懂这个技术细节，据说能让网络连接更安全。</p><p><strong>ECH协议核心作用简介</strong></p><blockquote><ul><li>ECH协议（Encrypted Client Hello，加密客户端问候）是Cloudflare推出的加密技术，其核心作用是隐藏你的访问域名（SNI），具体原理与优势如下：</li><li>在传统HTTPS连接中，SNI（服务器名称指示）字段以明文形式传输，这就导致中间网络（如运营商、网关等）能轻易识别你所访问的具体站点，存在隐私泄露和针对性封锁的风险。</li><li>而ECH协议会将SNI信息加密后再发送，中间网络仅能检测到你与Cloudflare建立了连接，却无法解析出你实际访问的目标域名。这一特性大幅提升了网络访问的隐私安全性与抗封锁能力。</li><li>简单来说：开启ECH后，别人只知道你连了Cloudflare，却不知道你具体连的是哪个站点～</li><li>详细说明可查看 Cloudflare 官方文档：<a href="https://developers.cloudflare.com/ssl/edge-certificates/ech/">ECH协议</a></li><li>另外可以通过 <a href="https://www.cloudflare.com/zh-cn/ssl/encrypted-sni/#results">浏览体验安全检查</a> 测试自身环境——目前我的测试结果里，除了“安全 SNI”未通过，其余项均正常。不过查了一圈，似乎需要开启浏览器的特定功能才能触发，但暂时没找到对应的设置方式。</li></ul></blockquote><h2 id="一、-ECH-Workers-服务部署"><a href="#一、-ECH-Workers-服务部署" class="headerlink" title="一、 ECH-Workers 服务部署"></a>一、 ECH-Workers 服务部署</h2><ul><li>ECH-Workers 部署方式,可使用  Cloudflare Snippets 与 Cloudflare worker 两种方式进行部署。下方是部署的代码。</li><li>群内提供我已部署好的无限流量 Snippets 版 ECH 服务地址进行体验，可直接加群获取。 <strong>建议自行部署</strong></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">WS_READY_STATE_OPEN</span> = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">WS_READY_STATE_CLOSING</span> = <span class="number">2</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">CF_FALLBACK_IPS</span> = [<span class="string">&#x27;[2a00:1098:2b::1:6815:5881]&#x27;</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 复用 TextEncoder，避免重复创建</span></span><br><span class="line"><span class="keyword">const</span> encoder = <span class="keyword">new</span> <span class="title class_">TextEncoder</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123; connect &#125; <span class="keyword">from</span> <span class="string">&#x27;cloudflare:sockets&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">fetch</span>(<span class="params">request, env, ctx</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> token = <span class="string">&#x27;&#x27;</span>; <span class="comment">// 这是密码，不写则无密码</span></span><br><span class="line">      <span class="keyword">const</span> upgradeHeader = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Upgrade&#x27;</span>);</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (!upgradeHeader || upgradeHeader.<span class="title function_">toLowerCase</span>() !== <span class="string">&#x27;websocket&#x27;</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title function_">URL</span>(request.<span class="property">url</span>).<span class="property">pathname</span> === <span class="string">&#x27;/&#x27;</span> </span><br><span class="line">          ? <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;WebSocket Proxy Server&#x27;</span>, &#123; <span class="attr">status</span>: <span class="number">200</span> &#125;)</span><br><span class="line">          : <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Expected WebSocket&#x27;</span>, &#123; <span class="attr">status</span>: <span class="number">426</span> &#125;);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (token &amp;&amp; request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Sec-WebSocket-Protocol&#x27;</span>) !== token) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Unauthorized&#x27;</span>, &#123; <span class="attr">status</span>: <span class="number">401</span> &#125;);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> [client, server] = <span class="title class_">Object</span>.<span class="title function_">values</span>(<span class="keyword">new</span> <span class="title class_">WebSocketPair</span>());</span><br><span class="line">      server.<span class="title function_">accept</span>();</span><br><span class="line">      </span><br><span class="line">      <span class="title function_">handleSession</span>(server).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> <span class="title function_">safeCloseWebSocket</span>(server));</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 修复 spread 类型错误</span></span><br><span class="line">      <span class="keyword">const</span> responseInit = &#123;</span><br><span class="line">        <span class="attr">status</span>: <span class="number">101</span>,</span><br><span class="line">        <span class="attr">webSocket</span>: client</span><br><span class="line">      &#125;;</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> (token) &#123;</span><br><span class="line">        responseInit.<span class="property">headers</span> = &#123; <span class="string">&#x27;Sec-WebSocket-Protocol&#x27;</span>: token &#125;;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="literal">null</span>, responseInit);</span><br><span class="line">      </span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(err.<span class="title function_">toString</span>(), &#123; <span class="attr">status</span>: <span class="number">500</span> &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">handleSession</span>(<span class="params">webSocket</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> remoteSocket, remoteWriter, remoteReader;</span><br><span class="line">  <span class="keyword">let</span> isClosed = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">cleanup</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (isClosed) <span class="keyword">return</span>;</span><br><span class="line">    isClosed = <span class="literal">true</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">try</span> &#123; remoteWriter?.<span class="title function_">releaseLock</span>(); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">    <span class="keyword">try</span> &#123; remoteReader?.<span class="title function_">releaseLock</span>(); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">    <span class="keyword">try</span> &#123; remoteSocket?.<span class="title function_">close</span>(); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">    </span><br><span class="line">    remoteWriter = remoteReader = remoteSocket = <span class="literal">null</span>;</span><br><span class="line">    <span class="title function_">safeCloseWebSocket</span>(webSocket);</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">pumpRemoteToWebSocket</span> = <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">while</span> (!isClosed &amp;&amp; remoteReader) &#123;</span><br><span class="line">        <span class="keyword">const</span> &#123; done, value &#125; = <span class="keyword">await</span> remoteReader.<span class="title function_">read</span>();</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (done) <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">if</span> (webSocket.<span class="property">readyState</span> !== <span class="variable constant_">WS_READY_STATE_OPEN</span>) <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">if</span> (value?.<span class="property">byteLength</span> &gt; <span class="number">0</span>) webSocket.<span class="title function_">send</span>(value);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (!isClosed) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123; webSocket.<span class="title function_">send</span>(<span class="string">&#x27;CLOSE&#x27;</span>); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">      <span class="title function_">cleanup</span>();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">parseAddress</span> = (<span class="params">addr</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (addr[<span class="number">0</span>] === <span class="string">&#x27;[&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> end = addr.<span class="title function_">indexOf</span>(<span class="string">&#x27;]&#x27;</span>);</span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">host</span>: addr.<span class="title function_">substring</span>(<span class="number">1</span>, end),</span><br><span class="line">        <span class="attr">port</span>: <span class="built_in">parseInt</span>(addr.<span class="title function_">substring</span>(end + <span class="number">2</span>), <span class="number">10</span>)</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> sep = addr.<span class="title function_">lastIndexOf</span>(<span class="string">&#x27;:&#x27;</span>);</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      <span class="attr">host</span>: addr.<span class="title function_">substring</span>(<span class="number">0</span>, sep),</span><br><span class="line">      <span class="attr">port</span>: <span class="built_in">parseInt</span>(addr.<span class="title function_">substring</span>(sep + <span class="number">1</span>), <span class="number">10</span>)</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">isCFError</span> = (<span class="params">err</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> msg = err?.<span class="property">message</span>?.<span class="title function_">toLowerCase</span>() || <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">return</span> msg.<span class="title function_">includes</span>(<span class="string">&#x27;proxy request&#x27;</span>) || </span><br><span class="line">           msg.<span class="title function_">includes</span>(<span class="string">&#x27;cannot connect&#x27;</span>) || </span><br><span class="line">           msg.<span class="title function_">includes</span>(<span class="string">&#x27;cloudflare&#x27;</span>);</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">connectToRemote</span> = <span class="keyword">async</span> (<span class="params">targetAddr, firstFrameData</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; host, port &#125; = <span class="title function_">parseAddress</span>(targetAddr);</span><br><span class="line">    <span class="keyword">const</span> attempts = [<span class="literal">null</span>, ...<span class="variable constant_">CF_FALLBACK_IPS</span>];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; attempts.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        remoteSocket = <span class="title function_">connect</span>(&#123;</span><br><span class="line">          <span class="attr">hostname</span>: attempts[i] || host,</span><br><span class="line">          port</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (remoteSocket.<span class="property">opened</span>) <span class="keyword">await</span> remoteSocket.<span class="property">opened</span>;</span><br><span class="line"></span><br><span class="line">        remoteWriter = remoteSocket.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        remoteReader = remoteSocket.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 发送首帧数据</span></span><br><span class="line">        <span class="keyword">if</span> (firstFrameData) &#123;</span><br><span class="line">          <span class="keyword">await</span> remoteWriter.<span class="title function_">write</span>(encoder.<span class="title function_">encode</span>(firstFrameData));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        webSocket.<span class="title function_">send</span>(<span class="string">&#x27;CONNECTED&#x27;</span>);</span><br><span class="line">        <span class="title function_">pumpRemoteToWebSocket</span>();</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">      &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        <span class="comment">// 清理失败的连接</span></span><br><span class="line">        <span class="keyword">try</span> &#123; remoteWriter?.<span class="title function_">releaseLock</span>(); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">        <span class="keyword">try</span> &#123; remoteReader?.<span class="title function_">releaseLock</span>(); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">        <span class="keyword">try</span> &#123; remoteSocket?.<span class="title function_">close</span>(); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">        remoteWriter = remoteReader = remoteSocket = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 如果不是 CF 错误或已是最后尝试，抛出错误</span></span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isCFError</span>(err) || i === attempts.<span class="property">length</span> - <span class="number">1</span>) &#123;</span><br><span class="line">          <span class="keyword">throw</span> err;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  webSocket.<span class="title function_">addEventListener</span>(<span class="string">&#x27;message&#x27;</span>, <span class="title function_">async</span> (event) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (isClosed) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> data = event.<span class="property">data</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">typeof</span> data === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (data.<span class="title function_">startsWith</span>(<span class="string">&#x27;CONNECT:&#x27;</span>)) &#123;</span><br><span class="line">          <span class="keyword">const</span> sep = data.<span class="title function_">indexOf</span>(<span class="string">&#x27;|&#x27;</span>, <span class="number">8</span>);</span><br><span class="line">          <span class="keyword">await</span> <span class="title function_">connectToRemote</span>(</span><br><span class="line">            data.<span class="title function_">substring</span>(<span class="number">8</span>, sep),</span><br><span class="line">            data.<span class="title function_">substring</span>(sep + <span class="number">1</span>)</span><br><span class="line">          );</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (data.<span class="title function_">startsWith</span>(<span class="string">&#x27;DATA:&#x27;</span>)) &#123;</span><br><span class="line">          <span class="keyword">if</span> (remoteWriter) &#123;</span><br><span class="line">            <span class="keyword">await</span> remoteWriter.<span class="title function_">write</span>(encoder.<span class="title function_">encode</span>(data.<span class="title function_">substring</span>(<span class="number">5</span>)));</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (data === <span class="string">&#x27;CLOSE&#x27;</span>) &#123;</span><br><span class="line">          <span class="title function_">cleanup</span>();</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> (data <span class="keyword">instanceof</span> <span class="title class_">ArrayBuffer</span> &amp;&amp; remoteWriter) &#123;</span><br><span class="line">        <span class="keyword">await</span> remoteWriter.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(data));</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123; webSocket.<span class="title function_">send</span>(<span class="string">&#x27;ERROR:&#x27;</span> + err.<span class="property">message</span>); &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">      <span class="title function_">cleanup</span>();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  webSocket.<span class="title function_">addEventListener</span>(<span class="string">&#x27;close&#x27;</span>, cleanup);</span><br><span class="line">  webSocket.<span class="title function_">addEventListener</span>(<span class="string">&#x27;error&#x27;</span>, cleanup);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">safeCloseWebSocket</span>(<span class="params">ws</span>) &#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (ws.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_OPEN</span> || </span><br><span class="line">        ws.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_CLOSING</span>) &#123;</span><br><span class="line">      ws.<span class="title function_">close</span>(<span class="number">1000</span>, <span class="string">&#x27;Server closed&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">catch</span> &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Cloudflare-Snippets-部署"><a href="#Cloudflare-Snippets-部署" class="headerlink" title="Cloudflare Snippets 部署"></a>Cloudflare Snippets 部署</h3><ol><li><p>若选择 Cloudflare Snippets 部署，可参考教程：<a href="https://blog.zrf.me/p/Cloudflare-Snippets/">Cloudflare Snippets 免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选</a> </p></li><li><p>无需重复执行教程内所有步骤，仅需跳过「第二步：设置 UUID (可选)」，其余步骤完全一致，部署代码直接使用本文上方的 ECH-Workers 代码即可。</p></li><li><p>部署完成后，需将设置好的主机名整理为「域名:443」格式（示例：ech.zrf.me:443），该地址即为后续需使用的服务地址。</p></li></ol><h3 id="Cloudflare-worker-部署"><a href="#Cloudflare-worker-部署" class="headerlink" title="Cloudflare worker 部署"></a>Cloudflare worker 部署</h3><p>此方案最为实用，即使 Cloudflare 默认分配的 <code>xxx.workers.dev</code> 域名在中国大陆被阻断，配合 ECH 客户端也能实现无感直连。</p><ol><li><p>新建 Worker 服务，名称可自定义（本文使用默认名称），完成创建后点击「部署」；<br><img src="https://img.zrf.me/20251204235642745.webp" alt="新建 Worker 服务"><br><img src="https://img.zrf.me/20251204235751902.webp" alt="点击「部署」"></p></li><li><p>部署完成后，点击右上角「编辑代码」；<br><img src="https://img.zrf.me/20251204235852419.webp" alt="点击右上角「编辑代码」"></p></li><li><p>进入代码编辑界面，清空编辑器原有代码，粘贴本文上方的 ECH-Workers 代码，点击「保存并部署」；<br><img src="https://img.zrf.me/20251205000121872.webp" alt="点击「保存并部署」"></p></li><li><p>获取服务地址，返回 Worker 概览页面，复制 Cloudflare 分配的默认域名（格式如 <code>xxx.workers.dev</code>）。</p></li></ol><ul><li><strong>注意</strong>：虽然该域名在浏览器中直接访问可能无法打开（被墙），但不要担心，这正是 ECH 技术的优点之一。</li><li><strong>地址格式</strong>：请在域名后加上端口 <code>:443</code>。<ul><li>示例：<code>crimson-art-0bbc.zrfme.workers.dev:443</code></li></ul></li></ul><p><img src="https://img.zrf.me/20251205003825573.webp" alt="获取服务地址"></p><h2 id="二、-客户端工具下载"><a href="#二、-客户端工具下载" class="headerlink" title="二、 客户端工具下载"></a>二、 客户端工具下载</h2><p>请加入下方 Telegram 社群获取专用客户端（群文件中包含 PC 版和 Android 版）：</p><ul><li><strong>下载地址</strong> ：<a href="https://t.me/lsmoo">点击加入电报社群 (@lsmoo)</a></li><li><strong>软件说明</strong> ：<ul><li><strong>PC 版 (Win)</strong> ：由群内大佬 <a href="https://t.me/JPCCF">@CCF</a> 基于 <a href="https://t.me/CF_NAT">CF_NAT</a> 开源项目修改制作。</li><li><strong>Android 版</strong> ：使用原版 APK。</li><li><em>注：目前暂无 iOS 版本。</em></li></ul></li></ul><p><img src="https://img.zrf.me/20251205003808539.webp" alt="群文件指引"></p><h2 id="三、-Android-手机版使用教程"><a href="#三、-Android-手机版使用教程" class="headerlink" title="三、 Android 手机版使用教程"></a>三、 Android 手机版使用教程</h2><p>下载安装后，请按照以下逻辑填写关键信息：</p><ol><li><p><strong>服务器地址</strong> ：<br>填写第一步中获取的 Workers 地址，格式必须为 <code>域名:443</code>。</p><ul><li><em>示例</em>：<code>crimson-art-0bbc.zrfme.workers.dev:443</code></li></ul></li><li><p><strong>优选 IP (核心步骤)</strong> ：</p><ul><li><strong>情况 A</strong>（使用 workers.dev 默认域名）：<strong>必须填写</strong> Cloudflare 的优选 IP。因为默认域名DNS被污染，我们需要强制指定一个干净的 IP 进行握手。优选获取：<a href="https://blog.zrf.me/p/cf/">CloudFlare 优选方案汇总 持续更新中</a></li><li><strong>情况 B</strong>（使用自定义域名）：如果您的 Worker 绑定了自定义域名且该域名未被墙，不写优选IP也可直连，看自己使用情况而定。</li><li>我图中所用 <strong>优选IP</strong> 不保证能长时间使用。</li></ul></li><li><p><strong>身份令牌 (可选步骤)</strong> ：</p><ul><li>既安卓软件中的 <strong>身份令牌</strong> ，PC软件中的 <strong>TOKEN</strong> ，密码内容由你设置，在代码中修改此处设置<code>const token = &#39;blog.zrf.me&#39;; </code> ，如设置需在手机端或电脑端进行填写。</li></ul></li><li><p><strong>启动代理</strong> ：<br>根据需求选择「全局模式」或「分应用代理」，点击底部按钮启动即可。</p></li></ol><p><img src="https://img.zrf.me/20251205004606003.webp" alt="安卓版配置图解"></p><h2 id="四、-PC-电脑版配置教程"><a href="#四、-PC-电脑版配置教程" class="headerlink" title="四、 PC 电脑版配置教程"></a>四、 PC 电脑版配置教程</h2><p>PC 端采用 <strong>“ECH GUI + v2rayN”</strong> 的组合模式。</p><ol><li><p>解压群文件内的 PC 版压缩包，双击运行 <strong>ech-win-gui.exe</strong> ；<br><img src="https://img.zrf.me/20251205005452853.webp" alt="ech-win-gui.exe"></p></li><li><p>请按以下配置项要求，准确填写相关内容（图示参考见对应位置）<br><img src="https://img.zrf.me/20251205013455642.webp" alt="配置项"></p><table><thead><tr><th align="left">必填配置项</th><th align="left">填写说明</th><th align="left">示例值</th></tr></thead><tbody><tr><td align="left"><strong>服务地址</strong></td><td align="left">你的 Workers 域名 + 端口</td><td align="left">Workers部署  <code>xxx.workers.dev:443</code> 或 Snippets部署 <code>ech.zrf.me:443</code></td></tr><tr><td align="left"><strong>监听地址</strong></td><td align="left">本地转发端口（建议默认）</td><td align="left"><code>127.0.0.1:30000</code></td></tr><tr><td align="left"><strong>优选IP&#x2F;域名</strong></td><td align="left"><strong>必填</strong> ，筛选后的 优选CF IP</td><td align="left"><code>104.16.x.x</code> 或优选域名，优选获取：<a href="https://blog.zrf.me/p/cf/">CloudFlare 优选方案汇总 持续更新中</a></td></tr><tr><td align="left"><strong>ECH域名</strong></td><td align="left">固定值，勿改</td><td align="left"><code>cloudflare-ech.com</code></td></tr><tr><td align="left"><strong>DOH服务器</strong></td><td align="left"><strong>必填</strong></td><td align="left"><code>dns.alidns.com/dns-query</code></td></tr><tr><td align="left"><strong>TOKEN 配置</strong></td><td align="left"><strong>可选</strong> ，既安卓软件中的 <strong>身份令牌</strong> ，PC软件中的 <strong>TOKEN</strong> ，密码内容由你设置</td><td align="left">在代码中修改此处设置<code>const token = &#39;blog.zrf.me&#39;; </code></td></tr></tbody></table></li><li><p>全部填写完毕后，我们打开 v2rayN 软件 或 NekoBox 这类的可以自由编辑节点的软件。我以 v2rayN 为例。点击左上角「配置项」→「添加 SOCKS」<br><img src="https://img.zrf.me/20251205014314226.webp" alt="「添加 SOCKS」"></p></li><li><p>填写 SOCKS 配置项：（图示参考见对应位置）<br><img src="https://img.zrf.me/20251205033851108.webp" alt="填写 SOCKS 配置项"></p><table><thead><tr><th>必填配置项</th><th>内容</th></tr></thead><tbody><tr><td>名称</td><td>（随意填写）</td></tr><tr><td>地址</td><td>127.0.0.1</td></tr><tr><td>端口</td><td>30000</td></tr></tbody></table></li><li><p>点击「确定」完成创建，随后点击「启动代理」，右键选择新建的节点设为「活动」，测试延迟显示正常后，开启「自动配置系统代理」即可使用。<br><img src="https://img.zrf.me/20251205015847278.webp" alt="连接成功"></p></li><li><p>好了，完结撒花。我只是简单写个流程图，大佬勿喷。</p></li></ol><h2 id="致谢与来源说明"><a href="#致谢与来源说明" class="headerlink" title="致谢与来源说明"></a>致谢与来源说明</h2><p>特别感谢群内大佬 <a href="https://t.me/JPCCF">@CCF</a> 基于 <a href="https://t.me/CF_NAT">CF_NAT</a> 开源项目，定制修改了适配本教程的 PC 端专用客户端，让部署后的使用更便捷；同时感谢 <a href="https://t.me/CF_NAT">CF_NAT</a> 频道提供的开源核心技术支持。<br>本文相关工具、技术方案均来源于：</p><ul><li>客户端开发：<a href="https://t.me/JPCCF">CCF</a>（定制修改）</li><li>核心开源项目：<a href="https://t.me/CF_NAT">CF_NAT</a></li><li>ECH 协议技术支持：<a href="https://developers.cloudflare.com/ssl/edge-certificates/ech/">Cloudflare 官方文档</a></li></ul><p>工具下载：如需获取工具或交流技术，可加入电报社群：<a href="https://t.me/lsmoo">点击加入电报社群 (@lsmoo)</a>（群文件含 PC&#x2F;安卓客户端）<br>额外福利：群内提供我已部署好的无限流量 Snippets 版 ECH 服务地址，可直接加群获取使用；</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;免费不限流量！ECH-Workers-代理部署教程：Workers-Snippets-双方案-PC-安卓多端适配&quot;&gt;&lt;a href=&quot;#免费不限流量！ECH-Workers-代理部署教程：Workers-Snippets-双方案-PC-安卓多端适配&quot; class=</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="隐私" scheme="https://blog.zrf.me/tags/%E9%9A%90%E7%A7%81/"/>
    
    <category term="科学上网" scheme="https://blog.zrf.me/tags/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="代理工具" scheme="https://blog.zrf.me/tags/%E4%BB%A3%E7%90%86%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Clash" scheme="https://blog.zrf.me/tags/Clash/"/>
    
    <category term="CDN" scheme="https://blog.zrf.me/tags/CDN/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
  </entry>
  
  <entry>
    <title>踩坑预警：支付宝众安碎屏险+京修店双重避坑，第一次拆机的搞笑翻车现场</title>
    <link href="https://blog.zrf.me/p/Talk-20251124/"/>
    <id>https://blog.zrf.me/p/Talk-20251124/</id>
    <published>2025-11-24T02:17:27.000Z</published>
    <updated>2026-02-25T21:20:37.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="踩坑预警：支付宝众安碎屏险-京修店双重避坑，第一次拆机的搞笑翻车现场"><a href="#踩坑预警：支付宝众安碎屏险-京修店双重避坑，第一次拆机的搞笑翻车现场" class="headerlink" title="踩坑预警：支付宝众安碎屏险+京修店双重避坑，第一次拆机的搞笑翻车现场"></a>踩坑预警：支付宝众安碎屏险+京修店双重避坑，第一次拆机的搞笑翻车现场</h1><p>满心以为买了4年的碎屏险能在手机碎屏时派上用场，结果先遭保险公司“套路拒赔”，后遇京东维修“劣质服务”——这波连环踩坑的经历，我必须写出来给大家避避雷！</p><h2 id="一、手机碎屏后，4年碎屏险直接成“摆设”？"><a href="#一、手机碎屏后，4年碎屏险直接成“摆设”？" class="headerlink" title="一、手机碎屏后，4年碎屏险直接成“摆设”？"></a>一、手机碎屏后，4年碎屏险直接成“摆设”？</h2><p>事情要从手机摔碎屏说起。在医院陪护时，手机不小心从病床滑落，屏幕左下角磕出一小块破损，不算严重但影响使用。想起自己在支付宝上连续买了4年众安保险的碎屏险（服务商是“马上修”），当即在支付宝发起理赔。</p><p><strong>最下角碎屏状态(得感谢顺丰老哥，差点没这张图了，找老哥要的)</strong><br><img src="https://img.zrf.me/20251124200444893.webp" alt="碎屏状态"></p><p><strong>首次投保时间截图（按月支付，每月支付宝自动扣款，一年93块钱左右，四年不就快四百了）：</strong><br><img src="https://img.zrf.me/20251124172723774.webp" alt="首次投保时间截图"></p><table><thead><tr><th align="left">缴费次数</th><th align="left">缴费&#x2F;周期起始时间</th><th align="left">保障期范围</th><th align="left">备注</th></tr></thead><tbody><tr><td align="left">第1次</td><td align="left">2022年5月</td><td align="left">2022.05-2023.05</td><td align="left">首次参保</td></tr><tr><td align="left">第2次</td><td align="left">2023年5月</td><td align="left">2023.05-2024.05</td><td align="left">第一次续保</td></tr><tr><td align="left">第3次</td><td align="left">2024年5月</td><td align="left">2024.05-2025.05</td><td align="left">第二次续保</td></tr><tr><td align="left">第4次</td><td align="left">2025年5月</td><td align="left">2025.05-2026.06</td><td align="left">第三次续保</td></tr></tbody></table><p>按客服要求，我把手机通过顺丰寄了过去，本以为理赔会顺理成章，结果等来的是直接拒修通知。</p><p>拒保理由：“手机存在非官方拆修记录，不在保障范围内”。<br><img src="https://img.zrf.me/20251124181802223.webp" alt="拒保理由"></p><p>我一头雾水：手机只在小米之家做过官方维修——之前换电池时，售后同步帮我更换了破损的后盖（后盖是我在闲鱼买的），全程都是官方操作，还能提供维修凭证。可“马上修”却咬死“私自更换后盖”，坚持拒修。</p><p>咨询我的一个律师朋友后，他明确告知这属于不合理拒保，并给了我具体的投诉方向和沟通话术。我立刻向支付宝客服投诉维权，等了五六天，<strong>中间有多次交涉</strong>，众安终于有了回应，可给出的第一个方案直接让我气笑—— <strong>只愿意赔付400元</strong> ！ <strong>（那如果不是我这么去较真。我这钱不是就打水漂了）</strong></p><p>我当时误以为自己买了3年保险（后来整理记录才发现是4年），直接回怼：“我3年保费都花了三四百，你这赔付还不够保费钱！”拒绝后，对方才松口，说可以让我线下自行维修，950元内报销（小米原厂更换费用就是950元，只是机型较久暂无物料）。<strong>现在想来，我从这一步就彻底错了——其实早在联系小米官方时，就已确认线上线下均无对应维修物料，当时我本该直接申请直接报销理赔金额、无需维修，而非转而通过淘宝、京东等非官方渠道自行维修，不然也不会踩下面说的京东的大坑。</strong></p><p>后来我才知道，众安给其他客户直接赔付900元现金，合着是看我维权态度坚决才一步步“升级”方案，这套路也太明显了！保险公司的赔付标准完全不透明，<strong>能少赔就少赔</strong>，<strong>能忽悠就忽悠</strong>，丝毫没有长期投保客户该有的保障待遇。</p><ul><li>某平台一个小伙伴的同款手机与保险公司<br><img src="https://img.zrf.me/20251124191124580.webp" alt="某平台一个小伙伴的同款手机与保险公司"></li></ul><h2 id="二、京东维修踩大坑：650元换屏，越修越差还维权无门"><a href="#二、京东维修踩大坑：650元换屏，越修越差还维权无门" class="headerlink" title="二、京东维修踩大坑：650元换屏，越修越差还维权无门"></a>二、京东维修踩大坑：650元换屏，越修越差还维权无门</h2><p>既然原厂没物料，我就联系了京东维修，对方报价650元，承诺更换屏幕总成（外屏+内屏）。想着京东是大平台，应该靠谱，结果这才是踩坑的开始。<strong>大家避坑！这个“京修服务官方旗舰店”真的要慎选！</strong></p><p>先给大家贴一下我购买维修服务的订单截图：<br><img src="https://img.zrf.me/20251124210053839.webp" alt="京东维修订单截图"></p><p>下单前我特意问客服：“国产屏是哪个厂家的？华星光电还是其他品牌？”<br>客服只含糊其辞说“就是国产屏”，压根拿不出生产厂家信息，现在才知道，这就是劣质配件的前兆——不少网友也吐槽京东维修存在“以次充好”的问题，用无品牌劣质屏冒充合格配件，维修后频繁出问题。</p><ul><li>等手机寄回来，我当场傻眼，问题比修之前还多：</li></ul><ol><li><p>屏幕上有两个明显的圆点，像坏点一样，看着十分明显，我觉得这就是瑕疵屏幕。<br><img src="https://img.zrf.me/20251124173509938.webp" alt="维修问题佐证截图1"><br><img src="https://img.zrf.me/20251124173606462.webp" alt="维修问题佐证截图2"></p></li><li><p><strong>调节刷新率时，屏幕色差特别明显</strong>，还会自行掉刷新率，颜色忽明忽暗（肉眼非常明显，但拍照很难拍出来）；</p></li><li><p>更离谱的是指纹识别锁屏变得不灵敏，之前一触即开，现在反复按压好几次才能解锁，甚至出现指纹失败次数上限，需要图形解锁（偶发）；</p></li><li><p>联系京东维修客服反馈，对方居然轻飘飘一句“国产屏就是这样”，完全没有解决问题的态度，这和其他用户遇到的“售后扯皮、拒不负责”如出一辙。</p></li><li><p>无奈之下只能接受这个结果，650元维修费用虽然由众安保险报销，但原本的16+512主力机，硬生生被修得不如之前，只能沦为备用机。</p></li></ol><p><strong>京东作为平台，对第三方维修服务商的监管严重缺位，所谓的“维修保障”根本就是空话，花了钱还得受气。</strong></p><h2 id="三、两波踩坑后，总结的“避坑指南”"><a href="#三、两波踩坑后，总结的“避坑指南”" class="headerlink" title="三、两波踩坑后，总结的“避坑指南”"></a>三、两波踩坑后，总结的“避坑指南”</h2><h3 id="（一）投保碎屏险：警惕“套路赔付”，守住维权底线"><a href="#（一）投保碎屏险：警惕“套路赔付”，守住维权底线" class="headerlink" title="（一）投保碎屏险：警惕“套路赔付”，守住维权底线"></a>（一）投保碎屏险：警惕“套路赔付”，守住维权底线</h3><ol><li>别迷信“连续投保”的保障：哪怕买了好几年，理赔时保险公司仍可能找“非官方拆修”等理由拒保，一定要保留所有官方维修凭证（包括维修单、沟通记录），这是维权关键；</li><li>拒绝不合理低赔付：遇到赔付金额远低于维修成本的方案，果断投诉（支付宝&#x2F;微信平台投诉+12378银保监投诉），很多保险公司就是“欺软怕硬”；</li><li>看清赔付规则：投保前明确“是否直接赔付现金”“维修报销范围”，避免后续被套路，优先选赔付透明、口碑好的保险公司。</li></ol><h3 id="（二）第三方维修：京东这类坑千万别踩"><a href="#（二）第三方维修：京东这类坑千万别踩" class="headerlink" title="（二）第三方维修：京东这类坑千万别踩"></a>（二）第三方维修：京东这类坑千万别踩</h3><ol><li>坚决问清配件来源：更换屏幕等核心部件时，要求客服明确告知品牌、生产厂家，最好写进维修协议，避免被“三无国产屏”忽悠；</li><li>确认售后保障：提前问清维修后出现坏点、功能失灵等问题，是否支持返工、退款，拒绝“维修后概不负责”的霸王条款；</li><li>老旧机型优先等官方物料：第三方维修的老旧机型配件质量参差不齐，适配性差，容易出现指纹失灵、刷新率异常等问题，能等官方物料就尽量等。</li></ol><h2 id="四、自行拆机需谨慎（翻车现场）"><a href="#四、自行拆机需谨慎（翻车现场）" class="headerlink" title="四、自行拆机需谨慎（翻车现场）"></a>四、自行拆机需谨慎（翻车现场）</h2><ol><li><p>我的备用机（12+256机型）电池老化，先在酷安发帖询问“哪家电池靠谱”，有位酷安老哥推荐了一家淘宝店铺，我花60元在这家店买了块电池邮寄到家。出院后，我第一次尝试自行拆机更换——虽然手机较老，不怕影响后续保障，但如果是还在保险期内的手机，私自拆机可能会成为保险公司拒保的理由，大家一定要慎重权衡。</p><p><strong>说个搞笑的后续：后来我试着自己动手换电池（这可是我头回拆机），装完一瞅，桌上居然多出来两颗螺丝！一个零件！不过好笑归好笑，真换完了倒觉得这事儿其实还挺简单~</strong><br><img src="https://img.zrf.me/20251121105315984.webp" alt="拆机"></p></li><li><p>这波经历下来，我算是看透了部分保险公司的“套路”和京东这类大平台的“售后摆烂”。<br>希望我的踩坑实录能帮大家少走弯路，投保时多留个心眼，维修时多一份警惕，别像我一样花了钱还受气！</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;踩坑预警：支付宝众安碎屏险-京修店双重避坑，第一次拆机的搞笑翻车现场&quot;&gt;&lt;a href=&quot;#踩坑预警：支付宝众安碎屏险-京修店双重避坑，第一次拆机的搞笑翻车现场&quot; class=&quot;headerlink&quot; title=&quot;踩坑预警：支付宝众安碎屏险+京修店双重避坑，第一</summary>
      
    
    
    
    <category term="日常闲聊" scheme="https://blog.zrf.me/categories/%E6%97%A5%E5%B8%B8%E9%97%B2%E8%81%8A/"/>
    
    
    <category term="日常" scheme="https://blog.zrf.me/tags/%E6%97%A5%E5%B8%B8/"/>
    
    <category term="闲聊" scheme="https://blog.zrf.me/tags/%E9%97%B2%E8%81%8A/"/>
    
  </entry>
  
  <entry>
    <title>Cloudflare Snippets 免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选</title>
    <link href="https://blog.zrf.me/p/Cloudflare-Snippets/"/>
    <id>https://blog.zrf.me/p/Cloudflare-Snippets/</id>
    <published>2025-09-27T02:17:27.000Z</published>
    <updated>2025-09-28T08:17:27.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Cloudflare-Snippets-免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选"><a href="#Cloudflare-Snippets-免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选" class="headerlink" title="Cloudflare Snippets 免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选"></a>Cloudflare Snippets 免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选</h1><p>在上一篇 <strong><a href="https://blog.zrf.me/p/MiSub/">《MiSub - 一款强大的开源订阅转换与聚合管理工具》</a></strong> 中，我们不仅详细介绍了如何部署功能强大的 MiSub，还在开篇留下了一个悬念——Cloudflare  <strong>Snippets</strong>。当时我们提到：“我们下次会介绍如何将它与本次的项目结合，实现一个非常酷的功能”。</p><p><strong>现在，兑现承诺的时刻到了！</strong></p><p>本篇教程将手把手带你利用 Cloudflare Snippets 这一“赛博大善人”的免费福利，从零开始部署一个属于你自己的、高性能不限量的 VLESS 代理节点，并将其无缝添加到你已经部署好的 MiSub 中，实现节点的统一管理与分发。</p><p><strong>但是，在开始之前，有一个重要的前提。</strong></p><h2 id="前置条件：检查你是否是“天选之子”"><a href="#前置条件：检查你是否是“天选之子”" class="headerlink" title="前置条件：检查你是否是“天选之子”"></a><strong>前置条件：检查你是否是“天选之子”</strong></h2><p><strong>Cloudflare Snippets</strong> 虽然官方说明它仅对付费计划（Pro、Business 和 Enterprise）提供，但 Cloudflare 部分免费（Free）计划的用户也有资格，大部分的免费域名，之前我们发过的.me域名，.pp.ua域名，.ggff域名，大部分都有资格的。</p><p>因此，在深入学习本教程之前，请务必先确认你是否拥有这个“白嫖”的权限。</p><h4 id="检查路径："><a href="#检查路径：" class="headerlink" title="检查路径："></a><strong>检查路径：</strong></h4><ol><li>登录 <a href="https://dash.cloudflare.com/">Cloudflare 仪表盘</a>，选择你的域名。</li><li>在左侧导航栏中找到 **规则 (Rules)**，然后点击其下的 <strong>Snippets</strong> 选项。</li></ol><p><img src="https://img.zrf.me/20250924204625299.webp" alt="检查 Cloudflare Snippets 访问权限"></p><h4 id="判断结果："><a href="#判断结果：" class="headerlink" title="判断结果："></a><strong>判断结果：</strong></h4><ul><li><strong>如果你的界面如上图所示</strong>：能看到“创建片段”的按钮，那么恭喜你！本篇教程就是为你量身打造的，你可以继续阅读下去。</li><li><strong>如果你的 Snippets 选项中 显示 在边缘解锁自定义逻辑</strong>：如下图所示，Cloudflare Snippets控制您的边缘配置 — 短而强大的 JavaScript 片段，可动态定制您的网站或应用程序。Pro、Business 和 Enterprise 计划免费提供。则说明该功能尚未对你的域名开放。这种情况下，后续的步骤将无法进行。</li></ul><p><img src="https://img.zrf.me/20250927225411481.webp" alt="在边缘解锁自定义逻辑"></p><hr><p>如果你已经确认自己是那个幸运儿，那么，让我们一起站在巨人的肩膀上，玩起来吧。</p><h2 id="1：CF-Snippet-部署源码"><a href="#1：CF-Snippet-部署源码" class="headerlink" title="1：CF Snippet 部署源码"></a>1：CF Snippet 部署源码</h2><ul><li><p>感谢 CM 大佬以及多位大佬在 Snippet 部署上的探索与分享。下文贴出的源码均由 CM 大佬修改整合。由于代码可能随时更新，建议大家收藏原作者的发布页以获取最新更新：<a href="https://bp.sub.cmliussss.net/">https://bp.sub.cmliussss.net/</a></p></li><li><p><strong>白嫖哥源码</strong></p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">FIXED_UUID</span> = <span class="string">&#x27;&#x27;</span>;<span class="comment">// 建议修改为自己的规范化UUID，如不需要可留空</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">fetch</span>(<span class="params">request</span>) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(request.<span class="property">url</span>);</span><br><span class="line">            <span class="comment">// 检查是否为 WebSocket 升级请求</span></span><br><span class="line">            <span class="keyword">const</span> upgradeHeader = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Upgrade&#x27;</span>);</span><br><span class="line">            <span class="keyword">if</span> (upgradeHeader !== <span class="string">&#x27;websocket&#x27;</span>) &#123;</span><br><span class="line">                <span class="comment">// 将 request.cf 对象转换为 JSON 字符串</span></span><br><span class="line">                <span class="keyword">const</span> jsonData = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(request.<span class="property">cf</span>, <span class="literal">null</span>, <span class="number">2</span>); <span class="comment">// 使用2个空格缩进，使输出更易读</span></span><br><span class="line">                <span class="comment">// 创建 Response 对象，设置正确的 Content-Type 头</span></span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(jsonData, &#123;</span><br><span class="line">                    <span class="attr">status</span>: <span class="number">200</span>,</span><br><span class="line">                    <span class="attr">headers</span>: &#123;</span><br><span class="line">                        <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;application/json;charset=UTF-8&#x27;</span> <span class="comment">// 标准 JSON 内容类型[6,7](@ref)</span></span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">let</span> socks5Address = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;socks5&#x27;</span>) || url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;http&#x27;</span>) || <span class="literal">null</span>;</span><br><span class="line">                <span class="keyword">let</span> parsedSocks5Address = &#123;&#125;;</span><br><span class="line">                <span class="keyword">let</span> enableSocks = <span class="literal">null</span>;</span><br><span class="line">                <span class="keyword">let</span> enableGlobalSocks = url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;globalproxy&#x27;</span>);</span><br><span class="line">                <span class="keyword">let</span> <span class="title class_">ProxyIP</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">                <span class="keyword">let</span> <span class="title class_">ProxyPort</span> = <span class="number">443</span>;</span><br><span class="line">                <span class="keyword">if</span> ((url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5=&#x27;</span>) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/s5=&#x27;</span>)) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>)))) &#123;</span><br><span class="line">                    socks5Address = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;5=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                    enableGlobalSocks = url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>) ? <span class="literal">true</span> : enableGlobalSocks;</span><br><span class="line">                &#125; <span class="keyword">if</span> ((url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http=&#x27;</span>))) &#123;</span><br><span class="line">                    socks5Address = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;/http=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http://&#x27;</span>)) &#123;</span><br><span class="line">                    socks5Address = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;://&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;#&#x27;</span>)[<span class="number">0</span>];</span><br><span class="line">                    <span class="keyword">if</span> (socks5Address.<span class="title function_">includes</span>(<span class="string">&#x27;@&#x27;</span>)) &#123;</span><br><span class="line">                        <span class="keyword">const</span> lastAtIndex = socks5Address.<span class="title function_">lastIndexOf</span>(<span class="string">&#x27;@&#x27;</span>);</span><br><span class="line">                        <span class="keyword">let</span> userPassword = socks5Address.<span class="title function_">substring</span>(<span class="number">0</span>, lastAtIndex).<span class="title function_">replaceAll</span>(<span class="string">&#x27;%3D&#x27;</span>, <span class="string">&#x27;=&#x27;</span>);</span><br><span class="line">                        <span class="keyword">const</span> base64Regex = <span class="regexp">/^(?:[A-Z0-9+/]&#123;4&#125;)*(?:[A-Z0-9+/]&#123;2&#125;==|[A-Z0-9+/]&#123;3&#125;=)?$/i</span>;</span><br><span class="line">                        <span class="keyword">if</span> (base64Regex.<span class="title function_">test</span>(userPassword) &amp;&amp; !userPassword.<span class="title function_">includes</span>(<span class="string">&#x27;:&#x27;</span>)) userPassword = <span class="title function_">atob</span>(userPassword);</span><br><span class="line">                        socks5Address = <span class="string">`<span class="subst">$&#123;userPassword&#125;</span>@<span class="subst">$&#123;socks5Address.substring(lastAtIndex + <span class="number">1</span>)&#125;</span>`</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    enableGlobalSocks = <span class="literal">true</span>;<span class="comment">//开启全局SOCKS5</span></span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (socks5Address) &#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        parsedSocks5Address = <span class="title function_">socks5AddressParser</span>(socks5Address);</span><br><span class="line">                        enableSocks = url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;http://&#x27;</span>) ? <span class="string">&#x27;http&#x27;</span> : <span class="string">&#x27;socks5&#x27;</span>;</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                        enableSocks = <span class="literal">null</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    enableSocks = <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;proxyip&#x27;</span>) || url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;ip&#x27;</span>)) &#123;</span><br><span class="line">                    <span class="title class_">ProxyIP</span> = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;proxyip&#x27;</span>) || url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;ip&#x27;</span>);</span><br><span class="line">                    enableSocks = <span class="literal">null</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)) &#123;</span><br><span class="line">                    <span class="title class_">ProxyIP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                    enableSocks = <span class="literal">null</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip.&#x27;</span>)) &#123;</span><br><span class="line">                    <span class="title class_">ProxyIP</span> = <span class="string">`proxyip.<span class="subst">$&#123;url.pathname.toLowerCase().split(<span class="string">&quot;/proxyip.&quot;</span>)[<span class="number">1</span>]&#125;</span>`</span>;</span><br><span class="line">                    enableSocks = <span class="literal">null</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/pyip=&#x27;</span>)) &#123;</span><br><span class="line">                    <span class="title class_">ProxyIP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/pyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                    enableSocks = <span class="literal">null</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/ip=&#x27;</span>)) &#123;</span><br><span class="line">                    <span class="title class_">ProxyIP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/ip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                    enableSocks = <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">await</span> <span class="title function_">handleSPESSWebSocket</span>(request, &#123;</span><br><span class="line">                    parsedSocks5Address,</span><br><span class="line">                    enableSocks,</span><br><span class="line">                    enableGlobalSocks,</span><br><span class="line">                    <span class="title class_">ProxyIP</span>,</span><br><span class="line">                    <span class="title class_">ProxyPort</span></span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(err &amp;&amp; err.<span class="property">stack</span> ? err.<span class="property">stack</span> : <span class="title class_">String</span>(err), &#123; <span class="attr">status</span>: <span class="number">500</span> &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">handleSPESSWebSocket</span>(<span class="params">request, config</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123;</span><br><span class="line">        parsedSocks5Address,</span><br><span class="line">        enableSocks,</span><br><span class="line">        enableGlobalSocks,</span><br><span class="line">        <span class="title class_">ProxyIP</span>,</span><br><span class="line">        <span class="title class_">ProxyPort</span></span><br><span class="line">    &#125; = config;</span><br><span class="line">    <span class="keyword">const</span> wsPair = <span class="keyword">new</span> <span class="title class_">WebSocketPair</span>();</span><br><span class="line">    <span class="keyword">const</span> [clientWS, serverWS] = <span class="title class_">Object</span>.<span class="title function_">values</span>(wsPair);</span><br><span class="line"></span><br><span class="line">    serverWS.<span class="title function_">accept</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// WebSocket心跳机制，每30秒发送一次ping</span></span><br><span class="line">    <span class="keyword">let</span> heartbeatInterval = <span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (serverWS.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_OPEN</span>) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                serverWS.<span class="title function_">send</span>(<span class="string">&#x27;ping&#x27;</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (e) &#123; &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, <span class="number">30000</span>);</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">clearHeartbeat</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (heartbeatInterval) &#123;</span><br><span class="line">            <span class="built_in">clearInterval</span>(heartbeatInterval);</span><br><span class="line">            heartbeatInterval = <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    serverWS.<span class="title function_">addEventListener</span>(<span class="string">&#x27;close&#x27;</span>, clearHeartbeat);</span><br><span class="line">    serverWS.<span class="title function_">addEventListener</span>(<span class="string">&#x27;error&#x27;</span>, clearHeartbeat);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理 WebSocket 数据流</span></span><br><span class="line">    <span class="keyword">const</span> earlyDataHeader = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;sec-websocket-protocol&#x27;</span>) || <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">const</span> wsReadable = <span class="title function_">createWebSocketReadableStream</span>(serverWS, earlyDataHeader);</span><br><span class="line">    <span class="keyword">let</span> remoteSocket = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">let</span> udpStreamWrite = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">let</span> isDns = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    wsReadable.<span class="title function_">pipeTo</span>(<span class="keyword">new</span> <span class="title class_">WritableStream</span>(&#123;</span><br><span class="line">        <span class="keyword">async</span> <span class="title function_">write</span>(<span class="params">chunk</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (isDns &amp;&amp; udpStreamWrite) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">udpStreamWrite</span>(chunk);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (remoteSocket) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">const</span> writer = remoteSocket.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">                    <span class="keyword">await</span> writer.<span class="title function_">write</span>(chunk);</span><br><span class="line">                    writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                    <span class="title function_">closeSocket</span>(remoteSocket);</span><br><span class="line">                    <span class="keyword">throw</span> err;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> result = <span class="title function_">parseVLESSHeader</span>(chunk);</span><br><span class="line">            <span class="keyword">if</span> (result.<span class="property">hasError</span>) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(result.<span class="property">message</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> vlessRespHeader = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([result.<span class="property">vlessVersion</span>[<span class="number">0</span>], <span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">const</span> rawClientData = chunk.<span class="title function_">slice</span>(result.<span class="property">rawDataIndex</span>);</span><br><span class="line">            <span class="keyword">if</span> (result.<span class="property">isUDP</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (result.<span class="property">portRemote</span> === <span class="number">53</span>) &#123;</span><br><span class="line">                    isDns = <span class="literal">true</span>;</span><br><span class="line">                    <span class="keyword">const</span> &#123; write &#125; = <span class="keyword">await</span> <span class="title function_">handleUDPOutBound</span>(serverWS, vlessRespHeader);</span><br><span class="line">                    udpStreamWrite = write;</span><br><span class="line">                    <span class="title function_">udpStreamWrite</span>(rawClientData);</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;UDP代理仅支持DNS(端口53)&#x27;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">connectAndWrite</span>(<span class="params">address, port</span>) &#123;</span><br><span class="line">                <span class="keyword">const</span> tcpSocket = <span class="keyword">await</span> <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: address, <span class="attr">port</span>: port &#125;, &#123; <span class="attr">allowHalfOpen</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">                remoteSocket = tcpSocket;</span><br><span class="line">                <span class="keyword">const</span> writer = tcpSocket.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">                <span class="keyword">await</span> writer.<span class="title function_">write</span>(rawClientData);</span><br><span class="line">                writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">                <span class="keyword">return</span> tcpSocket;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">connectAndWriteSocks</span>(<span class="params">address, port</span>) &#123;</span><br><span class="line">                <span class="keyword">const</span> tcpSocket = enableSocks === <span class="string">&#x27;socks5&#x27;</span></span><br><span class="line">                    ? <span class="keyword">await</span> <span class="title function_">socks5Connect</span>(result.<span class="property">addressType</span>, address, port, parsedSocks5Address)</span><br><span class="line">                    : <span class="keyword">await</span> <span class="title function_">httpConnect</span>(result.<span class="property">addressType</span>, address, port, parsedSocks5Address);</span><br><span class="line">                remoteSocket = tcpSocket;</span><br><span class="line">                <span class="keyword">const</span> writer = tcpSocket.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">                <span class="keyword">await</span> writer.<span class="title function_">write</span>(rawClientData);</span><br><span class="line">                writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">                <span class="keyword">return</span> tcpSocket;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">retry</span>(<span class="params"></span>) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">let</span> tcpSocket;</span><br><span class="line">                    <span class="keyword">if</span> (enableSocks === <span class="string">&#x27;socks5&#x27;</span>) &#123;</span><br><span class="line">                        tcpSocket = <span class="keyword">await</span> <span class="title function_">socks5Connect</span>(result.<span class="property">addressType</span>, result.<span class="property">addressRemote</span>, result.<span class="property">portRemote</span>, parsedSocks5Address);</span><br><span class="line">                    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (enableSocks === <span class="string">&#x27;http&#x27;</span>) &#123;</span><br><span class="line">                        tcpSocket = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(result.<span class="property">addressType</span>, result.<span class="property">addressRemote</span>, result.<span class="property">portRemote</span>, parsedSocks5Address);</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="keyword">const</span> proxyConfig = <span class="keyword">await</span> <span class="title function_">getProxyConfiguration</span>(request.<span class="property">cf</span> &amp;&amp; request.<span class="property">cf</span>.<span class="property">colo</span>, result.<span class="property">addressRemote</span>, result.<span class="property">portRemote</span>, <span class="title class_">ProxyIP</span>, <span class="title class_">ProxyPort</span>);</span><br><span class="line">                        tcpSocket = <span class="keyword">await</span> <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: proxyConfig.<span class="property">ip</span>, <span class="attr">port</span>: proxyConfig.<span class="property">port</span> &#125;, &#123; <span class="attr">allowHalfOpen</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">                    &#125;</span><br><span class="line">                    remoteSocket = tcpSocket;</span><br><span class="line">                    <span class="keyword">const</span> writer = tcpSocket.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">                    <span class="keyword">await</span> writer.<span class="title function_">write</span>(rawClientData);</span><br><span class="line">                    writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">                    tcpSocket.<span class="property">closed</span>.<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123; &#125;).<span class="title function_">finally</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">                        <span class="keyword">if</span> (serverWS.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_OPEN</span>) &#123;</span><br><span class="line">                            serverWS.<span class="title function_">close</span>(<span class="number">1000</span>, <span class="string">&#x27;连接已关闭&#x27;</span>);</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;);</span><br><span class="line">                    <span class="title function_">pipeRemoteToWebSocket</span>(tcpSocket, serverWS, vlessRespHeader, <span class="literal">null</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                    <span class="title function_">closeSocket</span>(remoteSocket);</span><br><span class="line">                    serverWS.<span class="title function_">close</span>(<span class="number">1011</span>, <span class="string">&#x27;代理连接失败: &#x27;</span> + (err &amp;&amp; err.<span class="property">message</span> ? err.<span class="property">message</span> : err));</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (enableGlobalSocks) &#123;</span><br><span class="line">                    <span class="keyword">const</span> tcpSocket = <span class="keyword">await</span> <span class="title function_">connectAndWriteSocks</span>(result.<span class="property">addressRemote</span>, result.<span class="property">portRemote</span>);</span><br><span class="line">                    <span class="title function_">pipeRemoteToWebSocket</span>(tcpSocket, serverWS, vlessRespHeader, retry);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">const</span> tcpSocket = <span class="keyword">await</span> <span class="title function_">connectAndWrite</span>(result.<span class="property">addressRemote</span>, result.<span class="property">portRemote</span>);</span><br><span class="line">                    <span class="title function_">pipeRemoteToWebSocket</span>(tcpSocket, serverWS, vlessRespHeader, retry);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                <span class="title function_">closeSocket</span>(remoteSocket);</span><br><span class="line">                serverWS.<span class="title function_">close</span>(<span class="number">1011</span>, <span class="string">&#x27;连接失败: &#x27;</span> + (err &amp;&amp; err.<span class="property">message</span> ? err.<span class="property">message</span> : err));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="title function_">close</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (remoteSocket) &#123;</span><br><span class="line">                <span class="title function_">closeSocket</span>(remoteSocket);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">closeSocket</span>(remoteSocket);</span><br><span class="line">        serverWS.<span class="title function_">close</span>(<span class="number">1011</span>, <span class="string">&#x27;内部错误: &#x27;</span> + (err &amp;&amp; err.<span class="property">message</span> ? err.<span class="property">message</span> : err));</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="literal">null</span>, &#123;</span><br><span class="line">        <span class="attr">status</span>: <span class="number">101</span>,</span><br><span class="line">        <span class="attr">webSocket</span>: clientWS,</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">createWebSocketReadableStream</span>(<span class="params">ws, earlyDataHeader</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ReadableStream</span>(&#123;</span><br><span class="line">        <span class="title function_">start</span>(<span class="params">controller</span>) &#123;</span><br><span class="line">            ws.<span class="title function_">addEventListener</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">event</span> =&gt;</span> &#123;</span><br><span class="line">                controller.<span class="title function_">enqueue</span>(event.<span class="property">data</span>);</span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">            ws.<span class="title function_">addEventListener</span>(<span class="string">&#x27;close&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">                controller.<span class="title function_">close</span>();</span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">            ws.<span class="title function_">addEventListener</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">                controller.<span class="title function_">error</span>(err);</span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (earlyDataHeader) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">const</span> decoded = <span class="title function_">atob</span>(earlyDataHeader.<span class="title function_">replace</span>(<span class="regexp">/-/g</span>, <span class="string">&#x27;+&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/_/g</span>, <span class="string">&#x27;/&#x27;</span>));</span><br><span class="line">                    <span class="keyword">const</span> data = <span class="title class_">Uint8Array</span>.<span class="title function_">from</span>(decoded, <span class="function"><span class="params">c</span> =&gt;</span> c.<span class="title function_">charCodeAt</span>(<span class="number">0</span>));</span><br><span class="line">                    controller.<span class="title function_">enqueue</span>(data.<span class="property">buffer</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 只允许固定UUID</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">parseVLESSHeader</span>(<span class="params">buffer</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (buffer.<span class="property">byteLength</span> &lt; <span class="number">24</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123; <span class="attr">hasError</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">&#x27;无效的头部长度&#x27;</span> &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> view = <span class="keyword">new</span> <span class="title class_">DataView</span>(buffer);</span><br><span class="line">    <span class="keyword">const</span> version = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(buffer.<span class="title function_">slice</span>(<span class="number">0</span>, <span class="number">1</span>));</span><br><span class="line">    <span class="keyword">const</span> uuid = <span class="title function_">formatUUID</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(buffer.<span class="title function_">slice</span>(<span class="number">1</span>, <span class="number">17</span>)));</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable constant_">FIXED_UUID</span> &amp;&amp; uuid !== <span class="variable constant_">FIXED_UUID</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123; <span class="attr">hasError</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">&#x27;无效的用户&#x27;</span> &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> optionsLength = view.<span class="title function_">getUint8</span>(<span class="number">17</span>);</span><br><span class="line">    <span class="keyword">const</span> command = view.<span class="title function_">getUint8</span>(<span class="number">18</span> + optionsLength);</span><br><span class="line">    <span class="keyword">let</span> isUDP = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">if</span> (command === <span class="number">1</span>) &#123;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (command === <span class="number">2</span>) &#123;</span><br><span class="line">        isUDP = <span class="literal">true</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123; <span class="attr">hasError</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">&#x27;不支持的命令，仅支持TCP(01)和UDP(02)&#x27;</span> &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> offset = <span class="number">19</span> + optionsLength;</span><br><span class="line">    <span class="keyword">const</span> port = view.<span class="title function_">getUint16</span>(offset);</span><br><span class="line">    offset += <span class="number">2</span>;</span><br><span class="line">    <span class="keyword">const</span> addressType = view.<span class="title function_">getUint8</span>(offset++);</span><br><span class="line">    <span class="keyword">let</span> address = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">switch</span> (addressType) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">            address = <span class="title class_">Array</span>.<span class="title function_">from</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(buffer.<span class="title function_">slice</span>(offset, offset + <span class="number">4</span>))).<span class="title function_">join</span>(<span class="string">&#x27;.&#x27;</span>);</span><br><span class="line">            offset += <span class="number">4</span>;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">            <span class="keyword">const</span> domainLength = view.<span class="title function_">getUint8</span>(offset++);</span><br><span class="line">            address = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(buffer.<span class="title function_">slice</span>(offset, offset + domainLength));</span><br><span class="line">            offset += domainLength;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">            <span class="keyword">const</span> ipv6 = [];</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++) &#123;</span><br><span class="line">                ipv6.<span class="title function_">push</span>(view.<span class="title function_">getUint16</span>(offset).<span class="title function_">toString</span>(<span class="number">16</span>).<span class="title function_">padStart</span>(<span class="number">4</span>, <span class="string">&#x27;0&#x27;</span>));</span><br><span class="line">                offset += <span class="number">2</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            address = ipv6.<span class="title function_">join</span>(<span class="string">&#x27;:&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/(^|:)0+(\w)/g</span>, <span class="string">&#x27;$1$2&#x27;</span>);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="attr">default</span>:</span><br><span class="line">            <span class="keyword">return</span> &#123; <span class="attr">hasError</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">&#x27;不支持的地址类型&#x27;</span> &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">hasError</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="attr">addressRemote</span>: address,</span><br><span class="line">        <span class="attr">portRemote</span>: port,</span><br><span class="line">        <span class="attr">rawDataIndex</span>: offset,</span><br><span class="line">        <span class="attr">vlessVersion</span>: version,</span><br><span class="line">        isUDP,</span><br><span class="line">        addressType</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">pipeRemoteToWebSocket</span>(<span class="params">remoteSocket, ws, vlessHeader, retry = <span class="literal">null</span></span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> headerSent = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> hasIncomingData = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    remoteSocket.<span class="property">readable</span>.<span class="title function_">pipeTo</span>(<span class="keyword">new</span> <span class="title class_">WritableStream</span>(&#123;</span><br><span class="line">        <span class="title function_">write</span>(<span class="params">chunk</span>) &#123;</span><br><span class="line">            hasIncomingData = <span class="literal">true</span>;</span><br><span class="line">            <span class="keyword">if</span> (ws.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_OPEN</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (!headerSent) &#123;</span><br><span class="line">                    <span class="keyword">const</span> combined = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(vlessHeader.<span class="property">byteLength</span> + chunk.<span class="property">byteLength</span>);</span><br><span class="line">                    combined.<span class="title function_">set</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(vlessHeader), <span class="number">0</span>);</span><br><span class="line">                    combined.<span class="title function_">set</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(chunk), vlessHeader.<span class="property">byteLength</span>);</span><br><span class="line">                    ws.<span class="title function_">send</span>(combined.<span class="property">buffer</span>);</span><br><span class="line">                    headerSent = <span class="literal">true</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    ws.<span class="title function_">send</span>(chunk);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="title function_">close</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!hasIncomingData &amp;&amp; retry) &#123;</span><br><span class="line">                <span class="title function_">retry</span>();</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (ws.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_OPEN</span>) &#123;</span><br><span class="line">                ws.<span class="title function_">close</span>(<span class="number">1000</span>, <span class="string">&#x27;正常关闭&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="title function_">abort</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="title function_">closeSocket</span>(remoteSocket);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">closeSocket</span>(remoteSocket);</span><br><span class="line">        <span class="keyword">if</span> (ws.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_OPEN</span>) &#123;</span><br><span class="line">            ws.<span class="title function_">close</span>(<span class="number">1011</span>, <span class="string">&#x27;数据传输错误&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">closeSocket</span>(<span class="params">socket</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (socket) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            socket.<span class="title function_">close</span>();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">formatUUID</span>(<span class="params">bytes</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> hex = <span class="title class_">Array</span>.<span class="title function_">from</span>(bytes, <span class="function"><span class="params">b</span> =&gt;</span> b.<span class="title function_">toString</span>(<span class="number">16</span>).<span class="title function_">padStart</span>(<span class="number">2</span>, <span class="string">&#x27;0&#x27;</span>)).<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="string">`<span class="subst">$&#123;hex.slice(<span class="number">0</span>, <span class="number">8</span>)&#125;</span>-<span class="subst">$&#123;hex.slice(<span class="number">8</span>, <span class="number">12</span>)&#125;</span>-<span class="subst">$&#123;hex.slice(<span class="number">12</span>, <span class="number">16</span>)&#125;</span>-<span class="subst">$&#123;hex.slice(<span class="number">16</span>, <span class="number">20</span>)&#125;</span>-<span class="subst">$&#123;hex.slice(<span class="number">20</span>)&#125;</span>`</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">socks5AddressParser</span>(<span class="params">address</span>) &#123;</span><br><span class="line">    <span class="comment">// 使用 &quot;@&quot; 分割地址，分为认证部分和服务器地址部分</span></span><br><span class="line">    <span class="keyword">const</span> lastAtIndex = address.<span class="title function_">lastIndexOf</span>(<span class="string">&quot;@&quot;</span>);</span><br><span class="line">    <span class="keyword">let</span> [latter, former] = lastAtIndex === -<span class="number">1</span> ? [address, <span class="literal">undefined</span>] : [address.<span class="title function_">substring</span>(lastAtIndex + <span class="number">1</span>), address.<span class="title function_">substring</span>(<span class="number">0</span>, lastAtIndex)];</span><br><span class="line">    <span class="keyword">let</span> username, password, hostname, port;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果存在 former 部分，说明提供了认证信息</span></span><br><span class="line">    <span class="keyword">if</span> (former) &#123;</span><br><span class="line">        <span class="keyword">const</span> formers = former.<span class="title function_">split</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (formers.<span class="property">length</span> !== <span class="number">2</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：认证部分必须是 &quot;username:password&quot; 的形式&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        [username, password] = formers;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 解析服务器地址部分</span></span><br><span class="line">    <span class="keyword">const</span> latters = latter.<span class="title function_">split</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">    <span class="comment">// 检查是否是IPv6地址带端口格式 [xxx]:port</span></span><br><span class="line">    <span class="keyword">if</span> (latters.<span class="property">length</span> &gt; <span class="number">2</span> &amp;&amp; latter.<span class="title function_">includes</span>(<span class="string">&quot;]:&quot;</span>)) &#123;</span><br><span class="line">        <span class="comment">// IPv6地址带端口格式：[2001:db8::1]:8080</span></span><br><span class="line">        port = <span class="title class_">Number</span>(latter.<span class="title function_">split</span>(<span class="string">&quot;]:&quot;</span>)[<span class="number">1</span>].<span class="title function_">replace</span>(<span class="regexp">/[^\d]/g</span>, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        hostname = latter.<span class="title function_">split</span>(<span class="string">&quot;]:&quot;</span>)[<span class="number">0</span>] + <span class="string">&quot;]&quot;</span>; <span class="comment">// 正确提取hostname部分</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (latters.<span class="property">length</span> === <span class="number">2</span>) &#123;</span><br><span class="line">        <span class="comment">// IPv4地址带端口或域名带端口</span></span><br><span class="line">        port = <span class="title class_">Number</span>(latters.<span class="title function_">pop</span>().<span class="title function_">replace</span>(<span class="regexp">/[^\d]/g</span>, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        hostname = latters.<span class="title function_">join</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        port = <span class="number">80</span>;</span><br><span class="line">        hostname = latter;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">isNaN</span>(port)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：端口号必须是数字&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理 IPv6 地址的特殊情况</span></span><br><span class="line">    <span class="comment">// IPv6 地址包含多个冒号，所以必须用方括号括起来，如 [2001:db8::1]</span></span><br><span class="line">    <span class="keyword">const</span> regex = <span class="regexp">/^\[.*\]$/</span>;</span><br><span class="line">    <span class="keyword">if</span> (hostname.<span class="title function_">includes</span>(<span class="string">&quot;:&quot;</span>) &amp;&amp; !regex.<span class="title function_">test</span>(hostname)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：IPv6 地址必须用方括号括起来，如 [2001:db8::1]&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)&#123;3&#125;(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(hostname)) hostname = `$&#123;atob(&#x27;d3d3Lg==&#x27;)&#125;$&#123;hostname&#125;$&#123;atob(&#x27;LmlwLjA5MDIyNy54eXo=&#x27;)&#125;`;</span></span><br><span class="line">    <span class="comment">// 返回解析后的结果</span></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        username,  <span class="comment">// 用户名，如果没有则为 undefined</span></span><br><span class="line">        password,  <span class="comment">// 密码，如果没有则为 undefined</span></span><br><span class="line">        hostname,  <span class="comment">// 主机名，可以是域名、IPv4 或 IPv6 地址</span></span><br><span class="line">        port, <span class="comment">// 端口号，已转换为数字类型</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 修正socks5Connect函数，不再引用parsedSocks5Address</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">socks5Connect</span>(<span class="params">addressType, addressRemote, portRemote, socks5Address</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; username, password, hostname, port &#125; = socks5Address;</span><br><span class="line">    <span class="keyword">const</span> socket = <span class="title function_">connect</span>(&#123;</span><br><span class="line">        hostname,</span><br><span class="line">        port,</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">const</span> socksGreeting = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">2</span>]);</span><br><span class="line">    <span class="keyword">const</span> writer = socket.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">    <span class="keyword">await</span> writer.<span class="title function_">write</span>(socksGreeting);</span><br><span class="line">    <span class="keyword">const</span> reader = socket.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">    <span class="keyword">const</span> encoder = <span class="keyword">new</span> <span class="title class_">TextEncoder</span>();</span><br><span class="line">    <span class="keyword">let</span> res = (<span class="keyword">await</span> reader.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">    <span class="keyword">if</span> (res[<span class="number">0</span>] !== <span class="number">0x05</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`socks server version error: <span class="subst">$&#123;res[<span class="number">0</span>]&#125;</span> expected: 5`</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (res[<span class="number">1</span>] === <span class="number">0xff</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;no acceptable methods&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (res[<span class="number">1</span>] === <span class="number">0x02</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!username || !password) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;please provide username/password&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">const</span> authRequest = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([</span><br><span class="line">            <span class="number">1</span>,</span><br><span class="line">            username.<span class="property">length</span>,</span><br><span class="line">            ...encoder.<span class="title function_">encode</span>(username),</span><br><span class="line">            password.<span class="property">length</span>,</span><br><span class="line">            ...encoder.<span class="title function_">encode</span>(password)</span><br><span class="line">        ]);</span><br><span class="line">        <span class="keyword">await</span> writer.<span class="title function_">write</span>(authRequest);</span><br><span class="line">        res = (<span class="keyword">await</span> reader.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">        <span class="keyword">if</span> (res[<span class="number">0</span>] !== <span class="number">0x01</span> || res[<span class="number">1</span>] !== <span class="number">0x00</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;fail to auth socks server&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> <span class="variable constant_">DSTADDR</span>;</span><br><span class="line">    <span class="keyword">switch</span> (addressType) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">            <span class="variable constant_">DSTADDR</span> = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(</span><br><span class="line">                [<span class="number">1</span>, ...addressRemote.<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>).<span class="title function_">map</span>(<span class="title class_">Number</span>)]</span><br><span class="line">            );</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">            <span class="variable constant_">DSTADDR</span> = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(</span><br><span class="line">                [<span class="number">3</span>, addressRemote.<span class="property">length</span>, ...encoder.<span class="title function_">encode</span>(addressRemote)]</span><br><span class="line">            );</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">            <span class="variable constant_">DSTADDR</span> = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(</span><br><span class="line">                [<span class="number">4</span>, ...addressRemote.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="title function_">flatMap</span>(<span class="function"><span class="params">x</span> =&gt;</span> [<span class="built_in">parseInt</span>(x.<span class="title function_">slice</span>(<span class="number">0</span>, <span class="number">2</span>), <span class="number">16</span>), <span class="built_in">parseInt</span>(x.<span class="title function_">slice</span>(<span class="number">2</span>), <span class="number">16</span>)])]</span><br><span class="line">            );</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="attr">default</span>:</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`invalid addressType is <span class="subst">$&#123;addressType&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> socksRequest = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">1</span>, <span class="number">0</span>, ...<span class="variable constant_">DSTADDR</span>, portRemote &gt;&gt; <span class="number">8</span>, portRemote &amp; <span class="number">0xff</span>]);</span><br><span class="line">    <span class="keyword">await</span> writer.<span class="title function_">write</span>(socksRequest);</span><br><span class="line">    res = (<span class="keyword">await</span> reader.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">    <span class="keyword">if</span> (res[<span class="number">1</span>] === <span class="number">0x00</span>) &#123;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;fail to open socks connection&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">    reader.<span class="title function_">releaseLock</span>();</span><br><span class="line">    <span class="keyword">return</span> socket;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">httpConnect</span>(<span class="params">addressType, addressRemote, portRemote, socks5Address</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; username, password, hostname, port &#125; = socks5Address;</span><br><span class="line">    <span class="keyword">const</span> sock = <span class="keyword">await</span> <span class="title function_">connect</span>(&#123;</span><br><span class="line">        <span class="attr">hostname</span>: hostname,</span><br><span class="line">        <span class="attr">port</span>: port</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 构建HTTP CONNECT请求</span></span><br><span class="line">    <span class="keyword">let</span> connectRequest = <span class="string">`CONNECT <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span> HTTP/1.1\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Host: <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span>\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加代理认证（如果需要）</span></span><br><span class="line">    <span class="keyword">if</span> (username &amp;&amp; password) &#123;</span><br><span class="line">        <span class="keyword">const</span> authString = <span class="string">`<span class="subst">$&#123;username&#125;</span>:<span class="subst">$&#123;password&#125;</span>`</span>;</span><br><span class="line">        <span class="keyword">const</span> base64Auth = <span class="title function_">btoa</span>(authString);</span><br><span class="line">        connectRequest += <span class="string">`Proxy-Authorization: Basic <span class="subst">$&#123;base64Auth&#125;</span>\r\n`</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    connectRequest += <span class="string">`User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Proxy-Connection: Keep-Alive\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Connection: Keep-Alive\r\n`</span>; <span class="comment">// 添加标准 Connection 头</span></span><br><span class="line">    connectRequest += <span class="string">`\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 发送连接请求</span></span><br><span class="line">        <span class="keyword">const</span> writer = sock.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        <span class="keyword">await</span> writer.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(connectRequest));</span><br><span class="line">        writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;发送HTTP CONNECT请求失败:&#x27;</span>, err);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`发送HTTP CONNECT请求失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 读取HTTP响应</span></span><br><span class="line">    <span class="keyword">const</span> reader = sock.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">    <span class="keyword">let</span> respText = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">let</span> connected = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> responseBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> &#123; value, done &#125; = <span class="keyword">await</span> reader.<span class="title function_">read</span>();</span><br><span class="line">            <span class="keyword">if</span> (done) &#123;</span><br><span class="line">                <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 合并接收到的数据</span></span><br><span class="line">            <span class="keyword">const</span> newBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(responseBuffer.<span class="property">length</span> + value.<span class="property">length</span>);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(responseBuffer);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(value, responseBuffer.<span class="property">length</span>);</span><br><span class="line">            responseBuffer = newBuffer;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 将收到的数据转换为文本</span></span><br><span class="line">            respText = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(responseBuffer);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 检查是否收到完整的HTTP响应头</span></span><br><span class="line">            <span class="keyword">if</span> (respText.<span class="title function_">includes</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>)) &#123;</span><br><span class="line">                <span class="comment">// 分离HTTP头和可能的数据部分</span></span><br><span class="line">                <span class="keyword">const</span> headersEndPos = respText.<span class="title function_">indexOf</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>) + <span class="number">4</span>;</span><br><span class="line">                <span class="keyword">const</span> headers = respText.<span class="title function_">substring</span>(<span class="number">0</span>, headersEndPos);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 检查响应状态</span></span><br><span class="line">                <span class="keyword">if</span> (headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.1 200&#x27;</span>) || headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.0 200&#x27;</span>)) &#123;</span><br><span class="line">                    connected = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">                    <span class="comment">// 如果响应头之后还有数据，我们需要保存这些数据以便后续处理</span></span><br><span class="line">                    <span class="keyword">if</span> (headersEndPos &lt; responseBuffer.<span class="property">length</span>) &#123;</span><br><span class="line">                        <span class="keyword">const</span> remainingData = responseBuffer.<span class="title function_">slice</span>(headersEndPos);</span><br><span class="line">                        <span class="comment">// 创建一个缓冲区来存储这些数据，以便稍后使用</span></span><br><span class="line">                        <span class="keyword">const</span> dataStream = <span class="keyword">new</span> <span class="title class_">ReadableStream</span>(&#123;</span><br><span class="line">                            <span class="title function_">start</span>(<span class="params">controller</span>) &#123;</span><br><span class="line">                                controller.<span class="title function_">enqueue</span>(remainingData);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;);</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 创建一个新的TransformStream来处理额外数据</span></span><br><span class="line">                        <span class="keyword">const</span> &#123; readable, writable &#125; = <span class="keyword">new</span> <span class="title class_">TransformStream</span>();</span><br><span class="line">                        dataStream.<span class="title function_">pipeTo</span>(writable).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;处理剩余数据错误:&#x27;</span>, err));</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 替换原始readable流</span></span><br><span class="line">                        <span class="comment">// @ts-ignore</span></span><br><span class="line">                        sock.<span class="property">readable</span> = readable;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">const</span> errorMsg = <span class="string">`HTTP代理连接失败: <span class="subst">$&#123;headers.split(<span class="string">&#x27;\r\n&#x27;</span>)[<span class="number">0</span>]&#125;</span>`</span>;</span><br><span class="line">                    <span class="variable language_">console</span>.<span class="title function_">error</span>(errorMsg);</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(errorMsg);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        reader.<span class="title function_">releaseLock</span>();</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`处理HTTP代理响应失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    reader.<span class="title function_">releaseLock</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!connected) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接失败: 未收到成功响应&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> sock;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">handleUDPOutBound</span>(<span class="params">webSocket, vlessResponseHeader</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> isVlessHeaderSent = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">const</span> transformStream = <span class="keyword">new</span> <span class="title class_">TransformStream</span>(&#123;</span><br><span class="line">        <span class="title function_">start</span>(<span class="params">controller</span>) &#123;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="title function_">transform</span>(<span class="params">chunk, controller</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index &lt; chunk.<span class="property">byteLength</span>;) &#123;</span><br><span class="line">                <span class="keyword">const</span> lengthBuffer = chunk.<span class="title function_">slice</span>(index, index + <span class="number">2</span>);</span><br><span class="line">                <span class="keyword">const</span> udpPacketLength = <span class="keyword">new</span> <span class="title class_">DataView</span>(lengthBuffer).<span class="title function_">getUint16</span>(<span class="number">0</span>);</span><br><span class="line">                <span class="keyword">const</span> udpData = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(</span><br><span class="line">                    chunk.<span class="title function_">slice</span>(index + <span class="number">2</span>, index + <span class="number">2</span> + udpPacketLength)</span><br><span class="line">                );</span><br><span class="line">                index = index + <span class="number">2</span> + udpPacketLength;</span><br><span class="line">                controller.<span class="title function_">enqueue</span>(udpData);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="title function_">flush</span>(<span class="params">controller</span>) &#123;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    transformStream.<span class="property">readable</span>.<span class="title function_">pipeTo</span>(<span class="keyword">new</span> <span class="title class_">WritableStream</span>(&#123;</span><br><span class="line">        <span class="keyword">async</span> <span class="title function_">write</span>(<span class="params">chunk</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> resp = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&#x27;https://1.1.1.1/dns-query&#x27;</span>,</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">                    <span class="attr">headers</span>: &#123;</span><br><span class="line">                        <span class="string">&#x27;content-type&#x27;</span>: <span class="string">&#x27;application/dns-message&#x27;</span>,</span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="attr">body</span>: chunk,</span><br><span class="line">                &#125;)</span><br><span class="line">            <span class="keyword">const</span> dnsQueryResult = <span class="keyword">await</span> resp.<span class="title function_">arrayBuffer</span>();</span><br><span class="line">            <span class="keyword">const</span> udpSize = dnsQueryResult.<span class="property">byteLength</span>;</span><br><span class="line">            <span class="keyword">const</span> udpSizeBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([(udpSize &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xff</span>, udpSize &amp; <span class="number">0xff</span>]);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (webSocket.<span class="property">readyState</span> === <span class="variable constant_">WS_READY_STATE_OPEN</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (isVlessHeaderSent) &#123;</span><br><span class="line">                    webSocket.<span class="title function_">send</span>(<span class="keyword">await</span> <span class="keyword">new</span> <span class="title class_">Blob</span>([udpSizeBuffer, dnsQueryResult]).<span class="title function_">arrayBuffer</span>());</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    webSocket.<span class="title function_">send</span>(<span class="keyword">await</span> <span class="keyword">new</span> <span class="title class_">Blob</span>([vlessResponseHeader, udpSizeBuffer, dnsQueryResult]).<span class="title function_">arrayBuffer</span>());</span><br><span class="line">                    isVlessHeaderSent = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)).<span class="title function_">catch</span>(<span class="function">(<span class="params">error</span>) =&gt;</span> &#123;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> writer = transformStream.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="title function_">write</span>(<span class="params">chunk</span>) &#123;</span><br><span class="line">            writer.<span class="title function_">write</span>(chunk);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ========== 必要常量和依赖 ==========</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">WS_READY_STATE_OPEN</span> = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; connect &#125; <span class="keyword">from</span> <span class="string">&#x27;cloudflare:sockets&#x27;</span>;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">getProxyConfiguration</span>(<span class="params">colo, addressRemote, portRemote, ProxyIP, ProxyPort</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="title class_">ProxyIP</span> || <span class="title class_">ProxyIP</span> == <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line">        <span class="title class_">ProxyIP</span> = <span class="string">&#x27;proxyip.fxxk.dedyn.io&#x27;</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title class_">ProxyIP</span>.<span class="title function_">includes</span>(<span class="string">&#x27;]:&#x27;</span>)) &#123;</span><br><span class="line">        <span class="title class_">ProxyPort</span> = <span class="title class_">ProxyIP</span>.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">1</span>] || <span class="title class_">ProxyPort</span>;</span><br><span class="line">        <span class="title class_">ProxyIP</span> = <span class="title class_">ProxyIP</span>.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">0</span>] + <span class="string">&quot;]&quot;</span> || <span class="title class_">ProxyIP</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title class_">ProxyIP</span>.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="property">length</span> === <span class="number">2</span>) &#123;</span><br><span class="line">        <span class="title class_">ProxyPort</span> = <span class="title class_">ProxyIP</span>.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">1</span>] || <span class="title class_">ProxyPort</span>;</span><br><span class="line">        <span class="title class_">ProxyIP</span> = <span class="title class_">ProxyIP</span>.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">0</span>] || <span class="title class_">ProxyIP</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">ProxyIP</span>.<span class="title function_">includes</span>(<span class="string">&#x27;.tp&#x27;</span>)) <span class="title class_">ProxyPort</span> = <span class="title class_">ProxyIP</span>.<span class="title function_">split</span>(<span class="string">&#x27;.tp&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>)[<span class="number">0</span>] || <span class="title class_">ProxyPort</span>;</span><br><span class="line">    <span class="keyword">return</span> &#123; <span class="attr">ip</span>: <span class="title class_">ProxyIP</span> || addressRemote, <span class="attr">port</span>: <span class="title class_">ProxyPort</span> || portRemote &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><strong>天书12源码</strong></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">FIXED_UUID</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="comment">//1. 天书版12.0重构版队列传输模式改，本版再次改变传输逻辑，大幅度提升传输稳定性，建议pages部署，这版是全功能开发者研究版，不适合小白部署</span></span><br><span class="line"><span class="keyword">import</span> &#123; connect &#125; <span class="keyword">from</span> <span class="string">&#x27;cloudflare:sockets&#x27;</span>;</span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////配置区块////////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="keyword">let</span> 反代<span class="variable constant_">IP</span> = <span class="string">&#x27;&#x27;</span> <span class="comment">//反代IP或域名，反代IP端口一般情况下不用填写，如果你非要用非标反代的话，可以填&#x27;ts.hpc.tw:443&#x27;这样</span></span><br><span class="line"><span class="keyword">let</span> 启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span> <span class="comment">//如果启用此功能，原始反代将失效，很多S5不一定支持ipv6，启用则需禁用doh查询ipv6功能</span></span><br><span class="line"><span class="keyword">let</span> 启用<span class="title class_">SOCKS5</span>全局反代 = <span class="literal">false</span> <span class="comment">//选择是否启用SOCKS5全局反代，启用后所有访问都是S5的落地【无论你客户端选什么节点】，访问路径是客户端--CF--SOCKS5，当然启用此功能后延迟=CF+SOCKS5，带宽取决于SOCKS5的带宽，不再享受CF高速和随时满带宽的待遇</span></span><br><span class="line"><span class="keyword">let</span> 我的<span class="title class_">SOCKS5</span>账号 = <span class="string">&#x27;&#x27;</span>; <span class="comment">//格式&#x27;账号:密码@地址:端口&#x27;，示例admin:admin@127.0.0.1:443或admin:admin@[IPV6]:443，支持无账号密码示例@127.0.0.1:443</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////个性化配置///////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="comment">//以下是适合开发者研究的个性化配置，如果你是小白保持默认别动就行</span></span><br><span class="line"><span class="keyword">let</span> 启用新版传输模式 = <span class="literal">false</span> <span class="comment">//开启则使用队列传输方式，关闭则是原始管道流传输方式</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> 启动控流机制 = <span class="literal">false</span> <span class="comment">//仅新版传输方式有效，选择是否启动控流机制，true启动，false关闭，使用控流可降低CPU超时的概率，提升连接稳定性，适合轻度使用，日常使用应该绰绰有余</span></span><br><span class="line"><span class="keyword">let</span> 传输控流延迟 = <span class="number">200</span>; <span class="comment">//单位毫秒，每传输2m数据暂停多少毫秒</span></span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////网页入口////////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">fetch</span>(<span class="params">访问请求</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (访问请求.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Upgrade&#x27;</span>) === <span class="string">&#x27;websocket&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(访问请求.<span class="property">url</span>);</span><br><span class="line">            我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;socks5&#x27;</span>) || url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>全局反代 = url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;globalproxy&#x27;</span>);</span><br><span class="line">            <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5=&#x27;</span>) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/s5=&#x27;</span>)) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>))) &#123;</span><br><span class="line">                我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;5=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="string">&#x27;socks5&#x27;</span>;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>全局反代 = url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>) ? <span class="literal">true</span> : 启用<span class="title class_">SOCKS5</span>全局反代;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http=&#x27;</span>)) &#123;</span><br><span class="line">                我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;/http=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="string">&#x27;http&#x27;</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http://&#x27;</span>)) &#123;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/http://&#x27;</span>)) ? <span class="string">&#x27;http&#x27;</span> : <span class="string">&#x27;socks5&#x27;</span>;</span><br><span class="line">                我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;://&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;#&#x27;</span>)[<span class="number">0</span>];</span><br><span class="line">                <span class="keyword">if</span> (我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">includes</span>(<span class="string">&#x27;@&#x27;</span>)) &#123;</span><br><span class="line">                    <span class="keyword">const</span> lastAtIndex = 我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">lastIndexOf</span>(<span class="string">&#x27;@&#x27;</span>);</span><br><span class="line">                    <span class="keyword">let</span> userPassword = 我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">substring</span>(<span class="number">0</span>, lastAtIndex).<span class="title function_">replaceAll</span>(<span class="string">&#x27;%3D&#x27;</span>, <span class="string">&#x27;=&#x27;</span>);</span><br><span class="line">                    <span class="keyword">const</span> base64Regex = <span class="regexp">/^(?:[A-Z0-9+/]&#123;4&#125;)*(?:[A-Z0-9+/]&#123;2&#125;==|[A-Z0-9+/]&#123;3&#125;=)?$/i</span>;</span><br><span class="line">                    <span class="keyword">if</span> (base64Regex.<span class="title function_">test</span>(userPassword) &amp;&amp; !userPassword.<span class="title function_">includes</span>(<span class="string">&#x27;:&#x27;</span>)) userPassword = <span class="title function_">atob</span>(userPassword);</span><br><span class="line">                    我的<span class="title class_">SOCKS5</span>账号 = <span class="string">`<span class="subst">$&#123;userPassword&#125;</span>@<span class="subst">$&#123;我的SOCKS5账号.substring(lastAtIndex + <span class="number">1</span>)&#125;</span>`</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>全局反代 = <span class="literal">true</span>;<span class="comment">//开启全局SOCKS5</span></span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (我的<span class="title class_">SOCKS5</span>账号) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号);</span><br><span class="line">                    启用<span class="title class_">SOCKS5</span>反代 = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;http&#x27;</span>) ? <span class="string">&#x27;http&#x27;</span> : 启用<span class="title class_">SOCKS5</span>反代;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                    启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;proxyip&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;proxyip&#x27;</span>);</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip.&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = <span class="string">`proxyip.<span class="subst">$&#123;url.pathname.toLowerCase().split(<span class="string">&quot;/proxyip.&quot;</span>)[<span class="number">1</span>]&#125;</span>`</span>;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/pyip=&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/pyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/ip=&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/ip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">await</span> 升级<span class="variable constant_">WS</span>请求(访问请求);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Hello World!&#x27;</span>, &#123; <span class="attr">status</span>: <span class="number">200</span> &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">////////////////////////////////////////////////////////////////////////脚本主要架构//////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="comment">//第一步，读取和构建基础访问结构</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 升级<span class="variable constant_">WS</span>请求(访问请求) &#123;</span><br><span class="line">    <span class="keyword">const</span> 创建<span class="variable constant_">WS</span>接口 = <span class="keyword">new</span> <span class="title class_">WebSocketPair</span>();</span><br><span class="line">    <span class="keyword">const</span> [客户端, <span class="variable constant_">WS</span>接口] = <span class="title class_">Object</span>.<span class="title function_">values</span>(创建<span class="variable constant_">WS</span>接口);</span><br><span class="line">    <span class="variable constant_">WS</span>接口.<span class="title function_">accept</span>();</span><br><span class="line">    <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>, <span class="number">0</span>]));</span><br><span class="line">    处理<span class="variable constant_">WS</span>请求(访问请求, <span class="variable constant_">WS</span>接口)</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="literal">null</span>, &#123; <span class="attr">status</span>: <span class="number">101</span>, <span class="attr">webSocket</span>: 客户端 &#125;); <span class="comment">//一切准备就绪后，回复客户端WS连接升级成功</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 处理<span class="variable constant_">WS</span>请求(访问请求, <span class="variable constant_">WS</span>接口) &#123;</span><br><span class="line">    <span class="keyword">let</span> 转换二进制数据;</span><br><span class="line">    <span class="keyword">const</span> 读取<span class="variable constant_">WS</span>数据头 = 访问请求.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;sec-websocket-protocol&#x27;</span>); <span class="comment">//读取访问标头中的WS通信数据</span></span><br><span class="line">    <span class="keyword">if</span> (!读取<span class="variable constant_">WS</span>数据头) &#123;</span><br><span class="line">        转换二进制数据 = <span class="keyword">await</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="variable constant_">WS</span>接口.<span class="title function_">addEventListener</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">event</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="title function_">resolve</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(event.<span class="property">data</span>));</span><br><span class="line">            &#125;, &#123; <span class="attr">once</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        转换二进制数据 = 转换<span class="variable constant_">WS</span>数据头为二进制数据(读取<span class="variable constant_">WS</span>数据头); <span class="comment">//解码目标访问数据，传递给TCP握手进程</span></span><br><span class="line">    &#125;</span><br><span class="line">    解析<span class="variable constant_">VL</span>标头(转换二进制数据, <span class="variable constant_">WS</span>接口); <span class="comment">//解析VL数据并进行TCP握手</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> 转换<span class="variable constant_">WS</span>数据头为二进制数据(<span class="variable constant_">WS</span>数据头) &#123;</span><br><span class="line">    <span class="keyword">const</span> base64URL转换为标准base64 = <span class="variable constant_">WS</span>数据头.<span class="title function_">replace</span>(<span class="regexp">/-/g</span>, <span class="string">&#x27;+&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/_/g</span>, <span class="string">&#x27;/&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> 解码base64 = <span class="title function_">atob</span>(base64URL转换为标准base64);</span><br><span class="line">    <span class="keyword">const</span> 转换为二进制数组 = <span class="title class_">Uint8Array</span>.<span class="title function_">from</span>(解码base64, <span class="function"><span class="params">c</span> =&gt;</span> c.<span class="title function_">charCodeAt</span>(<span class="number">0</span>));</span><br><span class="line">    <span class="keyword">return</span> 转换为二进制数组;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//第二步，解读VL协议数据，创建TCP握手</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 解析<span class="variable constant_">VL</span>标头(二进制数据, <span class="variable constant_">WS</span>接口, <span class="variable constant_">TCP</span>接口) &#123;</span><br><span class="line">    <span class="keyword">let</span> 识别地址类型, 访问地址, 地址长度;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">const</span> 获取数据定位 = 二进制数据[<span class="number">17</span>];</span><br><span class="line">        <span class="keyword">const</span> 提取端口索引 = <span class="number">18</span> + 获取数据定位 + <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">const</span> 访问端口 = <span class="keyword">new</span> <span class="title class_">DataView</span>(二进制数据.<span class="property">buffer</span>, 提取端口索引, <span class="number">2</span>).<span class="title function_">getUint16</span>(<span class="number">0</span>);</span><br><span class="line">        <span class="keyword">if</span> (访问端口 === <span class="number">53</span>) &#123; <span class="comment">//这个处理是应对某些客户端优先强制查询dns的情况，也是通过加密通道udp over tcp的，放心使用</span></span><br><span class="line">            <span class="keyword">const</span> 提取<span class="variable constant_">DNS</span>查询报文 = 二进制数据.<span class="title function_">slice</span>(提取端口索引 + <span class="number">9</span>);</span><br><span class="line">            <span class="keyword">const</span> 查询<span class="variable constant_">DOH</span>结果 = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&#x27;https://1.1.1.1/dns-query&#x27;</span>, &#123; <span class="comment">//不是所有doh都支持二进制查询，默认的是最快的地址，想更换可以换成&quot;https://dns.google/dns-query&quot;</span></span><br><span class="line">                <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">                <span class="attr">headers</span>: &#123;</span><br><span class="line">                    <span class="string">&#x27;content-type&#x27;</span>: <span class="string">&#x27;application/dns-message&#x27;</span>,</span><br><span class="line">                &#125;,</span><br><span class="line">                <span class="attr">body</span>: 提取<span class="variable constant_">DNS</span>查询报文</span><br><span class="line">            &#125;)</span><br><span class="line">            <span class="keyword">const</span> 提取<span class="variable constant_">DOH</span>结果 = <span class="keyword">await</span> 查询<span class="variable constant_">DOH</span>结果.<span class="title function_">arrayBuffer</span>();</span><br><span class="line">            <span class="keyword">const</span> 构建长度头部 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([(提取<span class="variable constant_">DOH</span>结果.<span class="property">byteLength</span> &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xff</span>, 提取<span class="variable constant_">DOH</span>结果.<span class="property">byteLength</span> &amp; <span class="number">0xff</span>]);</span><br><span class="line">            <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(<span class="keyword">await</span> <span class="keyword">new</span> <span class="title class_">Blob</span>([构建长度头部, 提取<span class="variable constant_">DOH</span>结果, <span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(生成随机字符串())]).<span class="title function_">arrayBuffer</span>());</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">const</span> 提取地址索引 = 提取端口索引 + <span class="number">2</span>;</span><br><span class="line">        识别地址类型 = 二进制数据[提取地址索引];</span><br><span class="line">        <span class="keyword">let</span> 地址信息索引 = 提取地址索引 + <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">switch</span> (识别地址类型) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">                地址长度 = <span class="number">4</span>;</span><br><span class="line">                访问地址 = 二进制数据.<span class="title function_">slice</span>(地址信息索引, 地址信息索引 + 地址长度).<span class="title function_">join</span>(<span class="string">&#x27;.&#x27;</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">                地址长度 = 二进制数据[地址信息索引];</span><br><span class="line">                地址信息索引 += <span class="number">1</span>;</span><br><span class="line">                访问地址 = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(二进制数据.<span class="title function_">slice</span>(地址信息索引, 地址信息索引 + 地址长度));</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">                地址长度 = <span class="number">16</span>;</span><br><span class="line">                <span class="keyword">const</span> ipv6 = [];</span><br><span class="line">                <span class="keyword">const</span> 读取<span class="title class_">IPV6</span>地址 = <span class="keyword">new</span> <span class="title class_">DataView</span>(二进制数据.<span class="property">buffer</span>, 地址信息索引, <span class="number">16</span>);</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++) ipv6.<span class="title function_">push</span>(读取<span class="title class_">IPV6</span>地址.<span class="title function_">getUint16</span>(i * <span class="number">2</span>).<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">                访问地址 = ipv6.<span class="title function_">join</span>(<span class="string">&#x27;:&#x27;</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="attr">default</span>:</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的访问地址&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable constant_">FIXED_UUID</span> &amp;&amp; 验证<span class="variable constant_">VL</span>的密钥(二进制数据.<span class="title function_">slice</span>(<span class="number">1</span>, <span class="number">17</span>)) !== <span class="variable constant_">FIXED_UUID</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;UUID验证失败&#x27;</span>);</span><br><span class="line">        <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">            <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> 创建<span class="title class_">SOCKS5</span>接口(识别地址类型, 访问地址, 访问端口);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">            <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(访问地址, 访问端口);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (识别地址类型 === <span class="number">3</span>) &#123;</span><br><span class="line">                    <span class="keyword">const</span> 转换<span class="title class_">IPV6</span>地址 = <span class="string">`[<span class="subst">$&#123;访问地址&#125;</span>]`</span></span><br><span class="line">                    <span class="variable constant_">TCP</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 转换<span class="title class_">IPV6</span>地址, <span class="attr">port</span>: 访问端口 &#125;);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="variable constant_">TCP</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 访问地址, <span class="attr">port</span>: 访问端口 &#125;);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">await</span> <span class="variable constant_">TCP</span>接口.<span class="property">opened</span>;</span><br><span class="line">            &#125; <span class="keyword">catch</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span>) &#123;</span><br><span class="line">                    <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> 创建<span class="title class_">SOCKS5</span>接口(识别地址类型, 访问地址, 访问端口);</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span>) &#123;</span><br><span class="line">                    <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(访问地址, 访问端口);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">let</span> [反代<span class="variable constant_">IP</span>地址, 反代<span class="variable constant_">IP</span>端口] = 解析地址端口(反代<span class="variable constant_">IP</span>);</span><br><span class="line">                    <span class="variable constant_">TCP</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 反代<span class="variable constant_">IP</span>地址, <span class="attr">port</span>: 反代<span class="variable constant_">IP</span>端口 &#125;);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">await</span> <span class="variable constant_">TCP</span>接口.<span class="property">opened</span>;</span><br><span class="line">        <span class="keyword">const</span> 写入初始数据 = 二进制数据.<span class="title function_">slice</span>(地址信息索引 + 地址长度)</span><br><span class="line">        <span class="keyword">const</span> 传输数据 = <span class="variable constant_">TCP</span>接口.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        <span class="keyword">if</span> (写入初始数据.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(写入初始数据);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (启用新版传输模式) &#123;</span><br><span class="line">            <span class="keyword">const</span> 读取数据 = <span class="variable constant_">TCP</span>接口.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">            队列传输管道(访问地址, 传输数据, 读取数据, <span class="variable constant_">WS</span>接口); <span class="comment">//建立WS接口与TCP接口的传输管道</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            原始传输管道(传输数据, <span class="variable constant_">TCP</span>接口, <span class="variable constant_">WS</span>接口)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">`连接握手失败: <span class="subst">$&#123;e&#125;</span>`</span>, &#123; <span class="attr">status</span>: <span class="number">500</span> &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> 验证<span class="variable constant_">VL</span>的密钥(字节数组, 起始位置 = <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> 十六进制表 = <span class="title class_">Array</span>.<span class="title function_">from</span>(&#123; <span class="attr">length</span>: <span class="number">256</span> &#125;, <span class="function">(<span class="params">_, 值</span>) =&gt;</span></span><br><span class="line">        (值 + <span class="number">256</span>).<span class="title function_">toString</span>(<span class="number">16</span>).<span class="title function_">slice</span>(<span class="number">1</span>)</span><br><span class="line">    );</span><br><span class="line">    <span class="keyword">const</span> 分段结构 = [<span class="number">4</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">6</span>];</span><br><span class="line">    <span class="keyword">let</span> 当前索引 = 起始位置;</span><br><span class="line">    <span class="keyword">const</span> 格式化<span class="variable constant_">UUID</span> = 分段结构</span><br><span class="line">        .<span class="title function_">map</span>(段长度 =&gt;</span><br><span class="line">            <span class="title class_">Array</span>.<span class="title function_">from</span>(&#123; <span class="attr">length</span>: 段长度 &#125;, <span class="function">() =&gt;</span> 十六进制表[字节数组[当前索引++]]).<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">        )</span><br><span class="line">        .<span class="title function_">join</span>(<span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">        .<span class="title function_">toLowerCase</span>();</span><br><span class="line">    <span class="keyword">return</span> 格式化<span class="variable constant_">UUID</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">globalThis.<span class="property">DNS</span>缓存记录 = globalThis.<span class="property">DNS</span>缓存记录 ??= <span class="keyword">new</span> <span class="title class_">Map</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> 解析地址端口(反代<span class="variable constant_">IP</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> proxyIP = 反代<span class="variable constant_">IP</span>.<span class="title function_">toLowerCase</span>();</span><br><span class="line">    <span class="keyword">let</span> 地址 = proxyIP, 端口 = <span class="number">443</span>;</span><br><span class="line">    <span class="keyword">if</span> (!proxyIP || proxyIP == <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line">        地址 = <span class="string">&#x27;proxyip.fxxk.dedyn.io&#x27;</span>; <span class="comment">//默认反代</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (proxyIP.<span class="title function_">includes</span>(<span class="string">&#x27;]:&#x27;</span>)) &#123;</span><br><span class="line">        端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">1</span>] || 端口;</span><br><span class="line">        地址 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">0</span>] + <span class="string">&quot;]&quot;</span> || 地址;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="property">length</span> === <span class="number">2</span>) &#123;</span><br><span class="line">        端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">1</span>] || 端口;</span><br><span class="line">        地址 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">0</span>] || 地址;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (proxyIP.<span class="title function_">includes</span>(<span class="string">&#x27;.tp&#x27;</span>)) 端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;.tp&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>)[<span class="number">0</span>] || 端口;</span><br><span class="line">    <span class="keyword">return</span> [地址, 端口];</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//第三步，创建客户端WS-CF-目标的传输通道并监听状态</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 原始传输管道(传输数据, <span class="variable constant_">TCP</span>接口, <span class="variable constant_">WS</span>接口) &#123;</span><br><span class="line">    <span class="variable constant_">WS</span>接口.<span class="title function_">addEventListener</span>(<span class="string">&#x27;message&#x27;</span>, <span class="keyword">async</span> event =&gt; &#123; <span class="keyword">try</span> &#123; <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(event.<span class="property">data</span>)) &#125; <span class="keyword">catch</span> &#123; &#125;; &#125;); <span class="comment">//监听客户端WS接口后续数据，推送给TCP接口</span></span><br><span class="line">    <span class="variable constant_">TCP</span>接口.<span class="property">readable</span>.<span class="title function_">pipeTo</span>(<span class="keyword">new</span> <span class="title class_">WritableStream</span>(&#123; <span class="keyword">async</span> <span class="title function_">write</span>(<span class="params">返回数据</span>) &#123; <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(返回数据) &#125; &#125;)); <span class="comment">//将TCP接口返回的数据回写至客户端WS接口</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 队列传输管道(访问地址, 传输数据, 读取数据, <span class="variable constant_">WS</span>接口, 传输队列 = <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(), 开始传输时间 = performance.<span class="title function_">now</span>(), 字节计数 = <span class="number">0</span>, 累计传输字节数 = <span class="number">0</span>, 大数据包 = <span class="literal">false</span>, 已结束 = <span class="literal">false</span>) &#123;</span><br><span class="line">    <span class="variable constant_">WS</span>接口.<span class="title function_">addEventListener</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">event</span> =&gt;</span> 传输队列 = 传输队列.<span class="title function_">then</span>(<span class="title function_">async</span> () =&gt; &#123;</span><br><span class="line">        <span class="keyword">let</span> 分段初值 = <span class="number">0</span></span><br><span class="line">        <span class="keyword">let</span> 分段大小 = <span class="number">4</span> * <span class="number">1024</span>;</span><br><span class="line">        <span class="keyword">const</span> <span class="variable constant_">WS</span>数据 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(event.<span class="property">data</span>);</span><br><span class="line">        <span class="keyword">while</span> (分段初值 &lt; <span class="variable constant_">WS</span>数据.<span class="property">length</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> 数据块 = <span class="variable constant_">WS</span>数据.<span class="title function_">slice</span>(分段初值, 分段初值 + 分段大小);</span><br><span class="line">            <span class="keyword">try</span> &#123; <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(数据块) &#125; <span class="keyword">catch</span> &#123; &#125;;</span><br><span class="line">            累计传输字节数 += 数据块.<span class="property">length</span>;</span><br><span class="line">            分段初值 += 分段大小;</span><br><span class="line">        &#125;</span><br><span class="line">        累计传输字节数 += <span class="variable constant_">WS</span>数据.<span class="property">length</span>;</span><br><span class="line">    &#125;).<span class="title function_">catch</span>());</span><br><span class="line">    <span class="keyword">const</span> 保活 = <span class="built_in">setInterval</span>(<span class="title function_">async</span> () =&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (已结束) &#123;</span><br><span class="line">            <span class="built_in">clearInterval</span>(保活);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            传输队列 = 传输队列.<span class="title function_">then</span>(<span class="title function_">async</span> () =&gt; <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="number">0</span>))).<span class="title function_">catch</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, <span class="number">30000</span>);</span><br><span class="line">    <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> &#123; <span class="attr">done</span>: 流结束, <span class="attr">value</span>: 返回数据 &#125; = <span class="keyword">await</span> 读取数据.<span class="title function_">read</span>();</span><br><span class="line">        <span class="keyword">if</span> (返回数据 &amp;&amp; 返回数据.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!大数据包 &amp;&amp; 返回数据.<span class="property">length</span> &gt;= <span class="number">4096</span>) &#123;</span><br><span class="line">                <span class="keyword">let</span> <span class="variable constant_">TCP</span>缓存 = [];</span><br><span class="line">                <span class="keyword">let</span> <span class="variable constant_">TCP</span>缓存长度 = <span class="number">0</span>;</span><br><span class="line">                大数据包 = <span class="literal">true</span>;</span><br><span class="line">                <span class="variable constant_">TCP</span>缓存.<span class="title function_">push</span>(返回数据);</span><br><span class="line">                <span class="variable constant_">TCP</span>缓存长度 += 返回数据.<span class="property">length</span>;</span><br><span class="line">                <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                    <span class="keyword">const</span> &#123; <span class="attr">done</span>: 流结束, <span class="attr">value</span>: 返回数据 &#125; = <span class="keyword">await</span> 读取数据.<span class="title function_">read</span>();</span><br><span class="line">                    <span class="keyword">if</span> (流结束) 已结束 = <span class="literal">true</span>;</span><br><span class="line">                    <span class="keyword">if</span> (返回数据 &amp;&amp; 返回数据.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                        <span class="variable constant_">TCP</span>缓存.<span class="title function_">push</span>(返回数据);</span><br><span class="line">                        <span class="variable constant_">TCP</span>缓存长度 += 返回数据.<span class="property">length</span>;</span><br><span class="line">                        <span class="keyword">if</span> (返回数据.<span class="property">length</span> &lt; <span class="number">4096</span> || <span class="variable constant_">TCP</span>缓存长度 &gt;= <span class="number">512</span> * <span class="number">1024</span>) &#123;</span><br><span class="line">                            <span class="keyword">let</span> 合并偏移 = <span class="number">0</span>;</span><br><span class="line">                            <span class="keyword">let</span> 待推送数据 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="variable constant_">TCP</span>缓存长度);</span><br><span class="line">                            <span class="keyword">for</span> (<span class="keyword">const</span> 数据块 <span class="keyword">of</span> <span class="variable constant_">TCP</span>缓存) &#123;</span><br><span class="line">                                待推送数据.<span class="title function_">set</span>(数据块, 合并偏移);</span><br><span class="line">                                合并偏移 += 数据块.<span class="property">length</span>;</span><br><span class="line">                            &#125;</span><br><span class="line">                            传输队列 = 传输队列.<span class="title function_">then</span>(<span class="function">() =&gt;</span> <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(待推送数据)).<span class="title function_">catch</span>();</span><br><span class="line">                            累计传输字节数 += 待推送数据.<span class="property">length</span>;</span><br><span class="line">                            大数据包 = <span class="literal">false</span>;</span><br><span class="line">                            <span class="keyword">break</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                传输队列 = 传输队列.<span class="title function_">then</span>(<span class="function">() =&gt;</span> <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(返回数据)).<span class="title function_">catch</span>();</span><br><span class="line">                累计传输字节数 += 返回数据.<span class="property">length</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (启动控流机制 &amp;&amp; (累计传输字节数 - 字节计数) &gt; <span class="number">2</span> * <span class="number">1024</span> * <span class="number">1024</span>) &#123;</span><br><span class="line">                传输队列 = 传输队列.<span class="title function_">then</span>(<span class="title function_">async</span> () =&gt; <span class="keyword">await</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> <span class="built_in">setTimeout</span>(resolve, 传输控流延迟))).<span class="title function_">catch</span>();</span><br><span class="line">                字节计数 = 累计传输字节数;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (流结束 || 已结束) &#123; 已结束 = <span class="literal">true</span>; <span class="keyword">break</span>; &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////SOCKS5部分//////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 创建<span class="title class_">SOCKS5</span>接口(识别地址类型, 访问地址, 访问端口, 转换访问地址, 传输数据, 读取数据) &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="title class_">SOCKS5</span>接口, 账号, 密码, 地址, 端口;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        (&#123; 账号, 密码, 地址, 端口 &#125; = <span class="keyword">await</span> 获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号));</span><br><span class="line">        <span class="title class_">SOCKS5</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 地址, <span class="attr">port</span>: 端口 &#125;);</span><br><span class="line">        <span class="keyword">await</span> <span class="title class_">SOCKS5</span>接口.<span class="property">opened</span>;</span><br><span class="line">        传输数据 = <span class="title class_">SOCKS5</span>接口.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        读取数据 = <span class="title class_">SOCKS5</span>接口.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">        <span class="keyword">const</span> 转换数组 = <span class="keyword">new</span> <span class="title class_">TextEncoder</span>(); <span class="comment">//把文本内容转换为字节数组，如账号，密码，域名，方便与S5建立连接</span></span><br><span class="line">        <span class="keyword">const</span> 构建<span class="variable constant_">S5</span>认证 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">2</span>]); <span class="comment">//构建认证信息,支持无认证和用户名/密码认证</span></span><br><span class="line">        <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(构建<span class="variable constant_">S5</span>认证); <span class="comment">//发送认证信息，确认目标是否需要用户名密码认证</span></span><br><span class="line">        <span class="keyword">const</span> 读取认证要求 = (<span class="keyword">await</span> 读取数据.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">        <span class="keyword">if</span> (读取认证要求[<span class="number">1</span>] === <span class="number">0x02</span>) &#123; <span class="comment">//检查是否需要用户名/密码认证</span></span><br><span class="line">            <span class="keyword">if</span> (!账号 || !密码) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`未配置账号密码`</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> 构建账号密码包 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">1</span>, 账号.<span class="property">length</span>, ...转换数组.<span class="title function_">encode</span>(账号), 密码.<span class="property">length</span>, ...转换数组.<span class="title function_">encode</span>(密码)]); <span class="comment">//构建账号密码数据包，把字符转换为字节数组</span></span><br><span class="line">            <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(构建账号密码包); <span class="comment">//发送账号密码认证信息</span></span><br><span class="line">            <span class="keyword">const</span> 读取账号密码认证结果 = (<span class="keyword">await</span> 读取数据.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">            <span class="keyword">if</span> (读取账号密码认证结果[<span class="number">0</span>] !== <span class="number">0x01</span> || 读取账号密码认证结果[<span class="number">1</span>] !== <span class="number">0x00</span>) &#123; <span class="comment">//检查账号密码认证结果，认证失败则退出</span></span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`账号密码错误`</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">switch</span> (识别地址类型) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">1</span>: <span class="comment">// IPv4</span></span><br><span class="line">                转换访问地址 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">1</span>, ...访问地址.<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>).<span class="title function_">map</span>(<span class="title class_">Number</span>)]);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">2</span>: <span class="comment">// 域名</span></span><br><span class="line">                转换访问地址 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">3</span>, 访问地址.<span class="property">length</span>, ...转换数组.<span class="title function_">encode</span>(访问地址)]);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">3</span>: <span class="comment">// IPv6</span></span><br><span class="line">                转换访问地址 = 转换为<span class="title class_">Socks5IPv6</span>地址(访问地址);</span><br><span class="line">                <span class="keyword">function</span> 转换为<span class="title class_">Socks5IPv6</span>地址(原始地址) &#123;</span><br><span class="line">                    <span class="keyword">const</span> 去括号地址 = 原始地址.<span class="title function_">startsWith</span>(<span class="string">&#x27;[&#x27;</span>) &amp;&amp; 原始地址.<span class="title function_">endsWith</span>(<span class="string">&#x27;]&#x27;</span>)</span><br><span class="line">                        ? 原始地址.<span class="title function_">slice</span>(<span class="number">1</span>, -<span class="number">1</span>)</span><br><span class="line">                        : 原始地址;</span><br><span class="line">                    <span class="keyword">const</span> 分段 = 去括号地址.<span class="title function_">split</span>(<span class="string">&#x27;::&#x27;</span>);</span><br><span class="line">                    <span class="keyword">const</span> 前缀 = 分段[<span class="number">0</span>] ? 分段[<span class="number">0</span>].<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="title function_">filter</span>(<span class="title class_">Boolean</span>) : [];</span><br><span class="line">                    <span class="keyword">const</span> 后缀 = 分段[<span class="number">1</span>] ? 分段[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="title function_">filter</span>(<span class="title class_">Boolean</span>) : [];</span><br><span class="line">                    <span class="keyword">const</span> 填充数量 = <span class="number">8</span> - (前缀.<span class="property">length</span> + 后缀.<span class="property">length</span>);</span><br><span class="line">                    <span class="keyword">if</span> (填充数量 &lt; <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;IPv6地址格式错误&#x27;</span>);</span><br><span class="line">                    <span class="keyword">const</span> 完整分段 = [...前缀, ...<span class="title class_">Array</span>(填充数量).<span class="title function_">fill</span>(<span class="string">&#x27;0&#x27;</span>), ...后缀];</span><br><span class="line">                    <span class="keyword">const</span> <span class="title class_">IPv6</span>字节 = 完整分段.<span class="title function_">flatMap</span>(字段 =&gt; &#123;</span><br><span class="line">                        <span class="keyword">const</span> 数值 = <span class="built_in">parseInt</span>(字段 || <span class="string">&#x27;0&#x27;</span>, <span class="number">16</span>);</span><br><span class="line">                        <span class="keyword">return</span> [(数值 &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xff</span>, 数值 &amp; <span class="number">0xff</span>];</span><br><span class="line">                    &#125;);</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0x04</span>, ...<span class="title class_">IPv6</span>字节]);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">const</span> 构建转换后的访问地址 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">1</span>, <span class="number">0</span>, ...转换访问地址, 访问端口 &gt;&gt; <span class="number">8</span>, 访问端口 &amp; <span class="number">0xff</span>]); <span class="comment">//构建转换好的地址消息</span></span><br><span class="line">        <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(构建转换后的访问地址); <span class="comment">//发送转换后的地址</span></span><br><span class="line">        <span class="keyword">const</span> 检查返回响应 = (<span class="keyword">await</span> 读取数据.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">        <span class="keyword">if</span> (检查返回响应[<span class="number">0</span>] !== <span class="number">0x05</span> || 检查返回响应[<span class="number">1</span>] !== <span class="number">0x00</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`目标地址连接失败，访问地址: <span class="subst">$&#123;访问地址&#125;</span>，地址类型: <span class="subst">$&#123;识别地址类型&#125;</span>`</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        传输数据.<span class="title function_">releaseLock</span>();</span><br><span class="line">        读取数据.<span class="title function_">releaseLock</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">SOCKS5</span>接口;</span><br><span class="line">    &#125; <span class="keyword">catch</span> &#123; &#125;;</span><br><span class="line">    传输数据?.<span class="title function_">releaseLock</span>();</span><br><span class="line">    读取数据?.<span class="title function_">releaseLock</span>();</span><br><span class="line">    <span class="keyword">await</span> <span class="title class_">SOCKS5</span>接口?.<span class="title function_">close</span>();</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`所有SOCKS5账号失效`</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 获取<span class="title class_">SOCKS5</span>账号(<span class="title class_">SOCKS5</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> 分隔账号 = <span class="title class_">SOCKS5</span>.<span class="title function_">includes</span>(<span class="string">&quot;@&quot;</span>) ? <span class="title class_">SOCKS5</span>.<span class="title function_">lastIndexOf</span>(<span class="string">&quot;@&quot;</span>) : -<span class="number">1</span>;</span><br><span class="line">    <span class="keyword">const</span> 账号段 = <span class="title class_">SOCKS5</span>.<span class="title function_">slice</span>(<span class="number">0</span>, 分隔账号);</span><br><span class="line">    <span class="keyword">const</span> 地址段 = 分隔账号 !== -<span class="number">1</span> ? <span class="title class_">SOCKS5</span>.<span class="title function_">slice</span>(分隔账号 + <span class="number">1</span>) : <span class="title class_">SOCKS5</span>;</span><br><span class="line">    <span class="keyword">const</span> [账号, 密码] = [账号段.<span class="title function_">slice</span>(<span class="number">0</span>, 账号段.<span class="title function_">lastIndexOf</span>(<span class="string">&quot;:&quot;</span>)), 账号段.<span class="title function_">slice</span>(账号段.<span class="title function_">lastIndexOf</span>(<span class="string">&quot;:&quot;</span>) + <span class="number">1</span>)];</span><br><span class="line">    <span class="keyword">const</span> [地址, 端口] = 解析地址端口(地址段);</span><br><span class="line">    <span class="keyword">return</span> &#123; 账号, 密码, 地址, 端口 &#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////订阅页面////////////////////////////////////////////////////////////////////////</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> 生成随机字符串(最小长度 = <span class="number">8</span>, 最大长度 = <span class="number">24</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> 字符集 = <span class="string">&#x27;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&#x27;</span>;</span><br><span class="line">    <span class="keyword">const</span> 长度 = 最小长度 + <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * (最大长度 - 最小长度 + <span class="number">1</span>));</span><br><span class="line">    <span class="keyword">const</span> 结果 = [];</span><br><span class="line">    <span class="keyword">const</span> 随机字节 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(长度);</span><br><span class="line">    crypto.<span class="title function_">getRandomValues</span>(随机字节);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; 长度; i++) &#123;</span><br><span class="line">        <span class="keyword">const</span> 随机索引 = 随机字节[i] % 字符集.<span class="property">length</span>;</span><br><span class="line">        结果.<span class="title function_">push</span>(字符集[随机索引]);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> 结果.<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">httpConnect</span>(<span class="params">addressRemote, portRemote</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> parsedSocks5Address = <span class="keyword">await</span> 获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号);</span><br><span class="line">    <span class="keyword">const</span> &#123; username, password, hostname, port &#125; = parsedSocks5Address;</span><br><span class="line">    <span class="keyword">const</span> sock = <span class="keyword">await</span> <span class="title function_">connect</span>(&#123;</span><br><span class="line">        <span class="attr">hostname</span>: hostname,</span><br><span class="line">        <span class="attr">port</span>: port</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 构建HTTP CONNECT请求</span></span><br><span class="line">    <span class="keyword">let</span> connectRequest = <span class="string">`CONNECT <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span> HTTP/1.1\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Host: <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span>\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加代理认证（如果需要）</span></span><br><span class="line">    <span class="keyword">if</span> (username &amp;&amp; password) &#123;</span><br><span class="line">        <span class="keyword">const</span> authString = <span class="string">`<span class="subst">$&#123;username&#125;</span>:<span class="subst">$&#123;password&#125;</span>`</span>;</span><br><span class="line">        <span class="keyword">const</span> base64Auth = <span class="title function_">btoa</span>(authString);</span><br><span class="line">        connectRequest += <span class="string">`Proxy-Authorization: Basic <span class="subst">$&#123;base64Auth&#125;</span>\r\n`</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    connectRequest += <span class="string">`User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Proxy-Connection: Keep-Alive\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Connection: Keep-Alive\r\n`</span>; <span class="comment">// 添加标准 Connection 头</span></span><br><span class="line">    connectRequest += <span class="string">`\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 发送连接请求</span></span><br><span class="line">        <span class="keyword">const</span> writer = sock.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        <span class="keyword">await</span> writer.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(connectRequest));</span><br><span class="line">        writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;发送HTTP CONNECT请求失败:&#x27;</span>, err);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`发送HTTP CONNECT请求失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 读取HTTP响应</span></span><br><span class="line">    <span class="keyword">const</span> reader = sock.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">    <span class="keyword">let</span> respText = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">let</span> connected = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> responseBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> &#123; value, done &#125; = <span class="keyword">await</span> reader.<span class="title function_">read</span>();</span><br><span class="line">            <span class="keyword">if</span> (done) &#123;</span><br><span class="line">                <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 合并接收到的数据</span></span><br><span class="line">            <span class="keyword">const</span> newBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(responseBuffer.<span class="property">length</span> + value.<span class="property">length</span>);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(responseBuffer);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(value, responseBuffer.<span class="property">length</span>);</span><br><span class="line">            responseBuffer = newBuffer;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 将收到的数据转换为文本</span></span><br><span class="line">            respText = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(responseBuffer);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 检查是否收到完整的HTTP响应头</span></span><br><span class="line">            <span class="keyword">if</span> (respText.<span class="title function_">includes</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>)) &#123;</span><br><span class="line">                <span class="comment">// 分离HTTP头和可能的数据部分</span></span><br><span class="line">                <span class="keyword">const</span> headersEndPos = respText.<span class="title function_">indexOf</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>) + <span class="number">4</span>;</span><br><span class="line">                <span class="keyword">const</span> headers = respText.<span class="title function_">substring</span>(<span class="number">0</span>, headersEndPos);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 检查响应状态</span></span><br><span class="line">                <span class="keyword">if</span> (headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.1 200&#x27;</span>) || headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.0 200&#x27;</span>)) &#123;</span><br><span class="line">                    connected = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">                    <span class="comment">// 如果响应头之后还有数据，我们需要保存这些数据以便后续处理</span></span><br><span class="line">                    <span class="keyword">if</span> (headersEndPos &lt; responseBuffer.<span class="property">length</span>) &#123;</span><br><span class="line">                        <span class="keyword">const</span> remainingData = responseBuffer.<span class="title function_">slice</span>(headersEndPos);</span><br><span class="line">                        <span class="comment">// 创建一个缓冲区来存储这些数据，以便稍后使用</span></span><br><span class="line">                        <span class="keyword">const</span> dataStream = <span class="keyword">new</span> <span class="title class_">ReadableStream</span>(&#123;</span><br><span class="line">                            <span class="title function_">start</span>(<span class="params">controller</span>) &#123;</span><br><span class="line">                                controller.<span class="title function_">enqueue</span>(remainingData);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;);</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 创建一个新的TransformStream来处理额外数据</span></span><br><span class="line">                        <span class="keyword">const</span> &#123; readable, writable &#125; = <span class="keyword">new</span> <span class="title class_">TransformStream</span>();</span><br><span class="line">                        dataStream.<span class="title function_">pipeTo</span>(writable).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;处理剩余数据错误:&#x27;</span>, err));</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 替换原始readable流</span></span><br><span class="line">                        <span class="comment">// @ts-ignore</span></span><br><span class="line">                        sock.<span class="property">readable</span> = readable;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">const</span> errorMsg = <span class="string">`HTTP代理连接失败: <span class="subst">$&#123;headers.split(<span class="string">&#x27;\r\n&#x27;</span>)[<span class="number">0</span>]&#125;</span>`</span>;</span><br><span class="line">                    <span class="variable language_">console</span>.<span class="title function_">error</span>(errorMsg);</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(errorMsg);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        reader.<span class="title function_">releaseLock</span>();</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`处理HTTP代理响应失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    reader.<span class="title function_">releaseLock</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!connected) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接失败: 未收到成功响应&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> sock;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><strong>天书13源码(不支持ios客户端、ed配置)</strong></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">FIXED_UUID</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; connect &#125; <span class="keyword">from</span> <span class="string">&#x27;cloudflare:sockets&#x27;</span>;</span><br><span class="line"><span class="comment">//本脚本不支持任何苹果ios客户端</span></span><br><span class="line"><span class="comment">//说明：抛弃了ed配置，不要设置/?ed=2560等任何ed，重构全部传输逻辑，去除订阅功能，自己手戳节点，支持基础反代路径传参/proxyip=，建议pages部署</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> 反代<span class="variable constant_">IP</span> = <span class="string">&#x27;&#x27;</span> <span class="comment">//反代IP或域名，反代IP端口一般情况下不用填写，如果你非要用非标反代的话，可以填&#x27;ts.hpc.tw:443&#x27;这样</span></span><br><span class="line"><span class="keyword">let</span> 启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span> <span class="comment">//如果启用此功能，原始反代将失效，很多S5不一定支持ipv6，启用则需禁用doh查询ipv6功能</span></span><br><span class="line"><span class="keyword">let</span> 启用<span class="title class_">SOCKS5</span>全局反代 = <span class="literal">false</span> <span class="comment">//选择是否启用SOCKS5全局反代，启用后所有访问都是S5的落地【无论你客户端选什么节点】，访问路径是客户端--CF--SOCKS5，当然启用此功能后延迟=CF+SOCKS5，带宽取决于SOCKS5的带宽，不再享受CF高速和随时满带宽的待遇</span></span><br><span class="line"><span class="keyword">let</span> 我的<span class="title class_">SOCKS5</span>账号 = <span class="string">&#x27;&#x27;</span>;<span class="comment">//格式&#x27;账号:密码@地址:端口&#x27;，示例admin:admin@127.0.0.1:443或admin:admin@[IPV6]:443，支持无账号密码示例@127.0.0.1:443</span></span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////流控配置////////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="keyword">let</span> 启动控流机制 = <span class="literal">false</span> <span class="comment">//true启动，false关闭，使用控流可降低CPU超时的概率，提升连接稳定性，适合轻度使用，日常使用应该绰绰有余</span></span><br><span class="line"><span class="keyword">let</span> 传输控流大小 = <span class="number">64</span>; <span class="comment">//单位字节，相当于分片大小</span></span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////主要架构////////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">fetch</span>(<span class="params">访问请求</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (访问请求.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Upgrade&#x27;</span>) === <span class="string">&#x27;websocket&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(访问请求.<span class="property">url</span>);</span><br><span class="line">            我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;socks5&#x27;</span>) || url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>全局反代 = url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;globalproxy&#x27;</span>);</span><br><span class="line">            <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5=&#x27;</span>) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/s5=&#x27;</span>)) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>))) &#123;</span><br><span class="line">                我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;5=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="string">&#x27;socks5&#x27;</span>;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>全局反代 = url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>) ? <span class="literal">true</span> : 启用<span class="title class_">SOCKS5</span>全局反代;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http=&#x27;</span>)) &#123;</span><br><span class="line">                我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;/http=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="string">&#x27;http&#x27;</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http://&#x27;</span>)) &#123;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/http://&#x27;</span>)) ? <span class="string">&#x27;http&#x27;</span> : <span class="string">&#x27;socks5&#x27;</span>;</span><br><span class="line">                我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;://&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;#&#x27;</span>)[<span class="number">0</span>];</span><br><span class="line">                <span class="keyword">if</span> (我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">includes</span>(<span class="string">&#x27;@&#x27;</span>)) &#123;</span><br><span class="line">                    <span class="keyword">const</span> lastAtIndex = 我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">lastIndexOf</span>(<span class="string">&#x27;@&#x27;</span>);</span><br><span class="line">                    <span class="keyword">let</span> userPassword = 我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">substring</span>(<span class="number">0</span>, lastAtIndex).<span class="title function_">replaceAll</span>(<span class="string">&#x27;%3D&#x27;</span>, <span class="string">&#x27;=&#x27;</span>);</span><br><span class="line">                    <span class="keyword">const</span> base64Regex = <span class="regexp">/^(?:[A-Z0-9+/]&#123;4&#125;)*(?:[A-Z0-9+/]&#123;2&#125;==|[A-Z0-9+/]&#123;3&#125;=)?$/i</span>;</span><br><span class="line">                    <span class="keyword">if</span> (base64Regex.<span class="title function_">test</span>(userPassword) &amp;&amp; !userPassword.<span class="title function_">includes</span>(<span class="string">&#x27;:&#x27;</span>)) userPassword = <span class="title function_">atob</span>(userPassword);</span><br><span class="line">                    我的<span class="title class_">SOCKS5</span>账号 = <span class="string">`<span class="subst">$&#123;userPassword&#125;</span>@<span class="subst">$&#123;我的SOCKS5账号.substring(lastAtIndex + <span class="number">1</span>)&#125;</span>`</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>全局反代 = <span class="literal">true</span>;<span class="comment">//开启全局SOCKS5</span></span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (我的<span class="title class_">SOCKS5</span>账号) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号);</span><br><span class="line">                    启用<span class="title class_">SOCKS5</span>反代 = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;http&#x27;</span>) ? <span class="string">&#x27;http&#x27;</span> : 启用<span class="title class_">SOCKS5</span>反代;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                    启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;proxyip&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;proxyip&#x27;</span>);</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip.&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = <span class="string">`proxyip.<span class="subst">$&#123;url.pathname.toLowerCase().split(<span class="string">&quot;/proxyip.&quot;</span>)[<span class="number">1</span>]&#125;</span>`</span>;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/pyip=&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/pyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/ip=&#x27;</span>)) &#123;</span><br><span class="line">                反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/ip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">const</span> [客户端, <span class="variable constant_">WS</span>接口] = <span class="title class_">Object</span>.<span class="title function_">values</span>(<span class="keyword">new</span> <span class="title class_">WebSocketPair</span>());</span><br><span class="line">            <span class="variable constant_">WS</span>接口.<span class="title function_">accept</span>();</span><br><span class="line">            <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>, <span class="number">0</span>]));</span><br><span class="line">            启动传输管道(<span class="variable constant_">WS</span>接口);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="literal">null</span>, &#123; <span class="attr">status</span>: <span class="number">101</span>, <span class="attr">webSocket</span>: 客户端 &#125;); <span class="comment">//一切准备就绪后，回复客户端WS连接升级成功</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Hello World!&#x27;</span>, &#123; <span class="attr">status</span>: <span class="number">200</span> &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 启动传输管道(<span class="variable constant_">WS</span>接口, <span class="variable constant_">TCP</span>接口) &#123;</span><br><span class="line">    <span class="keyword">let</span> 识别地址类型, 访问地址, 地址长度, 首包数据 = <span class="literal">false</span>, 首包处理完成 = <span class="literal">null</span>, 传输数据, 读取数据, 传输队列 = <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(), 累计传输字节数 = <span class="number">0</span>, 开始传输时间 = performance.<span class="title function_">now</span>();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="variable constant_">WS</span>接口.<span class="title function_">addEventListener</span>(<span class="string">&#x27;message&#x27;</span>, <span class="keyword">async</span> event =&gt; &#123;</span><br><span class="line">            <span class="keyword">if</span> (!首包数据) &#123;</span><br><span class="line">                首包数据 = <span class="literal">true</span>;</span><br><span class="line">                首包处理完成 = 解析首包数据(event.<span class="property">data</span>);</span><br><span class="line">                传输队列 = 传输队列.<span class="title function_">then</span>(<span class="function">() =&gt;</span> 首包处理完成).<span class="title function_">catch</span>(<span class="function"><span class="params">e</span> =&gt;</span> &#123; <span class="keyword">throw</span> (e) &#125;);</span><br><span class="line">                累计传输字节数 += event.<span class="property">data</span>.<span class="property">length</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">await</span> 首包处理完成;</span><br><span class="line">                传输队列 = 传输队列.<span class="title function_">then</span>(<span class="function">() =&gt;</span> 传输数据.<span class="title function_">write</span>(event.<span class="property">data</span>)).<span class="title function_">catch</span>(<span class="function"><span class="params">e</span> =&gt;</span> &#123; <span class="keyword">throw</span> (e) &#125;);</span><br><span class="line">                累计传输字节数 += event.<span class="property">data</span>.<span class="property">length</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">async</span> <span class="keyword">function</span> 解析首包数据(首包数据) &#123;</span><br><span class="line">            <span class="keyword">const</span> 二进制数据 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(首包数据);</span><br><span class="line">            <span class="keyword">const</span> 验证<span class="variable constant_">VL</span>的密钥 = <span class="function">(<span class="params">a, i = <span class="number">0</span></span>) =&gt;</span> [...a.<span class="title function_">slice</span>(i, i + <span class="number">16</span>)].<span class="title function_">map</span>(<span class="function"><span class="params">b</span> =&gt;</span> b.<span class="title function_">toString</span>(<span class="number">16</span>).<span class="title function_">padStart</span>(<span class="number">2</span>, <span class="string">&#x27;0&#x27;</span>)).<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/(.&#123;8&#125;)(.&#123;4&#125;)(.&#123;4&#125;)(.&#123;4&#125;)(.&#123;12&#125;)/</span>, <span class="string">&#x27;$1-$2-$3-$4-$5&#x27;</span>);</span><br><span class="line">            <span class="keyword">if</span> (<span class="variable constant_">FIXED_UUID</span> &amp;&amp; 验证<span class="variable constant_">VL</span>的密钥(二进制数据.<span class="title function_">slice</span>(<span class="number">1</span>, <span class="number">17</span>)) !== <span class="variable constant_">FIXED_UUID</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;UUID验证失败&#x27;</span>);</span><br><span class="line">            <span class="keyword">const</span> 提取端口索引 = <span class="number">18</span> + 二进制数据[<span class="number">17</span>] + <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">const</span> 访问端口 = <span class="keyword">new</span> <span class="title class_">DataView</span>(二进制数据.<span class="property">buffer</span>, 提取端口索引, <span class="number">2</span>).<span class="title function_">getUint16</span>(<span class="number">0</span>);</span><br><span class="line">            <span class="keyword">if</span> (访问端口 === <span class="number">53</span>) &#123; <span class="comment">//这个处理是应对某些客户端优先强制查询dns的情况，通过加密通道udp over tcp的</span></span><br><span class="line">                <span class="keyword">const</span> 提取<span class="variable constant_">DNS</span>查询报文 = 二进制数据.<span class="title function_">slice</span>(提取端口索引 + <span class="number">9</span>);</span><br><span class="line">                <span class="keyword">const</span> 查询<span class="variable constant_">DOH</span>结果 = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&#x27;https://1.1.1.1/dns-query&#x27;</span>, &#123;</span><br><span class="line">                    <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">                    <span class="attr">headers</span>: &#123;</span><br><span class="line">                        <span class="string">&#x27;content-type&#x27;</span>: <span class="string">&#x27;application/dns-message&#x27;</span>,</span><br><span class="line">                    &#125;,</span><br><span class="line">                    <span class="attr">body</span>: 提取<span class="variable constant_">DNS</span>查询报文</span><br><span class="line">                &#125;)</span><br><span class="line">                <span class="keyword">const</span> 提取<span class="variable constant_">DOH</span>结果 = <span class="keyword">await</span> 查询<span class="variable constant_">DOH</span>结果.<span class="title function_">arrayBuffer</span>();</span><br><span class="line">                <span class="keyword">const</span> 构建长度头部 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([(提取<span class="variable constant_">DOH</span>结果.<span class="property">byteLength</span> &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xff</span>, 提取<span class="variable constant_">DOH</span>结果.<span class="property">byteLength</span> &amp; <span class="number">0xff</span>]);</span><br><span class="line">                <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(<span class="keyword">await</span> <span class="keyword">new</span> <span class="title class_">Blob</span>([构建长度头部, 提取<span class="variable constant_">DOH</span>结果]));</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> 提取地址索引 = 提取端口索引 + <span class="number">2</span>;</span><br><span class="line">            识别地址类型 = 二进制数据[提取地址索引];</span><br><span class="line">            <span class="keyword">let</span> 地址信息索引 = 提取地址索引 + <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">switch</span> (识别地址类型) &#123;</span><br><span class="line">                <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">                    地址长度 = <span class="number">4</span>;</span><br><span class="line">                    访问地址 = 二进制数据.<span class="title function_">slice</span>(地址信息索引, 地址信息索引 + 地址长度).<span class="title function_">join</span>(<span class="string">&#x27;.&#x27;</span>);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">                    地址长度 = 二进制数据[地址信息索引];</span><br><span class="line">                    地址信息索引 += <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">const</span> 访问域名 = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(二进制数据.<span class="title function_">slice</span>(地址信息索引, 地址信息索引 + 地址长度));</span><br><span class="line">                    访问地址 = 访问域名;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">                    地址长度 = <span class="number">16</span>;</span><br><span class="line">                    <span class="keyword">const</span> ipv6 = [];</span><br><span class="line">                    <span class="keyword">const</span> 读取<span class="title class_">IPV6</span>地址 = <span class="keyword">new</span> <span class="title class_">DataView</span>(二进制数据.<span class="property">buffer</span>, 地址信息索引, <span class="number">16</span>);</span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++) ipv6.<span class="title function_">push</span>(读取<span class="title class_">IPV6</span>地址.<span class="title function_">getUint16</span>(i * <span class="number">2</span>).<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">                    访问地址 = ipv6.<span class="title function_">join</span>(<span class="string">&#x27;:&#x27;</span>);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="attr">default</span>:</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的访问地址&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">                <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> 创建<span class="title class_">SOCKS5</span>接口(识别地址类型, 访问地址, 访问端口);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">                <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(访问地址, 访问端口);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">if</span> (识别地址类型 === <span class="number">3</span>) &#123;</span><br><span class="line">                        <span class="keyword">const</span> 转换<span class="title class_">IPV6</span>地址 = <span class="string">`[<span class="subst">$&#123;访问地址&#125;</span>]`</span></span><br><span class="line">                        <span class="variable constant_">TCP</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 转换<span class="title class_">IPV6</span>地址, <span class="attr">port</span>: 访问端口 &#125;);</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="variable constant_">TCP</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 访问地址, <span class="attr">port</span>: 访问端口 &#125;);</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">await</span> <span class="variable constant_">TCP</span>接口.<span class="property">opened</span>;</span><br><span class="line">                &#125; <span class="keyword">catch</span> &#123;</span><br><span class="line">                    <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span>) &#123;</span><br><span class="line">                        <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> 创建<span class="title class_">SOCKS5</span>接口(识别地址类型, 访问地址, 访问端口);</span><br><span class="line">                    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span>) &#123;</span><br><span class="line">                        <span class="variable constant_">TCP</span>接口 = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(访问地址, 访问端口);</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="keyword">let</span> [反代<span class="variable constant_">IP</span>地址, 反代<span class="variable constant_">IP</span>端口] = 解析地址端口(反代<span class="variable constant_">IP</span>);</span><br><span class="line">                        <span class="variable constant_">TCP</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 反代<span class="variable constant_">IP</span>地址, <span class="attr">port</span>: 反代<span class="variable constant_">IP</span>端口 &#125;);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">await</span> <span class="variable constant_">TCP</span>接口.<span class="property">opened</span>;</span><br><span class="line">            传输数据 = <span class="variable constant_">TCP</span>接口.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">            读取数据 = <span class="variable constant_">TCP</span>接口.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">            <span class="keyword">const</span> 写入初始数据 = 二进制数据.<span class="title function_">slice</span>(地址信息索引 + 地址长度)</span><br><span class="line">            <span class="keyword">if</span> (写入初始数据) <span class="keyword">try</span> &#123; <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(写入初始数据) &#125; <span class="keyword">catch</span> (e) &#123; <span class="keyword">throw</span> (e) &#125;;</span><br><span class="line">            启动回传管道();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">async</span> <span class="keyword">function</span> 启动回传管道() &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                <span class="keyword">await</span> 传输队列;</span><br><span class="line">                <span class="keyword">const</span> &#123; <span class="attr">done</span>: 流结束, <span class="attr">value</span>: 返回数据 &#125; = <span class="keyword">await</span> 读取数据.<span class="title function_">read</span>();</span><br><span class="line">                <span class="keyword">if</span> (返回数据 &amp;&amp; 返回数据.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (启动控流机制) &#123;</span><br><span class="line">                        <span class="keyword">let</span> 分段初值 = <span class="number">0</span></span><br><span class="line">                        <span class="keyword">let</span> 分段大小 = 传输控流大小;</span><br><span class="line">                        <span class="keyword">while</span> (分段初值 &lt; 返回数据.<span class="property">length</span>) &#123;</span><br><span class="line">                            <span class="keyword">const</span> 数据块 = 返回数据.<span class="title function_">slice</span>(分段初值, 分段初值 + 分段大小);</span><br><span class="line">                            传输队列 = 传输队列.<span class="title function_">then</span>(<span class="function">() =&gt;</span> <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(数据块)).<span class="title function_">catch</span>(<span class="function"><span class="params">e</span> =&gt;</span> &#123; <span class="keyword">throw</span> (e) &#125;);</span><br><span class="line">                            分段初值 += 分段大小;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        传输队列 = 传输队列.<span class="title function_">then</span>(<span class="function">() =&gt;</span> <span class="variable constant_">WS</span>接口.<span class="title function_">send</span>(返回数据)).<span class="title function_">catch</span>(<span class="function"><span class="params">e</span> =&gt;</span> &#123; <span class="keyword">throw</span> (e) &#125;);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                累计传输字节数 += 返回数据.<span class="property">length</span>;</span><br><span class="line">                <span class="keyword">if</span> (流结束) <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;传输完成&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123; <span class="keyword">await</span> <span class="variable constant_">TCP</span>接口.<span class="property">close</span>?.() &#125; <span class="keyword">catch</span> &#123; &#125;;</span><br><span class="line">        <span class="variable constant_">WS</span>接口.<span class="property">close</span>?.();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">globalThis.<span class="property">DNS</span>缓存记录 = globalThis.<span class="property">DNS</span>缓存记录 ??= <span class="keyword">new</span> <span class="title class_">Map</span>();</span><br><span class="line"><span class="comment">//////////////////////////////////////////////////////////////////////////SOCKS5部分//////////////////////////////////////////////////////////////////////</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 创建<span class="title class_">SOCKS5</span>接口(识别地址类型, 访问地址, 访问端口, 转换访问地址, 传输数据, 读取数据) &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="title class_">SOCKS5</span>接口, 账号, 密码, 地址, 端口;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        (&#123; 账号, 密码, 地址, 端口 &#125; = <span class="keyword">await</span> 获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号));</span><br><span class="line">        <span class="title class_">SOCKS5</span>接口 = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 地址, <span class="attr">port</span>: 端口 &#125;);</span><br><span class="line">        <span class="keyword">await</span> <span class="title class_">SOCKS5</span>接口.<span class="property">opened</span>;</span><br><span class="line">        传输数据 = <span class="title class_">SOCKS5</span>接口.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        读取数据 = <span class="title class_">SOCKS5</span>接口.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">        <span class="keyword">const</span> 转换数组 = <span class="keyword">new</span> <span class="title class_">TextEncoder</span>(); <span class="comment">//把文本内容转换为字节数组，如账号，密码，域名，方便与S5建立连接</span></span><br><span class="line">        <span class="keyword">const</span> 构建<span class="variable constant_">S5</span>认证 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">2</span>]); <span class="comment">//构建认证信息,支持无认证和用户名/密码认证</span></span><br><span class="line">        <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(构建<span class="variable constant_">S5</span>认证); <span class="comment">//发送认证信息，确认目标是否需要用户名密码认证</span></span><br><span class="line">        <span class="keyword">const</span> 读取认证要求 = (<span class="keyword">await</span> 读取数据.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">        <span class="keyword">if</span> (读取认证要求[<span class="number">1</span>] === <span class="number">0x02</span>) &#123; <span class="comment">//检查是否需要用户名/密码认证</span></span><br><span class="line">            <span class="keyword">if</span> (!账号 || !密码) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`未配置账号密码`</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">const</span> 构建账号密码包 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">1</span>, 账号.<span class="property">length</span>, ...转换数组.<span class="title function_">encode</span>(账号), 密码.<span class="property">length</span>, ...转换数组.<span class="title function_">encode</span>(密码)]); <span class="comment">//构建账号密码数据包，把字符转换为字节数组</span></span><br><span class="line">            <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(构建账号密码包); <span class="comment">//发送账号密码认证信息</span></span><br><span class="line">            <span class="keyword">const</span> 读取账号密码认证结果 = (<span class="keyword">await</span> 读取数据.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">            <span class="keyword">if</span> (读取账号密码认证结果[<span class="number">0</span>] !== <span class="number">0x01</span> || 读取账号密码认证结果[<span class="number">1</span>] !== <span class="number">0x00</span>) &#123; <span class="comment">//检查账号密码认证结果，认证失败则退出</span></span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`账号密码错误`</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">switch</span> (识别地址类型) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">1</span>: <span class="comment">// IPv4</span></span><br><span class="line">                转换访问地址 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">1</span>, ...访问地址.<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>).<span class="title function_">map</span>(<span class="title class_">Number</span>)]);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">2</span>: <span class="comment">// 域名</span></span><br><span class="line">                转换访问地址 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">3</span>, 访问地址.<span class="property">length</span>, ...转换数组.<span class="title function_">encode</span>(访问地址)]);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">3</span>: <span class="comment">// IPv6</span></span><br><span class="line">                转换访问地址 = 转换为<span class="title class_">Socks5IPv6</span>地址(访问地址);</span><br><span class="line">                <span class="keyword">function</span> 转换为<span class="title class_">Socks5IPv6</span>地址(原始地址) &#123;</span><br><span class="line">                    <span class="keyword">const</span> 去括号地址 = 原始地址.<span class="title function_">startsWith</span>(<span class="string">&#x27;[&#x27;</span>) &amp;&amp; 原始地址.<span class="title function_">endsWith</span>(<span class="string">&#x27;]&#x27;</span>)</span><br><span class="line">                        ? 原始地址.<span class="title function_">slice</span>(<span class="number">1</span>, -<span class="number">1</span>)</span><br><span class="line">                        : 原始地址;</span><br><span class="line">                    <span class="keyword">const</span> 分段 = 去括号地址.<span class="title function_">split</span>(<span class="string">&#x27;::&#x27;</span>);</span><br><span class="line">                    <span class="keyword">const</span> 前缀 = 分段[<span class="number">0</span>] ? 分段[<span class="number">0</span>].<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="title function_">filter</span>(<span class="title class_">Boolean</span>) : [];</span><br><span class="line">                    <span class="keyword">const</span> 后缀 = 分段[<span class="number">1</span>] ? 分段[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="title function_">filter</span>(<span class="title class_">Boolean</span>) : [];</span><br><span class="line">                    <span class="keyword">const</span> 填充数量 = <span class="number">8</span> - (前缀.<span class="property">length</span> + 后缀.<span class="property">length</span>);</span><br><span class="line">                    <span class="keyword">if</span> (填充数量 &lt; <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;IPv6地址格式错误&#x27;</span>);</span><br><span class="line">                    <span class="keyword">const</span> 完整分段 = [...前缀, ...<span class="title class_">Array</span>(填充数量).<span class="title function_">fill</span>(<span class="string">&#x27;0&#x27;</span>), ...后缀];</span><br><span class="line">                    <span class="keyword">const</span> <span class="title class_">IPv6</span>字节 = 完整分段.<span class="title function_">flatMap</span>(字段 =&gt; &#123;</span><br><span class="line">                        <span class="keyword">const</span> 数值 = <span class="built_in">parseInt</span>(字段 || <span class="string">&#x27;0&#x27;</span>, <span class="number">16</span>);</span><br><span class="line">                        <span class="keyword">return</span> [(数值 &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xff</span>, 数值 &amp; <span class="number">0xff</span>];</span><br><span class="line">                    &#125;);</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0x04</span>, ...<span class="title class_">IPv6</span>字节]);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">const</span> 构建转换后的访问地址 = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">1</span>, <span class="number">0</span>, ...转换访问地址, 访问端口 &gt;&gt; <span class="number">8</span>, 访问端口 &amp; <span class="number">0xff</span>]); <span class="comment">//构建转换好的地址消息</span></span><br><span class="line">        <span class="keyword">await</span> 传输数据.<span class="title function_">write</span>(构建转换后的访问地址); <span class="comment">//发送转换后的地址</span></span><br><span class="line">        <span class="keyword">const</span> 检查返回响应 = (<span class="keyword">await</span> 读取数据.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">        <span class="keyword">if</span> (检查返回响应[<span class="number">0</span>] !== <span class="number">0x05</span> || 检查返回响应[<span class="number">1</span>] !== <span class="number">0x00</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`目标地址连接失败，访问地址: <span class="subst">$&#123;访问地址&#125;</span>，地址类型: <span class="subst">$&#123;识别地址类型&#125;</span>`</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        传输数据.<span class="title function_">releaseLock</span>();</span><br><span class="line">        读取数据.<span class="title function_">releaseLock</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">SOCKS5</span>接口;</span><br><span class="line">    &#125; <span class="keyword">catch</span> &#123; &#125;;</span><br><span class="line"></span><br><span class="line">    传输数据?.<span class="title function_">releaseLock</span>();</span><br><span class="line">    读取数据?.<span class="title function_">releaseLock</span>();</span><br><span class="line">    <span class="keyword">await</span> <span class="title class_">SOCKS5</span>接口?.<span class="title function_">close</span>();</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`所有SOCKS5账号失效`</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 获取<span class="title class_">SOCKS5</span>账号(address) &#123;</span><br><span class="line">    <span class="comment">// 使用 &quot;@&quot; 分割地址，分为认证部分和服务器地址部分</span></span><br><span class="line">    <span class="keyword">const</span> lastAtIndex = address.<span class="title function_">lastIndexOf</span>(<span class="string">&quot;@&quot;</span>);</span><br><span class="line">    <span class="keyword">let</span> [latter, former] = lastAtIndex === -<span class="number">1</span> ? [address, <span class="literal">undefined</span>] : [address.<span class="title function_">substring</span>(lastAtIndex + <span class="number">1</span>), address.<span class="title function_">substring</span>(<span class="number">0</span>, lastAtIndex)];</span><br><span class="line">    <span class="keyword">let</span> username, password, hostname, port;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果存在 former 部分，说明提供了认证信息</span></span><br><span class="line">    <span class="keyword">if</span> (former) &#123;</span><br><span class="line">        <span class="keyword">const</span> formers = former.<span class="title function_">split</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (formers.<span class="property">length</span> !== <span class="number">2</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：认证部分必须是 &quot;username:password&quot; 的形式&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        [username, password] = formers;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 解析服务器地址部分</span></span><br><span class="line">    <span class="keyword">const</span> latters = latter.<span class="title function_">split</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">    <span class="comment">// 检查是否是IPv6地址带端口格式 [xxx]:port</span></span><br><span class="line">    <span class="keyword">if</span> (latters.<span class="property">length</span> &gt; <span class="number">2</span> &amp;&amp; latter.<span class="title function_">includes</span>(<span class="string">&quot;]:&quot;</span>)) &#123;</span><br><span class="line">        <span class="comment">// IPv6地址带端口格式：[2001:db8::1]:8080</span></span><br><span class="line">        port = <span class="title class_">Number</span>(latter.<span class="title function_">split</span>(<span class="string">&quot;]:&quot;</span>)[<span class="number">1</span>].<span class="title function_">replace</span>(<span class="regexp">/[^\d]/g</span>, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        hostname = latter.<span class="title function_">split</span>(<span class="string">&quot;]:&quot;</span>)[<span class="number">0</span>] + <span class="string">&quot;]&quot;</span>; <span class="comment">// 正确提取hostname部分</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (latters.<span class="property">length</span> === <span class="number">2</span>) &#123;</span><br><span class="line">        <span class="comment">// IPv4地址带端口或域名带端口</span></span><br><span class="line">        port = <span class="title class_">Number</span>(latters.<span class="title function_">pop</span>().<span class="title function_">replace</span>(<span class="regexp">/[^\d]/g</span>, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        hostname = latters.<span class="title function_">join</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        port = <span class="number">80</span>;</span><br><span class="line">        hostname = latter;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">isNaN</span>(port)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：端口号必须是数字&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理 IPv6 地址的特殊情况</span></span><br><span class="line">    <span class="comment">// IPv6 地址包含多个冒号，所以必须用方括号括起来，如 [2001:db8::1]</span></span><br><span class="line">    <span class="keyword">const</span> regex = <span class="regexp">/^\[.*\]$/</span>;</span><br><span class="line">    <span class="keyword">if</span> (hostname.<span class="title function_">includes</span>(<span class="string">&quot;:&quot;</span>) &amp;&amp; !regex.<span class="title function_">test</span>(hostname)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：IPv6 地址必须用方括号括起来，如 [2001:db8::1]&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)&#123;3&#125;(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(hostname)) hostname = `$&#123;atob(&#x27;d3d3Lg==&#x27;)&#125;$&#123;hostname&#125;$&#123;atob(&#x27;LmlwLjA5MDIyNy54eXo=&#x27;)&#125;`;</span></span><br><span class="line">    <span class="comment">// 返回解析后的结果</span></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        username,  <span class="comment">// 用户名，如果没有则为 undefined</span></span><br><span class="line">        password,  <span class="comment">// 密码，如果没有则为 undefined</span></span><br><span class="line">        hostname,  <span class="comment">// 主机名，可以是域名、IPv4 或 IPv6 地址</span></span><br><span class="line">        port, <span class="comment">// 端口号，已转换为数字类型</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> 解析地址端口(反代<span class="variable constant_">IP</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> proxyIP = 反代<span class="variable constant_">IP</span>.<span class="title function_">toLowerCase</span>();</span><br><span class="line">    <span class="keyword">let</span> 地址 = proxyIP, 端口 = <span class="number">443</span>;</span><br><span class="line">    <span class="keyword">if</span> (!proxyIP || proxyIP == <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line">        地址 = <span class="string">&#x27;proxyip.fxxk.dedyn.io&#x27;</span>; <span class="comment">//默认反代</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (proxyIP.<span class="title function_">includes</span>(<span class="string">&#x27;]:&#x27;</span>)) &#123;</span><br><span class="line">        端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">1</span>] || 端口;</span><br><span class="line">        地址 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">0</span>] + <span class="string">&quot;]&quot;</span> || 地址;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="property">length</span> === <span class="number">2</span>) &#123;</span><br><span class="line">        端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">1</span>] || 端口;</span><br><span class="line">        地址 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">0</span>] || 地址;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (proxyIP.<span class="title function_">includes</span>(<span class="string">&#x27;.tp&#x27;</span>)) 端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;.tp&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>)[<span class="number">0</span>] || 端口;</span><br><span class="line">    <span class="keyword">return</span> [地址, 端口];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">httpConnect</span>(<span class="params">addressRemote, portRemote</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> parsedSocks5Address = <span class="keyword">await</span> 获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号);</span><br><span class="line">    <span class="keyword">const</span> &#123; username, password, hostname, port &#125; = parsedSocks5Address;</span><br><span class="line">    <span class="keyword">const</span> sock = <span class="keyword">await</span> <span class="title function_">connect</span>(&#123;</span><br><span class="line">        <span class="attr">hostname</span>: hostname,</span><br><span class="line">        <span class="attr">port</span>: port</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 构建HTTP CONNECT请求</span></span><br><span class="line">    <span class="keyword">let</span> connectRequest = <span class="string">`CONNECT <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span> HTTP/1.1\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Host: <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span>\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加代理认证（如果需要）</span></span><br><span class="line">    <span class="keyword">if</span> (username &amp;&amp; password) &#123;</span><br><span class="line">        <span class="keyword">const</span> authString = <span class="string">`<span class="subst">$&#123;username&#125;</span>:<span class="subst">$&#123;password&#125;</span>`</span>;</span><br><span class="line">        <span class="keyword">const</span> base64Auth = <span class="title function_">btoa</span>(authString);</span><br><span class="line">        connectRequest += <span class="string">`Proxy-Authorization: Basic <span class="subst">$&#123;base64Auth&#125;</span>\r\n`</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    connectRequest += <span class="string">`User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Proxy-Connection: Keep-Alive\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Connection: Keep-Alive\r\n`</span>; <span class="comment">// 添加标准 Connection 头</span></span><br><span class="line">    connectRequest += <span class="string">`\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 发送连接请求</span></span><br><span class="line">        <span class="keyword">const</span> writer = sock.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        <span class="keyword">await</span> writer.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(connectRequest));</span><br><span class="line">        writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;发送HTTP CONNECT请求失败:&#x27;</span>, err);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`发送HTTP CONNECT请求失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 读取HTTP响应</span></span><br><span class="line">    <span class="keyword">const</span> reader = sock.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">    <span class="keyword">let</span> respText = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">let</span> connected = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> responseBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> &#123; value, done &#125; = <span class="keyword">await</span> reader.<span class="title function_">read</span>();</span><br><span class="line">            <span class="keyword">if</span> (done) &#123;</span><br><span class="line">                <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 合并接收到的数据</span></span><br><span class="line">            <span class="keyword">const</span> newBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(responseBuffer.<span class="property">length</span> + value.<span class="property">length</span>);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(responseBuffer);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(value, responseBuffer.<span class="property">length</span>);</span><br><span class="line">            responseBuffer = newBuffer;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 将收到的数据转换为文本</span></span><br><span class="line">            respText = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(responseBuffer);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 检查是否收到完整的HTTP响应头</span></span><br><span class="line">            <span class="keyword">if</span> (respText.<span class="title function_">includes</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>)) &#123;</span><br><span class="line">                <span class="comment">// 分离HTTP头和可能的数据部分</span></span><br><span class="line">                <span class="keyword">const</span> headersEndPos = respText.<span class="title function_">indexOf</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>) + <span class="number">4</span>;</span><br><span class="line">                <span class="keyword">const</span> headers = respText.<span class="title function_">substring</span>(<span class="number">0</span>, headersEndPos);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 检查响应状态</span></span><br><span class="line">                <span class="keyword">if</span> (headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.1 200&#x27;</span>) || headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.0 200&#x27;</span>)) &#123;</span><br><span class="line">                    connected = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">                    <span class="comment">// 如果响应头之后还有数据，我们需要保存这些数据以便后续处理</span></span><br><span class="line">                    <span class="keyword">if</span> (headersEndPos &lt; responseBuffer.<span class="property">length</span>) &#123;</span><br><span class="line">                        <span class="keyword">const</span> remainingData = responseBuffer.<span class="title function_">slice</span>(headersEndPos);</span><br><span class="line">                        <span class="comment">// 创建一个缓冲区来存储这些数据，以便稍后使用</span></span><br><span class="line">                        <span class="keyword">const</span> dataStream = <span class="keyword">new</span> <span class="title class_">ReadableStream</span>(&#123;</span><br><span class="line">                            <span class="title function_">start</span>(<span class="params">controller</span>) &#123;</span><br><span class="line">                                controller.<span class="title function_">enqueue</span>(remainingData);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;);</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 创建一个新的TransformStream来处理额外数据</span></span><br><span class="line">                        <span class="keyword">const</span> &#123; readable, writable &#125; = <span class="keyword">new</span> <span class="title class_">TransformStream</span>();</span><br><span class="line">                        dataStream.<span class="title function_">pipeTo</span>(writable).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;处理剩余数据错误:&#x27;</span>, err));</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 替换原始readable流</span></span><br><span class="line">                        <span class="comment">// @ts-ignore</span></span><br><span class="line">                        sock.<span class="property">readable</span> = readable;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">const</span> errorMsg = <span class="string">`HTTP代理连接失败: <span class="subst">$&#123;headers.split(<span class="string">&#x27;\r\n&#x27;</span>)[<span class="number">0</span>]&#125;</span>`</span>;</span><br><span class="line">                    <span class="variable language_">console</span>.<span class="title function_">error</span>(errorMsg);</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(errorMsg);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        reader.<span class="title function_">releaseLock</span>();</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`处理HTTP代理响应失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    reader.<span class="title function_">releaseLock</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!connected) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接失败: 未收到成功响应&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> sock;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><strong>ymyuuu源码(支持xhttp)</strong></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">FIXED_UUID</span> = <span class="string">&#x27;&#x27;</span>;<span class="comment">// 建议修改为自己的规范化UUID，如不需要可留空</span></span><br><span class="line"><span class="keyword">import</span> &#123; connect &#125; <span class="keyword">from</span> <span class="string">&#x27;cloudflare:sockets&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> 反代<span class="variable constant_">IP</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> 启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line"><span class="keyword">let</span> 启用<span class="title class_">SOCKS5</span>全局反代 = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">let</span> 我的<span class="title class_">SOCKS5</span>账号 = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">    <span class="keyword">async</span> <span class="title function_">fetch</span>(<span class="params">request</span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(request.<span class="property">url</span>);</span><br><span class="line">        我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;socks5&#x27;</span>) || url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line">        启用<span class="title class_">SOCKS5</span>全局反代 = url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;globalproxy&#x27;</span>);</span><br><span class="line">        <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5=&#x27;</span>) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/s5=&#x27;</span>)) || (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>))) &#123;</span><br><span class="line">            我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;5=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="string">&#x27;socks5&#x27;</span>;</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>全局反代 = url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/gs5=&#x27;</span>) ? <span class="literal">true</span> : 启用<span class="title class_">SOCKS5</span>全局反代;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http=&#x27;</span>)) &#123;</span><br><span class="line">            我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;/http=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="string">&#x27;http&#x27;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/socks5://&#x27;</span>) || url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/http://&#x27;</span>)) &#123;</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/http://&#x27;</span>)) ? <span class="string">&#x27;http&#x27;</span> : <span class="string">&#x27;socks5&#x27;</span>;</span><br><span class="line">            我的<span class="title class_">SOCKS5</span>账号 = url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;://&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;#&#x27;</span>)[<span class="number">0</span>];</span><br><span class="line">            <span class="keyword">if</span> (我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">includes</span>(<span class="string">&#x27;@&#x27;</span>)) &#123;</span><br><span class="line">                <span class="keyword">const</span> lastAtIndex = 我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">lastIndexOf</span>(<span class="string">&#x27;@&#x27;</span>);</span><br><span class="line">                <span class="keyword">let</span> userPassword = 我的<span class="title class_">SOCKS5</span>账号.<span class="title function_">substring</span>(<span class="number">0</span>, lastAtIndex).<span class="title function_">replaceAll</span>(<span class="string">&#x27;%3D&#x27;</span>, <span class="string">&#x27;=&#x27;</span>);</span><br><span class="line">                <span class="keyword">const</span> base64Regex = <span class="regexp">/^(?:[A-Z0-9+/]&#123;4&#125;)*(?:[A-Z0-9+/]&#123;2&#125;==|[A-Z0-9+/]&#123;3&#125;=)?$/i</span>;</span><br><span class="line">                <span class="keyword">if</span> (base64Regex.<span class="title function_">test</span>(userPassword) &amp;&amp; !userPassword.<span class="title function_">includes</span>(<span class="string">&#x27;:&#x27;</span>)) userPassword = <span class="title function_">atob</span>(userPassword);</span><br><span class="line">                我的<span class="title class_">SOCKS5</span>账号 = <span class="string">`<span class="subst">$&#123;userPassword&#125;</span>@<span class="subst">$&#123;我的SOCKS5账号.substring(lastAtIndex + <span class="number">1</span>)&#125;</span>`</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>全局反代 = <span class="literal">true</span>;<span class="comment">//开启全局SOCKS5</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (我的<span class="title class_">SOCKS5</span>账号) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号);</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;http&#x27;</span>) ? <span class="string">&#x27;http&#x27;</span> : 启用<span class="title class_">SOCKS5</span>反代;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">                启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (url.<span class="property">searchParams</span>.<span class="title function_">has</span>(<span class="string">&#x27;proxyip&#x27;</span>)) &#123;</span><br><span class="line">            反代<span class="variable constant_">IP</span> = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;proxyip&#x27;</span>);</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)) &#123;</span><br><span class="line">            反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/proxyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/proxyip.&#x27;</span>)) &#123;</span><br><span class="line">            反代<span class="variable constant_">IP</span> = <span class="string">`proxyip.<span class="subst">$&#123;url.pathname.toLowerCase().split(<span class="string">&quot;/proxyip.&quot;</span>)[<span class="number">1</span>]&#125;</span>`</span>;</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/pyip=&#x27;</span>)) &#123;</span><br><span class="line">            反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/pyip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(<span class="string">&#x27;/ip=&#x27;</span>)) &#123;</span><br><span class="line">            反代<span class="variable constant_">IP</span> = url.<span class="property">pathname</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">split</span>(<span class="string">&#x27;/ip=&#x27;</span>)[<span class="number">1</span>];</span><br><span class="line">            启用<span class="title class_">SOCKS5</span>反代 = <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// WebSocket 处理</span></span><br><span class="line">        <span class="keyword">if</span> (request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Upgrade&#x27;</span>)?.<span class="title function_">toLowerCase</span>() === <span class="string">&#x27;websocket&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">handleWebSocket</span>(request);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (request.<span class="property">method</span> === <span class="string">&#x27;POST&#x27;</span>) &#123;</span><br><span class="line">                <span class="comment">// XHTTP 处理</span></span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">handleXhttp</span>(request);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Hello World!&#x27;</span>, &#123; <span class="attr">status</span>: <span class="number">200</span> &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// XHTTP 处理函数</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">handleXhttp</span>(<span class="params">request</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> vlessHeader = <span class="keyword">await</span> <span class="title function_">readVlessHeader</span>(request.<span class="property">body</span>.<span class="title function_">getReader</span>());</span><br><span class="line">    <span class="keyword">if</span> (!vlessHeader) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Invalid VLESS header&#x27;</span>, &#123;</span><br><span class="line">        <span class="attr">status</span>: <span class="number">400</span></span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 连接到远程</span></span><br><span class="line">    <span class="keyword">let</span> remote = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">        remote = <span class="keyword">await</span> <span class="title function_">socks5Connect</span>(vlessHeader.<span class="property">hostname</span>, vlessHeader.<span class="property">port</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">        remote = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(vlessHeader.<span class="property">hostname</span>, vlessHeader.<span class="property">port</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            remote = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: vlessHeader.<span class="property">hostname</span>, <span class="attr">port</span>: vlessHeader.<span class="property">port</span> &#125;);</span><br><span class="line">            <span class="keyword">await</span> remote.<span class="property">opened</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span>) &#123;</span><br><span class="line">                remote = <span class="keyword">await</span> <span class="title function_">socks5Connect</span>(vlessHeader.<span class="property">hostname</span>, vlessHeader.<span class="property">port</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span>) &#123;</span><br><span class="line">                remote = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(vlessHeader.<span class="property">hostname</span>, vlessHeader.<span class="property">port</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">let</span> [反代<span class="variable constant_">IP</span>地址, 反代<span class="variable constant_">IP</span>端口] = 解析地址端口(反代<span class="variable constant_">IP</span>);</span><br><span class="line">                remote = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 反代<span class="variable constant_">IP</span>地址, <span class="attr">port</span>: 反代<span class="variable constant_">IP</span>端口 &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> remote.<span class="property">opened</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!remote) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Connect failed&#x27;</span>, &#123;</span><br><span class="line">        <span class="attr">status</span>: <span class="number">502</span></span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 创建双向数据流</span></span><br><span class="line">    <span class="keyword">const</span> &#123;</span><br><span class="line">        readable,</span><br><span class="line">        writable</span><br><span class="line">    &#125; = <span class="keyword">new</span> <span class="title class_">TransformStream</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 上传流：请求 -&gt; 远程</span></span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">uploadPipe</span> = <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="keyword">const</span> writer = remote.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        <span class="keyword">if</span> (vlessHeader.<span class="property">data</span>?.<span class="property">length</span>) <span class="keyword">await</span> writer.<span class="title function_">write</span>(vlessHeader.<span class="property">data</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> reader = vlessHeader.<span class="property">reader</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                <span class="keyword">const</span> &#123;</span><br><span class="line">                    value,</span><br><span class="line">                    done</span><br><span class="line">                &#125; = <span class="keyword">await</span> reader.<span class="title function_">read</span>();</span><br><span class="line">                <span class="keyword">if</span> (done) <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">if</span> (value) <span class="keyword">await</span> writer.<span class="title function_">write</span>(value);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> &#123; &#125;</span><br><span class="line">        writer.<span class="title function_">close</span>();</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 下载流：远程 -&gt; 响应</span></span><br><span class="line">    <span class="keyword">const</span> downloadPipe = <span class="keyword">new</span> <span class="title class_">TransformStream</span>(&#123;</span><br><span class="line">        <span class="title function_">start</span>(<span class="params">ctrl</span>) &#123;</span><br><span class="line">            ctrl.<span class="title function_">enqueue</span>(vlessHeader.<span class="property">resp</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    remote.<span class="property">readable</span>.<span class="title function_">pipeTo</span>(downloadPipe.<span class="property">writable</span>).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123; &#125;);</span><br><span class="line">    <span class="title function_">uploadPipe</span>().<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123; &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(downloadPipe.<span class="property">readable</span>, &#123;</span><br><span class="line">        <span class="attr">headers</span>: &#123;</span><br><span class="line">            <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;application/grpc&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;X-Accel-Buffering&#x27;</span>: <span class="string">&#x27;no&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;Cache-Control&#x27;</span>: <span class="string">&#x27;no-store&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// WebSocket 处理函数（保持原有逻辑）</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">handleWebSocket</span>(<span class="params">request</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> [client, ws] = <span class="title class_">Object</span>.<span class="title function_">values</span>(<span class="keyword">new</span> <span class="title class_">WebSocketPair</span>());</span><br><span class="line">    ws.<span class="title function_">accept</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> remote = <span class="literal">null</span>,</span><br><span class="line">        udpWriter = <span class="literal">null</span>,</span><br><span class="line">        isDNS = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">ReadableStream</span>(&#123;</span><br><span class="line">        <span class="title function_">start</span>(<span class="params">ctrl</span>) &#123;</span><br><span class="line">            ws.<span class="title function_">addEventListener</span>(<span class="string">&#x27;message&#x27;</span>, <span class="function"><span class="params">e</span> =&gt;</span> ctrl.<span class="title function_">enqueue</span>(e.<span class="property">data</span>));</span><br><span class="line">            ws.<span class="title function_">addEventListener</span>(<span class="string">&#x27;close&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">                remote?.<span class="title function_">close</span>();</span><br><span class="line">                ctrl.<span class="title function_">close</span>();</span><br><span class="line">            &#125;);</span><br><span class="line">            ws.<span class="title function_">addEventListener</span>(<span class="string">&#x27;error&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">                remote?.<span class="title function_">close</span>();</span><br><span class="line">                ctrl.<span class="title function_">error</span>();</span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">const</span> early = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;sec-websocket-protocol&#x27;</span>);</span><br><span class="line">            <span class="keyword">if</span> (early) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    ctrl.<span class="title function_">enqueue</span>(<span class="title class_">Uint8Array</span>.<span class="title function_">from</span>(<span class="title function_">atob</span>(early.<span class="title function_">replace</span>(<span class="regexp">/-/g</span>, <span class="string">&#x27;+&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/_/g</span>, <span class="string">&#x27;/&#x27;</span>)),</span><br><span class="line">                        <span class="function"><span class="params">c</span> =&gt;</span> c.<span class="title function_">charCodeAt</span>(<span class="number">0</span>)).<span class="property">buffer</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> &#123; &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;).<span class="title function_">pipeTo</span>(<span class="keyword">new</span> <span class="title class_">WritableStream</span>(&#123;</span><br><span class="line">        <span class="keyword">async</span> <span class="title function_">write</span>(<span class="params">data</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (isDNS) <span class="keyword">return</span> udpWriter?.<span class="title function_">write</span>(data);</span><br><span class="line">            <span class="keyword">if</span> (remote) &#123;</span><br><span class="line">                <span class="keyword">const</span> w = remote.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">                <span class="keyword">await</span> w.<span class="title function_">write</span>(data);</span><br><span class="line">                w.<span class="title function_">releaseLock</span>();</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (data.<span class="property">byteLength</span> &lt; <span class="number">24</span>) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// UUID验证</span></span><br><span class="line">            <span class="keyword">if</span> (<span class="variable constant_">FIXED_UUID</span>) &#123;</span><br><span class="line">                <span class="keyword">const</span> uuidBytes = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(data.<span class="title function_">slice</span>(<span class="number">1</span>, <span class="number">17</span>));</span><br><span class="line">                <span class="keyword">const</span> expectedUUID = <span class="variable constant_">FIXED_UUID</span>.<span class="title function_">replace</span>(<span class="regexp">/-/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">16</span>; i++) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (uuidBytes[i] !== <span class="built_in">parseInt</span>(expectedUUID.<span class="title function_">substr</span>(i * <span class="number">2</span>, <span class="number">2</span>), <span class="number">16</span>)) <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">const</span> view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data);</span><br><span class="line">            <span class="keyword">const</span> optLen = view.<span class="title function_">getUint8</span>(<span class="number">17</span>);</span><br><span class="line">            <span class="keyword">const</span> cmd = view.<span class="title function_">getUint8</span>(<span class="number">18</span> + optLen);</span><br><span class="line">            <span class="keyword">if</span> (cmd !== <span class="number">1</span> &amp;&amp; cmd !== <span class="number">2</span>) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">let</span> pos = <span class="number">19</span> + optLen;</span><br><span class="line">            <span class="keyword">const</span> port = view.<span class="title function_">getUint16</span>(pos);</span><br><span class="line">            <span class="keyword">const</span> type = view.<span class="title function_">getUint8</span>(pos + <span class="number">2</span>);</span><br><span class="line">            pos += <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">let</span> addr = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">            <span class="keyword">if</span> (type === <span class="number">1</span>) &#123;</span><br><span class="line">                addr =</span><br><span class="line">                    <span class="string">`<span class="subst">$&#123;view.getUint8(pos)&#125;</span>.<span class="subst">$&#123;view.getUint8(pos + <span class="number">1</span>)&#125;</span>.<span class="subst">$&#123;view.getUint8(pos + <span class="number">2</span>)&#125;</span>.<span class="subst">$&#123;view.getUint8(pos + <span class="number">3</span>)&#125;</span>`</span>;</span><br><span class="line">                pos += <span class="number">4</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type === <span class="number">2</span>) &#123;</span><br><span class="line">                <span class="keyword">const</span> len = view.<span class="title function_">getUint8</span>(pos++);</span><br><span class="line">                addr = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(data.<span class="title function_">slice</span>(pos, pos + len));</span><br><span class="line">                pos += len;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type === <span class="number">3</span>) &#123;</span><br><span class="line">                <span class="keyword">const</span> ipv6 = [];</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++, pos += <span class="number">2</span>) ipv6.<span class="title function_">push</span>(view.<span class="title function_">getUint16</span>(pos).<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">                addr = ipv6.<span class="title function_">join</span>(<span class="string">&#x27;:&#x27;</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">const</span> header = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([data[<span class="number">0</span>], <span class="number">0</span>]);</span><br><span class="line">            <span class="keyword">const</span> payload = data.<span class="title function_">slice</span>(pos);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// UDP DNS</span></span><br><span class="line">            <span class="keyword">if</span> (cmd === <span class="number">2</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (port !== <span class="number">53</span>) <span class="keyword">return</span>;</span><br><span class="line">                isDNS = <span class="literal">true</span>;</span><br><span class="line">                <span class="keyword">let</span> sent = <span class="literal">false</span>;</span><br><span class="line">                <span class="keyword">const</span> &#123;</span><br><span class="line">                    readable,</span><br><span class="line">                    writable</span><br><span class="line">                &#125; = <span class="keyword">new</span> <span class="title class_">TransformStream</span>(&#123;</span><br><span class="line">                    <span class="title function_">transform</span>(<span class="params">chunk, ctrl</span>) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; chunk.<span class="property">byteLength</span>;) &#123;</span><br><span class="line">                            <span class="keyword">const</span> len = <span class="keyword">new</span> <span class="title class_">DataView</span>(chunk.<span class="title function_">slice</span>(i, i + <span class="number">2</span>)).<span class="title function_">getUint16</span>(<span class="number">0</span>);</span><br><span class="line">                            ctrl.<span class="title function_">enqueue</span>(chunk.<span class="title function_">slice</span>(i + <span class="number">2</span>, i + <span class="number">2</span> + len));</span><br><span class="line">                            i += <span class="number">2</span> + len;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;);</span><br><span class="line"></span><br><span class="line">                readable.<span class="title function_">pipeTo</span>(<span class="keyword">new</span> <span class="title class_">WritableStream</span>(&#123;</span><br><span class="line">                    <span class="keyword">async</span> <span class="title function_">write</span>(<span class="params">query</span>) &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            <span class="keyword">const</span> resp = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&#x27;https://1.1.1.1/dns-query&#x27;</span>, &#123;</span><br><span class="line">                                <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">                                <span class="attr">headers</span>: &#123;</span><br><span class="line">                                    <span class="string">&#x27;content-type&#x27;</span>: <span class="string">&#x27;application/dns-message&#x27;</span></span><br><span class="line">                                &#125;,</span><br><span class="line">                                <span class="attr">body</span>: query</span><br><span class="line">                            &#125;);</span><br><span class="line">                            <span class="keyword">if</span> (ws.<span class="property">readyState</span> === <span class="number">1</span>) &#123;</span><br><span class="line">                                <span class="keyword">const</span> result = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="keyword">await</span> resp</span><br><span class="line">                                    .<span class="title function_">arrayBuffer</span>());</span><br><span class="line">                                ws.<span class="title function_">send</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>([...(sent ? [] : header),</span><br><span class="line">                                result.<span class="property">length</span> &gt;&gt; <span class="number">8</span>, result.<span class="property">length</span> &amp;</span><br><span class="line">                                <span class="number">0xff</span>, ...result</span><br><span class="line">                                ]));</span><br><span class="line">                                sent = <span class="literal">true</span>;</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125; <span class="keyword">catch</span> &#123; &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;));</span><br><span class="line">                udpWriter = writable.<span class="title function_">getWriter</span>();</span><br><span class="line">                <span class="keyword">return</span> udpWriter.<span class="title function_">write</span>(payload);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// TCP连接</span></span><br><span class="line">            <span class="keyword">let</span> sock = <span class="literal">null</span>;</span><br><span class="line">            <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">                sock = <span class="keyword">await</span> <span class="title function_">socks5Connect</span>(addr, port);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span> &amp;&amp; 启用<span class="title class_">SOCKS5</span>全局反代) &#123;</span><br><span class="line">                sock = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(addr, port);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    sock = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: addr, <span class="attr">port</span>: port &#125;);</span><br><span class="line">                    <span class="keyword">await</span> sock.<span class="property">opened</span>;</span><br><span class="line">                &#125; <span class="keyword">catch</span> &#123;</span><br><span class="line">                    <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;socks5&#x27;</span>) &#123;</span><br><span class="line">                        sock = <span class="keyword">await</span> <span class="title function_">socks5Connect</span>(addr, port);</span><br><span class="line">                    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (启用<span class="title class_">SOCKS5</span>反代 == <span class="string">&#x27;http&#x27;</span>) &#123;</span><br><span class="line">                        sock = <span class="keyword">await</span> <span class="title function_">httpConnect</span>(addr, port);</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="keyword">let</span> [反代<span class="variable constant_">IP</span>地址, 反代<span class="variable constant_">IP</span>端口] = 解析地址端口(反代<span class="variable constant_">IP</span>);</span><br><span class="line">                        sock = <span class="title function_">connect</span>(&#123; <span class="attr">hostname</span>: 反代<span class="variable constant_">IP</span>地址, <span class="attr">port</span>: 反代<span class="variable constant_">IP</span>端口 &#125;);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">await</span> sock.<span class="property">opened</span>;</span><br><span class="line">            <span class="keyword">if</span> (!sock) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">            remote = sock;</span><br><span class="line">            <span class="keyword">const</span> w = sock.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">            <span class="keyword">await</span> w.<span class="title function_">write</span>(payload);</span><br><span class="line">            w.<span class="title function_">releaseLock</span>();</span><br><span class="line"></span><br><span class="line">            <span class="keyword">let</span> sent = <span class="literal">false</span>;</span><br><span class="line">            sock.<span class="property">readable</span>.<span class="title function_">pipeTo</span>(<span class="keyword">new</span> <span class="title class_">WritableStream</span>(&#123;</span><br><span class="line">                <span class="title function_">write</span>(<span class="params">chunk</span>) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (ws.<span class="property">readyState</span> === <span class="number">1</span>) &#123;</span><br><span class="line">                        ws.<span class="title function_">send</span>(sent ? chunk : <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([...header, ...</span><br><span class="line">                            <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(chunk)</span><br><span class="line">                        ]));</span><br><span class="line">                        sent = <span class="literal">true</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;,</span><br><span class="line">                <span class="attr">close</span>: <span class="function">() =&gt;</span> ws.<span class="property">readyState</span> === <span class="number">1</span> &amp;&amp; ws.<span class="title function_">close</span>(),</span><br><span class="line">                <span class="attr">abort</span>: <span class="function">() =&gt;</span> ws.<span class="property">readyState</span> === <span class="number">1</span> &amp;&amp; ws.<span class="title function_">close</span>()</span><br><span class="line">            &#125;)).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123; &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123; &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="literal">null</span>, &#123;</span><br><span class="line">        <span class="attr">status</span>: <span class="number">101</span>,</span><br><span class="line">        <span class="attr">webSocket</span>: client</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// UUID 工具函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">parseUUID</span>(<span class="params">uuid</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> uuid.<span class="title function_">replaceAll</span>(<span class="string">&#x27;-&#x27;</span>, <span class="string">&#x27;&#x27;</span>).<span class="title function_">match</span>(<span class="regexp">/.&#123;2&#125;/g</span>).<span class="title function_">map</span>(<span class="function"><span class="params">x</span> =&gt;</span> <span class="built_in">parseInt</span>(x, <span class="number">16</span>));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// SOCKS5连接</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">socks5Connect</span>(<span class="params">targetHost, targetPort</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> parsedSocks5Address = <span class="keyword">await</span> 获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号);</span><br><span class="line">    <span class="keyword">const</span> &#123; username, password, hostname, port &#125; = parsedSocks5Address;</span><br><span class="line">    <span class="keyword">const</span> sock = <span class="title function_">connect</span>(&#123;</span><br><span class="line">        <span class="attr">hostname</span>: hostname,</span><br><span class="line">        <span class="attr">port</span>: port</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">await</span> sock.<span class="property">opened</span>;</span><br><span class="line">    <span class="keyword">const</span> w = sock.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">    <span class="keyword">const</span> r = sock.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">    <span class="keyword">await</span> w.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">2</span>]));</span><br><span class="line">    <span class="keyword">const</span> auth = (<span class="keyword">await</span> r.<span class="title function_">read</span>()).<span class="property">value</span>;</span><br><span class="line">    <span class="keyword">if</span> (auth[<span class="number">1</span>] === <span class="number">2</span> &amp;&amp; username) &#123;</span><br><span class="line">        <span class="keyword">const</span> user = <span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(username);</span><br><span class="line">        <span class="keyword">const</span> pass = <span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(password);</span><br><span class="line">        <span class="keyword">await</span> w.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">1</span>, user.<span class="property">length</span>, ...user, pass.<span class="property">length</span>, ...pass]));</span><br><span class="line">        <span class="keyword">await</span> r.<span class="title function_">read</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> domain = <span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(targetHost);</span><br><span class="line">    <span class="keyword">await</span> w.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">5</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">3</span>, domain.<span class="property">length</span>, ...domain,</span><br><span class="line">        targetPort &gt;&gt; <span class="number">8</span>, targetPort &amp; <span class="number">0xff</span></span><br><span class="line">    ]));</span><br><span class="line">    <span class="keyword">await</span> r.<span class="title function_">read</span>();</span><br><span class="line">    w.<span class="title function_">releaseLock</span>();</span><br><span class="line">    r.<span class="title function_">releaseLock</span>();</span><br><span class="line">    <span class="keyword">return</span> sock;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// VLESS Header 解析</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">readVlessHeader</span>(<span class="params">reader</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> buffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="number">1024</span>);</span><br><span class="line">    <span class="keyword">let</span> offset = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> &#123;</span><br><span class="line">            value,</span><br><span class="line">            done</span><br><span class="line">        &#125; = <span class="keyword">await</span> reader.<span class="title function_">read</span>();</span><br><span class="line">        <span class="keyword">if</span> (done) &#123;</span><br><span class="line">            <span class="keyword">if</span> (offset === <span class="number">0</span>) <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (offset + value.<span class="property">length</span> &gt; buffer.<span class="property">length</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> newBuf = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(offset + value.<span class="property">length</span>);</span><br><span class="line">            newBuf.<span class="title function_">set</span>(buffer.<span class="title function_">slice</span>(<span class="number">0</span>, offset));</span><br><span class="line">            buffer = newBuf;</span><br><span class="line">        &#125;</span><br><span class="line">        buffer.<span class="title function_">set</span>(value, offset);</span><br><span class="line">        offset += value.<span class="property">length</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 跳过版本和UUID(17字节)，读取addon长度</span></span><br><span class="line">        <span class="keyword">if</span> (offset &lt; <span class="number">18</span>) <span class="keyword">continue</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// UUID验证</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="variable constant_">FIXED_UUID</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> uuidBytes = <span class="title function_">parseUUID</span>(<span class="variable constant_">FIXED_UUID</span>);</span><br><span class="line">            <span class="keyword">if</span> (!buffer.<span class="title function_">slice</span>(<span class="number">1</span>, <span class="number">17</span>).<span class="title function_">every</span>(<span class="function">(<span class="params">b, i</span>) =&gt;</span> b === uuidBytes[i])) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">const</span> addonLen = buffer[<span class="number">17</span>];</span><br><span class="line">        <span class="keyword">if</span> (offset &lt; <span class="number">18</span> + addonLen + <span class="number">1</span>) <span class="keyword">continue</span>;</span><br><span class="line">        <span class="keyword">const</span> cmd = buffer[<span class="number">18</span> + addonLen];</span><br><span class="line">        <span class="keyword">if</span> (cmd !== <span class="number">1</span>) <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> portIndex = <span class="number">18</span> + addonLen + <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">const</span> port = (buffer[portIndex] &lt;&lt; <span class="number">8</span>) | buffer[portIndex + <span class="number">1</span>];</span><br><span class="line">        <span class="keyword">const</span> atypeIndex = portIndex + <span class="number">2</span>;</span><br><span class="line">        <span class="keyword">const</span> atype = buffer[atypeIndex];</span><br><span class="line">        <span class="keyword">let</span> hostIndex = atypeIndex + <span class="number">1</span>,</span><br><span class="line">            hostLen = <span class="number">0</span>,</span><br><span class="line">            hostname = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">switch</span> (atype) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">1</span>: <span class="comment">// IPv4</span></span><br><span class="line">                hostLen = <span class="number">4</span>;</span><br><span class="line">                <span class="keyword">if</span> (offset &lt; hostIndex + hostLen) <span class="keyword">continue</span>;</span><br><span class="line">                hostname = <span class="title class_">Array</span>.<span class="title function_">from</span>(buffer.<span class="title function_">slice</span>(hostIndex, hostIndex + hostLen)).<span class="title function_">join</span>(<span class="string">&#x27;.&#x27;</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">2</span>: <span class="comment">// 域名</span></span><br><span class="line">                hostLen = buffer[hostIndex];</span><br><span class="line">                <span class="keyword">if</span> (offset &lt; hostIndex + <span class="number">1</span> + hostLen) <span class="keyword">continue</span>;</span><br><span class="line">                hostname = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(buffer.<span class="title function_">slice</span>(hostIndex + <span class="number">1</span>, hostIndex + <span class="number">1</span> + hostLen));</span><br><span class="line">                hostLen++;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">3</span>: <span class="comment">// IPv6</span></span><br><span class="line">                hostLen = <span class="number">16</span>;</span><br><span class="line">                <span class="keyword">if</span> (offset &lt; hostIndex + hostLen) <span class="keyword">continue</span>;</span><br><span class="line">                <span class="keyword">const</span> dv = <span class="keyword">new</span> <span class="title class_">DataView</span>(buffer.<span class="property">buffer</span>, hostIndex, <span class="number">16</span>);</span><br><span class="line">                <span class="keyword">const</span> parts = [];</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++) parts.<span class="title function_">push</span>(dv.<span class="title function_">getUint16</span>(i * <span class="number">2</span>).<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">                hostname = parts.<span class="title function_">join</span>(<span class="string">&#x27;:&#x27;</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="attr">default</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> headerLen = hostIndex + hostLen;</span><br><span class="line">        <span class="keyword">const</span> data = buffer.<span class="title function_">slice</span>(headerLen, offset);</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            hostname,</span><br><span class="line">            port,</span><br><span class="line">            data,</span><br><span class="line">            <span class="attr">resp</span>: <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([buffer[<span class="number">0</span>], <span class="number">0</span>]),</span><br><span class="line">            reader</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> 获取<span class="title class_">SOCKS5</span>账号(address) &#123;</span><br><span class="line">    <span class="comment">// 使用 &quot;@&quot; 分割地址，分为认证部分和服务器地址部分</span></span><br><span class="line">    <span class="keyword">const</span> lastAtIndex = address.<span class="title function_">lastIndexOf</span>(<span class="string">&quot;@&quot;</span>);</span><br><span class="line">    <span class="keyword">let</span> [latter, former] = lastAtIndex === -<span class="number">1</span> ? [address, <span class="literal">undefined</span>] : [address.<span class="title function_">substring</span>(lastAtIndex + <span class="number">1</span>), address.<span class="title function_">substring</span>(<span class="number">0</span>, lastAtIndex)];</span><br><span class="line">    <span class="keyword">let</span> username, password, hostname, port;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果存在 former 部分，说明提供了认证信息</span></span><br><span class="line">    <span class="keyword">if</span> (former) &#123;</span><br><span class="line">        <span class="keyword">const</span> formers = former.<span class="title function_">split</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (formers.<span class="property">length</span> !== <span class="number">2</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：认证部分必须是 &quot;username:password&quot; 的形式&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        [username, password] = formers;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 解析服务器地址部分</span></span><br><span class="line">    <span class="keyword">const</span> latters = latter.<span class="title function_">split</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">    <span class="comment">// 检查是否是IPv6地址带端口格式 [xxx]:port</span></span><br><span class="line">    <span class="keyword">if</span> (latters.<span class="property">length</span> &gt; <span class="number">2</span> &amp;&amp; latter.<span class="title function_">includes</span>(<span class="string">&quot;]:&quot;</span>)) &#123;</span><br><span class="line">        <span class="comment">// IPv6地址带端口格式：[2001:db8::1]:8080</span></span><br><span class="line">        port = <span class="title class_">Number</span>(latter.<span class="title function_">split</span>(<span class="string">&quot;]:&quot;</span>)[<span class="number">1</span>].<span class="title function_">replace</span>(<span class="regexp">/[^\d]/g</span>, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        hostname = latter.<span class="title function_">split</span>(<span class="string">&quot;]:&quot;</span>)[<span class="number">0</span>] + <span class="string">&quot;]&quot;</span>; <span class="comment">// 正确提取hostname部分</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (latters.<span class="property">length</span> === <span class="number">2</span>) &#123;</span><br><span class="line">        <span class="comment">// IPv4地址带端口或域名带端口</span></span><br><span class="line">        port = <span class="title class_">Number</span>(latters.<span class="title function_">pop</span>().<span class="title function_">replace</span>(<span class="regexp">/[^\d]/g</span>, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        hostname = latters.<span class="title function_">join</span>(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        port = <span class="number">80</span>;</span><br><span class="line">        hostname = latter;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">isNaN</span>(port)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：端口号必须是数字&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理 IPv6 地址的特殊情况</span></span><br><span class="line">    <span class="comment">// IPv6 地址包含多个冒号，所以必须用方括号括起来，如 [2001:db8::1]</span></span><br><span class="line">    <span class="keyword">const</span> regex = <span class="regexp">/^\[.*\]$/</span>;</span><br><span class="line">    <span class="keyword">if</span> (hostname.<span class="title function_">includes</span>(<span class="string">&quot;:&quot;</span>) &amp;&amp; !regex.<span class="title function_">test</span>(hostname)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;无效的 SOCKS 地址格式：IPv6 地址必须用方括号括起来，如 [2001:db8::1]&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)&#123;3&#125;(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(hostname)) hostname = `$&#123;atob(&#x27;d3d3Lg==&#x27;)&#125;$&#123;hostname&#125;$&#123;atob(&#x27;LmlwLjA5MDIyNy54eXo=&#x27;)&#125;`;</span></span><br><span class="line">    <span class="comment">// 返回解析后的结果</span></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        username,  <span class="comment">// 用户名，如果没有则为 undefined</span></span><br><span class="line">        password,  <span class="comment">// 密码，如果没有则为 undefined</span></span><br><span class="line">        hostname,  <span class="comment">// 主机名，可以是域名、IPv4 或 IPv6 地址</span></span><br><span class="line">        port, <span class="comment">// 端口号，已转换为数字类型</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> 解析地址端口(反代<span class="variable constant_">IP</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> proxyIP = 反代<span class="variable constant_">IP</span>.<span class="title function_">toLowerCase</span>();</span><br><span class="line">    <span class="keyword">let</span> 地址 = proxyIP, 端口 = <span class="number">443</span>;</span><br><span class="line">    <span class="keyword">if</span> (!proxyIP || proxyIP == <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line">        地址 = <span class="string">&#x27;proxyip.fxxk.dedyn.io&#x27;</span>; <span class="comment">//默认反代</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (proxyIP.<span class="title function_">includes</span>(<span class="string">&#x27;]:&#x27;</span>)) &#123;</span><br><span class="line">        端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">1</span>] || 端口;</span><br><span class="line">        地址 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;]:&#x27;</span>)[<span class="number">0</span>] + <span class="string">&quot;]&quot;</span> || 地址;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>).<span class="property">length</span> === <span class="number">2</span>) &#123;</span><br><span class="line">        端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">1</span>] || 端口;</span><br><span class="line">        地址 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>)[<span class="number">0</span>] || 地址;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (proxyIP.<span class="title function_">includes</span>(<span class="string">&#x27;.tp&#x27;</span>)) 端口 = proxyIP.<span class="title function_">split</span>(<span class="string">&#x27;.tp&#x27;</span>)[<span class="number">1</span>].<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>)[<span class="number">0</span>] || 端口;</span><br><span class="line">    <span class="keyword">return</span> [地址, 端口];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">httpConnect</span>(<span class="params">addressRemote, portRemote</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> parsedSocks5Address = <span class="keyword">await</span> 获取<span class="title class_">SOCKS5</span>账号(我的<span class="title class_">SOCKS5</span>账号);</span><br><span class="line">    <span class="keyword">const</span> &#123; username, password, hostname, port &#125; = parsedSocks5Address;</span><br><span class="line">    <span class="keyword">const</span> sock = <span class="keyword">await</span> <span class="title function_">connect</span>(&#123;</span><br><span class="line">        <span class="attr">hostname</span>: hostname,</span><br><span class="line">        <span class="attr">port</span>: port</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 构建HTTP CONNECT请求</span></span><br><span class="line">    <span class="keyword">let</span> connectRequest = <span class="string">`CONNECT <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span> HTTP/1.1\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Host: <span class="subst">$&#123;addressRemote&#125;</span>:<span class="subst">$&#123;portRemote&#125;</span>\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加代理认证（如果需要）</span></span><br><span class="line">    <span class="keyword">if</span> (username &amp;&amp; password) &#123;</span><br><span class="line">        <span class="keyword">const</span> authString = <span class="string">`<span class="subst">$&#123;username&#125;</span>:<span class="subst">$&#123;password&#125;</span>`</span>;</span><br><span class="line">        <span class="keyword">const</span> base64Auth = <span class="title function_">btoa</span>(authString);</span><br><span class="line">        connectRequest += <span class="string">`Proxy-Authorization: Basic <span class="subst">$&#123;base64Auth&#125;</span>\r\n`</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    connectRequest += <span class="string">`User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Proxy-Connection: Keep-Alive\r\n`</span>;</span><br><span class="line">    connectRequest += <span class="string">`Connection: Keep-Alive\r\n`</span>; <span class="comment">// 添加标准 Connection 头</span></span><br><span class="line">    connectRequest += <span class="string">`\r\n`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 发送连接请求</span></span><br><span class="line">        <span class="keyword">const</span> writer = sock.<span class="property">writable</span>.<span class="title function_">getWriter</span>();</span><br><span class="line">        <span class="keyword">await</span> writer.<span class="title function_">write</span>(<span class="keyword">new</span> <span class="title class_">TextEncoder</span>().<span class="title function_">encode</span>(connectRequest));</span><br><span class="line">        writer.<span class="title function_">releaseLock</span>();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;发送HTTP CONNECT请求失败:&#x27;</span>, err);</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`发送HTTP CONNECT请求失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 读取HTTP响应</span></span><br><span class="line">    <span class="keyword">const</span> reader = sock.<span class="property">readable</span>.<span class="title function_">getReader</span>();</span><br><span class="line">    <span class="keyword">let</span> respText = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">let</span> connected = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> responseBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> &#123; value, done &#125; = <span class="keyword">await</span> reader.<span class="title function_">read</span>();</span><br><span class="line">            <span class="keyword">if</span> (done) &#123;</span><br><span class="line">                <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接中断&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 合并接收到的数据</span></span><br><span class="line">            <span class="keyword">const</span> newBuffer = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(responseBuffer.<span class="property">length</span> + value.<span class="property">length</span>);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(responseBuffer);</span><br><span class="line">            newBuffer.<span class="title function_">set</span>(value, responseBuffer.<span class="property">length</span>);</span><br><span class="line">            responseBuffer = newBuffer;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 将收到的数据转换为文本</span></span><br><span class="line">            respText = <span class="keyword">new</span> <span class="title class_">TextDecoder</span>().<span class="title function_">decode</span>(responseBuffer);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 检查是否收到完整的HTTP响应头</span></span><br><span class="line">            <span class="keyword">if</span> (respText.<span class="title function_">includes</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>)) &#123;</span><br><span class="line">                <span class="comment">// 分离HTTP头和可能的数据部分</span></span><br><span class="line">                <span class="keyword">const</span> headersEndPos = respText.<span class="title function_">indexOf</span>(<span class="string">&#x27;\r\n\r\n&#x27;</span>) + <span class="number">4</span>;</span><br><span class="line">                <span class="keyword">const</span> headers = respText.<span class="title function_">substring</span>(<span class="number">0</span>, headersEndPos);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 检查响应状态</span></span><br><span class="line">                <span class="keyword">if</span> (headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.1 200&#x27;</span>) || headers.<span class="title function_">startsWith</span>(<span class="string">&#x27;HTTP/1.0 200&#x27;</span>)) &#123;</span><br><span class="line">                    connected = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">                    <span class="comment">// 如果响应头之后还有数据，我们需要保存这些数据以便后续处理</span></span><br><span class="line">                    <span class="keyword">if</span> (headersEndPos &lt; responseBuffer.<span class="property">length</span>) &#123;</span><br><span class="line">                        <span class="keyword">const</span> remainingData = responseBuffer.<span class="title function_">slice</span>(headersEndPos);</span><br><span class="line">                        <span class="comment">// 创建一个缓冲区来存储这些数据，以便稍后使用</span></span><br><span class="line">                        <span class="keyword">const</span> dataStream = <span class="keyword">new</span> <span class="title class_">ReadableStream</span>(&#123;</span><br><span class="line">                            <span class="title function_">start</span>(<span class="params">controller</span>) &#123;</span><br><span class="line">                                controller.<span class="title function_">enqueue</span>(remainingData);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;);</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 创建一个新的TransformStream来处理额外数据</span></span><br><span class="line">                        <span class="keyword">const</span> &#123; readable, writable &#125; = <span class="keyword">new</span> <span class="title class_">TransformStream</span>();</span><br><span class="line">                        dataStream.<span class="title function_">pipeTo</span>(writable).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;处理剩余数据错误:&#x27;</span>, err));</span><br><span class="line"></span><br><span class="line">                        <span class="comment">// 替换原始readable流</span></span><br><span class="line">                        <span class="comment">// @ts-ignore</span></span><br><span class="line">                        sock.<span class="property">readable</span> = readable;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">const</span> errorMsg = <span class="string">`HTTP代理连接失败: <span class="subst">$&#123;headers.split(<span class="string">&#x27;\r\n&#x27;</span>)[<span class="number">0</span>]&#125;</span>`</span>;</span><br><span class="line">                    <span class="variable language_">console</span>.<span class="title function_">error</span>(errorMsg);</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(errorMsg);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line">        reader.<span class="title function_">releaseLock</span>();</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">`处理HTTP代理响应失败: <span class="subst">$&#123;err.message&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    reader.<span class="title function_">releaseLock</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!connected) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;HTTP代理连接失败: 未收到成功响应&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> sock;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="2：部署-Cloudflare-Snippet-并-创建-VLESS-节点"><a href="#2：部署-Cloudflare-Snippet-并-创建-VLESS-节点" class="headerlink" title="2：部署 Cloudflare Snippet 并 创建 VLESS 节点"></a>2：部署 Cloudflare Snippet 并 创建 VLESS 节点</h2><h3 id="2-1：部署-Cloudflare-Snippet"><a href="#2-1：部署-Cloudflare-Snippet" class="headerlink" title="2.1：部署 Cloudflare Snippet"></a><strong>2.1：部署 Cloudflare Snippet</strong></h3><h4 id="第一步：创建并粘贴源码"><a href="#第一步：创建并粘贴源码" class="headerlink" title="第一步：创建并粘贴源码"></a><strong>第一步：创建并粘贴源码</strong></h4><ol><li>登录 <a href="https://dash.cloudflare.com/">Cloudflare</a>，选择你的域名，并进入 <strong>规则 → Snippets</strong> 页面。</li><li>点击 <strong>创建片段</strong>。<br><img src="https://img.zrf.me/20250927165830476.webp" alt="创建片段"></li><li>在左上角的 <strong>片段名称</strong> 处，为你即将创建的片段设置一个方便识别的名称。</li><li>任意选择一个上文提供的源码进行复制，然后粘贴到左侧的 <code>snippet.js</code> 代码编辑器中。<br><img src="https://img.zrf.me/20250927204053802.webp" alt="粘贴源码到编辑器"></li></ol><h4 id="第二步：设置-UUID-可选"><a href="#第二步：设置-UUID-可选" class="headerlink" title="第二步：设置 UUID (可选)"></a><strong>第二步：设置 UUID (可选)</strong></h4><p>为了增强安全性，建议为你的服务设置一个 UUID（即验证密码）。当然，你也可以跳过此步。</p><ol><li>打开 v2rayN 软件，点击左上角的 <strong>配置文件</strong> → <strong>添加[VLESS]配置文件</strong>。<br><img src="https://img.zrf.me/20250927202124163.webp" alt="在v2rayN中添加VLESS配置文件"></li><li>在弹出的窗口中，点击 <strong>生成</strong> 按钮来创建一个新的 UUID，并复制它。<br><img src="https://img.zrf.me/20250927204236557.webp" alt="生成并复制UUID"></li><li>回到 Cloudflare Snippet 编辑器，将刚刚复制的 UUID 粘贴到源码中指定的位置。<br><img src="https://img.zrf.me/20250927204722475.webp" alt="将UUID粘贴到源码中"></li></ol><h4 id="第三步：配置片段触发规则"><a href="#第三步：配置片段触发规则" class="headerlink" title="第三步：配置片段触发规则"></a><strong>第三步：配置片段触发规则</strong></h4><ol><li>完成源码编辑后，点击右上角的 <strong>片段规则</strong>。</li><li>在规则设置中，选择 <strong>自定义筛选表达式</strong>，并按以下方式配置：<ul><li><strong>字段</strong>: 选择 <strong>主机名</strong>。</li><li><strong>运算符</strong>: 选择 <strong>等于</strong>。</li><li><strong>值</strong>: 填写你计划用于此服务的域名（例如 <code>ts.ddff.me</code>，<strong>请务必替换成你自己的域名</strong>）。</li></ul></li><li>点击 <strong>完成</strong> 保存规则。</li></ol><p><img src="https://img.zrf.me/20250927211408540.webp" alt="设置片段触发规则"></p><h4 id="第四步：部署-Snippet-并创建-DNS-记录"><a href="#第四步：部署-Snippet-并创建-DNS-记录" class="headerlink" title="第四步：部署 Snippet 并创建 DNS 记录"></a><strong>第四步：部署 Snippet 并创建 DNS 记录</strong></h4><ol><li>点击页面右上角的 <strong>部署</strong> 按钮。</li><li>在弹出的确认窗口中，系统会提示 <strong>创建新代理 DNS 记录</strong>。</li><li>在 <strong>IPv4 地址</strong> 字段中，填写一个占位地址：<code>192.0.2.1</code>。</li><li>最后，点击 <strong>创建记录和部署规则</strong>。<br><img src="https://img.zrf.me/20250927211531043.webp" alt="创建DNS记录并部署"></li><li>稍等片刻，看到右侧显示 <strong>活动</strong> 状态，部署成功。<br><img src="https://img.zrf.me/20250927211637068.webp" alt="部署成功"></li></ol><blockquote><p><strong>提示</strong>：本教程以天书大佬的源码为例。你也可以尝试部署其他作者（如白嫖哥）的源码，部署流程完全相同，可以自行测试选择最适合你的版本。</p></blockquote><hr><h3 id="2-2：创建-VLESS-客户端配置"><a href="#2-2：创建-VLESS-客户端配置" class="headerlink" title="2.2：创建 VLESS 客户端配置"></a><strong>2.2：创建 VLESS 客户端配置</strong></h3><p>现在，我们需要在客户端（如 v2rayN）中手动配置一个 VLESS 节点来连接刚刚部署好的服务。</p><ul><li>在 v2rayN 中，参照下图填写必要的连接参数：<ul><li><strong>别名</strong>：为你的节点设置一个自定义名称。</li><li><strong>UUID</strong>：<strong>必须填写你之前在源码中设置的那个 UUID</strong>。如果未设置，则可以随意生成。</li><li><strong>地址</strong> &#x2F; <strong>端口</strong>：地址填写你上面设置的子域名，端口填写 <code>443</code>。也可以使用优选域名。</li><li><strong>传输协议</strong>：选择 <strong>ws</strong> (WebSocket)。</li><li><strong>伪装域名</strong>：填写你上面设置的子域名。</li><li><strong>路径</strong>：</li></ul><ol><li>你可能会发现，使用 Cloudflare 部署的节点无法打开某些网站，这通常是因为目标网站也使用了 Cloudflare CDN。</li><li>为了解决这个问题，CM 大佬内建了一个巧妙的功能：通过在路径中加入一个 proxyip 参数，来指定一个“代理IP”绕过访问限制。</li><li>你只需将下方参数附加到路径中即可。如果你有访问速度更快的 proxyip，也可以自行替换。此方法仅针对上述CM佬 与 白嫖哥 源码，其他版本请自行测试。（白嫖哥源码格式: <strong>&#x2F;ip&#x3D;IP地址</strong>）   <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">/ip=proxyip.fxxk.dedyn.io</span><br><span class="line">/proxyip=proxyip.fxxk.dedyn.io</span><br><span class="line">/pyip=proxyip.fxxk.dedyn.io</span><br></pre></td></tr></table></figure></li></ol><ul><li><strong>传输层安全</strong>：选择 <strong>tls</strong>。</li><li><strong>SNI</strong>：填写你上面设置的-子域名。</li><li><strong>跳过证书验证</strong>：选择 <strong>true</strong>。</li></ul></li></ul><p><img src="https://img.zrf.me/20250927212506082.webp" alt="VLESS节点基础配置"><br><img src="https://img.zrf.me/20250927212650387.webp" alt="VLESS节点传输配置"></p><ul><li>填写完毕后，点击 <strong>确定</strong> 保存配置。</li></ul><h3 id="2-3：测试连接"><a href="#2-3：测试连接" class="headerlink" title="2.3：测试连接"></a><strong>2.3：测试连接</strong></h3><ol><li>回到 v2rayN 主界面，右键点击刚刚创建的节点。</li><li>选择 <strong>测试服务器真连接延迟</strong>。</li><li>如果延迟测试成功并显示数值，则表示节点已经可以正常使用。</li></ol><p><img src="https://img.zrf.me/20250927214730080.webp" alt="测试节点真连接延迟"></p><h2 id="3：完美联动！将新节点添加到-MiSub"><a href="#3：完美联动！将新节点添加到-MiSub" class="headerlink" title="3：完美联动！将新节点添加到 MiSub"></a><strong>3：完美联动！将新节点添加到 MiSub</strong></h2><p>最后，也是最激动人心的一步：我们将这个亲手创建的免费节点，加入到我们的 MiSub 订阅项目中！</p><h3 id="3-1：添加节点"><a href="#3-1：添加节点" class="headerlink" title="3.1：添加节点"></a><strong>3.1：添加节点</strong></h3><ol><li>在 v2rayN 中，选中刚刚创建并测试成功的节点，按 <code>Ctrl+C</code> 复制节点的分享链接（<code>vless://...</code>）。</li><li>打开你部署好的 MiSub 管理页面，并使用管理员密码登录。</li><li>在左侧导航栏选择 <strong>手动节点</strong>。</li><li>在输入框中 <strong>粘贴</strong> 刚刚复制的 <code>vless://</code> 链接，然后点击 <strong>添加节点</strong>。MiSub 会自动解析链接并添加。<br>   <img src="https://img.zrf.me/20250927232751279.webp" alt="添加节点"></li><li>切换到左侧的 <strong>订阅分组</strong>，选择一个你想添加此节点的分组（或新建一个）。</li><li>在编辑分组的页面，从右侧的“手动节点”列表中 <strong>勾选</strong> 你刚刚添加的节点，然后界面上方点保存。<br>   <img src="https://img.zrf.me/20250927232732368.webp" alt="选择节点"></li><li><strong>大功告成！</strong> 现在，所有使用这个订阅分组链接的客户端，在更新订阅后，都会自动看到这个全新的、由你亲手打造的 VLESS 节点！</li></ol><h3 id="3-2：添加优选订阅"><a href="#3-2：添加优选订阅" class="headerlink" title="3.2：添加优选订阅"></a><strong>3.2：添加优选订阅</strong></h3><p>你亲手创建的 VLESS 节点虽然只有一个，但它的潜力远不止于此。通过 Cloudflare 的“节点优选”技术，我们可以将这个单节点“裂变”成包含数百个高速 IP 的订阅，让你的客户端自动选择当前网络环境下最快的线路。</p><p>这不仅能显著提升连接速度和稳定性，还能在遇到网络波动时自动切换，体验更佳。</p><p><strong>操作步骤：</strong></p><ol><li><p><strong>获取原始节点链接</strong><br>在 v2rayN 中，右键点击我们刚刚创建并测试成功的 VLESS 节点，选择“复制分享链接”，获取到 <code>vless://...</code> 格式的链接。</p></li><li><p><strong>生成优选订阅</strong><br>打开 <strong>优选订阅生成器</strong> 网站：<a href="https://zrf.zrf.me/">https://zrf.zrf.me/</a></p><ul><li>在 <strong>“节点链接”</strong> 输入框中，<strong>粘贴</strong> 刚刚复制的 <code>vless://</code> 链接。</li><li>点击 <strong>“生成优选订阅”</strong> 按钮。</li></ul></li><li><p><strong>复制生成的订阅链接</strong><br>页面会生成一条全新的 <strong>优选订阅地址</strong>。这条地址就是我们最终的“成果”，它内部包含了大量经过优选的 Cloudflare IP 节点。请完整复制它。<br><img src="https://img.zrf.me/20250928000722643.webp" alt="生成优选订阅"></p></li><li><p><strong>将优选订阅添加至 MiSub</strong><br>现在，回到你的 MiSub 管理界面。这次我们不是添加“手动节点”，而是要添加“订阅”。</p><ul><li>进入 <strong>“订阅”</strong> 管理页面。</li><li>将刚刚复制的优-选订阅地址粘贴进去，添加并保存。<br><img src="https://img.zrf.me/20250928002402700.webp" alt="添加优选订阅"></li><li>别忘了在 <strong>“订阅分组”</strong> 中勾选这个新的优选订阅。</li></ul></li></ol><p>现在，当你的客户端更新 MiSub 提供的订阅链接时，你得到的就不再是一个孤零零的节点，而是成百上千个已经优选好的高速节点！</p><p><img src="https://img.zrf.me/20250928001303386.webp" alt="更新 MiSub"></p><h3 id="3-3：更进一步：聚合多个优选订阅"><a href="#3-3：更进一步：聚合多个优选订阅" class="headerlink" title="3.3：更进一步：聚合多个优选订阅"></a><strong>3.3：更进一步：聚合多个优选订阅</strong></h3><p>一个优选订阅器还不够？没问题！网络上有多位大佬都在维护各自的优选订阅服务，你可以将它们全部利用起来。</p><ol><li>访问 <strong><a href="https://blog.zrf.me/p/cf/#%E8%AE%A2%E9%98%85%E5%99%A8%E6%B1%87%E6%80%BB">CloudFlare 优选订阅器汇总</a></strong> 页面。</li><li>将你的 <code>vless://</code> 链接分别粘贴到列表中的多个订阅器里，生成多条不同的优选订阅链接。</li><li>将所有这些生成的优选订阅链接，<strong>全部</strong> 添加到你的 MiSub 的“订阅”列表中。</li></ol><p>通过这种方式，你的 MiSub 就成了一个强大的“超级优选聚合器”，节点多到用不完，真正实现网络自由。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Cloudflare-Snippets-免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选&quot;&gt;&lt;a href=&quot;#Cloudflare-Snippets-免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选&quot; clas</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="隐私" scheme="https://blog.zrf.me/tags/%E9%9A%90%E7%A7%81/"/>
    
    <category term="科学上网" scheme="https://blog.zrf.me/tags/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="代理工具" scheme="https://blog.zrf.me/tags/%E4%BB%A3%E7%90%86%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Clash" scheme="https://blog.zrf.me/tags/Clash/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    <category term="订阅转换" scheme="https://blog.zrf.me/tags/%E8%AE%A2%E9%98%85%E8%BD%AC%E6%8D%A2/"/>
    
  </entry>
  
  <entry>
    <title>MiSub - 一款强大的开源订阅转换与聚合管理工具 (保姆级部署教程)</title>
    <link href="https://blog.zrf.me/p/MiSub/"/>
    <id>https://blog.zrf.me/p/MiSub/</id>
    <published>2025-09-23T20:17:27.000Z</published>
    <updated>2026-02-25T21:20:37.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="MiSub-一款强大的开源订阅转换与聚合管理工具"><a href="#MiSub-一款强大的开源订阅转换与聚合管理工具" class="headerlink" title="MiSub: 一款强大的开源订阅转换与聚合管理工具"></a>MiSub: 一款强大的开源订阅转换与聚合管理工具</h1><p><strong>前言</strong>：</p><p>最近发现“赛博大善人” <strong>Cloudflare</strong> 貌似在内测 <strong>Cloudflare Snippets</strong> 功能，有可能后续都会开放！</p><p>官方说这只是付费用户的专属（仅对Pro、Business 和 Enterprise 计划免费提供），但我发现一些Free免费计划的域名竟然也能“白嫖”！想知道你是不是那个幸运儿吗？可以按以下路径检查：</p><ol><li>登录 <a href="https://dash.cloudflare.com/">Cloudflare</a>，选择你的域名。</li><li>导航至 <strong>规则 (Rules) → Snippets</strong>。</li></ol><p>如果你的界面如下图所示，那么恭喜你，可以抢先体验！我们下次会介绍如何将它与本次的项目结合，实现一个非常酷的功能，站在多位大佬的肩膀上。 <a href="https://blog.zrf.me/p/Cloudflare-Snippets/">Cloudflare Snippets 免费部署VLESS不限流量节点：MiSub用户进阶教程，实现订阅聚合与优选</a></p><p><img src="https://img.zrf.me/20250924204625299.webp" alt="Cloudflare Snippets"></p><p>当然本文的主角是 MiSub ，一个我深度体验数月后极力推荐的强大订阅管理项目。 它由群内大佬开发，采用 Cloudflare 与 Vue 3 技术栈，创新地结合了订阅分组与 D1 数据库支持，完美解决了 KV 写入限制，让你能为自己或他人无忧地创建并分享高度定制化的订阅链接。 这篇博文将带你了解并完成它的整个部署过程。</p><h2 id="MiSub-界面预览"><a href="#MiSub-界面预览" class="headerlink" title="MiSub 界面预览"></a>MiSub 界面预览</h2><p><img src="https://img.zrf.me/20250924223409988.webp" alt="MiSub 界面预览"><br><img src="https://img.zrf.me/20250925023936329.webp" alt="MiSub 界面预览"></p><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li><p><strong>强大的订阅分组 (Profiles)</strong></p><ul><li><strong>自由组合</strong>: 你可以建立任意数量的订阅组，例如「家庭共享」、「影音串流」、「游戏专用」等。</li><li><strong>精准控制</strong>: 每个组可以自由勾选包含哪些「机场订阅」和「手动节点」。</li><li><strong>专属连结</strong>: 每个订阅组都会生成一条独立的订阅连结，档名也会自动使用你的分组名称，分享和管理都极为清晰方便。</li><li><strong>全选&#x2F;全不选</strong>: 在编辑分组时，可以一键选择或取消选择所有订阅和节点，操作便捷。</li></ul></li><li><p><strong>订阅与节点分离管理</strong></p><ul><li>我们将可线上更新的「机场订阅」和你手动新增的「单个节点」作为两种不同实体进行独立管理，逻辑清晰，互不干扰。</li></ul></li><li><p><strong>智慧化的管理体验</strong></p><ul><li><strong>批量汇入</strong>: 一键贴上多个订阅连结或节点连结，系统会自动分类，分别存入「订阅」和「手动节点」列表。</li><li><strong>一键排序</strong>: 对大量手动节点感到头痛？一键即可按照地区（如 HK, TW, SG, US 等）自动排序。</li><li><strong>手动拖曳排序</strong>: 无论是机场订阅还是手动节点，都可以直接拖曳排序，调整其在最终订阅档中的顺序。</li><li><strong>流量与到期时间显示</strong>: 在订阅卡片上清晰地显示机场的已用&#x2F;总流量以及订阅到期时间，并以不同颜色高亮提醒。</li><li><strong>自动获取节点资讯</strong>: 新增订阅或节点时，系统会自动从连结中提取名称。</li></ul></li><li><p><strong>精致的 UI&#x2F;UX</strong></p><ul><li>支援明亮&#x2F;暗黑模式，并能跟随系统自动切换，提供舒适的视觉体验。</li><li>带有「磨砂玻璃」质感的现代化卡片设计，风格统一。</li><li>对长列表（订阅和手动节点）提供分页功能，保证大量资料下的性能和可用性。</li><li>完善的交互逻辑，如“你有未保存的变更”提示、“放弃更改”功能、模态框编辑、以及各种操作的载入状态提示，体验流畅。</li></ul></li><li><p><strong>强大且易用的订阅连结生成</strong></p><ul><li><strong>一个面板，满足所有需求</strong>: 在右侧的「生成订阅连结」面板中，你可以一步完成“选择内容（分组或全部）”和“选择格式”。</li><li><strong>自适应连结</strong>: 提供一条通用连结，可智慧识别客户端类型 (Clash, Sing-Box 等) 并下发对应配置。</li><li><strong>多格式支援</strong>: 为 Clash, Sing-Box, Surge, Loon, Base64 等主流客户端和格式提供专属订阅连结。</li></ul></li><li><p><strong>安全与客製化</strong></p><ul><li><strong>密码保护</strong>: 管理介面由你自订的管理员密码进行保护，确保你的数据安全。</li><li><strong>高度可客製化</strong>: 在设定中，你可以自订输出档名、<code>subconverter</code> 位址、TG 推播等多种选项。</li><li><strong>双重存储支持</strong>: 支持 Cloudflare KV 和 D1 数据库两种存储方式，可根据需求自由选择。</li></ul></li><li><p><strong>D1 数据库支持</strong></p><ul><li><strong>解决写入限制</strong>: D1 数据库没有 KV 的写入频率限制，适合频繁更新的场景。</li><li><strong>一键数据迁移</strong>: 内置迁移工具，可将现有 KV 数据无缝迁移到 D1。</li><li><strong>智能存储选择</strong>: 在设置中可以选择使用 KV 存储（默认）或 D1 数据库。</li><li><strong>性能优化</strong>: 针对不同存储类型进行了专门优化，确保最佳性能。</li></ul></li><li><p><strong>技术栈</strong></p><ul><li><strong>前端</strong>: Vue 3 + Vite + Tailwind CSS，带来现代化、响应迅速的用户界面。</li><li><strong>后端</strong>: Cloudflare Pages Functions，实现无服务器、全球分布的后端逻辑。</li><li><strong>资料储存</strong>: Cloudflare KV + D1 数据库（双重支持），提供灵活、高效的数据存储方案。</li></ul></li></ul><h2 id="部署指南"><a href="#部署指南" class="headerlink" title="部署指南"></a>部署指南</h2><p>本项目天生为 Cloudflare Pages 设计，可以一键部署，享受全球 CDN 加速和无服务器的便利。</p><h3 id="1-Fork-本仓库"><a href="#1-Fork-本仓库" class="headerlink" title="1. Fork 本仓库"></a>1. Fork 本仓库</h3><p>首先打开 <a href="https://github.com/imzyb/MiSub">https://github.com/imzyb/MiSub</a> 点击项目页面右上角 <strong>Star（点个星星！）</strong> 然后点击 <strong>Fork</strong> 按钮,将此项目复制到你自己的 GitHub 仓库中。</p><p><img src="https://img.zrf.me/20250924204107281.webp" alt="Fork 本仓库"></p><h3 id="2-创建-Cloudflare-Pages-项目"><a href="#2-创建-Cloudflare-Pages-项目" class="headerlink" title="2. 创建 Cloudflare Pages 项目"></a>2. 创建 Cloudflare Pages 项目</h3><ol><li><p>登录 Cloudflare 控制台，进入 <strong>Workers &amp; Pages</strong>。<br>   <img src="https://img.zrf.me/20250924224011883.webp" alt="Workers &amp; Pages"></p></li><li><p>选择“创建应用程式” -&gt; “Pages” -&gt; “导入现有 Git 存储库”。<br>   <img src="https://img.zrf.me/20250924224140863.webp" alt="导入现有 Git 存储库"></p></li><li><p>选择你刚刚 Fork 的仓库。<br>   <img src="https://img.zrf.me/20250924224305239.webp" alt="选择 Fork 的仓库"></p></li><li><p>在 <strong>“构建设置和部署”</strong> 页面，构建设定如下:</p><ul><li><strong>框架预设</strong>: <code>Vue</code> （选择后，下方自动填写）</li><li><strong>构建命令</strong>: <code>npm run build</code></li><li><strong>构建输出目录</strong>: <code>dist</code></li><li>点击“<strong>保存并部署</strong>”。</li></ul><p><img src="https://img.zrf.me/20250924224505435.webp" alt="构建部署"></p></li></ol><h3 id="3-绑定存储资源"><a href="#3-绑定存储资源" class="headerlink" title="3. 绑定存储资源"></a>3. 绑定存储资源</h3><p><strong>存储类型选择指南</strong></p><p>MiSub 提供 Cloudflare KV 和 D1 数据库两种存储方案，你可以根据自己的需求灵活选择 <strong>(不管你选 KV 还是 D1 ,KV都是优先必须设置的，否则无法正常使用。)</strong></p><table><thead><tr><th align="left">特性</th><th align="left">KV 存储</th><th align="left">D1 数据库</th></tr></thead><tbody><tr><td align="left"><strong>写入限制</strong></td><td align="left">有限制（1000次&#x2F;天）</td><td align="left">无限制</td></tr><tr><td align="left"><strong>查询速度</strong></td><td align="left">极快</td><td align="left">快</td></tr><tr><td align="left"><strong>适用场景</strong></td><td align="left">读多写少、配置简单</td><td align="left">频繁更新、数据量大</td></tr><tr><td align="left"><strong>配置复杂度</strong></td><td align="left">简单</td><td align="left">中等</td></tr><tr><td align="left"><strong>推荐使用</strong></td><td align="left">轻度使用、初次尝试</td><td align="left">重度使用、追求无忧体验</td></tr></tbody></table><p><strong>如何选择：</strong></p><ul><li><strong>新用户</strong>: 建议直接配置 D1 数据库，避免后续遇到写入限制，省心无忧。</li><li><strong>现有用户</strong>: 如果遇到 KV 写入限制，可使用内置迁移工具迁移到 D1，提升使用体验。</li><li><strong>轻度使用</strong>: 如果你不频繁更新订阅和节点，KV 存储完全够用，且配置更为简单。</li><li><strong>重度使用</strong>: D1 数据库是最佳选择，提供无写入限制的流畅体验，适合管理大量订阅和节点。</li></ul><h4 id="3-1-绑定-KV-命名空间（必须）"><a href="#3-1-绑定-KV-命名空间（必须）" class="headerlink" title="3.1 绑定 KV 命名空间（必须）"></a>3.1 绑定 KV 命名空间（必须）</h4><ul><li>不管你选 KV 还是 D1 这个 KV 是必须设置的，否则无法正常使用。</li><li>在项目创建完成后，首先去创建一个你自己的 KV 命名空间。</li></ul><p><img src="https://img.zrf.me/20250925004643161.webp" alt="创建 KV 命名空间"></p><ul><li>创建完成，进入该项目的“设置” -&gt; “绑定” -&gt; “KV 命名空间”。</li><li><strong>变数名称 (Variable name)</strong>: <code>MISUB_KV</code></li><li><strong>KV 命名空间 (KV namespace)</strong>: 选择刚创建的 KV 命名空间。</li></ul><p><img src="https://img.zrf.me/20250925005114146.webp" alt="绑定 KV 命名空间"></p><h4 id="3-2-绑定-D1-数据库（可选，推荐）"><a href="#3-2-绑定-D1-数据库（可选，推荐）" class="headerlink" title="3.2 绑定 D1 数据库（可选，推荐）"></a>3.2 绑定 D1 数据库（可选，推荐）</h4><p>如果你希望使用 D1 数据库来避免 KV 写入限制，请按以下步骤操作：</p><p><strong>创建 D1 数据库：</strong></p><ul><li>创建 D1 数据库，名称随意，点击创建。</li></ul><p><img src="https://img.zrf.me/20250924233422723.webp" alt="创建 D1 数据库"></p><p><strong>创建数据库表结构：</strong></p><ul><li>可以看到 <strong>你的数据库已成功创建！</strong> ，我们点击右上角的 <strong>Explore Data</strong></li></ul><p><img src="https://img.zrf.me/20250924235109909.webp" alt="Explore Data"></p><ul><li>来到 D1 数据库的 Query 界面，手动执行 <code>schema.sql</code> 中的 SQL 语句，原地址：<a href="https://github.com/imzyb/MiSub/blob/main/schema.sql">https://github.com/imzyb/MiSub/blob/main/schema.sql</a> 可以不用看原地址，我下面贴出来。</li><li>创建第一个表,粘贴到 Query 编辑框中，然后点击蓝色 <strong>RUN</strong>  按钮。你应该能看到 左侧出现了一个 <strong>subscriptions</strong> 表，如下图，依次执行不在贴图。<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> subscriptions (</span><br><span class="line">    id TEXT <span class="keyword">PRIMARY KEY</span>,</span><br><span class="line">    data TEXT <span class="keyword">NOT NULL</span>,</span><br><span class="line">    created_at DATETIME <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span>,</span><br><span class="line">    updated_at DATETIME <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure></li></ul><p><img src="https://img.zrf.me/20250924235629215.webp" alt="SQL"></p><ul><li>创建第二个表，清空 Query 编辑框 的内容，执行下方所有的代码。<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> profiles (</span><br><span class="line">    id TEXT <span class="keyword">PRIMARY KEY</span>,</span><br><span class="line">    data TEXT <span class="keyword">NOT NULL</span>,</span><br><span class="line">    created_at DATETIME <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span>,</span><br><span class="line">    updated_at DATETIME <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure></li><li>创建第三个表，清空 Query 编辑框 的内容，执行下方所有的代码。<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> settings (</span><br><span class="line">    key TEXT <span class="keyword">PRIMARY KEY</span>,</span><br><span class="line">    <span class="keyword">value</span> TEXT <span class="keyword">NOT NULL</span>,</span><br><span class="line">    created_at DATETIME <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span>,</span><br><span class="line">    updated_at DATETIME <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure></li><li>然后看左侧列表。 三张都齐了，最后，清空 Query 编辑框 的内容，执行下方所有的代码。<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> INDEX IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> idx_subscriptions_updated_at <span class="keyword">ON</span> subscriptions(updated_at);</span><br><span class="line"><span class="keyword">CREATE</span> INDEX IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> idx_profiles_updated_at <span class="keyword">ON</span> profiles(updated_at);</span><br><span class="line"><span class="keyword">CREATE</span> INDEX IF <span class="keyword">NOT</span> <span class="keyword">EXISTS</span> idx_settings_updated_at <span class="keyword">ON</span> settings(updated_at);</span><br></pre></td></tr></table></figure></li></ul><p><img src="https://img.zrf.me/20250925001022880.webp" alt="SQL"></p><ul><li>这样你的 D1 数据库 就成功创建完成。</li></ul><p><strong>在项目设定中绑定 D1 数据库：</strong></p><ul><li>进入项目的”设置” -&gt; “绑定” -&gt; “添加” -&gt; “D1 数据库”</li><li><strong>变数名称 (Variable name)</strong>: <code>MISUB_DB</code></li><li><strong>D1 数据库</strong>: 选择刚创建的数据库</li></ul><p><img src="https://img.zrf.me/20250925002136018.webp" alt="绑定 D1 数据库"></p><h3 id="4-设定环境变数"><a href="#4-设定环境变数" class="headerlink" title="4. 设定环境变数"></a>4. 设定环境变数</h3><p>在项目的“设定” -&gt; “环境变数”中，添加以下两个<strong>生产环境</strong>变数：</p><ul><li><code>ADMIN_PASSWORD</code><ul><li><strong>值</strong>: 设定一个你自己的管理员登录密码。</li></ul></li></ul><p><img src="https://img.zrf.me/20250925003428514.webp" alt="设定 ADMIN_PASSWORD"></p><ul><li><code>COOKIE_SECRET</code><ul><li><strong>值</strong>: 设定一个用于加密 Cookie 的、足够长且随机的字串（例如，你可以使用密码产生器生成一个64位的随机字串）。<a href="https://1password.com/zh-cn/password-generator">随机密码生成器</a></li></ul></li></ul><p><img src="https://img.zrf.me/20250925002802209.webp" alt="生成 64位的随机字串"><br><img src="https://img.zrf.me/20250925003230734.webp" alt="设定 COOKIE_SECRET"></p><h3 id="5-部署完成！"><a href="#5-部署完成！" class="headerlink" title="5. 部署完成！"></a>5. 部署完成！</h3><p>完成以上设定后，回到“部署”选项卡，重新部署一次你的项目，使环境变量设置生效。现在，你的 MiSub 就可以通过 Cloudflare 提供所提供的域名访问了！你也可以自行设置自定义域名，更好记。</p><p><img src="https://img.zrf.me/20250925003733587.webp" alt="重新部署 使环境变量设置生效"></p><p><strong>特别注意：</strong>  后续的版本迭代添加了 <strong>后台路径</strong> 所以默认域名是无法访问的需要在你在域名地址后添加 &#x2F;login 既可正确打开。</p><h2 id="简单使用"><a href="#简单使用" class="headerlink" title="简单使用"></a>简单使用</h2><blockquote><p>部署完成后，首要任务是进行全局设置。请打开你部署的 MiSub 项目地址，使用密码登录，然后点击右上角的“设置”按钮。</p><p><strong>请务必先配置此处</strong>，因为这里的设置（如默认订阅格式、后端地址等）是所有功能的基石，并将作为最高优先级，被所有订阅组和订阅链接默认采用。</p></blockquote><p><strong>自定义订阅Token、订阅组分享Token</strong>：</p><ul><li>简单来说，它就是让你给订阅链接自定义一个。 专属的、好记的“密码”或“名字” ，<strong>订阅组分享Token</strong>：比如，你给朋友一个链接。如果哪天不想让他用了，&#x2F;zrfme&#x2F;py 只需在后台改掉这个，这个名字为朋友，他手里的订阅链接就立刻失效了，而你自己的其他链接完全不受影响。</li></ul><p><strong>SubConverter后端地址</strong>：</p><ul><li>后端地址默认是使用的肥羊的后端，我们可以自行设置一个 <a href="https://blog.zrf.me/p/SubWeb/#%E8%AE%A2%E9%98%85%E8%BD%AC%E6%8D%A2%E5%89%8D%E7%AB%AF%E5%90%8E%E7%AB%AF-%E7%BD%91%E7%AB%99%E6%94%B6%E9%9B%86">订阅转换前端后端 网站收集</a> 这里的，都可以进行设置。你也可以使用我维护的 <strong>subapi.zrfme.com</strong></li></ul><p><strong>数据迁移</strong>：</p><ul><li>切换为 D1数据库 。（<strong>注意</strong>: 数据迁移是单向的，迁移后建议不要再切换回 KV 存储，以免数据不一致。）</li></ul><ol><li><strong>配置 D1 数据库</strong>（参考上面的步骤 3.2，确保 D1 数据库已创建并绑定）。</li><li><strong>登录管理界面</strong>，进入”设置”页面。</li><li>点击 <strong>迁移数据到 D1 数据</strong> 按钮。</li><li><strong>确认迁移</strong>，系统会自动将数据从 KV 迁移到 D1。</li><li><strong>迁移完成后</strong>，存储类型会自动切换为 D1 数据库。</li></ol><p><img src="https://img.zrf.me/20250925012046603.webp" alt="切换 D1数据库"></p><p><strong>Telegram Bot</strong>: </p><ul><li>设置成功后，每当 MiSub 自动或手动更新你的订阅时，它都会通过你自己创建的 Telegram 机器人，实时向你发送一条通知消息，你无需登录任何网站，只需看一眼 Telegram 消息，就能对自己的订阅状态了如指掌。</li></ul><p><strong>第一步：创建机器人并获取 Token</strong></p><ol><li>在 Telegram 中，搜索 <code>@BotFather</code> 并开始对话（这是官方用来创建和管理机器人的机器人）。</li><li>发送指令 <code>/newbot</code> 给它。</li><li>按照提示，依次为你的机器人取一个名字（例如 <code>我的订阅助手</code>）和一个用户名（必须以 <code>bot</code> 结尾，例如 <code>zrfsub_bot</code>）。</li><li>创建成功后，<code>@BotFather</code> 会发来一条包含 <strong>API Token</strong> 的消息。它是一长串字符，请<strong>完整复制</strong>下来，<strong>并且私聊一下你刚创建的机器人，避免收不到消息</strong>。</li></ol><p><img src="https://img.zrf.me/20250925020829082.webp" alt="创建机器人并获取 Token"></p><p><strong>第二步：获取你的 Chat ID</strong></p><ol><li>在 Telegram 中，加入群组 <a href="https://t.me/lsmoo">https://t.me/lsmoo</a>  并开始对话 <strong>群验证一定要做，机器人会给你发信息</strong></li><li>发送指令 <code>/id@KinhRoBot</code> 给它。</li><li>机器人会立刻回复你的个人信息，其中就包含了你的 <strong>ID</strong>。它通常是一串数字，请<strong>复制</strong>下来。</li></ol><p><img src="https://img.zrf.me/20250928210143799.webp" alt="获取你的 Chat ID"></p><p><strong>第三步：在 MiSub 中填写信息</strong></p><ol><li>回到 MiSub 的设置页面。</li><li>找到 Telegram Bot 相关的输入框。</li><li>将刚刚复制的 <strong>Bot Token</strong> 和 <strong>Chat ID</strong> 粘贴到对应的位置。</li><li>保存设置。</li></ol><p><img src="https://img.zrf.me/20250925021409673.webp" alt="在 MiSub 中填写信息"></p><p><strong>第四步：机器人订阅通知</strong></p><ol><li>随便使用一个软件，更新订阅地址，就可以收到订阅被访问的通知啦。这个还有流量使用提醒。</li></ol><p><img src="https://img.zrf.me/20250925022204342.webp" alt="机器人订阅通知"></p><h2 id="完结撒花！！！"><a href="#完结撒花！！！" class="headerlink" title="完结撒花！！！"></a>完结撒花！！！</h2>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;MiSub-一款强大的开源订阅转换与聚合管理工具&quot;&gt;&lt;a href=&quot;#MiSub-一款强大的开源订阅转换与聚合管理工具&quot; class=&quot;headerlink&quot; title=&quot;MiSub: 一款强大的开源订阅转换与聚合管理工具&quot;&gt;&lt;/a&gt;MiSub: 一款强大的开</summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="隐私" scheme="https://blog.zrf.me/tags/%E9%9A%90%E7%A7%81/"/>
    
    <category term="科学上网" scheme="https://blog.zrf.me/tags/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="代理工具" scheme="https://blog.zrf.me/tags/%E4%BB%A3%E7%90%86%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Clash" scheme="https://blog.zrf.me/tags/Clash/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    <category term="订阅转换" scheme="https://blog.zrf.me/tags/%E8%AE%A2%E9%98%85%E8%BD%AC%E6%8D%A2/"/>
    
  </entry>
  
  <entry>
    <title>Rewards - 一个高度可定制的赞赏展示页 为您的 Hexo 博客打造专属的动态赞赏墙</title>
    <link href="https://blog.zrf.me/p/Rewards/"/>
    <id>https://blog.zrf.me/p/Rewards/</id>
    <published>2025-07-29T12:28:27.000Z</published>
    <updated>2026-02-25T21:20:37.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Rewards-一个高度可定制的赞赏展示页-为您的-Hexo-博客打造专属的动态赞赏墙"><a href="#Rewards-一个高度可定制的赞赏展示页-为您的-Hexo-博客打造专属的动态赞赏墙" class="headerlink" title="Rewards - 一个高度可定制的赞赏展示页 为您的 Hexo 博客打造专属的动态赞赏墙"></a>Rewards - 一个高度可定制的赞赏展示页 为您的 Hexo 博客打造专属的动态赞赏墙</h1><p>作为一名博主，我们收到的每一份赞赏都凝聚着读者的心意与支持。但手动更新静态的感谢名单不仅繁琐，也缺乏时效性。现在，有了一个更优雅、更自动化的解决方案——Rewards 项目，一个专为个人博客打造的动态赞赏墙。</p><p>这不仅仅是一个简单的展示页，利用 Cloudflare Pages 实现全球极速分发，并借助 KV 存储提供高效、低成本的数据读写。最重要的是，它实现了彻底的<strong>“配置即代码”</strong>，您可以通过简单的环境变量设置，轻松定制页面的每一个细节，而无需触碰一行代码。</p><p>本篇文章将作为一份详尽的指南，带您完成两项核心任务：</p><ul><li>从零开始，在 Cloudflare 上成功部署您自己的 Rewards 赞赏页。</li><li>手把手教您如何将这个动态赞赏墙无缝集成到您的 Hexo Solitude 主题博客的“关于”页面中。</li></ul><h2 id="Rewards-一个高度可定制的赞赏展示页"><a href="#Rewards-一个高度可定制的赞赏展示页" class="headerlink" title="Rewards - 一个高度可定制的赞赏展示页"></a>Rewards - 一个高度可定制的赞赏展示页</h2><p>这是一个基于 Cloudflare Pages 和 KV 存储构建的、轻量级、高度可定制的赞赏记录展示页面。它允许您轻松地展示收到的赞赏，并通过环境变量进行全方位的个性化配置，无需修改任何代码。</p><h3 id="在线体验"><a href="#在线体验" class="headerlink" title="在线体验"></a>在线体验</h3><p>前端展示：<a href="https://rewards.zrfme.com/">https://rewards.zrfme.com</a><br>后端提交：<a href="https://rewards.zrfme.com/admin">https://rewards.zrfme.com/admin</a></p><h3 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h3><p><img src="https://img.zrf.me/20250727033124253.webp" alt="前端展示截图"><br><img src="https://img.zrf.me/20250727033139475.webp" alt="后台提交截图"></p><h3 id="功能特性"><a href="#功能特性" class="headerlink" title="功能特性"></a>功能特性</h3><ul><li><strong>🚀 Serverless 架构</strong>：完全托管在 Cloudflare 的全球网络上，无需自己的服务器。</li><li><strong>⚡️ 极速访问</strong>：得益于 Cloudflare Pages 的静态站点优化和 CDN 加速。</li><li><strong>📦 KV 数据存储</strong>：使用 Cloudflare KV 作为数据库，读写速度快，成本极低。</li><li><strong>🎨 高度可定制</strong>：从背景图片、标题、二维码到分页数量、高亮金额，几乎所有内容都可以通过环境变量进行配置。</li><li><strong>📱 响应式设计</strong>：在桌面和移动设备上都有良好的视觉效果。</li><li><strong>🔒 安全后台</strong>：提供一个独立的 <code>/admin</code> 页面，通过密码保护来提交新的赞赏记录。</li><li><strong>🌟 金额高亮</strong>：可以自定义金额阈值，为“大额”赞赏提供特殊颜色高亮。</li><li><strong>📄 自动分页</strong>：当赞赏记录过多时，自动生成分页导航。</li><li><strong>💨 平滑加载</strong>：优雅的加载动画和内容淡入效果，提升用户体验。</li></ul><h3 id="部署指南"><a href="#部署指南" class="headerlink" title="部署指南"></a>部署指南</h3><p><strong>第一步：获取代码</strong></p><p>首先打开 <a href="https://github.com/shaoyouvip/Rewards">https://github.com/shaoyouvip/Rewards</a> 点击项目页面右上角 <strong>Star（点个星星！！！）</strong> 然后点击 <strong>Fork</strong> 按钮,将此项目复制到您自己的 GitHub 仓库中。</p><p><img src="https://img.zrf.me/20250727024524271.webp" alt="Fork 项目"><br><img src="https://img.zrf.me/20250727025822326.webp" alt="Fork 项目"></p><p><strong>第二步：创建 KV 命名空间</strong></p><ol><li>打开 <a href="https://dash.cloudflare.com/">https://dash.cloudflare.com/</a> 登录到您的 Cloudflare 账户。</li><li>在左侧菜单中，进入 <strong>存储和数据库</strong> -&gt; <strong>KV</strong>。<br><img src="https://img.zrf.me/20250727024857595.webp" alt="创建KV命名空间"></li><li>点击 <strong>创建命名空间</strong>，为您的命名空间取一个名字，例如 <code>REWARDS_KV</code>，然后点击创建。<br><img src="https://img.zrf.me/20250727024958445.webp" alt="创建KV命名空间"></li></ol><p><strong>第三步：在 Cloudflare Pages 中创建项目</strong></p><ol><li>在 Cloudflare 仪表板中，进入 <strong>Workers 和 Pages</strong> -&gt; <strong>Pages</strong> 选项卡。<br><img src="https://img.zrf.me/20250727025440681.webp" alt="构建"></li><li>点击 <strong>创建项目</strong> -&gt; <strong>Pages</strong> -&gt; <strong>导入现有 Git 存储库</strong>。<br><img src="https://img.zrf.me/20250727025539387.webp" alt="构建"></li><li>选择您刚刚 <strong>Fork</strong> 的 GitHub 仓库。<br><img src="https://img.zrf.me/20250727030024014.webp" alt="构建"></li><li>在“<strong>设置构建和部署</strong>”页面，填写以下信息：<ul><li><strong>构建命令 (Build command)</strong>: (<strong>留空</strong>，不需要任何命令)</li><li><strong>构建输出目录 (Build output directory)</strong>: <code>public</code></li><li>点击“<strong>保存并部署</strong>”。<br><img src="https://img.zrf.me/20250727030116678.webp" alt="构建"></li></ul></li></ol><p><strong>第四步：绑定 KV 和设置环境变量</strong></p><ol><li>等待第一次部署完成后，点击下方的继续按钮，进入您刚刚创建的 Pages 项目的控制台。</li><li>点击 <strong>设置</strong> -&gt; <strong>绑定</strong> -&gt; <strong>KV 命名空间</strong>。<br><img src="https://img.zrf.me/20250727030729817.webp" alt="绑定 KV"></li><li>点击 <strong>添加绑定</strong>：<ul><li><strong>变量名称</strong>：<code>REWARDS_KV</code></li><li><strong>KV 命名空间</strong>：选择您在第二步中创建的 <code>REWARDS_KV</code>。</li><li>点击 <strong>保存</strong>。<br><img src="https://img.zrf.me/20250727031001276.webp" alt="KV 命名空间"></li></ul></li><li>现在，进入 <strong>设置</strong> -&gt; <strong>环境变量</strong>，在这里配置您的个性化信息。这是最关键的一步！<ul><li>点击 <strong>添加变量</strong>，然后根据下面的“配置说明”添加您需要的变量。<strong>必须设置 <code>FORM_SECRET</code> 以及您自己的收款码链接！变量参考下方详细说明</strong><br><img src="https://img.zrf.me/20250727031954421.webp" alt="添加变量"></li></ul></li><li>完成变量设置后，回到项目的<strong>部署</strong>页面，点击<strong>重新部署</strong>最新的版本。</li></ol><p><strong>恭喜！</strong> 您的专属赞赏页面现在已经部署完成了。</p><h3 id="⚙️-配置说明-环境变量"><a href="#⚙️-配置说明-环境变量" class="headerlink" title="⚙️ 配置说明 (环境变量)"></a>⚙️ 配置说明 (环境变量)</h3><p>您可以通过在 Cloudflare Pages 项目的 <strong>设置 -&gt; 环境变量</strong> 中添加以下变量来自定义您的页面。<strong>必须</strong>至少配置前三项。</p><table><thead><tr><th>变量名称</th><th>说明</th><th>默认值</th></tr></thead><tbody><tr><td><code>FORM_SECRET</code></td><td><strong>（必须）</strong> 访问 <code>/admin</code> 页面提交记录时所需的密码。</td><td><em>无</em></td></tr><tr><td><code>CONFIG_QR_WECHAT</code></td><td><strong>（必须）</strong> 您的微信收款二维码图片链接。</td><td><code>您的二维码链接</code></td></tr><tr><td><code>CONFIG_QR_ALIPAY</code></td><td><strong>（必须）</strong> 您的支付宝收款二维码图片链接。</td><td><code>您的二维码链接</code></td></tr><tr><td><code>CONFIG_PAGE_TITLE</code></td><td>浏览器标签页上显示的标题。</td><td><code>周润发的赞赏页面</code></td></tr><tr><td><code>CONFIG_BANNER_TITLE</code></td><td>页面顶部大标题下的副标题。</td><td><code>您的赞赏，是我的续命咖啡~</code></td></tr><tr><td><code>CONFIG_BACKGROUND_IMAGE_URL</code></td><td>整个页面的背景图片链接。</td><td><code>/img/bj.webp</code> (项目内图片)</td></tr><tr><td><code>CONFIG_FAVICON</code></td><td>浏览器标签页上显示的图标链接。</td><td><code>/img/icon.webp</code> (项目内图片)</td></tr><tr><td><code>CONFIG_INFO_TEXT</code></td><td>页面底部信息框中的提示文字。</td><td><code>如需修改昵称信息...</code></td></tr><tr><td><code>CONFIG_INFO_EMAIL</code></td><td>页面底部信息框中显示的联系邮箱。</td><td><code>zrf@zrf.me</code></td></tr><tr><td><code>CONFIG_FOOTER_HTML</code></td><td>最底部的版权信息，支持 HTML。</td><td><code>周润发: &lt;a href=&quot;https://d.zrf.me/blog&quot;&gt;博客&lt;/a&gt;</code></td></tr><tr><td><code>CONFIG_ROWS_PER_PAGE</code></td><td>每页显示的赞赏记录数，默认为10量。</td><td><code>10</code></td></tr><tr><td><code>CONFIG_HIGHLIGHT_PRIMARY</code></td><td>主要高亮（红色）的金额门槛。</td><td><code>100</code></td></tr><tr><td><code>CONFIG_HIGHLIGHT_SECONDARY</code></td><td>次要高亮（黄色）的金额门槛。</td><td><code>20</code></td></tr></tbody></table><h3 id="✍️-如何使用"><a href="#✍️-如何使用" class="headerlink" title="✍️ 如何使用"></a><strong>✍️ 如何使用</strong></h3><p>部署完成后，您可以通过以下链接访问您的赞赏页：</p><ul><li><strong>主页</strong>: <code>https://你的项目地址</code><ul><li><em>说明：这是公开的赞赏展示页面，所有人都可以访问查看。</em></li></ul></li><li><strong>后台</strong>: <code>https://你的项目地址/admin</code><ul><li><em>说明：这是用于手动添加赞赏记录的后台页面，需要输入密码才能提交。</em></li></ul></li><li><strong>JSON数据</strong>: <code>https://你的项目地址/api/rewards</code><ul><li><em>说明：这是一个公开的 API 链接，它会以 JSON 格式返回所有赞赏数据。您可以将此链接用于其他项目或进行二次开发。</em></li></ul></li></ul><h3 id="后台提交说明"><a href="#后台提交说明" class="headerlink" title="后台提交说明"></a><strong>后台提交说明</strong></h3><p>访问 <code>https://你的项目地址/admin</code> 提交页面后，您需要填写以下信息：</p><ul><li><strong>赞赏者名字</strong>: (必需) 填写赞赏者的昵称。</li><li><strong>金额</strong>: (必需) 填写收到的具体金额。</li><li><strong>提交时间 (可选)</strong>: 如果留空，系统会自动记录为当前时间。您也可以点击选择一个过去的时间点进行补录。</li><li><strong>提交密码</strong>: (必需) 输入您在 Cloudflare 环境变量 <code>FORM_SECRET</code> 中设置的密码。</li></ul><p>填写完毕后，点击“提交”按钮即可。</p><h2 id="Solitude主题博客-接入赞赏页"><a href="#Solitude主题博客-接入赞赏页" class="headerlink" title="Solitude主题博客 接入赞赏页"></a>Solitude主题博客 接入赞赏页</h2><p>本教程将指导您如何将 <strong>Rewards</strong> 赞赏页无缝集成到您的 Hexo Solitude 主题博客中，实现一个从 API 动态更新的赞赏墙。</p><blockquote><ul><li><strong>提示</strong>: 这个方法理论上也适用于其他类似主题（如<strong>安知鱼</strong>），只需根据您的主题文件结构稍作调整即可。</li></ul></blockquote><h3 id="文件修改概览"><a href="#文件修改概览" class="headerlink" title="文件修改概览"></a>文件修改概览</h3><p>在开始之前，请熟悉我们即将修改的几个核心文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├── _config.solitude.yml         # 主题配置文件</span><br><span class="line">├── source/</span><br><span class="line">│   ├── _data/</span><br><span class="line">│   │   └── about.yml            # “关于”页面的数据文件</span><br><span class="line">│   └── about/</span><br><span class="line">│       └── index.md             # “关于”页面的内容文件</span><br><span class="line">└── themes/</span><br><span class="line">    └── solitude/</span><br><span class="line">        └── layout/</span><br><span class="line">            └── includes/</span><br><span class="line">                └── page/</span><br><span class="line">                    └── about.pug        # “关于”页面的布局模板</span><br></pre></td></tr></table></figure><h3 id="第一部分：优化文章底部的“赞赏名单”链接"><a href="#第一部分：优化文章底部的“赞赏名单”链接" class="headerlink" title="第一部分：优化文章底部的“赞赏名单”链接"></a>第一部分：优化文章底部的“赞赏名单”链接</h3><p>此步骤旨在让您每篇文章底部的“赞赏作者”弹窗，可以正确链接到我们刚刚部署好的独立赞赏页面。</p><ol><li><p>我们需要更改的地方有博客文章页面底部 <strong>赞赏作者</strong> 这个按钮的 <strong>赞赏名单</strong> 页面。<br><img src="https://img.zrf.me/20250730010244595.webp" alt="文章底部的赞赏弹窗"></p></li><li><p>打开博客路径： <strong>_config.solitude.yml</strong> 搜索 <strong>打赏</strong> 或 <strong>Reward</strong> 关键词，找到如下配置把你的 <strong>赞赏名单</strong> 替换为你部署好的页面网址即可，如下图。<br><img src="https://img.zrf.me/20250730011209434.webp" alt="修改主题配置文件"></p></li></ol><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Reward</span></span><br><span class="line"><span class="comment"># 打赏</span></span><br><span class="line"><span class="attr">award:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">appreciators:</span> <span class="string">https://rewards.zrf.me/</span> <span class="comment"># 赞赏名单地址</span></span><br><span class="line">  <span class="comment"># Reward Title</span></span><br><span class="line">  <span class="comment"># 打赏标题</span></span><br><span class="line">  <span class="attr">title:</span> <span class="string">感谢您的赞赏</span> <span class="comment">#Thanks for your appreciation. / </span></span><br><span class="line">  <span class="attr">desc:</span> <span class="string">由于您的支持，我才能够实现写作的价值。</span> <span class="comment">#Because of your support, I realize the value of writing articles. / 由于您的支持，我才能够实现写作的价值。</span></span><br><span class="line">  <span class="comment"># Reward list</span></span><br><span class="line">  <span class="comment"># 打赏列表</span></span><br><span class="line">  <span class="attr">list:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">微信</span></span><br><span class="line">      <span class="attr">qcode:</span> <span class="string">/img/zsm_wx.webp</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">/img/zsm_wx.webp</span></span><br><span class="line">      <span class="attr">color:</span> <span class="string">var(--efu-black)</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">支付宝</span></span><br><span class="line">      <span class="attr">qcode:</span> <span class="string">/img/zsm_zfb.webp</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">/img/zsm_zfb.webp</span></span><br><span class="line">      <span class="attr">color:</span> <span class="string">var(--efu-black)</span></span><br></pre></td></tr></table></figure><h3 id="第二部分：在“关于”页面创建动态赞赏列表"><a href="#第二部分：在“关于”页面创建动态赞赏列表" class="headerlink" title="第二部分：在“关于”页面创建动态赞赏列表"></a>第二部分：在“关于”页面创建动态赞赏列表</h3><p>此步骤将在您的“关于”页面创建一个从 API 实时拉取数据的赞赏墙，并带有30分钟的浏览器缓存。</p><h4 id="步骤-1：向-index-md-注入核心脚本"><a href="#步骤-1：向-index-md-注入核心脚本" class="headerlink" title="步骤 1：向 index.md 注入核心脚本"></a>步骤 1：向 <code>index.md</code> 注入核心脚本</h4><ol><li>打开博客路径： <strong>source\about\index.md</strong> 复制下方代码进去，赞赏API改为你自己的， 格式: <strong>https:&#x2F;&#x2F;你的项目地址&#x2F;api&#x2F;rewards</strong> ，如下图。<br><img src="https://img.zrf.me/20250730033154369.webp" alt="向 `index.md` 注入核心脚本"></li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">function</span> <span class="title function_">loadRewardList</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> apiUrl = <span class="string">&quot;https://rewards.zrf.me/api/rewards&quot;</span>; <span class="comment">// 赞赏API</span></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> cacheKey = <span class="string">&quot;rewardListCache&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> cacheTimeKey = <span class="string">&quot;rewardListCacheTime&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> cacheTTL = <span class="number">30</span> * <span class="number">60</span> * <span class="number">1000</span>; <span class="comment">// 30分钟</span></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> rewardListContainer = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;.reward-list-all&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> totalAmountContainer = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;.reward-list-tips p&quot;</span>);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">formatTime</span>(<span class="params">dateStr</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> date = <span class="keyword">new</span> <span class="title class_">Date</span>(dateStr);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> year = date.<span class="title function_">getFullYear</span>();</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> month = <span class="title class_">String</span>(date.<span class="title function_">getMonth</span>() + <span class="number">1</span>).<span class="title function_">padStart</span>(<span class="number">2</span>, <span class="string">&#x27;0&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> day = <span class="title class_">String</span>(date.<span class="title function_">getDate</span>()).<span class="title function_">padStart</span>(<span class="number">2</span>, <span class="string">&#x27;0&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">return</span> <span class="string">`<span class="subst">$&#123;year&#125;</span>-<span class="subst">$&#123;month&#125;</span>-<span class="subst">$&#123;day&#125;</span>`</span>;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">createRewardItem</span>(<span class="params">&#123; name, money, date &#125;</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> item = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    item.<span class="property">className</span> = <span class="string">&quot;reward-list-item&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> nameDiv = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    nameDiv.<span class="property">className</span> = <span class="string">&quot;reward-list-item-name&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    nameDiv.<span class="property">textContent</span> = name;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> bottomGroup = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    bottomGroup.<span class="property">className</span> = <span class="string">&quot;reward-list-bottom-group&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> moneyDiv = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    moneyDiv.<span class="property">className</span> = <span class="string">&quot;reward-list-item-money&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    moneyDiv.<span class="property">innerHTML</span> = <span class="string">`¥ <span class="subst">$&#123;money&#125;</span>`</span>;</span></span><br><span class="line"><span class="language-javascript">    moneyDiv.<span class="property">style</span>.<span class="property">backgroundColor</span> = <span class="string">&quot;undefined&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> time = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;time&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    time.<span class="property">className</span> = <span class="string">&quot;datetime reward-list-item-time&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    time.<span class="title function_">setAttribute</span>(<span class="string">&quot;datetime&quot;</span>, <span class="keyword">new</span> <span class="title class_">Date</span>(date).<span class="title function_">toISOString</span>());</span></span><br><span class="line"><span class="language-javascript">    time.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&quot;inline&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    time.<span class="property">textContent</span> = <span class="title function_">formatTime</span>(date);</span></span><br><span class="line"><span class="language-javascript">    bottomGroup.<span class="title function_">appendChild</span>(moneyDiv);</span></span><br><span class="line"><span class="language-javascript">    bottomGroup.<span class="title function_">appendChild</span>(time);</span></span><br><span class="line"><span class="language-javascript">    item.<span class="title function_">appendChild</span>(nameDiv);</span></span><br><span class="line"><span class="language-javascript">    item.<span class="title function_">appendChild</span>(bottomGroup);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">return</span> item;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">renderList</span>(<span class="params">rewards</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> allItems = rewardListContainer.<span class="property">children</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> lastButton = allItems[allItems.<span class="property">length</span> - <span class="number">1</span>];</span></span><br><span class="line"><span class="language-javascript">    rewardListContainer.<span class="property">innerHTML</span> = <span class="string">&quot;&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">let</span> total = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">    rewards.<span class="title function_">forEach</span>(<span class="function"><span class="params">entry</span> =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">      total += <span class="title class_">Number</span>(entry.<span class="property">money</span> || <span class="number">0</span>);</span></span><br><span class="line"><span class="language-javascript">      rewardListContainer.<span class="title function_">appendChild</span>(<span class="title function_">createRewardItem</span>(entry));</span></span><br><span class="line"><span class="language-javascript">    &#125;);</span></span><br><span class="line"><span class="language-javascript">    rewardListContainer.<span class="title function_">appendChild</span>(lastButton);</span></span><br><span class="line"><span class="language-javascript">    totalAmountContainer.<span class="property">textContent</span> = <span class="string">`总金额：¥ <span class="subst">$&#123;total.toFixed(<span class="number">2</span>)&#125;</span>，将全部用于博客的维护和更新。`</span>;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">isCacheValid</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> timestamp = <span class="variable language_">localStorage</span>.<span class="title function_">getItem</span>(cacheTimeKey);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">if</span> (!timestamp) <span class="keyword">return</span> <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">return</span> <span class="title class_">Date</span>.<span class="title function_">now</span>() - <span class="title class_">Number</span>(timestamp) &lt; cacheTTL;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">if</span> (<span class="title function_">isCacheValid</span>()) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">try</span> &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> cachedData = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="variable language_">localStorage</span>.<span class="title function_">getItem</span>(cacheKey));</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">if</span> (<span class="title class_">Array</span>.<span class="title function_">isArray</span>(cachedData)) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">renderList</span>(cachedData);</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">return</span>;</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125; <span class="keyword">catch</span> (e) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">console</span>.<span class="title function_">warn</span>(<span class="string">&quot;缓存解析失败，尝试重新请求 API&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="title function_">fetch</span>(apiUrl)</span></span><br><span class="line"><span class="language-javascript">    .<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> res.<span class="title function_">json</span>())</span></span><br><span class="line"><span class="language-javascript">    .<span class="title function_">then</span>(<span class="function"><span class="params">json</span> =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> rewards = json.<span class="property">data</span> || [];</span></span><br><span class="line"><span class="language-javascript">      <span class="title function_">renderList</span>(rewards);</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">localStorage</span>.<span class="title function_">setItem</span>(cacheKey, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(rewards));</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">localStorage</span>.<span class="title function_">setItem</span>(cacheTimeKey, <span class="title class_">Date</span>.<span class="title function_">now</span>().<span class="title function_">toString</span>());</span></span><br><span class="line"><span class="language-javascript">    &#125;)</span></span><br><span class="line"><span class="language-javascript">    .<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&quot;读取赞赏数据失败：&quot;</span>, err);</span></span><br><span class="line"><span class="language-javascript">    &#125;);</span></span><br><span class="line"><span class="language-javascript">&#125;</span></span><br><span class="line"><span class="language-javascript"><span class="title function_">loadRewardList</span>();</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="步骤-2：修改-about-pug-布局"><a href="#步骤-2：修改-about-pug-布局" class="headerlink" title="步骤 2：修改 about.pug 布局"></a>步骤 2：修改 <code>about.pug</code> 布局</h4><p>此步骤是为了让 <code>index.md</code> 中注入的脚本能够被正确渲染到页面上。</p><ol><li>打开博客路径： <strong>themes\solitude\layout\includes\page\about.pug</strong> 在最下方添加一个 <code>!= page.content</code> 与上方 <code>include</code> 保持一样的缩进,如下图。<br><img src="https://img.zrf.me/20250730034522309.webp" alt="修改 `about.pug` 布局"></li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">if site.data.about</span><br><span class="line">    #about-page</span><br><span class="line">        include ../widgets/page/about/authorinfo</span><br><span class="line">        include ../widgets/page/about/contentinfo</span><br><span class="line">        include ../widgets/page/about/skillsinfo</span><br><span class="line">        include ../widgets/page/about/personalities</span><br><span class="line">        include ../widgets/page/about/motto</span><br><span class="line">        include ../widgets/page/about/hobbies</span><br><span class="line">        include ../widgets/page/about/other</span><br><span class="line">        include ../widgets/page/about/tenyear</span><br><span class="line">        include ../widgets/page/about/award</span><br><span class="line">        != page.content</span><br></pre></td></tr></table></figure><h4 id="步骤-3：配置-about-yml-占位符"><a href="#步骤-3：配置-about-yml-占位符" class="headerlink" title="步骤 3：配置 about.yml 占位符"></a>步骤 3：配置 about.yml 占位符</h4><p>此步骤为赞赏卡片提供基础的静态内容和加载时的占位符，以优化用户体验。</p><ol><li>打开博客路径：<strong>source_data\about.yml</strong> 拉到最下方找到 <strong>打赏列表</strong> 替换下方代码进去把原有的覆盖，如下图。<br><img src="https://img.zrf.me/20250730035206961.webp" alt="配置 about.yml 占位符"></li></ol><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 打赏列表</span></span><br><span class="line"><span class="attr">award:</span></span><br><span class="line">  <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">description:</span> <span class="string">感谢赞赏的人，因为你们，让我感受到写博客这件事情能够给你们创造了价值。这会让我在这条路上走得更远。</span></span><br><span class="line">  <span class="attr">tips:</span> <span class="string">总金额：¥</span> &#123;<span class="string">sum</span>&#125;<span class="string">，将全部用于博客的维护和更新。</span> <span class="comment"># 必须带 &#123;sum&#125;，否则无法显示总金额</span></span><br><span class="line"><span class="attr">rewardList:</span> <span class="comment"># 底部捐赠</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">赞赏数据加载中</span></span><br><span class="line">    <span class="attr">money:</span> <span class="number">0</span></span><br><span class="line">    <span class="attr">time:</span> <span class="number">2025-01-01</span></span><br></pre></td></tr></table></figure><p>完成以上所有步骤并重新部署您的 Hexo 博客后，您就拥有了一个功能强大、外观精美且完全自动化的赞赏系统！</p><h3 id="特别鸣谢"><a href="#特别鸣谢" class="headerlink" title="特别鸣谢"></a><strong>特别鸣谢</strong></h3><blockquote><ul><li><strong>技术帮助</strong>: <a href="https://blog.liushen.fun/">清羽飞扬</a></li><li><strong>灵感启发</strong>: <a href="https://blog.zhheo.com/">张洪 (zhheo)</a></li><li><strong>AI 编程助理</strong>: Gemini</li></ul></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Rewards-一个高度可定制的赞赏展示页-为您的-Hexo-博客打造专属的动态赞赏墙&quot;&gt;&lt;a href=&quot;#Rewards-一个高度可定制的赞赏展示页-为您的-Hexo-博客打造专属的动态赞赏墙&quot; class=&quot;headerlink&quot; title=&quot;Reward</summary>
      
    
    
    
    <category term="我的项目" scheme="https://blog.zrf.me/categories/%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="hexo" scheme="https://blog.zrf.me/tags/hexo/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="Solitude" scheme="https://blog.zrf.me/tags/Solitude/"/>
    
  </entry>
  
  <entry>
    <title>免费开YPT虚拟卡，解锁AWS一年免费服务器 + Phala Cloud免费容器 + 光帆3个月3T流量(保姆级教程)</title>
    <link href="https://blog.zrf.me/p/Notes-YPT-AWS/"/>
    <id>https://blog.zrf.me/p/Notes-YPT-AWS/</id>
    <published>2025-07-02T12:28:27.000Z</published>
    <updated>2026-02-25T21:20:37.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="免费开YPT虚拟卡，解锁AWS一年免费服务器-Phala-Cloud免费容器-光帆3个月3T流量-保姆级教程"><a href="#免费开YPT虚拟卡，解锁AWS一年免费服务器-Phala-Cloud免费容器-光帆3个月3T流量-保姆级教程" class="headerlink" title="免费开YPT虚拟卡，解锁AWS一年免费服务器 + Phala Cloud免费容器 + 光帆3个月3T流量(保姆级教程)"></a>免费开YPT虚拟卡，解锁AWS一年免费服务器 + Phala Cloud免费容器 + 光帆3个月3T流量(保姆级教程)</h1><p>想整个服务器玩玩，结果每次都卡在“绑定信用卡”这步，烦不烦？<br>特别是刚入门的时候，为了随便玩玩就绑上自己的真卡，心里总感觉有点犯嘀咕，万一哪天忘了被反薅一笔，那可就蛋疼了。<br>嘿嘿，别慌。今天我就是来带你钻这个“空子”的！<br>跟着我，咱们先去搞张免费的YPT虚拟卡当“万能钥匙”，然后就用它去把 AWS 一整年的免费服务器给“骗”到手，顺道再把 Phala Cloud 的免费容器也给办了。<br>这套白嫖连招下来，保姆级截图伺候，闭着眼都能成。<br>废话不多说，发车！</p><h2 id="一、开YPT虚拟卡"><a href="#一、开YPT虚拟卡" class="headerlink" title="一、开YPT虚拟卡"></a>一、开YPT虚拟卡</h2><h3 id="1-安装-YPT-应用"><a href="#1-安装-YPT-应用" class="headerlink" title="1. 安装 YPT 应用"></a>1. 安装 YPT 应用</h3><p>请通过以下任一官方渠道下载并安装 YPT 应用程序。</p><ul><li><strong>官网下载</strong>: <a href="https://www.ypt.com/en/download">https://www.ypt.com/en/download</a></li><li><strong>Google Play</strong>: <a href="https://play.google.com/store/apps/details?id=com.ypt.pay">YPT: Crypto Card &amp; Pay</a> (截止博文发布今日是2.0.5 版本)</li></ul><blockquote><p><strong>重要提示：关于版本选择</strong></p><ul><li>为确保程序稳定运行，<strong>建议安装或使用 2.0.5 版本</strong>。</li><li>根据用户反馈，<strong>2.0.6</strong> 版本可能存在问题，而最新的 <strong>2.0.7</strong> 版本稳定性尚待验证。</li><li>安装应用后，如果弹出更新提示，<strong>请务必选择忽略或直接关闭</strong>，以避免自动升级。</li></ul></blockquote><p><img src="https://img.zrf.me/20250702202915624.webp" alt="YPT App"></p><h3 id="2-获取免费共享账号"><a href="#2-获取免费共享账号" class="headerlink" title="2. 获取免费共享账号"></a>2. 获取免费共享账号</h3><ol><li><strong>加入社群</strong>：<a href="https://d.zrf.me/tgq">点击此处加入我们的Telegram群组</a>。</li><li><strong>免费获取</strong>：群内 zam 大佬会分享 <strong>免开卡费的YPT账号</strong>，你可以直接领取使用。</li><li><strong>登录邮箱</strong>：获取账号密码后，请前往 <a href="http://mail.cjmail.top/">此邮箱地址</a> 登录。</li></ol><blockquote><p><strong>请注意</strong>：</p><ul><li>这些账号由社群成员提供，包含联盟链接（AFF）。如果你选择充值，分享者会获得奖励。</li><li>充值完全自愿，不充值也能正常使用并体验许多功能。</li><li>为了更方便地使用此类服务，建议你准备一张虚拟信用卡。</li></ul></blockquote><h3 id="3-配置应用与安全设置"><a href="#3-配置应用与安全设置" class="headerlink" title="3. 配置应用与安全设置"></a>3. 配置应用与安全设置</h3><ol><li><p>登录成功后，进入 <strong>账户</strong> 页面，将语言设置为 <strong>繁体中文</strong>。<br><img src="https://img.zrf.me/20250702204420137.webp" alt="设置语言为繁体中文"></p></li><li><p>点击语言上方的 <strong>安全</strong> 选项，进入后设置一个 <strong>PIN</strong> 码。为避免后续操作出现问题，请先完成此步骤。在 <a href="http://mail.cjmail.top/">此邮箱地址</a> 获取验证码后输入即可设置。<br><img src="https://img.zrf.me/20250702213842157.webp" alt="设置PIN码"><br><img src="https://img.zrf.me/20250702214117968.webp" alt="输入验证码"></p></li></ol><h3 id="4-申请虚拟信用卡"><a href="#4-申请虚拟信用卡" class="headerlink" title="4. 申请虚拟信用卡"></a>4. 申请虚拟信用卡</h3><ol><li><p>进入 <strong>卡</strong> 页面，点击 <strong>申请卡</strong>，然后选择 <strong>添加新账单地址</strong>。<br><img src="https://img.zrf.me/20250702204547687.webp" alt="申请卡"><br><img src="https://img.zrf.me/20250702204650874.webp" alt="添加新账单地址"></p></li><li><p><strong>添加账单地址</strong>：表格<strong>只能以英文填写</strong>。建议使用 <a href="https://www.meiguodizhi.com/ca-address">地址生成器</a> 生成一个国外地址（例如加拿大）并复制填写，然后保存。<br><img src="https://img.zrf.me/20250702205856505.webp" alt="填写地址信息"></p></li><li><p><strong>使用优惠码支付</strong>：选择优惠码，下方的数字会自动填充到上方。使用后开卡费即为0元。点击 <strong>支付</strong>，并输入你之前设置的 <strong>PIN</strong> 码以确认。<br><img src="https://img.zrf.me/20250702214536057.webp" alt="使用优惠码"></p></li></ol><h3 id="5-等待开卡并更换账户信息（关键步骤）"><a href="#5-等待开卡并更换账户信息（关键步骤）" class="headerlink" title="5. 等待开卡并更换账户信息（关键步骤）"></a>5. 等待开卡并更换账户信息（关键步骤）</h3><ol><li><p><strong>等待开卡</strong>：支付完成后，回到 <strong>卡</strong> 页面，卡片状态会显示为 <strong>“开卡中”</strong>。此过程通常需要几分钟。<br><img src="https://img.zrf.me/20250702214948855.webp" alt="开卡中状态"></p></li><li><p><strong>更换账户信息 必须更改绑定邮箱与密码 不然号没了勿Q</strong>：在等待开卡时，进入 <strong>账户</strong> 页面，点击头像，此时会提示更换密码，点击 <strong>确认</strong> 并完成密码更改。随后，更改绑定的邮箱地址。完成所有信息更换后，卡片应该也已开通。<br><img src="https://img.zrf.me/20250702215102099.webp" alt="更改密码"><br><img src="https://img.zrf.me/20250702215213770.webp" alt="更改密码2"></p></li><li><p><strong>查看卡信息</strong>：开卡成功后，点击 <strong>查看</strong> 并输入 <strong>PIN</strong> 码，即可看到完整的卡号、有效期和 CVV 等信息。请妥善保存。<br><img src="https://img.zrf.me/20250702215846098.webp" alt="查看卡信息"></p></li></ol><p><strong>恭喜！你已成功开通 YPT 虚拟信用卡。</strong></p><hr><h2 id="二、Phala-Cloud-免费部署容器"><a href="#二、Phala-Cloud-免费部署容器" class="headerlink" title="二、Phala Cloud 免费部署容器"></a>二、Phala Cloud 免费部署容器</h2><blockquote><p>拥有虚拟信用卡的一个妙用是，可以用来验证并试用各种需要绑定银行卡的云服务平台（例如 AWS, GCP 等）。</p></blockquote><p>在上一篇博文 <a href="https://blog.zrf.me/p/SubWeb/">ZRF.ME | 在线订阅转换工具</a> 中，我们提到了如何自建订阅转换系统。本教程将演示如何利用 Phala Cloud 的容器服务，免费部署一个属于你自己的 Subconverter 后端。当然你可以部署其他任意支持的项目，我这里只做演示。</p><p><img src="https://img.zrf.me/20250702224049632.webp" alt="Phala Cloud"></p><h3 id="部署教程"><a href="#部署教程" class="headerlink" title="部署教程"></a>部署教程</h3><h4 id="步骤-1：注册-Phala-Cloud-账号"><a href="#步骤-1：注册-Phala-Cloud-账号" class="headerlink" title="步骤 1：注册 Phala Cloud 账号"></a>步骤 1：注册 Phala Cloud 账号</h4><p>首先，访问 <a href="https://cloud.phala.network/register">Phala Cloud 注册页面</a> 创建一个新账号。</p><blockquote><p><strong>注意</strong>：验证邮件可能会进入你的推广邮件箱或垃圾箱，请仔细查找。</p></blockquote><p><img src="https://img.zrf.me/20250702224346302.webp" alt="注册账号"></p><h4 id="步骤-2：设置支付信息"><a href="#步骤-2：设置支付信息" class="headerlink" title="步骤 2：设置支付信息"></a>步骤 2：设置支付信息</h4><p>注册完成后，点击页面右上角的广告横幅，选择 <strong>“立即设置”</strong>，然后输入你准备好的虚拟信用卡信息。该平台绑定卡片无需验资，会立即通过。</p><p><img src="https://img.zrf.me/20250702224919593.webp" alt="设置支付信息"></p><p>绑定成功后，点击 <strong>“回到主页”</strong>。</p><p><img src="https://img.zrf.me/20250702225202384.webp" alt="绑定成功"></p><h4 id="步骤-3：创建应用"><a href="#步骤-3：创建应用" class="headerlink" title="步骤 3：创建应用"></a>步骤 3：创建应用</h4><ol><li>在主页点击 <strong>“开始构建”</strong>。</li><li>选择 <strong>“使用 docker-compose.yml 文件”</strong> 的方式来部署。</li></ol><p><img src="https://img.zrf.me/20250702225507027.webp" alt="开始构建"></p><h4 id="步骤-4：配置-docker-compose-yml"><a href="#步骤-4：配置-docker-compose-yml" class="headerlink" title="步骤 4：配置 docker-compose.yml"></a>步骤 4：配置 <code>docker-compose.yml</code></h4><p>我们将部署由 <a href="https://github.com/asdlokj1qpi233/subconverter">asdlokj1qpi233</a> 维护的 Subconverter 版本。复制下方的配置，并粘贴到编辑器中，覆盖掉原有的默认内容。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">subconverter:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">asdlokj1qpi23/subconverter:latest</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">subconverter</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;15051:25500&quot;</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br></pre></td></tr></table></figure><p><img src="https://img.zrf.me/20250702230722505.webp" alt="配置 docker-compose"></p><h4 id="步骤-5：部署应用"><a href="#步骤-5：部署应用" class="headerlink" title="步骤 5：部署应用"></a>步骤 5：部署应用</h4><p>平台提供前6个月的免费额度，你可以选择合适的配置进行部署。确认无误后，点击 <strong>“部署”</strong> 并耐心等待。</p><p><img src="https://img.zrf.me/20250702231409781.webp" alt="开始部署"></p><p>部署完成后，点击 <strong>“查看详情”</strong> 进入应用管理页面。</p><p><img src="https://img.zrf.me/20250702232543777.webp" alt="部署完成"></p><h4 id="步骤-6：验证部署结果"><a href="#步骤-6：验证部署结果" class="headerlink" title="步骤 6：验证部署结果"></a>步骤 6：验证部署结果</h4><ol><li>在应用详情页面，找到 <strong>“网络(Network)”</strong> 选项卡，这里会显示你的应用访问地址。</li><li>要验证后端是否成功运行，请在访问链接的末尾加上 <code>/version</code>。</li></ol><p>例如：<code>https://1060e98895bedf43d3d738e3b7fc9120a0cbbbcf-15051.dstack-prod8.phala.network/version</code></p><p>如果你能成功看到版本信息，说明后端已部署完成。</p><blockquote><p><strong>注意</strong>：该容器服务的稳定性有待商榷，不建议用于生产环境或任何需要持久化存储数据的项目。如果你的项目对稳定性有较高要求，可以考虑申请和使用 AWS 等更为成熟可靠的云服务。</p></blockquote><p><img src="https://img.zrf.me/20250702232931477.webp" alt="验证部署"></p><hr><h2 id="三、AWS-免费服务器保姆级注册教程"><a href="#三、AWS-免费服务器保姆级注册教程" class="headerlink" title="三、AWS 免费服务器保姆级注册教程"></a>三、AWS 免费服务器保姆级注册教程</h2><p>本教程将一步步教你如何申请并开通一台 AWS 免费服务器。</p><h3 id="第一步：注册账号"><a href="#第一步：注册账号" class="headerlink" title="第一步：注册账号"></a>第一步：注册账号</h3><h4 id="1-打开官网，填写邮箱"><a href="#1-打开官网，填写邮箱" class="headerlink" title="1. 打开官网，填写邮箱"></a>1. 打开官网，填写邮箱</h4><p>访问亚马逊海外区注册链接：<a href="https://signin.aws.amazon.com/signup?request_type=register">https://signin.aws.amazon.com/signup?request_type&#x3D;register</a>。输入邮箱，设置账户名称，然后点击验证。<br><img src="https://img.zrf.me/20250703003937552.webp" alt="打开官网，填邮箱"></p><h4 id="2-验证邮箱"><a href="#2-验证邮箱" class="headerlink" title="2. 验证邮箱"></a>2. 验证邮箱</h4><p>在你的邮箱中查收验证码并填写。<br><img src="https://img.zrf.me/20250703004051626.webp" alt="验证邮箱"></p><h4 id="3-设置根用户密码"><a href="#3-设置根用户密码" class="headerlink" title="3. 设置根用户密码"></a>3. 设置根用户密码</h4><p>此密码拥有账户最高权限，请务必设置一个高强度密码。<br><img src="https://img.zrf.me/20250703004301181.webp" alt="设置根用户密码"></p><h4 id="4-填写联系信息"><a href="#4-填写联系信息" class="headerlink" title="4. 填写联系信息"></a>4. 填写联系信息</h4><p>可直接使用 <code>+86</code> 手机号进行验证。地址信息若不想填写真实信息，可使用 <a href="https://www.meiguodizhi.com/cn-address">中国地址生成器</a> 辅助填写。<br><img src="https://img.zrf.me/20250703004746109.webp" alt="填写联系信息"></p><h4 id="5-填写信用卡信息"><a href="#5-填写信用卡信息" class="headerlink" title="5. 填写信用卡信息"></a>5. 填写信用卡信息</h4><p>此步骤仅用于身份验证，使用免费套餐不会扣费。填入你之前申请的虚拟信用卡信息即可。<br><img src="https://img.zrf.me/20250703005000597.webp" alt="填写信用卡信息"></p><h4 id="6-再次手机验证"><a href="#6-再次手机验证" class="headerlink" title="6. 再次手机验证"></a>6. 再次手机验证</h4><p>再次输入手机号以完成最终的身份验证。<br><img src="https://img.zrf.me/20250703005126837.webp" alt="再次手机验证"></p><h4 id="7-选择免费支持计划"><a href="#7-选择免费支持计划" class="headerlink" title="7. 选择免费支持计划"></a>7. 选择免费支持计划</h4><p>选择 <strong>“基本支持 – 免费”</strong>，然后点击“完成注册”。成功后页面将跳转至 AWS 控制台主页。（手速快了，没截图）</p><h3 id="第二步：开通免费服务器"><a href="#第二步：开通免费服务器" class="headerlink" title="第二步：开通免费服务器"></a>第二步：开通免费服务器</h3><h4 id="8-选择服务器地区和启动实例"><a href="#8-选择服务器地区和启动实例" class="headerlink" title="8. 选择服务器地区和启动实例"></a>8. 选择服务器地区和启动实例</h4><p>首先，在控制台右上角选择你希望的服务器地区（例如：东京）。然后，开始创建实例（服务器）。<br><img src="https://img.zrf.me/20250703005732905.webp" alt="服务器地区"></p><p>在系统镜像选择中，务必选择带有 <strong>“符合条件的免费套餐”</strong> 标识的选项（例如：Debian）。</p><blockquote><p><strong>免费套餐说明</strong>：<br>新注册用户的第一年，每月可享750小时的 t2.micro 实例（足够一台机器不间断运行一个月）、30GB 存储空间、100GB 传出流量等额度，个人使用完全足够。</p></blockquote><p><img src="https://img.zrf.me/20250703005905570.webp" alt="选择Debian系统"><br><img src="https://img.zrf.me/20250703010247151.webp" alt="符合条件的免费套餐"></p><h4 id="9-创建密钥对（非常重要！）"><a href="#9-创建密钥对（非常重要！）" class="headerlink" title="9. 创建密钥对（非常重要！）"></a>9. 创建密钥对（非常重要！）</h4><p>这是你登录服务器的凭证。点击 <strong>“创建新密钥对”</strong>，自定义一个名称，创建后浏览器将自动下载一个 <code>.pem</code> 文件。</p><blockquote><p><strong>警告：此 <code>.pem</code> 文件是你登录服务器的唯一凭证，一旦丢失将无法找回。请务必立即将其妥善保管！</strong></p></blockquote><p><img src="https://img.zrf.me/20250703010636725.webp" alt="创建新密钥对"></p><h4 id="10-配置防火墙和硬盘"><a href="#10-配置防火墙和硬盘" class="headerlink" title="10. 配置防火墙和硬盘"></a>10. 配置防火墙和硬盘</h4><ul><li><strong>防火墙 (安全组)</strong>: 选择“创建安全组”，并勾选 <strong>“允许来自互联网的 HTTPS”</strong> 和 <strong>“允许来自互联网的 HTTP 流量”</strong>，否则你部署的网站将无法从公网访问。</li><li><strong>配置存储</strong>: 免费套餐最高支持 30GB 硬盘，可根据需求调整，默认大小也够用。</li></ul><p>完成以上配置后，点击 <strong>“启动实例”</strong>。<br><img src="https://img.zrf.me/20250703011218477.webp" alt="配置防火墙和硬盘"></p><h4 id="11-开机成功"><a href="#11-开机成功" class="headerlink" title="11. 开机成功"></a>11. 开机成功</h4><p>看到成功页面，即表示你的 AWS 服务器已成功启动。<br><img src="https://img.zrf.me/20250703011456114.webp" alt="开机成功！"></p><p>关于如何使用 SSH 连接服务器及后续操作，你可以在 YouTube 或 Bilibili 等平台找到大量详细教程。祝你使用愉快！</p><h2 id="四、AWS-Lightsail（光帆）-3个月免费服务器保姆级注册教程"><a href="#四、AWS-Lightsail（光帆）-3个月免费服务器保姆级注册教程" class="headerlink" title="四、AWS Lightsail（光帆） 3个月免费服务器保姆级注册教程"></a>四、AWS Lightsail（光帆） 3个月免费服务器保姆级注册教程</h2><blockquote><ul><li>如果你注册了 AWS 早点吧，这个也一起 申请了 免得后面出 水电费账单、电话账单或类似账单。</li><li>AWS Lightsail 免费三个月的时间计算规则如下：</li><li>起始时间：从你启动第一个符合条件的 Lightsail 资源的日期开始计算免费期，而非从注册账号的日期开始计算。</li><li>持续时长：免费试用持续 90 天，3 个月和 90 天是等同的时长表述。例如，若你在 2025 年 5 月 28 日启动第一个合格资源，免费期将到 2025 年 8 月 26 日左右（5 月 28 日 - 6 月 27 日为第一个月，6 月 28 日 - 7 月 27 日为第二个月，7 月 29 日 - 8 月 26 日为第三个月，共 90 天），并非简单的日历月计算（如 5 月启动就只到 7 月）。</li></ul></blockquote><h4 id="1-登录并创建实例"><a href="#1-登录并创建实例" class="headerlink" title="1. 登录并创建实例"></a>1. 登录并创建实例</h4><p>访问 Lightsail 官网：<a href="https://lightsail.aws.amazon.com/ls/webapp/create/instance">https://lightsail.aws.amazon.com/ls/webapp/create/instance</a>。使用你的 AWS 账号登录后，开始创建实例。<br><img src="https://img.zrf.me/20250703154234673.webp" alt="登录并创建实例"></p><h4 id="2-设置语言为中文"><a href="#2-设置语言为中文" class="headerlink" title="2. 设置语言为中文"></a>2. 设置语言为中文</h4><p>在页面右上角，可以根据个人习惯将语言设置为简体中文。<br><img src="https://img.zrf.me/20250703154343770.webp" alt="设置语言为中文"></p><h4 id="3-选择服务器地区"><a href="#3-选择服务器地区" class="headerlink" title="3. 选择服务器地区"></a>3. 选择服务器地区</h4><p>根据你的需求选择一个合适的服务器地区，例如，这里选择我尚未开通过的地区（如：韩国首尔）。<br><img src="https://img.zrf.me/20250703154559531.webp" alt="选择服务器地区"></p><h4 id="4-选择系统镜像"><a href="#4-选择系统镜像" class="headerlink" title="4. 选择系统镜像"></a>4. 选择系统镜像</h4><p>你可以根据需要选择 Linux 或 Windows 操作系统。本教程以 Debian 为例。<br><img src="https://img.zrf.me/20250703154836760.webp" alt="选择Debian系统"></p><h4 id="5-创建密钥对（非常重要！）"><a href="#5-创建密钥对（非常重要！）" class="headerlink" title="5. 创建密钥对（非常重要！）"></a>5. 创建密钥对（非常重要！）</h4><p>点击“创建新 SSH 密钥对”，创建后务必立即下载并妥善保管私有密钥文件。</p><blockquote><p><strong>警告：此密钥文件是你登录服务器的唯一凭证，一旦丢失将无法找回。请务必立即将其妥善保管！</strong></p></blockquote><p><img src="https://img.zrf.me/20250703155300373.webp" alt="创建新密钥对"></p><h4 id="6-选择免费计划"><a href="#6-选择免费计划" class="headerlink" title="6. 选择免费计划"></a>6. 选择免费计划</h4><p>选择网络类型为“双堆栈”。在实例计划中，选择包含 <strong>“前 3 个月免费”</strong> 标识的套餐。<br><img src="https://img.zrf.me/20250703161112416.webp" alt="选择免费计划"></p><h4 id="7-命名并启动实例"><a href="#7-命名并启动实例" class="headerlink" title="7. 命名并启动实例"></a>7. 命名并启动实例</h4><p>为你的实例设置一个名称（或使用默认名称），然后点击“创建实例”。<br><img src="https://img.zrf.me/20250703161731097.webp" alt="命名并启动实例"></p><h4 id="8-开通成功"><a href="#8-开通成功" class="headerlink" title="8. 开通成功"></a>8. 开通成功</h4><p>看到正在运行的实例，即表示你的 AWS Lightsail 服务器已成功启动。<br><img src="https://img.zrf.me/20250703165125484.webp" alt="开通成功"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;免费开YPT虚拟卡，解锁AWS一年免费服务器-Phala-Cloud免费容器-光帆3个月3T流量-保姆级教程&quot;&gt;&lt;a href=&quot;#免费开YPT虚拟卡，解锁AWS一年免费服务器-Phala-Cloud免费容器-光帆3个月3T流量-保姆级教程&quot; class=&quot;hea</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="隐私" scheme="https://blog.zrf.me/tags/%E9%9A%90%E7%A7%81/"/>
    
    <category term="科学上网" scheme="https://blog.zrf.me/tags/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    <category term="订阅转换" scheme="https://blog.zrf.me/tags/%E8%AE%A2%E9%98%85%E8%BD%AC%E6%8D%A2/"/>
    
    <category term="容器" scheme="https://blog.zrf.me/tags/%E5%AE%B9%E5%99%A8/"/>
    
    <category term="VPS" scheme="https://blog.zrf.me/tags/VPS/"/>
    
    <category term="虚拟信用卡" scheme="https://blog.zrf.me/tags/%E8%99%9A%E6%8B%9F%E4%BF%A1%E7%94%A8%E5%8D%A1/"/>
    
  </entry>
  
  <entry>
    <title>ZRF.ME | 在线订阅转换工具 - 自建一个属于你的订阅转换系统，告别订阅链接泄露，前端与后端部署教程</title>
    <link href="https://blog.zrf.me/p/SubWeb/"/>
    <id>https://blog.zrf.me/p/SubWeb/</id>
    <published>2025-06-28T20:17:27.000Z</published>
    <updated>2026-03-02T00:48:53.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ZRF-ME-在线订阅转换工具-自建一个属于你的订阅转换系统，告别订阅链接泄露，前端与后端部署教程"><a href="#ZRF-ME-在线订阅转换工具-自建一个属于你的订阅转换系统，告别订阅链接泄露，前端与后端部署教程" class="headerlink" title="ZRF.ME | 在线订阅转换工具 - 自建一个属于你的订阅转换系统，告别订阅链接泄露，前端与后端部署教程"></a>ZRF.ME | 在线订阅转换工具 - 自建一个属于你的订阅转换系统，告别订阅链接泄露，前端与后端部署教程</h1><p>最近一直关注的技术大佬“CM”发视频了，惊喜的发现他不仅发布了自建订阅转换后端的教程，还将其配套的前端项目 <strong>Sub-Web-Modify</strong> 也开源了。作为CM佬的忠实粉丝，我立刻动手，将这一整套前后端服务部署了起来，并顺手为它增加了一个小小的评论功能。(没有代码基础的我，当然是使用的AI)</p><p>你是否也曾遇到过这些问题：公共订阅转换服务规则集臃肿，导致转换失败？或是担心自己的订阅链接暴露，存在数据安全隐患？自建订阅转换服务正是解决这些痛点的完美方案。</p><p>本文将详细记录我从零到一的部署过程，内容涵盖后端（Subconverter）搭建、前端（Sub-Web-Modify）部署、订阅转换参数优化，希望能帮助你彻底摆脱对公共服务的依赖，构建一个属于自己的、安全高效的订阅转换系统。</p><blockquote><p>(致谢：本项目基于CM佬增强的 <a href="https://github.com/cmliu/sub-web-modify">Sub-Web-Modify</a>，它源于 <a href="https://github.com/CareyWang/sub-web">CareyWang&#x2F;sub-web</a> 项目，并由 <a href="https://github.com/youshandefeiyang">youshandefeiyang</a> 的出色工作启发。在此向所有贡献者表示感谢。)<br>(致谢：<a href="https://d.zrf.me/yxvm">由YXVM赞助服务</a> ，周润发HK订阅转换后端：<a href="https://subapi.zrfme.com/version">https://subapi.zrfme.com</a> ，使用其提供的服务器进行部署，并公开给大家使用)</p></blockquote><h2 id="ZRF-ME-在线订阅转换工具-在线体验"><a href="#ZRF-ME-在线订阅转换工具-在线体验" class="headerlink" title="ZRF.ME | 在线订阅转换工具 在线体验"></a>ZRF.ME | 在线订阅转换工具 在线体验</h2><ul><li>订阅转换前端：<a href="https://sub.zrfme.com/">https://sub.zrfme.com</a></li><li>周润发HK后端：<a href="https://subapi.zrfme.com/version">https://subapi.zrfme.com</a></li></ul><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><p><img src="https://img.zrf.me/20250629192122092.webp" alt="界面预览"><br><img src="https://img.zrf.me/20250629232345815.webp" alt="界面预览"></p><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li>这是一款功能强大的订阅转换工具，拥有现代化且美观易用的界面。它不仅能轻松实现 Clash、Surge、V2Ray 等多种主流订阅格式的相互转换，还提供了一系列高级定制功能。</li><li>核心转换能力：支持多种订阅格式，满足不同客户端的需求。</li><li>高级节点管理：通过关键字或正则表达式，轻松实现节点的 筛选 和批量 重命名。</li><li>强大的定制性：允许用户上传自定义远程配置，实现高度个性化的规则。</li><li>卓越的用户体验：</li><li>智能主题：支持亮&#x2F;暗色模式，并可自动跟随系统设置切换。</li><li>响应式设计：完美适配桌面和移动设备，随时随地轻松使用。</li><li>便捷分享：内置短链接生成功能，让订阅分享更加简单方便。</li></ul><h2 id="订阅转换前端后端-网站收集"><a href="#订阅转换前端后端-网站收集" class="headerlink" title="订阅转换前端后端 网站收集"></a>订阅转换前端后端 网站收集</h2><div class="tabs" id="span,3"><ul class="nav-tabs"><li class="tab active"><button type="button" data-href="#span,3-0">订阅转换后端</button></li><li class="tab"><button type="button" data-href="#span,3-1">订阅转换前端</button></li></ul><div class="tab-contents"><div class="tab-item-content active" id="span,3-0"><blockquote><ul><li><strong>后端是无用户界面的API服务，仅负责处理数据和逻辑。直接在浏览器访问其地址，看不到任何内容是完全正常的。</strong></li></ul></blockquote><table><thead><tr><th>名称</th><th>订阅转换后端API 地址</th></tr></thead><tbody><tr><td>周润发HK后端【由YXVM赞助服务】</td><td><a href="https://subapi.zrfme.com/">https://subapi.zrfme.com</a></td></tr><tr><td>CM负载均衡后端【vless reality+hy1+hy2】</td><td><a href="https://subapi.cmliussss.net/">https://subapi.cmliussss.net</a></td></tr><tr><td>CM应急备用后端【vless reality+hy1+hy2】</td><td><a href="https://subapi.fxxk.dedyn.io/">https://subapi.fxxk.dedyn.io</a></td></tr><tr><td>肥羊增强型后端【vless reality+hy1+hy2】</td><td><a href="https://url.v1.mk/">https://url.v1.mk</a></td></tr><tr><td>肥羊备用后端【vless reality+hy1+hy2】</td><td><a href="https://sub.d1.mk/">https://sub.d1.mk</a></td></tr><tr><td>白嫖哥【vless reality+hy1+hy2】</td><td><a href="https://api.sub.zaoy.cn/">https://api.sub.zaoy.cn</a></td></tr><tr><td>nameless13提供</td><td><a href="https://www.nameless13.com/">https://www.nameless13.com</a></td></tr><tr><td>subconverter作者提供</td><td><a href="https://sub.xeton.dev/">https://sub.xeton.dev</a></td></tr><tr><td>sub-web作者提供</td><td><a href="https://api.wcc.best/">https://api.wcc.best</a></td></tr><tr><td>920后端</td><td><a href="https://sub.xjz.im/">https://sub.xjz.im</a></td></tr><tr><td>Sublink后端（歪兔）</td><td><a href="https://api.sublink.dev/">https://api.sublink.dev</a></td></tr><tr><td>SoCloud 后端</td><td><a href="https://api.subcsub.com/">https://api.subcsub.com</a></td></tr></tbody></table></div><div class="tab-item-content" id="span,3-1"><blockquote><ul><li><strong>前端网页是为后端API服务提供的一个“图形操作界面”。它的主要目的是方便普通用户使用，但对于知道如何直接调用API的高级用户来说，前端并不是必需品。</strong></li></ul></blockquote><table><thead><tr><th>名称</th><th>订阅转换前端 地址</th></tr></thead><tbody><tr><td>周润发订阅转换</td><td><a href="https://sub.zrfme.com/">https://sub.zrfme.com</a></td></tr><tr><td>CM订阅转换</td><td><a href="https://sub.cmliussss.com/">https://sub.cmliussss.com</a></td></tr><tr><td>肥羊订阅转换</td><td><a href="https://suburl.v1.mk/">https://suburl.v1.mk</a></td></tr><tr><td>nameless13提供</td><td><a href="https://api.nameless13.com/">https://api.nameless13.com</a></td></tr><tr><td>subconverter作者提供</td><td><a href="https://sub.xeton.dev/">https://sub.xeton.dev</a></td></tr><tr><td>sub-web作者提供</td><td><a href="https://sub-web.netlify.app/">https://sub-web.netlify.app</a></td></tr><tr><td>920提供</td><td><a href="https://sub.xjz.im/">https://sub.xjz.im</a></td></tr><tr><td>Sublink（歪兔）</td><td><a href="https://sublink.dev/">https://sublink.dev</a></td></tr><tr><td>SoCloud 订阅转换</td><td><a href="https://subcsub.com/">https://subcsub.com</a></td></tr></tbody></table></div></div></div><h2 id="订阅转换前端部署"><a href="#订阅转换前端部署" class="headerlink" title="订阅转换前端部署"></a>订阅转换前端部署</h2><h3 id="Cloudflare-Pages-部署（推荐）"><a href="#Cloudflare-Pages-部署（推荐）" class="headerlink" title="Cloudflare Pages 部署（推荐）"></a>Cloudflare Pages 部署（推荐）</h3><ol><li><p>首先打开 <a href="https://github.com/shaoyouvip/sub-web-modify">https://github.com/shaoyouvip/sub-web-modify</a> 点击项目页面右上角 <strong>Starred（求个星星！！！）</strong> 然后点击 <strong>Fork</strong> 按钮,将此项目复制到您自己的 GitHub 仓库中。</p><ul><li><p>编辑 <code>src\views\Subconverter.vue</code>  使用电脑键盘快捷键 <strong>CTRL+F</strong> 搜索 <strong>subapi.zrfme.com</strong> 找到下方图片中的内容，并修改为你的订阅转换后端，这样设置后，稍后打开前端页面就是默认使用这个后端地址进行转换，如果你没有部署后端可以先默认使用我内置的。<strong>内置了CM佬与肥羊佬等可用的后端</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">form: &#123; sourceSubUrl: &quot;&quot;, clientType: &quot;&quot;, customBackend: this.getUrlParam() == &quot;&quot; ? &quot;https://subapi.zrfme.com&quot; : this.getUrlParam()</span><br></pre></td></tr></table></figure><p><img src="https://img.zrf.me/20250630002259227.webp" alt="Subconverter.vue"></p></li><li><p>编辑 <code>.env</code>  设置环境变量，其中的链接都可以随意更改。<strong>不推荐可忽略此步，建议使用CF的变量设置进行配置</strong><br><img src="https://img.zrf.me/20250630001303038.webp" alt="环境变量"></p></li></ul></li><li><p>连接到 Cloudflare Pages：</p><ul><li>打开 <a href="https://dash.cloudflare.com/">Cloudflare Dashboard</a> 创建，选择 Pages → 导入现有 Git 存储库 点开始使用 → 连接到 Git<br><img src="https://img.zrf.me/20250630002950933.webp" alt="连接到 Git"></li><li>选择你 Fork 的仓库<br><img src="https://img.zrf.me/20250630003305226.webp" alt="Fork仓库"></li></ul></li><li><p>配置构建设置：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">框架预设：Vue</span><br><span class="line">构建命令：npm run build</span><br><span class="line">构建输出目录：/dist</span><br></pre></td></tr></table></figure><p><img src="https://img.zrf.me/20250630003431233.webp" alt="配置构建设置"></p></li><li><p>设置CF中的环境变量 <strong>推荐使用</strong> ：</p><ul><li>环境变量的.env 文件中的都可设置，请自行修改：<a href="https://github.com/shaoyouvip/sub-web-modify/blob/master/.env">https://github.com/shaoyouvip/sub-web-modify/blob/master/.env</a><br><img src="https://img.zrf.me/20250630144547211.webp" alt="设置CF中的环境变量"></li></ul></li><li><p>部署订阅转换前端完成，每次在Github修改代码，这里都会同步进行更新，然后自己设置自定义域名即可。</p></li></ol><h2 id="订阅转换后端部署"><a href="#订阅转换后端部署" class="headerlink" title="订阅转换后端部署"></a>订阅转换后端部署</h2><p>都是部署的这位大佬维护的 <strong>Subconverter</strong> 版本：<a href="https://github.com/asdlokj1qpi233/subconverter">https://github.com/asdlokj1qpi233/subconverter</a></p><h3 id="支持的类型"><a href="#支持的类型" class="headerlink" title="支持的类型"></a>支持的类型</h3><table><thead><tr><th align="left">类型</th><th align="center">作为源</th><th align="center">作为目标</th><th align="left">目标名称</th></tr></thead><tbody><tr><td align="left">Clash</td><td align="center">✓</td><td align="center">✓</td><td align="left">clash</td></tr><tr><td align="left">ClashR</td><td align="center">✓</td><td align="center">✓</td><td align="left">clashr</td></tr><tr><td align="left">Quantumult</td><td align="center">✓</td><td align="center">✓</td><td align="left">quan</td></tr><tr><td align="left">Quantumult X</td><td align="center">✓</td><td align="center">✓</td><td align="left">quanx</td></tr><tr><td align="left">Loon</td><td align="center">✓</td><td align="center">✓</td><td align="left">loon</td></tr><tr><td align="left">SS (SIP002)</td><td align="center">✓</td><td align="center">✓</td><td align="left">ss</td></tr><tr><td align="left">SS Android</td><td align="center">✓</td><td align="center">✓</td><td align="left">sssub</td></tr><tr><td align="left">SSD</td><td align="center">✓</td><td align="center">✓</td><td align="left">ssd</td></tr><tr><td align="left">SSR</td><td align="center">✓</td><td align="center">✓</td><td align="left">ssr</td></tr><tr><td align="left">Surfboard</td><td align="center">✓</td><td align="center">✓</td><td align="left">surfboard</td></tr><tr><td align="left">Surge 2</td><td align="center">✓</td><td align="center">✓</td><td align="left">surge&amp;ver&#x3D;2</td></tr><tr><td align="left">Surge 3</td><td align="center">✓</td><td align="center">✓</td><td align="left">surge&amp;ver&#x3D;3</td></tr><tr><td align="left">Surge 4</td><td align="center">✓</td><td align="center">✓</td><td align="left">surge&amp;ver&#x3D;4</td></tr><tr><td align="left">Surge 5</td><td align="center">✓</td><td align="center">✓</td><td align="left">surge&amp;ver&#x3D;5</td></tr><tr><td align="left">V2Ray</td><td align="center">✓</td><td align="center">✓</td><td align="left">v2ray</td></tr><tr><td align="left">Telegram-liked HTTP&#x2F;Socks 5 links</td><td align="center">✓</td><td align="center">×</td><td align="left">Only as source</td></tr><tr><td align="left">Singbox</td><td align="center">✓</td><td align="center">✓</td><td align="left">singbox</td></tr></tbody></table><blockquote><p><strong>无 VPS 用户 CM佬有详细的视频教程,使用 ClawCloudRun 部署后端</strong></p></blockquote><ul><li>视频详细教程：<a href="https://youtu.be/31e9YBrnqw8">YouTube跳转查看</a> </li><li>博客图文教程：<a href="https://cmliussss.com/p/SUBAPI/">建订阅转换：API后端 🚨 告别订阅泄露风险！无需VPS，免费拥有专属私密转换服务，守护科学上网的节点</a></li></ul><blockquote><p><strong>有 VPS 用户 我简单演示一下 使用的 1PANEL图形化界面 部署后端</strong></p></blockquote><h3 id="创建容器"><a href="#创建容器" class="headerlink" title="创建容器"></a>创建容器</h3><ol><li><p>进入到 <strong>1PANEL后台管理</strong> 点击容器 → 创建容器，填写如下参数，完成后点击确定。</p><ul><li>名称：subconverter</li><li>镜像：<strong>asdlokj1qpi23&#x2F;subconverter:latest</strong> </li><li>服务器端口：15051 </li><li>容器端口：25500</li><li>重启规则：一直重启<figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">version: <span class="string">&#x27;3&#x27;</span></span><br><span class="line">services:</span><br><span class="line">subconverter:</span><br><span class="line">image: asdlokj1qpi23/subconverter:latest</span><br><span class="line">container_name: subconverter</span><br><span class="line">ports:</span><br><span class="line">  - <span class="string">&quot;15051:25500&quot;</span></span><br><span class="line">restart: always</span><br></pre></td></tr></table></figure></li></ul><p> <img src="https://img.zrf.me/20250630012653674.webp" alt="创建容器"></p></li><li><p>等待容器状态变为 <strong>已启动</strong> 打开 http:&#x2F;&#x2F;你的服务器IP:15051&#x2F;version 可以看到这个版本内容：<strong>subconverter v0.9.9-383deb5 backend</strong> 就表示部署成功了。<br><img src="https://img.zrf.me/20250630014217094.webp" alt="启动容器"></p></li></ol><h3 id="配置域名并安装证书"><a href="#配置域名并安装证书" class="headerlink" title="配置域名并安装证书"></a>配置域名并安装证书</h3><ol><li><p>配置域名，给这个 订阅转换后端 配置域名，我设置为：<strong><a href="https://subapi.zrfme.com/">https://subapi.zrfme.com</a></strong> 解析到你的服务器ip保存。<br><img src="https://img.zrf.me/20250630015718169.webp" alt="配置域名"></p></li><li><p>先确定你的服务器端口，我的是<strong>15051</strong><br><img src="https://img.zrf.me/20250816233720472.webp" alt="服务器端口"></p></li><li><p>来到  <strong>1panel</strong> → <strong>网站</strong> → <strong>网站</strong> → <strong>创建</strong> → <strong>反向代理</strong> → <strong>主域名</strong>&#x3D;你自己刚设置的域名。<strong>代理地址</strong>&#x3D;<a href="http://127.0.0.1:15051/">http://127.0.0.1:15051</a> （以你的为准）<br><img src="https://img.zrf.me/20250817004642319.webp" alt="反向代理"></p></li></ol><h3 id="安装证书后端部署完成"><a href="#安装证书后端部署完成" class="headerlink" title="安装证书后端部署完成"></a>安装证书后端部署完成</h3><ol><li><p>接下来回到 <strong>1panel</strong> → <strong>网站</strong> → <strong>证书</strong> → <strong>DNS账户</strong> → <strong>创建</strong> ，<strong>名称</strong>随你设置，因为我的域名托管到 <strong>cloudflare</strong>中的。选择类型为<strong>cloudflare</strong> ，<strong>EMAIL</strong>就是你<strong>cloudflare</strong>账号的邮箱。<br><img src="https://img.zrf.me/20250509023341644.webp" alt="安装证书1"><br><img src="https://img.zrf.me/20250509023630736.webp" alt="安装证书2"></p></li><li><p><strong>API Token</strong> 获取，我们打开 <a href="https://dash.cloudflare.com/">https://dash.cloudflare.com/</a> <strong>首页</strong> 右上角 <strong>配置文件</strong><br><img src="https://img.zrf.me/20250509024019637.webp" alt="API Token"></p></li><li><p><strong>API令牌</strong> → <strong>创建令牌</strong> 选择 <strong>编辑区域 DNS</strong> 点击 <strong>使用模板</strong>，<strong>区域资源</strong> 选择 <strong>所有区域</strong> → <strong>创建令牌</strong> 得到的 <strong>用户 API 令牌</strong> 填入 <strong>DNS账户</strong> 的 <strong>API Token</strong>。<br><img src="https://img.zrf.me/20250509024219066.webp" alt="API Token2"><br><img src="https://img.zrf.me/20250509024949519.webp" alt="API Token3"><br><img src="https://img.zrf.me/20250509024838677.webp" alt="API Token4"></p></li><li><p>申请  <code>zrfme.com</code> 与 <code>*.zrfme.com</code>  申请一次后续就不需要申请，创建项目就可以直接使用这个域名下的证书。<br><img src="https://img.zrf.me/20250630020846026.webp" alt="申请证书"></p></li><li><p>来到  <strong>1panel</strong> → <strong>网站</strong> → <strong>网站</strong> → <strong>配置</strong> → 如图设置然后保存。<br><img src="https://img.zrf.me/20250630021028018.webp" alt="配置证书"></p></li><li><p>然后浏览器可以打开你的域名：<a href="https://subapi.zrfme.com/version">https://subapi.zrfme.com/version</a>  显示版本内容，后端的部署就全部完成了。</p></li></ol><h2 id="特别致谢"><a href="#特别致谢" class="headerlink" title="特别致谢"></a>特别致谢</h2><p>特别感谢 <a href="https://d.zrf.me/yxvm">YxVM</a> 提供服务器赞助，让项目能够稳定运行，为大家带来更好的体验！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ZRF-ME-在线订阅转换工具-自建一个属于你的订阅转换系统，告别订阅链接泄露，前端与后端部署教程&quot;&gt;&lt;a href=&quot;#ZRF-ME-在线订阅转换工具-自建一个属于你的订阅转换系统，告别订阅链接泄露，前端与后端部署教程&quot; class=&quot;headerlink&quot; t</summary>
      
    
    
    
    <category term="我的项目" scheme="https://blog.zrf.me/categories/%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="隐私" scheme="https://blog.zrf.me/tags/%E9%9A%90%E7%A7%81/"/>
    
    <category term="科学上网" scheme="https://blog.zrf.me/tags/%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="Vercel" scheme="https://blog.zrf.me/tags/Vercel/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="网络安全" scheme="https://blog.zrf.me/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    <category term="订阅转换" scheme="https://blog.zrf.me/tags/%E8%AE%A2%E9%98%85%E8%BD%AC%E6%8D%A2/"/>
    
  </entry>
  
  <entry>
    <title>ZRF.ME | GitHub 文件加速代理 - 开发者福音：为 GitHub 下载提速的极简加速工具</title>
    <link href="https://blog.zrf.me/p/GitHub-Proxy/"/>
    <id>https://blog.zrf.me/p/GitHub-Proxy/</id>
    <published>2025-06-02T13:59:37.000Z</published>
    <updated>2026-03-02T00:48:53.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ZRF-ME-GitHub-文件加速代理-🚀"><a href="#ZRF-ME-GitHub-文件加速代理-🚀" class="headerlink" title="ZRF.ME | GitHub 文件加速代理 🚀"></a>ZRF.ME | GitHub 文件加速代理 🚀</h1><p>大家好！<br>如果你是开发者、开源爱好者，或者经常需要从 GitHub 下载资源，你可能遇到过这样的烦恼：GitHub 的文件下载速度慢，尤其是在国内网络环境下，无论是 Releases 文件还是 Raw 文件，经常卡顿，甚至让人抓狂。</p><p>为了解决这个问题，我搭建了 <strong><a href="https://d.zrf.me/gh">ZRF.ME | GitHub 文件加速代理</a></strong> —— 一个简单、免费、高效的工具页，帮你快速找到多个可用的 GitHub 加速服务，提高访问效率。</p><p>该站点整合了多个常用的 <strong>GitHub 文件加速工具</strong> 的特点，并在界面设计上进行了优化，旨在提供一个统一、便捷的访问入口。</p><p>📌 <strong>注意：[ZRF.ME | GitHub 加速] 目前暂未提供任何代理或缓存服务</strong>，仅作为工具导航页，供用户查找合适的加速源。</p><h2 id="ZRF-ME-GitHub-加速-在线体验"><a href="#ZRF-ME-GitHub-加速-在线体验" class="headerlink" title="ZRF.ME | GitHub 加速 在线体验"></a>ZRF.ME | GitHub 加速 在线体验</h2><ul><li>如加载慢，可稍等片刻</li><li>首选站点地址：<a href="https://d.zrf.me/gh">https://d.zrf.me/gh</a></li></ul><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><p><img src="https://img.zrf.me/20250602051052494.webp" alt="界面预览"></p><h2 id="核心功能亮点"><a href="#核心功能亮点" class="headerlink" title="核心功能亮点"></a>核心功能亮点</h2><p><strong>ZRF.ME | GitHub 加速</strong> 提供了以下强大功能，满足各种 GitHub 下载需求：</p><ul><li><strong>广泛资源支持</strong>：支持 GitHub 的 Releases、Raw 文件、Archive 打包、Gist，甚至部分 Git Clone 操作。</li><li><strong>自动缓存加速</strong>：资源通过代理节点缓存，显著提升访问速度（具体效果取决于节点质量）。</li><li><strong>大文件无忧</strong>：支持大文件下载，无大小限制，适合各种场景（视网络环境而定）。</li><li><strong>开箱即用</strong>：无需复杂配置，粘贴链接即可生成加速地址，简单高效。</li><li><strong>安全可靠</strong>：全站支持 HTTPS 加密，保护你的数据安全。</li><li><strong>智能节点管理</strong>：每小时自动检测节点状态，筛选延迟低于 500ms 的优质节点，确保服务稳定。</li></ul><h2 id="如何使用？"><a href="#如何使用？" class="headerlink" title="如何使用？"></a>如何使用？</h2><h2 id="如何使用-ZRF-ME-GitHub-文件加速？"><a href="#如何使用-ZRF-ME-GitHub-文件加速？" class="headerlink" title="如何使用 ZRF.ME | GitHub 文件加速？"></a>如何使用 ZRF.ME | GitHub 文件加速？</h2><p>使用 <strong>ZRF.ME | GitHub 加速</strong> 非常简单，只需三步：</p><ol><li><p><strong>访问网站</strong><br>打开 👉 ZRF.ME | GitHub 文件加速：<a href="https://d.zrf.me/gh">https://d.zrf.me/gh</a>。</p></li><li><p><strong>选择节点并输入 GitHub 链接</strong><br>从下拉列表中选择一个优质代理节点（支持延迟检测），然后粘贴你要加速的 GitHub 链接（如 Releases 或 Raw 文件地址）。</p><p><strong>示例：</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"># 原始 GitHub 链接示例</span><br><span class="line">https://raw.githubusercontent.com/aizhourf/check/main/README.md</span><br><span class="line">https://github.com/AaronFeng753/Waifu2x-Extension-GUI/releases/download/v3.125.01/Waifu2x-Extension-GUI-v3.125.01-Win64.7z</span><br><span class="line"></span><br><span class="line"># 代理链接示例（方法一：替换域名）</span><br><span class="line">https://gh.zrfme.com/raw.githubusercontent.com/aizhourf/check/main/README.md</span><br><span class="line"></span><br><span class="line"># 代理链接示例（方法二：添加前缀，本站转换器采用）</span><br><span class="line">https://gh.zrfme.com/https://raw.githubusercontent.com/aizhourf/check/main/README.md</span><br></pre></td></tr></table></figure></li><li><p>生成并下载：点击“转换”按钮，系统会生成加速后的链接。你可以选择复制链接、在新标签页打开，或直接下载资源。如像示例的是一个 <strong>.7z</strong> 的文件压缩包，点击 <strong>新标签页打开</strong> 就会使用你电脑中，默认的下载程序进行下载。<br><img src="https://img.zrf.me/20250602052634950.webp" alt="新标签页打开"></p></li><li><p>不同的加速源在下载速度上存在明显差异。本站提供的 <strong>节点状态检测</strong> 仅用于检测延迟和连通性，<strong>并不代表实际下载速度</strong>。如果发现某个加速源速度较慢或不可用，建议切换其他节点进行测试，以获得更好的体验。</p></li></ol><p><img src="https://img.zrf.me/20250602053137380.webp" alt="下载速度"></p><h2 id="如果您也愿意分享可用的加速源，欢迎投稿或留言反馈。"><a href="#如果您也愿意分享可用的加速源，欢迎投稿或留言反馈。" class="headerlink" title="如果您也愿意分享可用的加速源，欢迎投稿或留言反馈。"></a>如果您也愿意分享可用的加速源，欢迎投稿或留言反馈。</h2><h2 id="特别致谢"><a href="#特别致谢" class="headerlink" title="特别致谢"></a>特别致谢</h2><p>特别感谢 <a href="https://d.zrf.me/yxvm">YxVM</a> 提供服务器赞助，让项目能够稳定运行，为大家带来更好的体验！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ZRF-ME-GitHub-文件加速代理-🚀&quot;&gt;&lt;a href=&quot;#ZRF-ME-GitHub-文件加速代理-🚀&quot; class=&quot;headerlink&quot; title=&quot;ZRF.ME | GitHub 文件加速代理 🚀&quot;&gt;&lt;/a&gt;ZRF.ME | GitHub</summary>
      
    
    
    
    <category term="我的项目" scheme="https://blog.zrf.me/categories/%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="MacOS" scheme="https://blog.zrf.me/tags/MacOS/"/>
    
    <category term="Linux" scheme="https://blog.zrf.me/tags/Linux/"/>
    
    <category term="办公" scheme="https://blog.zrf.me/tags/%E5%8A%9E%E5%85%AC/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="代理工具" scheme="https://blog.zrf.me/tags/%E4%BB%A3%E7%90%86%E5%B7%A5%E5%85%B7/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
  </entry>
  
  <entry>
    <title>超低价注册.COM域名：Google Workspace土耳其区仅需14元/年详细教程</title>
    <link href="https://blog.zrf.me/p/Google-Workspace-Domains/"/>
    <id>https://blog.zrf.me/p/Google-Workspace-Domains/</id>
    <published>2025-05-10T19:39:22.000Z</published>
    <updated>2026-01-21T19:38:04.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="超低价注册-COM域名：Google-Workspace土耳其区仅需14元-年详细教程"><a href="#超低价注册-COM域名：Google-Workspace土耳其区仅需14元-年详细教程" class="headerlink" title="超低价注册.COM域名：Google Workspace土耳其区仅需14元&#x2F;年详细教程"></a>超低价注册.COM域名：Google Workspace土耳其区仅需14元&#x2F;年详细教程</h1><p>感谢群友的分享，这次总算薅到羊毛了。注册过程中遇到了一些波折，主要是手机号一直无法验证，实际上是因为IP不干净，换什么号码都没用。所以建议大家注册时一定要用干净的IP。我一直想薅个便宜的 .COM 域名，专门用来做 <strong>临时邮箱:</strong> <a href="https://mail.zrf.me/">https://mail.zrf.me</a> 服务，这次终于有机会了。需要域名的小伙伴千万别错过，这价格真的很划算！后续也考虑把域名分发给大家使用。之前的域名分发虽然能用，但体验一般，这次希望能做得更好。 <strong>注意说的是每年都14元。不是年抛，但是不能一次续费很多年，谁知道后面谷歌会不会改规则呢。</strong></p><p><img src="https://img.zrf.me/20250511093937116.webp" alt="价格浏览"></p><h2 id="事前准备"><a href="#事前准备" class="headerlink" title="事前准备"></a>事前准备</h2><ul><li>干净的IP，避免验证手机号一直不通过（<strong>必须</strong> ，<strong>IP检测地址，仅供参考也不是很准:</strong> <a href="https://ping0.cc/">https://ping0.cc</a> ）</li><li>支持外币的卡，我是使用的国内 <strong>建行VISA卡</strong> 。（<strong>必须</strong>）</li></ul><p><strong>如果申请成功，欢迎在评论区留言你使用的信用卡类型，方便其他小伙伴参考。</strong></p><blockquote><p> <strong>已知成功卡种</strong>：建行VISA卡，建行万事达，浦发运通卡，广发万事达卡，招行万事达卡，浦发VISA卡，<br> <strong>已知失败卡钟</strong>：中行万事达莫奈卡，pokepay，infini，master，（部分虚拟卡是不能注册的，会跳付款信息验证。）</p></blockquote><h2 id="注册-Google-Workspace"><a href="#注册-Google-Workspace" class="headerlink" title="注册 Google Workspace"></a>注册 Google Workspace</h2><ol><li><p>首先打开 <a href="https://workspace.google.com/intl/zh-CN/">https://workspace.google.com/intl/zh-CN/</a>  点击 <strong>开始免费试用</strong>。<br><img src="https://img.zrf.me/20250511061855247.webp" alt="开始免费试用"></p></li><li><p>地址选择 <strong>土耳其</strong> 根据你的信息随意填写。<br><img src="https://img.zrf.me/20250511062040583.webp" alt="信息"></p></li><li><p>根据你的信息随意填写。<br><img src="https://img.zrf.me/20250511062153931.webp" alt="信息2"></p></li><li><p>选择获取新的自定义域名。<br><img src="https://img.zrf.me/20250511062250826.webp" alt="获取新的自定义域名"></p></li><li><p>选择一个，你想要注册的域名搜索，可用选就行了。这里搜索似乎有限制，多次后会出现 <strong>429 请求过多</strong> 本来我选的是zrfme.com 这个域名，因为可能ip不干净，谷歌验证手机号没通过。<br><img src="https://img.zrf.me/20250511062341481.webp" alt="注册域名)"><br><img src="https://img.zrf.me/20250511062533198.webp" alt="注册域名"></p></li><li><p>打开 土耳其地址生成器：<a href="https://www.meiguodizhi.com/tr-address">https://www.meiguodizhi.com/tr-address</a>  填入对应信息。<br><img src="https://img.zrf.me/20250511062718541.webp" alt="地址生成"></p></li><li><p>设置登录的 <strong>账号密码</strong> 点击 <strong>同意并继续</strong><br><img src="https://img.zrf.me/20250511062857792.webp" alt="登录"></p></li><li><p>然后会让你登录你的账号密码，就是你刚设置的那个。<br><img src="https://img.zrf.me/20250511063132999.webp" alt="登录"></p></li><li><p>好这一步如果 ip 不干净就一直验证不过去。我躺枪了半天，把我还急死了。我最后还是使用国内的手机号成功验证。但是因为前面的那个账号验证不了，我换了个重新注册，就可以验证了。本来之前注册的是 zrfme.com 后面换成 itzrf.com 。<br><img src="https://img.zrf.me/20250511063235527.webp" alt="验证手机号"></p></li><li><p>验证通过就是这个页面了。点我已经了解。<br><img src="https://img.zrf.me/20250511063434806.webp" alt="验证通过"></p></li><li><p>商业标准版，点免费试用，稍后可以取消，这个不扣费。<br><img src="https://img.zrf.me/20250511063531338.webp" alt="免费试用"></p></li><li><p>可以看到，显示的 75 里拉&#x2F;年，如果后续一直这个价格那就太棒了。<br><img src="https://img.zrf.me/20250511063713517.webp" alt="结账)"></p></li><li><p>添加付款方式 我使用的是 visa卡 没有出现 群里佬说的风控问题，他是虚拟卡注册，建议还是不要用虚拟卡免得浪费机会。<br><img src="https://img.zrf.me/20250511064013333.webp" alt="付款方式"></p></li><li><p>接下来的步骤就是跳过跳过跳过。<br><img src="https://img.zrf.me/20250511070411080.webp" alt="跳过"><br><img src="https://img.zrf.me/20250511070412529.webp" alt="跳过"><br><img src="https://img.zrf.me/20250511070414007.webp" alt="跳过"></p></li></ol><h2 id="管理控制台"><a href="#管理控制台" class="headerlink" title="管理控制台"></a>管理控制台</h2><ol><li><p>会进入首页，打开 <a href="https://admin.google.com/ac/billing/subscriptions">https://admin.google.com/ac/billing/subscriptions</a><br><img src="https://img.zrf.me/20250511070405951.webp" alt="管理控制台"></p></li><li><p><strong>感谢兄弟的建议，应评论补充一点说明</strong>：</p><blockquote><ul><li>我们在取消订阅的 <strong>商务标准版</strong> 之后，将无法在使用，如下图其中的 Gmail、Google 文档、Google Meet 等产品。</li><li>打开这个地址，可以看到这个谷歌账户可以使用的 <strong>Google 服务</strong>  <a href="https://admin.google.com/ac/appslist/additional">https://admin.google.com/ac/appslist/additional</a></li></ul></blockquote><p><img src="https://img.zrf.me/20250511063531338.webp" alt="取消订阅3"><br><img src="https://img.zrf.me/20250527215251862.webp" alt="无法使用 Gmail"></p></li><li><p>来到 <strong>结算订阅</strong> 选择 <strong>商务标准版</strong> 进去下方更多取消订阅。<br><img src="https://img.zrf.me/20250511070400597.webp" alt="取消订阅"><br><img src="https://img.zrf.me/20250511070402179.webp" alt="取消订阅2"></p></li><li><p>点击域名注册 可以看到你的信息，付款方案 75.00 TRY&#x2F;域&#x2F;年，合约到期日期：2026年5月11日<br><img src="https://img.zrf.me/20250511070356516.webp" alt="域名信息"></p></li><li><p>进入你注册邮箱，会收到这样的邮件，验证一下。<br><img src="https://img.zrf.me/20250511070350254.webp" alt="验证"></p></li></ol><h2 id="Squarespace域名管理"><a href="#Squarespace域名管理" class="headerlink" title="Squarespace域名管理"></a>Squarespace域名管理</h2><ol><li><p>打开 <a href="https://account.squarespace.com/domains">https://account.squarespace.com/domains</a> 通过谷歌账号登录，而这个谷歌账号是你前面注册的域名邮箱那个号码。<br><img src="https://img.zrf.me/20250511070343212.webp" alt="Squarespace域名管理"><br><img src="https://img.zrf.me/20250511070344682.webp" alt="Squarespace域名管理2"></p></li><li><p>登录完成，可以看到你注册的域名。<br><img src="https://img.zrf.me/20250511070337591.webp" alt="Squarespace域名管理3"></p></li></ol><h2 id="托管-cloudflare"><a href="#托管-cloudflare" class="headerlink" title="托管 cloudflare"></a>托管 cloudflare</h2><ol><li>随后直接托管到 <a href="https://dash.cloudflare.com/">https://dash.cloudflare.com/</a> 美滋滋<br><img src="https://img.zrf.me/20250511070310977.webp" alt="cloudflare1"><br><img src="https://img.zrf.me/20250511070312646.webp" alt="cloudflare2"></li></ol><h2 id="授权管理账户（推荐设置）"><a href="#授权管理账户（推荐设置）" class="headerlink" title="授权管理账户（推荐设置）"></a>授权管理账户（推荐设置）</h2><ol><li><p>发现他这个可以授权其他号码来管理域名，这样你可以设置你的大号常用的邮箱进行管理。<br><img src="https://img.zrf.me/20250511071506693.webp" alt="授权管理账户1"></p></li><li><p>流程是发出邀请后，确认大号有收到邀请的邮件，退出你的当下的域名管理账号，使用谷歌登录或者其他方式创建你的账号，使用大号登录后，再去点击邮件中的确认邀请。有时候会提示没权限多点两下。<br><img src="https://img.zrf.me/20250511071508191.webp" alt="授权管理账户2"></p></li><li><p>这样就可以使用你的一个账号管理多个域名了。<br><img src="https://img.zrf.me/20250527223310312.webp" alt="多域名管理"></p></li></ol><h2 id="Cloudflare电子邮件路由功能设置（推荐设置）"><a href="#Cloudflare电子邮件路由功能设置（推荐设置）" class="headerlink" title="Cloudflare电子邮件路由功能设置（推荐设置）"></a>Cloudflare电子邮件路由功能设置（推荐设置）</h2><blockquote><ul><li>适用前提：仅当域名已托管至Cloudflare时可配置。</li><li>核心作用：购买域名时注册的谷歌账号仅用于域名管理，无邮箱功能。配置后可将所有域名相关邮件（如管理通知、验证邮件）转发至你的常用邮箱，避免遗漏重要信息。</li></ul></blockquote><p><strong>启用邮件路由功能</strong></p><ol><li><p>访问Cloudflare登录页：<a href="https://dash.cloudflare.com/%EF%BC%8C%E8%BE%93%E5%85%A5%E8%B4%A6%E5%8F%B7%E5%AF%86%E7%A0%81%E7%99%BB%E5%BD%95%E3%80%82">https://dash.cloudflare.com/，输入账号密码登录。</a></p></li><li><p>在“域名列表”中找到目标域名，点击域名名称进入管理后台。</p></li><li><p>在左侧菜单栏中，依次点击「电子邮件」→「电子邮件路由」。</p></li><li><p>点击页面中的“开始使用”或“启用”按钮（首次使用为“开始使用”，已有记录为“启用”）。</p></li><li><p>系统会自动生成所需DNS记录，确认无误后点击「添加记录并启用」（系统通常会自动配置，无需手动操作）</p></li></ol><p><strong>验证常用邮箱（关键步骤）</strong></p><p>只有完成验证，常用邮箱才能接收转发邮件，务必操作。</p><ol><li><p>在「目标地址」模块，点击「添加目标地址」，输入你的常用邮箱（如<a href="mailto:&#97;&#105;&#122;&#104;&#111;&#x75;&#114;&#117;&#110;&#x66;&#x61;&#64;&#103;&#x6d;&#97;&#105;&#x6c;&#46;&#99;&#111;&#109;">&#97;&#105;&#122;&#104;&#111;&#x75;&#114;&#117;&#110;&#x66;&#x61;&#64;&#103;&#x6d;&#97;&#105;&#x6c;&#46;&#99;&#111;&#109;</a>）并保存。</p></li><li><p>登录该常用邮箱，查找Cloudflare发送的验证邮件，点击邮件中的「验证电子邮件地址」按钮完成验证。</p></li></ol><p><strong>配置转发规则（推荐全部转发）</strong></p><p>推荐选择“全部地址转发”，确保所有发往该域名的邮件都能被接收，避免遗漏。</p><ol><li><p>在「路由规则」模块中，找到「Catch-all（全部接收）」选项，点击右侧「编辑」。</p></li><li><p>「操作」下拉菜单选择“发送到电子邮件”，「目标」选择已完成验证的常用邮箱。</p></li><li><p>确认规则状态为“活跃”，点击「保存」，最终配置完成如下图。</p></li></ol><p><img src="https://img.zrf.me/20251203145420604.webp" alt="邮件路由功能-全部地址转发"></p><p><strong>测试配置是否成功</strong></p><ol><li>使用一个与常用邮箱不同的其他邮箱，发送测试邮件至“任意前缀@你的域名.com”（例如<a href="mailto:&#122;&#x72;&#x66;&#x40;&#122;&#x72;&#102;&#109;&#101;&#46;&#99;&#x6f;&#x6d;">&#122;&#x72;&#x66;&#x40;&#122;&#x72;&#102;&#109;&#101;&#46;&#99;&#x6f;&#x6d;</a>），随后登录常用邮箱，检查是否成功收到该测试邮件。</li></ol><h2 id="遇到的问题补充说明"><a href="#遇到的问题补充说明" class="headerlink" title="遇到的问题补充说明"></a>遇到的问题补充说明</h2><p><strong>无法验证手机号码</strong></p><ol><li><p>我在教程前面说了，我起初是注册的 <a href="https://zrfme.com/">https://zrfme.com</a> 这个域名，但是因为始终无法验证号码，但是我又想要这个域名，所以间隔我发教程有个十几天了，两天前 <strong>5-24号</strong> 尝试又可以使用国内手机号进行验证了，如果出现无法验证号码卡住的，可以尝试过几天再去试试，或者重新注册了，但是重新注册之前被占用的域名就无法注册。<br><img src="https://img.zrf.me/20250527220126917.webp" alt="即刻短文"></p></li><li><p>如果一直验证不了手机号，你的域名会自动释放的，<strong>您的 Google Workspace 试用帐号被删除后，您最长可能需要等待 48 小时才能将域名 zrfme.com 用于其他 Google Workspace 帐号。</strong><br><img src="https://img.zrf.me/20250527221755964.webp" alt="2025年5月17日 收到的邮件"></p></li></ol><hr><p> <a href="https://support.google.com/a/answer/4377734?hl=zh#reg_expire&pay_for_years&renew_post_expire&transfer_domain&refund&cancel_domain_billing&no_domain_billing&">来自官方常见问题解答 原文引用 点击跳转</a></p><ol><li><p><strong>我的域名注册何时到期？</strong><br>您可以在管理控制台中查看您注册的域名的到期日期和续订日期。只需转到<strong>结算</strong> &gt; <strong>订阅</strong> &gt; <strong>域名注册</strong>。注册的域名的续订日期会显示在<strong>方案续订</strong>旁边。</p></li><li><p><strong>我可以一次性支付多年的费用吗？</strong><br>不可以。您不能一次性支付多年的费用，也无法在年度续订日期之前续订域名。如果您的域名已设为自动续订且您的付款方式是有效的，那么我们就会为您续订域名，而且您的 Google 服务也不会中断。</p></li><li><p><strong>我可以在域名过期后进行续订吗？</strong><br>或许可以。这取决于您的域名注册过期多久了。请参见<em>续订过期的域名注册</em>。</p></li><li><p><strong>我可以将域名转移给其他域名托管服务商吗？</strong><br>可以。将域名转移给其他域名托管服务商后，您可以在 Google 管理控制台之外管理域名。请务必在域名到期日期和续订日期之前完成转移。要查看相关日期，请在管理控制台中转到<strong>结算</strong> &gt; <strong>订阅</strong> &gt; <strong>域名注册</strong>。注册的域名的续订日期会显示在<strong>方案续订</strong>旁边。有关域名转移详情，请参阅<em>将您的域名转移到 Google Workspace 合作的托管服务商</em>。</p></li><li><p><strong>如果我误选了续订域名，可以获得退款吗？</strong><br>这取决于您的订阅。如果您的域名注册订阅被设为自动续订，且续订日期已过，那么就无法获得退款。不过，如果自动续订在到期日前 7 天内关闭，且续订费用已支付，就能获得退款。如要获得退款：</p><ul><li>请在续订日前 7 天内取消域名注册订阅。请参阅<em>如何取消我的域名注册订阅？</em></li><li>如需申请退款，请与 Google Workspace 支持团队联系。</li></ul></li><li><p><strong>为什么我的结算订阅中没有显示域名注册？</strong><br>如果 Google 管理控制台的结算订阅中没有显示域名注册，则说明您并未在注册 Google 服务时购买域名，也就是说，您的域名是另外购买的。这种情况下，您可以通过您的域名注册商网站管理域名。有关识别域名注册托管服务商的帮助，请参阅<em>识别您的域名托管服务商</em>。</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;超低价注册-COM域名：Google-Workspace土耳其区仅需14元-年详细教程&quot;&gt;&lt;a href=&quot;#超低价注册-COM域名：Google-Workspace土耳其区仅需14元-年详细教程&quot; class=&quot;headerlink&quot; title=&quot;超低价注册.</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="办公" scheme="https://blog.zrf.me/tags/%E5%8A%9E%E5%85%AC/"/>
    
    <category term="DNS" scheme="https://blog.zrf.me/tags/DNS/"/>
    
    <category term="最新资讯" scheme="https://blog.zrf.me/tags/%E6%9C%80%E6%96%B0%E8%B5%84%E8%AE%AF/"/>
    
    <category term="免费域名" scheme="https://blog.zrf.me/tags/%E5%85%8D%E8%B4%B9%E5%9F%9F%E5%90%8D/"/>
    
    <category term="域名注册" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%B3%A8%E5%86%8C/"/>
    
    <category term="域名托管" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%89%98%E7%AE%A1/"/>
    
    <category term="Google Workspace" scheme="https://blog.zrf.me/tags/Google-Workspace/"/>
    
    <category term="Squarespace" scheme="https://blog.zrf.me/tags/Squarespace/"/>
    
  </entry>
  
  <entry>
    <title>Twikoo评论+PicList+R2图床：博客评论图片上传与CDN加速最佳实践</title>
    <link href="https://blog.zrf.me/p/Notes-Twikoo-Piclist-R2/"/>
    <id>https://blog.zrf.me/p/Notes-Twikoo-Piclist-R2/</id>
    <published>2025-05-07T19:39:22.000Z</published>
    <updated>2025-05-07T19:39:22.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Twikoo评论-PicList-R2图床：博客评论图片上传与CDN加速最佳实践"><a href="#Twikoo评论-PicList-R2图床：博客评论图片上传与CDN加速最佳实践" class="headerlink" title="Twikoo评论+PicList+R2图床：博客评论图片上传与CDN加速最佳实践"></a>Twikoo评论+PicList+R2图床：博客评论图片上传与CDN加速最佳实践</h1><p>首先我们使用进行演示搭建服务的机器是<strong>YXVM</strong>提供，感谢大善人的赞助。</p><blockquote><p>NodeSupport计划是NodeSeek社区和合作商家主导的免费服务器赞助计划，为高质量博客、开源项目、tg频道、App等持续提供优质稳定的服务器资源。<br>为了规范化、透明化赞助和审批流程，我们开发了审批管理系统，用于处理免费机器的申请、续期、答疑、建议和检举投诉。<br>目前NodeSupport的vps服务器资源由YxVM大力赞助，项目处于试运营状态<a href="https://support.nodeget.com/page/promotion?id=116">NodeSupport计划申请</a></p></blockquote><h2 id="博主前言"><a href="#博主前言" class="headerlink" title="博主前言"></a>博主前言</h2><ul><li>博主我呢是对容器一点不熟悉，我也搜索过，hexo博客评论系统接入<strong>picgo-server</strong>服务，基本没有找到相关的文章，只能自己折腾，最终实现了自己想要的效果。这篇博文完整记录了我的操作流程，希望能为和我一样的新手小白提供参考和帮助，大佬无视，教程中有什么优化的可以提出指正。</li></ul><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><ul><li><a href="https://blog.zrf.me/message/">https://blog.zrf.me/message/</a> 效果浏览。</li><li>上传后的直链地址：<a href="https://webp.001315.xyz/blog/1746733312.webp">https://webp.001315.xyz/blog/1746733312.webp</a><br><img src="https://webp.001315.xyz/blog/1746733312.webp" alt="测试上传图片"><br><img src="https://img.zrf.me/20250509035239493.webp" alt="界面预览"></li></ul><h2 id="事前准备"><a href="#事前准备" class="headerlink" title="事前准备"></a>事前准备</h2><ul><li>域名（<strong>必须</strong>，你也可以使用免费域名）</li><li>已经开通R2储存功能（<strong>必须</strong>）</li><li>博客（<strong>必须</strong>，或接入Twikoo评论系统的其他站点）</li><li>一台安装了1Panel的服务器（<strong>必须</strong>，没有可以试着去<a href="https://support.nodeget.com/page/promotion?id=116">NodeSupport计划申请</a>）</li></ul><h2 id="部署教程"><a href="#部署教程" class="headerlink" title="部署教程"></a>部署教程</h2><h2 id="创建容器"><a href="#创建容器" class="headerlink" title="创建容器"></a>创建容器</h2><ol><li><p><strong>容器</strong> → <strong>创建容器</strong><br><img src="https://img.zrf.me/20250508232604195.webp" alt="创建容器"></p></li><li><p><strong>容器参数</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">容器名称=piclist  “名称随你设置”</span><br><span class="line">镜像勾选手动输入=kuingsmile/piclist:latest</span><br><span class="line">端口暴露端口： </span><br><span class="line">服务器=36677 容器=36677 协议=tcp</span><br><span class="line">挂载：“本机目录随你设置，我放在opt/zrf，这个文件夹下”</span><br><span class="line">本机目录=/opt/zrf/piclist  权限=读写 容器目录=/root/.piclist</span><br><span class="line">Command=node /usr/local/bin/picgo-server -k piclist123456  “其中 piclist123456 这个是上传的密码随你设置”</span><br><span class="line">Entrypoint=docker-entrypoint.sh</span><br></pre></td></tr></table></figure></li><li><p>如图所示，我没写的都默认即可。全部参数填写完毕点击右下角的 <strong>确认</strong><br><img src="https://img.zrf.me/20250508230457285.webp" alt="创建容器2"><br><img src="https://img.zrf.me/20250508231245880.webp" alt="创建容器3"></p></li><li><p>好等待容器 <strong>状态</strong> 变为 <strong>已启动</strong><br><img src="https://img.zrf.me/20250508235221378.webp" alt="容器状态已启动"></p></li><li><p>浏览器打开：<strong>http:&#x2F;&#x2F;你的服务器ip:36677</strong>  可以看到这样的内容就说明你的服务正确的启动了。<br><img src="https://img.zrf.me/20250509020404344.webp" alt="浏览服务"></p></li><li><p>接下来,打开 <strong>系统</strong>  → <strong>文件</strong> 打开你前面创建的<strong>本机目录</strong>的路径，你我的可能不一样，进入你设置的目录，打开 <strong>config.json</strong> 配置文件替换下方的json内容。<br><img src="https://img.zrf.me/20250508235622415.webp" alt="config.json"></p></li><li><p><strong>config.json 文件内容</strong></p></li></ol><ul><li>这些配置内容，是你开通了R2图床才有这些数据，我们先复制进去找到一个参数填写一个参数进去。</li></ul><p><img src="https://img.zrf.me/20250509004028080.webp" alt="config.json 文件内容"></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;picBed&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;current&quot;</span><span class="punctuation">:</span> <span class="string">&quot;aws-s3-plist&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;uploader&quot;</span><span class="punctuation">:</span> <span class="string">&quot;aws-s3-plist&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;aws-s3-plist&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;_configName&quot;</span><span class="punctuation">:</span> <span class="string">&quot;随意填写&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;accessKeyID&quot;</span><span class="punctuation">:</span> <span class="string">&quot;访问密钥 ID&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;secretAccessKey&quot;</span><span class="punctuation">:</span> <span class="string">&quot;机密访问密钥&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;bucketName&quot;</span><span class="punctuation">:</span> <span class="string">&quot;你的储存桶名&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;uploadPath&quot;</span><span class="punctuation">:</span> <span class="string">&quot;blog/&#123;timestamp&#125;.&#123;extName&#125;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;endpoint&quot;</span><span class="punctuation">:</span> <span class="string">&quot;为 S3 客户端使用管辖权地特定的终结点&quot;</span><span class="punctuation">,</span>  </span><br><span class="line">      <span class="attr">&quot;urlPrefix&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://webp.001315.xyz&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;pathStyleAccess&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;rejectUnauthorized&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;acl&quot;</span><span class="punctuation">:</span> <span class="string">&quot;public-read&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;disableBucketPrefixToURL&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;settings&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;autoRename&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;rename&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;useWebp&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;buildIn&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;compress&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;quality&quot;</span><span class="punctuation">:</span> <span class="number">50</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isConvert&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;convertFormat&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isReSize&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;reSizeWidth&quot;</span><span class="punctuation">:</span> <span class="number">500</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;reSizeHeight&quot;</span><span class="punctuation">:</span> <span class="number">500</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;skipReSizeOfSmallImg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isReSizeByPercent&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;reSizePercent&quot;</span><span class="punctuation">:</span> <span class="number">50</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isRotate&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;rotateDegree&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isRemoveExif&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isFlip&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isFlop&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;formatConvertObj&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;png&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;jpg&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;jpeg&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;bmp&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;tiff&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;heic&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;webp&quot;</span><span class="punctuation">:</span> <span class="string">&quot;webp&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;watermark&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;isAddWatermark&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkType&quot;</span><span class="punctuation">:</span> <span class="string">&quot;text&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;isFullScreenWatermark&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkDegree&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkText&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkFontPath&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkScaleRatio&quot;</span><span class="punctuation">:</span> <span class="number">0.15</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkColor&quot;</span><span class="punctuation">:</span> <span class="string">&quot;#CCCCCC73&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkImagePath&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;watermarkPosition&quot;</span><span class="punctuation">:</span> <span class="string">&quot;southeast&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;picgoPlugins&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span><span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h2 id="创建储存桶"><a href="#创建储存桶" class="headerlink" title="创建储存桶"></a>创建储存桶</h2><ol><li><p>获取<strong>R2储存桶</strong>设置参数。如果你还没有创建储存桶就创建一个。<br><img src="https://img.zrf.me/20250509001117437.webp" alt="创建储存桶"></p></li><li><p>选择美国西部的话，可以使用 <a href="https://webp.se/">WebP 云服务缓存</a> 来加快的你图片访问速度。我之前创建过名为<strong>img</strong>的储存桶就不创建了。名字你随意取。<br><img src="https://img.zrf.me/20250509002240996.webp" alt="创建储存桶2"></p></li></ol><h2 id="获取储存桶Token并填入config-json配置"><a href="#获取储存桶Token并填入config-json配置" class="headerlink" title="获取储存桶Token并填入config.json配置"></a>获取储存桶Token并填入config.json配置</h2><h3 id="参数："><a href="#参数：" class="headerlink" title="参数："></a>参数：</h3><ol><li><strong>configName</strong>&#x3D;随意填写</li><li><strong>bucketName</strong>&#x3D;你的储存桶名,</li><li><strong>uploadPath</strong>&#x3D;blog&#x2F;{timestamp}.{extName},其中的blog是在这个桶中创建一个 blog文件图片存在在这个目录，你也可以设置为： {fileName}.{extName} 就是放在根目录。</li></ol><ul><li>每个对应填写到你的<strong>config.json</strong>配置中，例子：<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;bucketName&quot;</span><span class="punctuation">:</span> <span class="string">&quot;img&quot;</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">&quot;uploadPath&quot;</span><span class="punctuation">:</span> <span class="string">&quot;blog/&#123;timestamp&#125;.&#123;extName&#125;&quot;</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">&quot;endpoint&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://xxxxxxxxxxxxx.r2.cloudflarestorage.com&quot;</span><span class="punctuation">,</span>  </span><br></pre></td></tr></table></figure></li></ul><h3 id="获取储存桶Token"><a href="#获取储存桶Token" class="headerlink" title="获取储存桶Token"></a>获取储存桶Token</h3><ol><li><p>回到创建储存桶的页面选择<strong>API</strong> → <strong>管理API令牌</strong> 创建 <strong>用户 API 令牌</strong><br><img src="https://img.zrf.me/20250509012419389.webp" alt="用户 API 令牌1"><br><img src="https://img.zrf.me/20250509012625012.webp" alt="用户 API 令牌2"></p></li><li><p>创建完成这个页面的Token值都找个地方保存一下，这些令牌值不会再次显示，如果你下次使用忘记就得重新创建。<br><img src="https://img.zrf.me/20250509013258752.webp" alt="用户 API 令牌 Token"></p></li><li><p><strong>urlPrefix</strong>&#x3D;可以是你的储存桶的<strong>自定义域名</strong>也可以是 <strong>WebP 云服务缓存</strong> 服务的分配的域名或者你其中设置的自定义域名。</p></li></ol><ul><li>因为博客的评论功能的图片并不是使用率非常高的，基本 <strong>WebP 云服务缓存</strong> 所提供的免费计划基本已经够用了。</li></ul><p><img src="https://img.zrf.me/20250509015256723.webp" alt="R2储存桶 自定义域名"></p><h2 id="设置-WebP-云服务缓存服务"><a href="#设置-WebP-云服务缓存服务" class="headerlink" title="设置 WebP 云服务缓存服务"></a>设置 WebP 云服务缓存服务</h2><ol><li><p>打开 <a href="https://dashboard.webp.se/">https://dashboard.webp.se/</a>  注册并登录账号就不演示了，<strong>创建代理</strong> → <strong>代理名称</strong>&#x3D;随意设置，<strong>源站地址</strong>&#x3D;你R2储存桶的自定义域名<br><img src="https://img.zrf.me/20250509020942857.webp" alt="WebP 云服务缓存服务1"></p></li><li><p>可以在这里设置自定义域名，根据平台的提示进行设置解析和TXT验证，等一会，激活就行，或者也可以使用平台分配的域名 <a href="https://b7038d2.webp.li/">https://b7038d2.webp.li</a> 这样的，反正最终，你需要填写的 <strong>urlPrefix</strong>&#x3D;代理地址（如果你不使用这个缓存服务就是你的储存桶的<strong>自定义域名</strong>）<br><img src="https://img.zrf.me/20250509021415692.webp" alt="WebP 云服务缓存服务2"></p></li><li><p>到此所有的<strong>config.json</strong>配置参数都获得并填写。右下角<strong>确定</strong>保存配置！<br><img src="https://img.zrf.me/20250509022710523.webp" alt="WebP 云服务缓存服务3"></p></li></ol><h2 id="配置域名并安装证书"><a href="#配置域名并安装证书" class="headerlink" title="配置域名并安装证书"></a>配置域名并安装证书</h2><h3 id="配置域名"><a href="#配置域名" class="headerlink" title="配置域名"></a>配置域名</h3><ol><li><p>给这个服务配置域名，我设置为：<strong>picgo-server.zrf.me</strong> 解析到你的服务器ip保存。<br><img src="https://img.zrf.me/20250509030524115.webp" alt="配置域名"></p></li><li><p>先确定你的容器内网ip及端口，我的是<strong>172.17.0.2:36677</strong><br><img src="https://img.zrf.me/20250509025344235.webp" alt="容器内网ip及端口"></p></li><li><p>来到  <strong>1panel</strong> → <strong>网站</strong> → <strong>网站</strong> → <strong>创建</strong> → <strong>反向代理</strong> → <strong>主域名</strong>&#x3D;你自己刚设置的域名。<strong>代理地址</strong>&#x3D;172.17.0.2:36677（以你的为准）<br><img src="https://img.zrf.me/20250509030644638.webp" alt="反向代理"></p></li></ol><h3 id="安装证书"><a href="#安装证书" class="headerlink" title="安装证书"></a>安装证书</h3><ol><li><p>接下来回到 <strong>1panel</strong> → <strong>网站</strong> → <strong>证书</strong> → <strong>DNS账户</strong> → <strong>创建</strong> ，<strong>名称</strong>随你设置，因为我的域名托管到 <strong>cloudflare</strong>中的。选择类型为<strong>cloudflare</strong> ，<strong>EMAIL</strong>就是你<strong>cloudflare</strong>账号的邮箱。<br><img src="https://img.zrf.me/20250509023341644.webp" alt="安装证书1"><br><img src="https://img.zrf.me/20250509023630736.webp" alt="安装证书2"></p></li><li><p><strong>API Token</strong> 获取，我们打开 <a href="https://dash.cloudflare.com/">https://dash.cloudflare.com/</a> <strong>首页</strong> 右上角 <strong>配置文件</strong><br><img src="https://img.zrf.me/20250509024019637.webp" alt="API Token"></p></li><li><p><strong>API令牌</strong> → <strong>创建令牌</strong> 选择 <strong>编辑区域 DNS</strong> 点击 <strong>使用模板</strong>，<strong>区域资源</strong> 选择 <strong>所有区域</strong> → <strong>创建令牌</strong> 得到的 <strong>用户 API 令牌</strong> 填入 <strong>DNS账户</strong> 的 <strong>API Token</strong>。<br><img src="https://img.zrf.me/20250509024219066.webp" alt="API Token2"><br><img src="https://img.zrf.me/20250509024949519.webp" alt="API Token3"><br><img src="https://img.zrf.me/20250509024838677.webp" alt="API Token4"></p></li><li><p><strong>从网站中获取</strong> 选你的这个域名，然后确定就可以申请了。日志显示：申请 [picgo-server.zrf.me] 证书成功！！ 这就申请成功了。<br><img src="https://img.zrf.me/20250509031202729.webp" alt="证书成功"><br><img src="https://img.zrf.me/20250509031618520.webp" alt="证书成功"></p></li><li><p>来到  <strong>1panel</strong> → <strong>网站</strong> → <strong>网站</strong> → <strong>配置</strong> → 如图设置然后保存。<br><img src="https://img.zrf.me/20250509031737845.webp" alt="配置证书"><br><img src="https://img.zrf.me/20250509031858131.webp" alt="配置证书"></p></li><li><p>重启容器（很重要）<br><img src="https://img.zrf.me/20250509032716939.webp" alt="重启容器"></p></li><li><p>然后浏览器可以打开你的域名：<a href="https://picgo-server.zrf.me/">https://picgo-server.zrf.me/</a> 显示我这样的就对的，到此所有的<strong>picgo-server</strong>服务安装完成</p></li></ol><h2 id="配置博客Twikoo评论"><a href="#配置博客Twikoo评论" class="headerlink" title="配置博客Twikoo评论"></a>配置博客Twikoo评论</h2><ol><li><p><strong>IMAGE_CDN_URL</strong>&#x3D;你自己刚设置的域名，<strong>IMAGE_CDN_TOKEN</strong>&#x3D;之前步骤的这个其中 piclist123456 这个是上传的密码随你设置，然后保存，去测试上传是否正常。<br><img src="https://img.zrf.me/20250509032820435.webp" alt="配置博客Twikoo评论"></p></li><li><p><a href="https://blog.zrf.me/message/">https://blog.zrf.me/message/</a> 效果浏览。我发现大图上传不了还是咋回事。有几张失败。<br>上传后的直链地址：<a href="https://webp.001315.xyz/blog/1746733312.webp">https://webp.001315.xyz/blog/1746733312.webp</a><br><img src="https://webp.001315.xyz/blog/1746733312.webp" alt="测试上传图片"></p></li><li><p>完结撒花。</p></li></ol><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p>NodeSupport计划申请：<a href="https://support.nodeget.com/page/promotion?id=116">https://support.nodeget.com/page/promotion?id=116</a></p></blockquote><blockquote><p>GitHub PicList：<a href="https://github.com/Kuingsmile/PicList">https://github.com/Kuingsmile/PicList</a></p></blockquote><blockquote><p>WebP 云服务缓存服务：<a href="https://dashboard.webp.se/">https://dashboard.webp.se/</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Twikoo评论-PicList-R2图床：博客评论图片上传与CDN加速最佳实践&quot;&gt;&lt;a href=&quot;#Twikoo评论-PicList-R2图床：博客评论图片上传与CDN加速最佳实践&quot; class=&quot;headerlink&quot; title=&quot;Twikoo评论+Pic</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="SSL证书" scheme="https://blog.zrf.me/tags/SSL%E8%AF%81%E4%B9%A6/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="壁纸" scheme="https://blog.zrf.me/tags/%E5%A3%81%E7%BA%B8/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="图像软件" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="hexo" scheme="https://blog.zrf.me/tags/hexo/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="图床" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%BA%8A/"/>
    
    <category term="图像处理" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86/"/>
    
    <category term="PicList" scheme="https://blog.zrf.me/tags/PicList/"/>
    
    <category term="Twikoo" scheme="https://blog.zrf.me/tags/Twikoo/"/>
    
    <category term="插件推荐" scheme="https://blog.zrf.me/tags/%E6%8F%92%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    <category term="WebP" scheme="https://blog.zrf.me/tags/WebP/"/>
    
    <category term="VS-PicList" scheme="https://blog.zrf.me/tags/VS-PicList/"/>
    
    <category term="图片管理" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E7%89%87%E7%AE%A1%E7%90%86/"/>
    
    <category term="高效书写" scheme="https://blog.zrf.me/tags/%E9%AB%98%E6%95%88%E4%B9%A6%E5%86%99/"/>
    
  </entry>
  
  <entry>
    <title>LibreTV 免费在线视频搜索与观看平台 快速部署教程（支持 Cloudflare Pages）</title>
    <link href="https://blog.zrf.me/p/LibreTV/"/>
    <id>https://blog.zrf.me/p/LibreTV/</id>
    <published>2025-04-14T03:18:00.000Z</published>
    <updated>2026-03-04T13:00:57.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="LibreTV-📺"><a href="#LibreTV-📺" class="headerlink" title="LibreTV 📺"></a>LibreTV 📺</h1><p>之前使用serv00部署的影视站G了，看到群里大佬部署了这个项目找了一下，看到这个项目也可以完美代替之前的，主要是部署都是一键很简单。<br>LibreTV 是一个开源的免费视频搜索和聚合平台，支持在线观看和自动跳转至资源站点。它无需数据库、后端即可部署，支持多平台和多语言，尤其适合想要快速搭建免费影视平台的朋友。</p><h2 id="在线体验："><a href="#在线体验：" class="headerlink" title="在线体验："></a>在线体验：</h2><p>（体验账号的账号密码都是：zrfme）建议自己注册账号独享自己的观影记录。</p><p>首选站点：<a href="https://ys.zrfme.com/">https://ys.zrfme.com</a></p><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><p><img src="https://img.zrf.me/20250414214326454.webp" alt="LibreTV 首页截图"><br><img src="https://img.zrf.me/20250414214449193.webp" alt="LibreTV 搜索截图"></p><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li>🎬 <strong>聚合搜索</strong>：整合多个资源站点，快速搜索影视资源。</li><li>🌐 <strong>多语言支持</strong>：内置多国语言，默认支持中文。</li><li>📦 <strong>静态部署</strong>：无后端需求，可部署在 GitHub Pages &#x2F; Cloudflare Pages。</li><li>📱 <strong>响应式设计</strong>：适配 PC 与移动端，体验流畅。</li><li>🧩 <strong>插件机制</strong>：支持添加自定义资源站点插件。</li><li>🔧 <strong>快速配置</strong>：配置简单，支持自定义默认语言、默认站点等。</li></ul><hr><h2 id="Fork-项目"><a href="#Fork-项目" class="headerlink" title="Fork 项目"></a>Fork 项目</h2><ol><li>打开 LibreTV 项目：<a href="https://github.com/bestZwei/LibreTV">https://github.com/bestZwei/LibreTV</a>，点击右上角 <code>Fork</code> 并为项目点个 ⭐。<br><img src="https://img.zrf.me/20250414212759040.webp" alt="GitHub 项目 Fork 示例"><br><img src="https://img.zrf.me/20250414213024464.webp" alt="GitHub 项目 Fork 完成示例"></li></ol><hr><h2 id="使用-Cloudflare-Pages-部署"><a href="#使用-Cloudflare-Pages-部署" class="headerlink" title="使用 Cloudflare Pages 部署"></a>使用 Cloudflare Pages 部署</h2><ol><li><p>打开 <a href="https://dash.cloudflare.com/">Cloudflare Pages 控制台</a> → 选择 <strong>Pages</strong> → <strong>连接到GIT</strong><br><img src="https://img.zrf.me/20250226043953641.webp" alt="Cloudflare Pages 控制台界面"></p></li><li><p>选择你刚 Fork 的仓库 <code>LibreTV</code> → 点击 <strong>开始设置</strong><br><img src="https://img.zrf.me/20250414213431546.webp" alt="选择 Fork 的 LibreTV 仓库"></p></li><li><p>填写部署信息</p></li></ol><ul><li><strong>项目名称</strong>：可自定义（如：libretv）</li><li><strong>构建命令</strong>：留空（无需构建）</li><li><strong>输出目录</strong>：留空（默认为根目录）</li></ul><p>如图所示：<br><img src="https://img.zrf.me/20250414213802430.webp" alt="Cloudflare Pages 构建设置"></p><hr><h2 id="使用-vercel-部署"><a href="#使用-vercel-部署" class="headerlink" title="使用 vercel 部署"></a>使用 vercel 部署</h2><ol><li><p>打开 <a href="https://vercel.com/new">New Project</a> → 选择你刚 Fork 的仓库 <code>LibreTV</code> → 点击 <strong>Import</strong> → 点击 <strong>Deploy</strong> 然后等待部署完成即可。<br><img src="https://img.zrf.me/20250414220436061.webp" alt="Vercel 新建项目界面"><br><img src="https://img.zrf.me/20250414220817506.webp" alt="Vercel 部署完成界面"></p></li><li><p>给项目设置自定义域名，套上 CDN 加速。详细教程参考：<a href="https://blog.zrf.me/p/55/">https://blog.zrf.me/p/55/</a> 其实就是设置个自定义域名，然后 <strong>CNAME</strong> 内容设置为 <code>vercel.001315.xyz</code> 。就套上加速了。</p></li><li><p>设置访问密码 Vercel: Dashboard &gt; 您的项目 &gt; Settings &gt; Environment Variables ，<strong>KEY</strong> 为<code>PASSWORD</code>  <strong>VALUE</strong> 为你想设置的访问密码：<code>aizrf</code> 。<br><img src="https://img.zrf.me/20250422203501291.webp" alt="Vercel-PASSWORD.webp"></p></li></ol><hr><h2 id="自定义配置"><a href="#自定义配置" class="headerlink" title="自定义配置"></a>自定义配置</h2><p><strong>豆瓣热门推荐</strong><br>豆瓣热门推荐 右上角的 &gt; 设置 &gt; 内容推荐 中进行打开！<br><img src="https://img.zrf.me/20250422204423287.webp" alt="豆瓣热门推荐.webp"></p><p><strong>密码保护</strong></p><p>要为您的 LibreTV 实例添加密码保护，只需在部署平台设置环境变量：</p><ul><li><strong>环境变量名</strong>：<code>PASSWORD</code></li><li><strong>值</strong>：你想设置的密码</li></ul><p><strong>各平台设置方法：</strong></p><ul><li><p><strong>Cloudflare Pages</strong>：<br><code>Dashboard</code> → 你的项目 → <code>设置</code> → <code>环境变量</code></p></li><li><p><strong>Vercel</strong>：<br><code>Dashboard</code> → 你的项目 → <code>Settings</code> → <code>Environment Variables</code></p></li><li><p><strong>Netlify</strong>：<br><code>Dashboard</code> → 你的项目 → <code>Site settings</code> → <code>Build &amp; deploy</code> → <code>Environment</code></p></li><li><p><strong>Docker</strong>：<br>启动参数添加 <code>-e PASSWORD=你的密码</code></p></li></ul><hr><p>项目主要配置在 <code>js/config.js</code> 文件中，你可以修改以下内容：</p><ul><li><strong>PROXY_URL</strong>：修改为你自己的代理服务地址。</li><li><strong>API_SITES</strong>：添加或修改视频源 API 接口。</li><li><strong>SITE_CONFIG</strong>：更改站点名称、描述等基本信息。</li><li><strong>PLAYER_CONFIG</strong>：调整播放器参数，如自动播放、广告过滤等。</li><li><strong>HIDE_BUILTIN_ADULT_APIS</strong>：用于控制是否隐藏内置的采集站 API，默认值为 <code>true</code>。设置为 <code>true</code> 时，内置的某些敏感 API 将不会在设置面板中显示，可根据实际需要修改配置。</li></ul><blockquote><p><strong>注意</strong>：若使用 Docker 部署，可进入容器，在 <code>/usr/share/nginx/html/js</code> 内修改相关配置。</p></blockquote><h2 id="特别致谢"><a href="#特别致谢" class="headerlink" title="特别致谢"></a>特别致谢</h2><p>特别感谢 <a href="https://d.zrf.me/yxvm">YxVM</a> 提供服务器赞助，让项目能够稳定运行，为大家带来更好的体验！</p><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p>首选站点：<a href="https://ys.zrfme.com/">https://ys.zrfme.com</a></p></blockquote><blockquote><p>Vercel托管站点提速小技巧：<a href="https://blog.zrf.me/p/55/">https://blog.zrf.me/p/55</a></p></blockquote><blockquote><p>GitHub LibreTV：<a href="https://github.com/bestZwei/LibreTV">https://github.com/bestZwei/LibreTV</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;LibreTV-📺&quot;&gt;&lt;a href=&quot;#LibreTV-📺&quot; class=&quot;headerlink&quot; title=&quot;LibreTV 📺&quot;&gt;&lt;/a&gt;LibreTV 📺&lt;/h1&gt;&lt;p&gt;之前使用serv00部署的影视站G了，看到群里大佬部署了这个项目找了一下，看</summary>
      
    
    
    
    <category term="我的项目" scheme="https://blog.zrf.me/categories/%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="影音视听" scheme="https://blog.zrf.me/tags/%E5%BD%B1%E9%9F%B3%E8%A7%86%E5%90%AC/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="Vercel" scheme="https://blog.zrf.me/tags/Vercel/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="视频聚合" scheme="https://blog.zrf.me/tags/%E8%A7%86%E9%A2%91%E8%81%9A%E5%90%88/"/>
    
    <category term="腾讯视频" scheme="https://blog.zrf.me/tags/%E8%85%BE%E8%AE%AF%E8%A7%86%E9%A2%91/"/>
    
  </entry>
  
  <entry>
    <title>Cloudflare R2 + Workers：在线网盘 使用 Cloudflare Pages 快速部署教程</title>
    <link href="https://blog.zrf.me/p/Cloudflare-R2-oss/"/>
    <id>https://blog.zrf.me/p/Cloudflare-R2-oss/</id>
    <published>2025-03-20T18:04:49.000Z</published>
    <updated>2025-03-20T18:04:49.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="利用-Cloudflare-R2-Workers-搭建在线网盘"><a href="#利用-Cloudflare-R2-Workers-搭建在线网盘" class="headerlink" title="利用 Cloudflare R2 + Workers 搭建在线网盘"></a><strong>利用 Cloudflare R2 + Workers 搭建在线网盘</strong></h1><p>   此前，我们发布了一篇博文，介绍如何利用 Cloudflare R2 与 PicList <a href="https://blog.zrf.me/p/PicList/">一款高效的云存储和图片托管平台</a> 来管理图片和文件。本项目 <strong>Cloudflare-R2-OSS</strong> 的思路与之类似，但提供了图形化界面，实现了类似网盘的功能，可用于存储软件、图片音频视频等文件。该方案无需借助其他额外工具，不过在上传大文件的体验上略逊于 PicList，例如超过300M的就无法上传。我们可以用到 PicList。</p><p>   PS:发布这篇文章后 <a href="https://www.liushen.fun/">清羽飞扬大佬</a> 留言刚好有二开基于 <strong>Cloudflare-R2-OSS</strong> 一个UI界面更好看且优雅的！果断部署更新！下方部署教程两个项目都通用。</p><h2 id="演示网站-账号密码：aizrf"><a href="#演示网站-账号密码：aizrf" class="headerlink" title="演示网站 账号密码：aizrf"></a><strong>演示网站 账号密码：aizrf</strong></h2><ul><li>演示网站为清羽飞扬大佬的 <strong>FlareDrive-R2</strong></li></ul><p><a href="https://pan.001315.xyz/">https://pan.001315.xyz/</a></p><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a><strong>界面预览</strong></h2><ul><li>图1为 <strong>Cloudflare-R2-OSS</strong> ，图2为 清羽飞扬大佬 的 <strong>FlareDrive-R2</strong> 。</li></ul><p><img src="https://img.zrf.me/20250321164824701.webp" alt="20250321164824701.webp"><br><img src="https://img.zrf.me/20250321170925421.webp" alt="20250321170925421.webp"></p><h2 id="下载测试"><a href="#下载测试" class="headerlink" title="下载测试"></a><strong>下载测试</strong></h2><ul><li>既然是网盘我们当然要测试下载速度，最快跑到 <strong>60 MB&#x2F;s</strong> 左右，均值在 <strong>20-30 MB&#x2F;s</strong> 左右，很快了，当然下载速度是根据你的网络带宽而定。</li></ul><p><img src="https://img.zrf.me/20250321223258742.webp" alt="20250321223258742.webp"></p><hr><h2 id="搭建教程"><a href="#搭建教程" class="headerlink" title="搭建教程"></a><strong>搭建教程</strong></h2><h3 id="Fork-仓库"><a href="#Fork-仓库" class="headerlink" title="Fork 仓库"></a><strong>Fork 仓库</strong></h3><p>   在 Github Fork 项目，自己选择部署哪一个。</p><ul><li>清羽飞扬大佬的 <strong>FlareDrive-R2</strong> ：<a href="https://github.com/willow-god/FlareDrive-R2">https://github.com/willow-god/FlareDrive-R2</a></li><li><strong>Cloudflare-R2-OSS</strong> ：<a href="https://github.com/ljxi/Cloudflare-R2-oss">https://github.com/ljxi/Cloudflare-R2-oss</a></li></ul><p><img src="https://img.zrf.me/20250321032450935.webp" alt="20250321032450935.webp"></p><h3 id="创建-R2-储存桶"><a href="#创建-R2-储存桶" class="headerlink" title="创建 R2 储存桶"></a><strong>创建 R2 储存桶</strong></h3><p>   前往 Cloudflare R2 新建一个 R2 储存桶。<br>   <img src="https://img.zrf.me/20250321032701989.webp" alt="20250321032701989.webp"><br>   设置你的存储桶名，名称随意设置，然后点击创建。<br>   <img src="https://img.zrf.me/20250321032835888.webp" alt="20250321032835888.webp"><br>   <strong>（第一种方法，不推荐使用，可直接忽略此步骤）</strong> 在储存桶设置中 <code>R2.dev 子域</code> 允许公开访问，复制公共储存桶 URL。 <strong>如开启 R2 存储桶的公开读写权限！你的存储资源有可能会被恶意刷取，造成资源付费。</strong><br>   <img src="https://img.zrf.me/20250321033713313.webp" alt="20250321033713313.webp"><br>   <code>公共 R2.dev 存储桶 URL</code> 保存下来，如下的格式。<br>   <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://pub-888888888888888.r2.dev</span><br></pre></td></tr></table></figure><br>   <strong>（第二种方法，推荐使用）</strong> 使用R2的 <code>自定义域名</code> 您的存储桶的内容将可以通过该域公开访问。连接的网站还可以受益于 Cloudflare 功能，如机器人管理、访问和缓存。<br>   <img src="https://img.zrf.me/20250413034329113.webp" alt="20250413034329113.webp"></p><p>   保存下来，稍后设置 <strong>PUBURL</strong> 变量使用此域名。</p><h3 id="新建-Cloudflare-Pages-站点"><a href="#新建-Cloudflare-Pages-站点" class="headerlink" title="新建 Cloudflare Pages 站点"></a><strong>新建 Cloudflare Pages 站点</strong></h3><p>   前往 Cloudflare Pages，新建站点，选择连接到 Git，并选择刚刚 Fork 的仓库。点击开始设置。<br>   <img src="https://img.zrf.me/20250321034308383.webp" alt="20250321034308383.webp"><br>   <img src="https://img.zrf.me/20250321034333026.webp" alt="20250321034333026.webp"><br>   <img src="https://img.zrf.me/20250321034432431.webp" alt="20250321034432431.webp"></p><h3 id="添加环境变量"><a href="#添加环境变量" class="headerlink" title="添加环境变量"></a><strong>添加环境变量</strong></h3><p>   项目名称可自行修改，其它项目保持默认设置。点击环境变量并添加如下变量，自用只需要设置个管理员账号就行，演示账号无需设置。 </p><ul><li>管理员的值代表允许写入的目录，多个目录请用英文逗号分隔。  </li><li>环境变量中请勿在目录前后添加逗号，否则会获得所有目录的写入权限。</li></ul><p><img src="https://img.zrf.me/20250321035355185.webp" alt="20250321035355185.webp"></p><table><thead><tr><th>变量名称</th><th>值</th><th>说明</th></tr></thead><tbody><tr><td>PUBURL</td><td>使用你刚设置的储存桶自定义域名</td><td>用于存储桶访问</td></tr><tr><td>GUEST</td><td>public&#x2F;</td><td>游客允许写入的目录</td></tr><tr><td>aizrf:aizrf</td><td>*</td><td>管理员权限（账号:密码形式，允许写入目录，多目录用英文逗号分隔）</td></tr><tr><td>zrf:zrf</td><td>zrf&#x2F;,zrfPublic&#x2F;</td><td>演示账号设置</td></tr></tbody></table><h3 id="绑定-R2-储存桶"><a href="#绑定-R2-储存桶" class="headerlink" title="绑定 R2 储存桶"></a><strong>绑定 R2 储存桶</strong></h3><p>   前往 Pages &gt; cloudflare-r2-oss &gt; 设置 &gt; 函数 &gt; R2 储存桶绑定，绑定对应的 R2 储存桶，变量名称为 <code>BUCKET</code>。<br>   <img src="https://img.zrf.me/20250321035953916.webp" alt="20250321035953916.webp"><br>   <img src="https://img.zrf.me/20250321040043230.webp" alt="20250321040043230.webp"></p><h3 id="重新部署"><a href="#重新部署" class="headerlink" title="重新部署"></a><strong>重新部署</strong></h3><p>   在部署页面点击重新部署按钮，完成设置后即可正式使用。<br>   <img src="https://img.zrf.me/20250321040225799.webp" alt="20250321040225799.webp"></p><h3 id="设置自定义域名"><a href="#设置自定义域名" class="headerlink" title="设置自定义域名"></a><strong>设置自定义域名</strong></h3><p>   因为我这是小号部署的项目，域名没有在这个账号托管，你有域名并且在 <strong>cloudflare</strong> 托管了可以一键设置。<br>   <img src="https://img.zrf.me/20250321041121946.webp" alt="20250321041121946.webp"><br>   <img src="https://img.zrf.me/20250321041257642.webp" alt="20250321041257642.webp"></p><h3 id="超过-300-MB-大文件上传"><a href="#超过-300-MB-大文件上传" class="headerlink" title="超过 300 MB 大文件上传"></a><strong>超过 300 MB 大文件上传</strong></h3><ul><li>超过 300 MB 的文件仅支持通过 <strong>S3 兼容性 API</strong> 或 <strong>Workers</strong> 进行上传。</li></ul><p>因此，建议采用 <strong>PicList</strong> 方案进行设置，详情请参考本篇博文 <a href="https://blog.zrf.me/p/PicList/">PicList - 一款高效的云存储和图片托管平台管理工具</a>。</p><p>如果你采用了分目录上传，例如演示网站中使用的 <strong>img</strong>、<strong>app</strong>、<strong>video</strong> 目录不在根目录下，<br>请在 <strong>PicList</strong> 的设置中修改 <strong>上传路径</strong> 参数，例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">video/&#123;fileName&#125;.&#123;extName&#125;</span><br></pre></td></tr></table></figure><p>对于<strong>自定义域名</strong>，请将你的域名后面加上 <code>/raw</code>，例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://pan.001315.xyz/raw</span><br></pre></td></tr></table></figure><p><img src="https://img.zrf.me/20250321200647126.webp" alt="20250321200647126.webp"></p><p><strong>并且关闭格式转换</strong><br>前往至 <strong>上传</strong> 👉 <strong>图片处理</strong> 👉 <strong>格式转换</strong> ，关闭转换webp格式。<br><img src="https://img.zrf.me/20250321204147131.webp" alt="20250321204147131.webp"></p><h2 id="博主留言"><a href="#博主留言" class="headerlink" title="博主留言"></a><strong>博主留言</strong></h2><ol><li><p>在使用 <strong>PicList</strong> 中 <strong>转换格式</strong> 功能启用状态，因为我一般默认设置为转换 <strong>webp格式</strong> ，但如上传zip、MP4 等格式，这些文件会自动转换为预设的webp格式。所以我每次想要上传视频等，非图片的文件时，我得手动去关闭格式转换，有点麻烦。所以我使用这个项目除非大文件，视频等一般不用  <strong>PicList</strong>  上传。<a href="https://github.com/Kuingsmile/PicList/issues/312">提了个issues已经通过，项目作者已经同意后续进行优化，很期待！！！</a></p></li><li><p>如通过 <strong>PicList</strong> 上传到 R2 在线网盘中是看不到略缩图的。下图两个是一个视频文件只是上传方式不一样。<br><img src="https://img.zrf.me/20250321213146861.webp" alt="20250321213146861.webp"></p></li></ol><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a><strong>相关链接</strong></h2><blockquote><ul><li>演示网站 账号密码：<code>aizrf</code> ：<a href="https://pan.001315.xyz/">https://pan.001315.xyz/</a></li><li>清羽飞扬大佬的 <strong>FlareDrive-R2</strong> ：<a href="https://github.com/willow-god/FlareDrive-R2">https://github.com/willow-god/FlareDrive-R2</a></li><li><strong>Cloudflare-R2-OSS</strong> ：<a href="https://github.com/ljxi/Cloudflare-R2-oss">https://github.com/ljxi/Cloudflare-R2-oss</a> </li><li>PicList - 一款高效的云存储和图片托管平台管理工具：<a href="https://blog.zrf.me/p/PicList/">https://blog.zrf.me/p/PicList/</a></li></ul></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;利用-Cloudflare-R2-Workers-搭建在线网盘&quot;&gt;&lt;a href=&quot;#利用-Cloudflare-R2-Workers-搭建在线网盘&quot; class=&quot;headerlink&quot; title=&quot;利用 Cloudflare R2 + Workers 搭建在</summary>
      
    
    
    
    <category term="我的项目" scheme="https://blog.zrf.me/categories/%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="图像软件" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="hexo" scheme="https://blog.zrf.me/tags/hexo/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="图床" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%BA%8A/"/>
    
    <category term="图像处理" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86/"/>
    
    <category term="在线网盘" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E7%BD%91%E7%9B%98/"/>
    
    <category term="PicList" scheme="https://blog.zrf.me/tags/PicList/"/>
    
  </entry>
  
  <entry>
    <title>LocalSend - 免费、开源、跨平台的局域网文件传输工具</title>
    <link href="https://blog.zrf.me/p/LocalSend/"/>
    <id>https://blog.zrf.me/p/LocalSend/</id>
    <published>2025-03-16T08:09:00.000Z</published>
    <updated>2025-07-08T16:56:05.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="LocalSend-开源无线局域网文件传输工具-🖥️"><a href="#LocalSend-开源无线局域网文件传输工具-🖥️" class="headerlink" title="LocalSend - 开源无线局域网文件传输工具 🖥️"></a>LocalSend - 开源无线局域网文件传输工具 🖥️</h1><p>LocalSend 是一款高性能且完全免费的开源无线局域网文件传输工具。它支持 Windows、macOS、Android、iOS 以及 Linux 平台，帮助你在多设备间实现不限速、不受文件大小限制的高效传输，同时保障安全保密。</p><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><p><img src="https://img.zrf.me/20250316163315351.webp" alt="界面预览"></p><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li><p><strong>去中心化</strong><br>无需中央服务器，即可实现点对点文件分享。</p></li><li><p><strong>跨平台支持</strong><br>同时兼容 Windows、macOS、Linux、Android 和 iOS 等平台。</p></li><li><p><strong>完全免费</strong><br>无广告、无跟踪，让您享受安全稳定的传输体验。</p></li><li><p><strong>开源项目</strong><br>源代码公开，欢迎任何开发者参与改进和贡献。</p></li><li><p><strong>端到端加密</strong><br>确保文件传输过程中仅发送方和接收方能访问数据，保障隐私安全。</p></li><li><p><strong>简单易用</strong><br>界面直观，无需注册，开启后自动发现同网设备。</p></li></ul><h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h2><h3 id="下载安装-LocalSend"><a href="#下载安装-LocalSend" class="headerlink" title="下载安装 LocalSend"></a>下载安装 LocalSend</h3><ol><li><p>前往官网或 GitHub 发布页下载对应安装包：</p><ul><li>官网：<a href="https://localsend.org/">https://localsend.org</a></li><li>GitHub：<a href="https://github.com/localsend/localsend/releases">https://github.com/localsend/localsend/releases</a></li></ul><p><img src="https://img.zrf.me/20250316163613164.webp" alt="下载预览"></p></li><li><p>根据您的操作系统选择下载：</p><ul><li><strong>Windows 用户</strong>：下载 <code>.exe</code> 安装包。</li><li><strong>macOS 用户</strong>：下载 <code>.dmg</code> 安装包。</li><li><strong>Linux 用户</strong>：下载 <code>.AppImage</code> 或 <code>.deb / .rpm</code> 安装包。</li></ul></li><li><p>安装完成后，即可启动 LocalSend 应用。</p></li></ol><h3 id="Android-手机"><a href="#Android-手机" class="headerlink" title="Android 手机"></a>Android 手机</h3><ol><li>打开 <strong>Google Play 商店</strong> 或 <strong>F-Droid</strong>。</li><li>搜索 <code>LocalSend</code> 并下载安装。若无法在应用商店找到，请直接访问 GitHub 发布页下载 APK：<ul><li><a href="https://github.com/localsend/localsend/releases">APK 下载链接</a></li></ul></li></ol><h3 id="iOS（iPhone-iPad）"><a href="#iOS（iPhone-iPad）" class="headerlink" title="iOS（iPhone &#x2F; iPad）"></a>iOS（iPhone &#x2F; iPad）</h3><ol><li>打开 <strong>App Store</strong>。</li><li>搜索 <code>LocalSend</code> 并下载安装。<ul><li><a href="https://apps.apple.com/us/app/localsend/id1661733229">App Store 下载链接</a></li></ul></li></ol><h3 id="前提条件"><a href="#前提条件" class="headerlink" title="前提条件"></a>前提条件</h3><ul><li>请确保所有设备均连接至同一局域网（例如同一 Wi-Fi 或手机热点）。</li><li>Windows&#x2F;macOS 用户请检查系统防火墙设置，允许 LocalSend 通信，首次启动时可能需要授权。</li></ul><h2 id="发送文件"><a href="#发送文件" class="headerlink" title="发送文件"></a>发送文件</h2><ol><li><p>启动 LocalSend 应用，进入主界面。</p></li><li><p>点击 <strong>【发送 Send】</strong> 按钮。</p></li><li><p>选择您需要传输的文件、文件夹、文本或剪贴板内容。</p><p><img src="https://img.zrf.me/20250316164344128.webp" alt="发送文件预览"></p></li><li><p>选择目标接收设备（确保对方设备已开启 LocalSend 并连接同一网络）。</p></li><li><p>点击【发送】按钮，等待对方确认即可完成传输。</p></li></ol><h2 id="接收文件"><a href="#接收文件" class="headerlink" title="接收文件"></a>接收文件</h2><ol><li><p>启动 LocalSend 应用并保持在主界面。</p></li><li><p>当有文件发送请求时，会弹出 <strong>接收请求</strong> 窗口。</p><p><img src="https://img.zrf.me/20250316164429743.webp" alt="接收请求预览"></p></li><li><p>点击 <strong>【接受】</strong> 按钮，文件将自动保存：</p><ul><li>安卓默认保存至 <code>/Downloads/LocalSend/</code>。</li><li>Windows&#x2F;macOS 用户可在应用设置中自定义保存路径。</li></ul></li></ol><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><ul><li><strong>LocalSend 官网</strong>：<a href="https://localsend.org/">https://localsend.org</a></li><li><strong>GitHub 项目</strong>：<a href="https://github.com/localsend/localsend/releases">https://github.com/localsend/localsend/releases</a></li></ul>]]></content>
    
    
    <summary type="html">LocalSend是一款高性能、完全免费的开源无线局域网文件传输工具，支持跨平台设备间的大文件和文本高速安全传输。</summary>
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="MacOS" scheme="https://blog.zrf.me/tags/MacOS/"/>
    
    <category term="Linux" scheme="https://blog.zrf.me/tags/Linux/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="iOS" scheme="https://blog.zrf.me/tags/iOS/"/>
    
    <category term="文件传输" scheme="https://blog.zrf.me/tags/%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93/"/>
    
    <category term="跨平台" scheme="https://blog.zrf.me/tags/%E8%B7%A8%E5%B9%B3%E5%8F%B0/"/>
    
    <category term="局域网" scheme="https://blog.zrf.me/tags/%E5%B1%80%E5%9F%9F%E7%BD%91/"/>
    
    <category term="安全" scheme="https://blog.zrf.me/tags/%E5%AE%89%E5%85%A8/"/>
    
  </entry>
  
  <entry>
    <title>Sink 一个带有分析功能的链接缩短器 使用 Cloudflare Pages 快速部署教程</title>
    <link href="https://blog.zrf.me/p/notes-sink/"/>
    <id>https://blog.zrf.me/p/notes-sink/</id>
    <published>2025-02-25T19:39:22.000Z</published>
    <updated>2026-03-02T00:48:53.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Sink"><a href="#Sink" class="headerlink" title="Sink"></a>Sink</h1><p>Sink 是一个带有分析功能的简单、快速、安全的链接缩短器。它可以快速部署到 Cloudflare Pages，不花一分钱。本文将详细介绍如何使用 Sink 部署一个功能强大的链接缩短器，它不仅支持 URL 缩短，还提供了丰富的分析功能和自定义选项，确保你的链接管理更加高效和安全。</p><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><p><img src="https://img.zrf.me/20250226065428915.webp" alt="Sink 界面预览"><br><img src="https://img.zrf.me/20250413033140226.webp" alt="Sink 界面预览"></p><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li><strong>URL 缩短</strong>：将您的 URL 压缩到最短长度。</li><li><strong>分析学</strong>：监控链路分析并收集有洞察力的统计数据。</li><li><strong>无服务器</strong>：无需传统服务器即可部署。</li><li><strong>可自定义的 Slug</strong>：支持个性化 slug 和 区分大小写。</li><li><strong>AI Slug</strong>：利用 AI 生成 slug。</li><li><strong>链接过期</strong>：设置链接的到期日期。</li></ul><h2 id="设置自动更新-Fork"><a href="#设置自动更新-Fork" class="headerlink" title="设置自动更新 Fork"></a>设置自动更新 Fork</h2><blockquote><p>自动同步 Fork 的项目：<a href="https://blog.zrf.me/p/64">https://blog.zrf.me/p/64</a></p></blockquote><h2 id="Fork-项目"><a href="#Fork-项目" class="headerlink" title="Fork 项目"></a>Fork 项目</h2><ol><li>首先打开 <a href="https://github.com/miantiao-me/Sink">https://github.com/miantiao-me/Sink</a> 在 GitHub 上 Fork 项目，并点个 <strong>Star</strong> 给与项目作者支持与鼓励！<br><img src="https://img.zrf.me/20250226040235045.webp" alt="20250226040235045.webp"><br><img src="https://img.zrf.me/20250226043755282.webp" alt="20250226043755282.webp"></li></ol><h2 id="Cloudflare部署"><a href="#Cloudflare部署" class="headerlink" title="Cloudflare部署"></a>Cloudflare部署</h2><ol><li><p>选择 <strong>Pages</strong> → <strong><img src="https://img.zrf.me/20250414220436061.webp" alt="连接到GIT"></strong><br><img src="https://img.zrf.me/20250226043953641.webp" alt="20250226043953641.webp"></p></li><li><p><strong>框架预设</strong> 选择 <strong>Nuxt.js</strong> 部署的页面不要关掉，获取下方的环境变量并填写。<br><img src="https://img.zrf.me/20250226044049453.webp" alt="20250226044049453.webp"></p></li></ol><h3 id="获取环境变量"><a href="#获取环境变量" class="headerlink" title="获取环境变量"></a>获取环境变量</h3><blockquote><p>环境变量,建议复制不出错。<a href="https://github.com/ccbikai/Sink/blob/master/docs/configuration.md">环境变量可选需要添加，文档说明</a></p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">NUXT_PUBLIC_PREVIEW_MODE=true</span><br><span class="line">NUXT_PUBLIC_SLUG_DEFAULT_LENGTH=5</span><br><span class="line">NUXT_SITE_TOKEN=SinkCool</span><br><span class="line">NUXT_REDIRECT_STATUS_CODE=308</span><br><span class="line">NUXT_LINK_CACHE_TTL=60</span><br><span class="line">NUXT_REDIRECT_WITH_QUERY=false</span><br><span class="line">NUXT_HOME_URL=&quot;https://sink.cool&quot;</span><br><span class="line">NUXT_CF_ACCOUNT_ID=123456</span><br><span class="line">NUXT_CF_API_TOKEN=CloudflareAPIToken</span><br><span class="line">NUXT_DATASET=sink</span><br><span class="line">NUXT_AI_MODEL=&quot;@cf/meta/llama-3-8b-instruct&quot;</span><br><span class="line">NUXT_AI_PROMPT=&quot;You are a URL shortening assistant......&quot;</span><br></pre></td></tr></table></figure><ol><li><p><code>NUXT_SITE_TOKEN</code> 我这里设置<code>aizrfcom</code>必须超过 8 个字符。这是登录仪表板的密码。</p></li><li><p><code>NUXT_CF_ACCOUNT_ID</code> 打开新的页面 <a href="https://dash.cloudflare.com/login">https://dash.cloudflare.com/login</a> 随便选择一个你的域名点进去，右侧下拉就可以看到 <strong>帐户 ID</strong> 复制去添加。<br><img src="https://img.zrf.me/20250226045958149.webp" alt="20250226045958149.webp"><br><img src="https://img.zrf.me/20250226050827334.webp" alt="20250226050827334.webp"></p></li><li><p><code>NUXT_CF_API_TOKEN</code> 最右上角 <strong>配置文件</strong><br><img src="https://img.zrf.me/20250226051501807.webp" alt="20250226051501807.webp"></p></li><li><p>创建API令牌<br><img src="https://img.zrf.me/20250226051554647.webp" alt="20250226051554647.webp"></p></li><li><p>选择<strong>阅读分析数据和日志</strong><br><img src="https://img.zrf.me/20250226051727410.webp" alt="20250226051727410.webp"></p></li><li><p>创建令牌的名称为 <strong>sink</strong> 当然你也可以默认，如果你项目多了，可能不知道这个 <strong>token</strong> 是干嘛的，建议备注名称，删除模板中其他两个，只保留 <strong>账户分析</strong> 。随后最下方点击 <strong>继续以显示摘要</strong> → <strong>创建API令牌</strong><br><img src="https://img.zrf.me/20250226052543057.webp" alt="20250226052543057.webp"></p></li><li><p>找地方保存下来，这 <strong>token</strong> 只显示一次。<br><img src="https://img.zrf.me/20250226053126423.webp" alt="20250226053126423.webp"></p></li><li><p>这是我填写完的效果，除了环境变量的值，你的与我不同，其他必须和图片一模一样，填写完成选择 <strong>保存并部署</strong> 。<br><img src="https://img.zrf.me/20250226054031627.webp" alt="20250226054031627.webp"></p></li><li><p>然后选择 <strong>继续处理项目</strong> 会出现一个提示点 <strong>继续</strong> 。<br><img src="https://img.zrf.me/20250226054749516.webp" alt="20250226054749516.webp"></p></li></ol><h3 id="创建与绑定-KV命名空间-和-Workers-AI"><a href="#创建与绑定-KV命名空间-和-Workers-AI" class="headerlink" title="创建与绑定 KV命名空间 和 Workers AI"></a>创建与绑定 KV命名空间 和 Workers AI</h3><ol><li><p>来到 <strong>储存和数据库</strong> → <strong>KV</strong> 名称随便取， 我这里设置 <strong>sink</strong> 并 <strong>添加</strong> 。<br><img src="https://img.zrf.me/20250226055741865.webp" alt="20250226055741865.webp"></p></li><li><p>看图操作，注意 <strong>KV命名空间</strong> 的 <strong>变量名称</strong> 一定是大写 <code>KV</code> 不要写错，然后保存。<br><img src="https://img.zrf.me/20250226060733838.webp" alt="20250226060733838.webp"></p></li><li><p><strong>Workers AI</strong> 的  <strong>变量名称</strong> 一定是大写 <code>AI</code> 不要写错，然后保存。<br><img src="https://img.zrf.me/20250226061309680.webp" alt="20250226061309680.webp"></p></li><li><p><strong>帐户详细信息</strong>下方，启用 <strong>分析引擎</strong> → <strong>数据分享功能</strong>。<br><img src="https://img.zrf.me/20250226062232065.webp" alt="20250226062232065.webp"><br><img src="https://img.zrf.me/20250226064449395.webp" alt="20250226064449395.webp"></p></li><li><p>回到项目 <strong>设置</strong> 看图操作，注意 <strong>Analytics Engine</strong> 的 <strong>变量名称</strong> 一定是大写 <code>ANALYTICS</code> 不要写错，值为 <strong>sink</strong><br><img src="https://img.zrf.me/20250226062944894.webp" alt="20250226062944894.webp"></p></li><li><p>好了，所有设置完成，在项目 <strong>部署页面</strong> 进行 <strong>重新部署</strong> 使刚设置的配置生效。部署时间大概为两分钟左右。<br><img src="https://img.zrf.me/20250226063348596.webp" alt="20250226063348596.webp"></p></li><li><p>这个时间我去设置一个自定义域名，设置为 <a href="https://sink.001315.xyz/">sink.001315.xyz</a> 用于体验项目给大家体验查看。<br><img src="https://img.zrf.me/20250226064034921.webp" alt="20250226064034921.webp"><br><img src="https://img.zrf.me/20250226064159507.webp" alt="20250226064159507.webp"></p></li></ol><h2 id="后续更新部署错误"><a href="#后续更新部署错误" class="headerlink" title="后续更新部署错误"></a>后续更新部署错误</h2><ol><li><p>2025年5月25日，更新这个项目，发现部署错误了，提示如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">00:03:45.065▲ [WARNING] The package &quot;node:async_hooks&quot; wasn&#x27;t found on the file system but is built into node.</span><br><span class="line">00:03:45.065</span><br><span class="line">00:03:45.065  Your Worker may throw errors at runtime unless you enable the &quot;nodejs_compat&quot; compatibility flag. Refer to https://developers.cloudflare.com/workers/runtime-apis/nodejs/ for more details. Imported from:</span><br><span class="line">00:03:45.065   - _worker.js/index.js</span><br><span class="line">00:03:45.065</span><br><span class="line">00:03:45.065</span><br><span class="line">00:03:45.065✨ Compiled Worker successfully</span><br><span class="line">00:03:46.216Found _routes.json in output directory. Uploading.</span><br><span class="line">00:03:46.226Validating asset output directory</span><br><span class="line">00:03:49.038Deploying your site to Cloudflare&#x27;s global network...</span><br><span class="line">00:03:51.326Parsed 1 valid redirect rule.</span><br><span class="line">00:03:51.327Parsed 3 valid header rules.</span><br><span class="line">00:03:52.763Uploading... (27/68)</span><br><span class="line">00:03:53.665Uploading... (41/68)</span><br><span class="line">00:03:53.934Uploading... (54/68)</span><br><span class="line">00:03:54.250Uploading... (68/68)</span><br><span class="line">00:03:54.250✨ Success! Uploaded 41 files (27 already uploaded) (2.00 sec)</span><br><span class="line">00:03:54.250</span><br><span class="line">00:03:54.705✨ Upload complete!</span><br><span class="line">00:03:58.157Success: Assets published!</span><br><span class="line">00:03:59.389Error: Failed to publish your Function. Got error: Uncaught Error: No such module &quot;node:buffer&quot;.</span><br><span class="line">  imported from &quot;bundledWorker-0.28418464400185184.mjs&quot;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://img.zrf.me/20250526151458411.webp" alt="更新部署错误"></p></li><li><p>我们来到项目 <strong>设置</strong> ➡ <strong>运行时</strong> ➡ <strong>兼容性标志</strong> ➡ <strong>生产兼容性标志</strong> 中添加 <strong>nodejs_compat</strong> 并保存。如图设置。<br><img src="https://img.zrf.me/20250526152312793.webp" alt="添加兼容性标志"></p></li><li><p>来到项目的 <strong>部署</strong> 重新部署一下项目，使其设置生效等待部署完成就可以了。<br><img src="https://img.zrf.me/20250526152711853.webp" alt="重新部署项目"></p></li></ol><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p>GitHub Sink：<a href="https://github.com/miantiao-me/Sink">https://github.com/miantiao-me/Sink</a></p></blockquote><blockquote><p>自动同步 Fork 的项目：<a href="https://blog.zrf.me/p/64">https://blog.zrf.me/p/64</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Sink&quot;&gt;&lt;a href=&quot;#Sink&quot; class=&quot;headerlink&quot; title=&quot;Sink&quot;&gt;&lt;/a&gt;Sink&lt;/h1&gt;&lt;p&gt;Sink 是一个带有分析功能的简单、快速、安全的链接缩短器。它可以快速部署到 Cloudflare Pages，不花一分钱。</summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="AI" scheme="https://blog.zrf.me/tags/AI/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="GitHub" scheme="https://blog.zrf.me/tags/GitHub/"/>
    
    <category term="链接缩短器" scheme="https://blog.zrf.me/tags/%E9%93%BE%E6%8E%A5%E7%BC%A9%E7%9F%AD%E5%99%A8/"/>
    
    <category term="分析" scheme="https://blog.zrf.me/tags/%E5%88%86%E6%9E%90/"/>
    
  </entry>
  
  <entry>
    <title>注册永久免费域名pp.ua 可托管Cloudflare 对比其他免费域名更加稳定</title>
    <link href="https://blog.zrf.me/p/notes-pp-ua/"/>
    <id>https://blog.zrf.me/p/notes-pp-ua/</id>
    <published>2025-02-21T20:27:28.000Z</published>
    <updated>2026-01-29T13:04:01.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="注册永久免费域名pp-ua"><a href="#注册永久免费域名pp-ua" class="headerlink" title="注册永久免费域名pp.ua"></a>注册永久免费域名pp.ua</h1><p>昨晚发现免费域名提供商<a href="https://nic.us.kg/">US.KG</a>又翻车了，我知道的是已经翻车3次了好像，其稳定性较差，门槛低易被滥用，但不得不承认其提供了一个非常便捷的免费域名注册服务，也非常感谢其提供的服务。但是相比之下，pp.ua 域名的注册门槛较高，但更加稳定。完成注册每年续订一次。与 US.KG 续订一样。稳定运行很多年了。<br><img src="https://img.zrf.me/20250222063637699.webp" alt="20250222063637699.webp"></p><hr><h2 id="事前准备"><a href="#事前准备" class="headerlink" title="事前准备"></a>事前准备</h2><ul><li>一个有效的电子邮件地址（<strong>必须</strong>，用于注册和验证）</li><li><a href="https://telegram.org/">Telegram</a>（<strong>必须</strong>，需要注册一个Telegram帐号，用于域名激活）</li><li>一张支持VISA的信用卡（<strong>必须</strong>，会消费1乌克兰币，但是马上回撤销交易给你退回，不收费的，仅用域名验证）</li></ul><h2 id="注册域名"><a href="#注册域名" class="headerlink" title="注册域名"></a>注册域名</h2><ol><li><p>打开 <a href="https://nic.ua/en/signup/tqczmwiu">nic.ua</a> 注册账号<br><img src="https://img.zrf.me/20250222043549291.webp" alt="注册账号"></p></li><li><p>进入注册的邮箱，进行邮箱验证<br><img src="https://img.zrf.me/20250222043604634.webp" alt="邮箱验证"></p></li><li><p>回到主页，搜索你想要注册的域名，我想要的是 <code>zrf.pp.ua</code>  <strong>在30天内一个账号，可最多注册3个.PP.UA后缀的域名</strong><br><img src="https://img.zrf.me/20250222043620128.webp" alt="搜索域名"></p></li><li><p>加入购物车，并点击结算<br><img src="https://img.zrf.me/20250222043703807.webp" alt="加入购物车"><br><img src="https://img.zrf.me/20250222043756466.webp" alt="点击结算"></p></li><li><p>填写信息，建议生成不要填写真实信息。<strong>唯一注意的是手机号需要填写你TG绑定的号码，后续要进行验证。</strong><br><img src="https://img.zrf.me/20250222044743065.webp" alt="填写信息"></p></li><li><p>看到你的域名了，需要验证XYK信息，需要支持VISA的卡<br><img src="https://img.zrf.me/20250222045803201.webp" alt="验证信息"></p></li><li><p>完成验证后返回网站，完成域名注册，但是需要进行激活<br><img src="https://img.zrf.me/20250222050124136.webp" alt="完成注册"></p></li></ol><h2 id="激活域名"><a href="#激活域名" class="headerlink" title="激活域名"></a>激活域名</h2><ol><li><p>打开 <a href="https://telegram.me/ppuabot">TG机器人</a>，点击机器人菜单 <strong>&#x2F;start</strong><br><img src="https://img.zrf.me/20250222051152063.webp" alt="TG机器人"></p></li><li><p>分享你的名片给他用于验证手机号码<br><img src="https://img.zrf.me/20250222051152063.webp" alt="分享名片"></p></li><li><p>按照图片顺序点击卡片菜单，输入你的域名，同意政策，选 <strong>YES</strong>，获取激活码<br><img src="https://img.zrf.me/20250222051829830.webp" alt="获取激活码"></p></li><li><p>打开 <a href="https://apu.drs.ua/en/index.jsp">apu.drs.ua</a>，输入激活码<br><img src="https://img.zrf.me/20250222052247642.webp" alt="输入激活码"></p></li><li><p>激活成功<br><img src="https://img.zrf.me/20250222052258357.webp" alt="激活成功"></p></li></ol><h2 id="域名托管在-Cloudflare"><a href="#域名托管在-Cloudflare" class="headerlink" title="域名托管在 Cloudflare"></a>域名托管在 Cloudflare</h2><ol><li><p>账户主页，添加域名<br><img src="https://img.zrf.me/20250222052629591.webp" alt="添加域名"></p></li><li><p>选择免费计划<br><img src="https://img.zrf.me/20250222052713243.webp" alt="选择免费计划"></p></li><li><p>删除之前的记录（如果你有的话），并点击激活<br><img src="https://img.zrf.me/20250222052937478.webp" alt="删除记录"></p></li><li><p>复制 Cloudflare 名称服务器 <code>piper.ns.cloudflare.com</code> 与 <code>pranab.ns.cloudflare.com</code>  ,不要照抄，每个人的不一样。<br><img src="https://img.zrf.me/20250222053246070.webp" alt="复制名称服务器"></p></li><li><p>打开 <a href="https://nic.ua/en/my/domains">nic.ua</a> 进入设置，设置你的 NS 服务器，选择自定义服务器，粘贴并保存<br><img src="https://img.zrf.me/20250222053347466.webp" alt="设置NS服务器"><br><img src="https://img.zrf.me/20250222053649093.webp" alt="粘贴并保存"></p></li><li><p>等待绑定成功，成功后会收到邮件通知<br><img src="https://img.zrf.me/20250222054113357.webp" alt="绑定成功"><br><img src="https://img.zrf.me/20250222054735194.webp" alt="邮件通知"></p></li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ol><li><p>在30天内一个账号，可最多注册3个.PP.UA后缀的域名</p></li><li><p>新注册域名有效期都是一年，可以在域名到期前3-4个月申请免费续订，跟us.kg基本一样。</p></li><li><p>pp.ua中注册的域名WHOIS信息是公开的，无法开启隐私保护。也就是你的注册信息都可以查到。</p></li></ol><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p> <a href="https://nic.ua/">PP.UA</a></p></blockquote><blockquote><p> <a href="https://nic.us.kg/">us.kg</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;注册永久免费域名pp-ua&quot;&gt;&lt;a href=&quot;#注册永久免费域名pp-ua&quot; class=&quot;headerlink&quot; title=&quot;注册永久免费域名pp.ua&quot;&gt;&lt;/a&gt;注册永久免费域名pp.ua&lt;/h1&gt;&lt;p&gt;昨晚发现免费域名提供商&lt;a href=&quot;https:</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="最新资讯" scheme="https://blog.zrf.me/tags/%E6%9C%80%E6%96%B0%E8%B5%84%E8%AE%AF/"/>
    
    <category term="Telegram" scheme="https://blog.zrf.me/tags/Telegram/"/>
    
    <category term="免费域名" scheme="https://blog.zrf.me/tags/%E5%85%8D%E8%B4%B9%E5%9F%9F%E5%90%8D/"/>
    
    <category term="域名注册" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%B3%A8%E5%86%8C/"/>
    
    <category term="信息安全" scheme="https://blog.zrf.me/tags/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="域名托管" scheme="https://blog.zrf.me/tags/%E5%9F%9F%E5%90%8D%E6%89%98%E7%AE%A1/"/>
    
    <category term="白嫖域名" scheme="https://blog.zrf.me/tags/%E7%99%BD%E5%AB%96%E5%9F%9F%E5%90%8D/"/>
    
    <category term="US.KG" scheme="https://blog.zrf.me/tags/US-KG/"/>
    
    <category term="pp.ua" scheme="https://blog.zrf.me/tags/pp-ua/"/>
    
    <category term="VISA信用卡" scheme="https://blog.zrf.me/tags/VISA%E4%BF%A1%E7%94%A8%E5%8D%A1/"/>
    
  </entry>
  
  <entry>
    <title>Epic 游戏喜加一：《F1® 车队经理 2024》《Apex Legends™》罗芭免费解锁捆绑包</title>
    <link href="https://blog.zrf.me/p/epic2025-2-14/"/>
    <id>https://blog.zrf.me/p/epic2025-2-14/</id>
    <published>2025-02-13T16:01:22.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.zrf.me/20250214050903373.webp" alt="今日限免"></p><h2 id="今日限免："><a href="#今日限免：" class="headerlink" title="今日限免："></a>今日限免：</h2><blockquote><p>点击前往<a href="https://d.zrf.me/epic2025-2-14-1">《F1® 车队经理 2024》</a></p></blockquote><blockquote><p>点击前往 <a href="https://d.zrf.me/epic2025-2-14-2">《Apex Legends™》罗芭免费解锁捆绑包</a></p></blockquote><h2 id="优惠截止于-2025-2-21-01-00"><a href="#优惠截止于-2025-2-21-01-00" class="headerlink" title="优惠截止于 2025&#x2F;2&#x2F;21 01:00"></a>优惠截止于 2025&#x2F;2&#x2F;21 01:00</h2><h2 id="下周限免："><a href="#下周限免：" class="headerlink" title="下周限免："></a>下周限免：</h2><blockquote><p>《僵尸世界大战：劫后余生》《Garden Story》</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.zrf.me/20250214050903373.webp&quot; alt=&quot;今日限免&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;今日限免：&quot;&gt;&lt;a href=&quot;#今日限免：&quot; class=&quot;headerlink&quot; title=&quot;今日限免：&quot;&gt;&lt;/a</summary>
      
    
    
    
    <category term="资源中心" scheme="https://blog.zrf.me/categories/%E8%B5%84%E6%BA%90%E4%B8%AD%E5%BF%83/"/>
    
    
    <category term="游戏" scheme="https://blog.zrf.me/tags/%E6%B8%B8%E6%88%8F/"/>
    
    <category term="Epic Games" scheme="https://blog.zrf.me/tags/Epic-Games/"/>
    
    <category term="Epic 喜加一" scheme="https://blog.zrf.me/tags/Epic-%E5%96%9C%E5%8A%A0%E4%B8%80/"/>
    
  </entry>
  
  <entry>
    <title>使用 VSCode 和 VS-PicList 插件高效管理 Markdown 图片及高效书写</title>
    <link href="https://blog.zrf.me/p/notes-vscode-vs-piclist/"/>
    <id>https://blog.zrf.me/p/notes-vscode-vs-piclist/</id>
    <published>2025-02-08T19:14:07.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="VSCode-VS-PicList"><a href="#VSCode-VS-PicList" class="headerlink" title="VSCode + VS-PicList"></a>VSCode + VS-PicList</h1><blockquote><p>这个组合我简直吹爆，彻底改变了我的书写习惯。使用 VSCode 书写 Markdown 格式时，VS-PicList 插件让图片上传变得更加高效便捷。它支持多种上传方式，并且可以直接删除和转换为 webp 格式。</p></blockquote><blockquote><p>VS-PicList 是一款功能丰富的 VSCode 扩展，专为无缝图像管理而设计。此扩展使您能够轻松地将图像上传到远程托管服务，并自动将生成的 URL 插入到当前活动的文件中。与其他解决方案不同，VS-PicList 拥有强大的功能集，包括图像压缩、水印和其他高级图像处理功能。</p></blockquote><h2 id="为什么推荐-VS-PicList-插件？"><a href="#为什么推荐-VS-PicList-插件？" class="headerlink" title="为什么推荐 VS-PicList 插件？"></a>为什么推荐 VS-PicList 插件？</h2><p>在我使用这款 <strong>VS-PicList</strong> 时，我也体验了其他不同的插件，例如 <strong>Markdown Image</strong>，它们也都是非常优秀的插件，但它们不是我们的主角。</p><p><img src="https://img.zrf.me/20250209055957093.webp" alt="20250209055957093.webp"></p><h3 id="插件功能对比"><a href="#插件功能对比" class="headerlink" title="插件功能对比"></a>插件功能对比</h3><p><strong>（如有误可以联系博主纠正，仅代表博主个人主观体验给出的参数对比）</strong></p><table><thead><tr><th>功能</th><th>Markdown Image</th><th>VS-PicList</th></tr></thead><tbody><tr><td>支持的输出格式</td><td>JPG, PNG</td><td>JPG, PNG, WebP</td></tr><tr><td>图片上传</td><td>支持</td><td>支持</td></tr><tr><td>同步删除云端文件</td><td>不支持</td><td>支持</td></tr><tr><td>图像压缩</td><td>不支持</td><td>支持</td></tr><tr><td>水印</td><td>不支持</td><td>支持</td></tr><tr><td>高级图像处理</td><td>不支持</td><td>支持</td></tr><tr><td>自动插入 URL</td><td>支持</td><td>支持</td></tr><tr><td>拖放上传</td><td>支持</td><td>支持</td></tr><tr><td>上传文件中的所有图像</td><td>不支持</td><td>支持</td></tr><tr><td>上传选定的图像</td><td>不支持</td><td>支持</td></tr><tr><td>远程服务器模式</td><td>不支持</td><td>支持</td></tr><tr><td>删除远程托管服务中的图片</td><td>不支持</td><td>支持</td></tr></tbody></table><p>当然 <strong>Markdown Image</strong> 不需要在使用时运行其他软件，这也是其优点之一，而使用 <strong>VS-PicList</strong> 的前提是，你必须同时使用 <strong>PicList</strong>。此前，我们介绍过这款软件：<a href="https://blog.zrf.me/p/PicList/">PicList - 一款高效的云存储和图片托管平台管理工具</a>。（看了才能理解我在说什么）本篇博文是对其进行一个使用补充。</p><h3 id="WebP格式与PNG格式对比"><a href="#WebP格式与PNG格式对比" class="headerlink" title="WebP格式与PNG格式对比"></a>WebP格式与PNG格式对比</h3><p>其中我们提到，我特别喜欢 <strong>PicList</strong> 的原因，尤其是支持<strong>同步删除云端文件</strong>和<strong>图片格式转换</strong>。也列出了 <strong>WebP格式的图片与PNG或JPG格式的优势比较</strong>。我使用两种格式的例子说明（同一图片都上传在R2桶中，只是格式不一样）：</p><ol><li><p>WEBP格式 图片大小： <strong>3.35 MB</strong><br>直链：<a href="https://img.zrf.me/20250209061851070.webp">https://img.zrf.me/20250209061851070.webp</a><br><img src="https://img.zrf.me/20250209061851070.webp" alt="20250209061851070.webp"><br><img src="https://img.zrf.me/20250209063134566.webp" alt="20250209063134566.webp"></p></li><li><p>PNG格式 图片大小： <strong>16.08 MB</strong><br>直链：<a href="https://img.zrf.me/20250209061826811.png">https://img.zrf.me/20250209061826811.png</a><br><img src="https://img.zrf.me/20250209061826811.png" alt="20250209061826811.png"><br><img src="https://img.zrf.me/20250209063514474.webp" alt="20250209063514474.webp"></p></li></ol><p>可打开直链对比一下图片画质，肉眼可见效果。你能否看出区别？这正是我选择使用WEBP格式的重要原因。WEBP格式不仅占用更小的存储空间，还能让访问者在浏览你的图片内容时，更快地加载图片内容，减少所需流量。</p><hr><h2 id="插件特点"><a href="#插件特点" class="headerlink" title="插件特点"></a>插件特点</h2><ul><li><strong>轻松上传</strong>：只需单击几下，即可将图像上传到您首选的远程图像托管服务。</li><li><strong>拖放上传</strong>：将图像从文件资源管理器直接拖放到工作文件中。</li><li><strong>全部上传</strong>：上传文件中的所有图像。</li><li><strong>上传选定</strong>：右键单击即可上传选定的图像。</li><li><strong>自动插入 URL</strong>：该扩展负责将图像 URL 直接插入到您的工作文件中。</li><li><strong>图像管理</strong>：通过 VSCode 中的 PicList 直接轻松删除存储在远程托管服务中的图像。</li><li><strong>高级图像处理</strong>：包括对图像压缩、水印和其他上传后操作的支持。</li><li><strong>远程服务器模式</strong>：支持使用在服务器或远程机器上运行的 PicList 和 piclist-core 服务。</li></ul><h2 id="安装与设置"><a href="#安装与设置" class="headerlink" title="安装与设置"></a>安装与设置</h2><ol><li><p>打开 <strong>VSCode</strong> 左侧边栏，搜索 <strong>PicList</strong> 或链接下载<a href="https://marketplace.visualstudio.com/items?itemName=Kuingsmile.vs-piclist">VS-PicList</a>并点击安装。我已经安装过了，所以这里显示卸载。安装完成后，关闭并重启 <strong>VSCode</strong> 使其插件生效。<br><img src="https://img.zrf.me/20250209050645978.webp" alt="20250209050645978.webp"></p></li><li><p>进入插件的 <strong>键盘快捷方式</strong> 默认快捷键可以自己点击修改，你顺手的。最常用的就下面这几个。<br><img src="https://img.zrf.me/20250209052718746.webp" alt="20250209052718746.webp"></p><blockquote><p><strong>PicList: Upload from clipboard</strong> &#x3D; 从剪贴板上传图像<br><strong>PicList: Upload from explorer</strong> &#x3D; 从资源管理器上传图像<br><strong>PicList: Delete Image by PicList</strong> &#x3D; 删除远程托管服务中的图片</p></blockquote></li><li><p>进入插件的设置，基本默认设置即可，开发者已经为你设置好了参数，因为你的上传各种参数都是在 <strong>PicList</strong> 软件中已经进行设置了（当然你得看了我之前那篇博文）。直接使用即可。<br><img src="https://img.zrf.me/20250209052002366.webp" alt="20250209052002366.webp"></p></li></ol><p><strong>相关参数说明</strong></p><p><strong>Upload API URL</strong></p><blockquote><p>这是PicList的上传api URL，默认为<code>http://127.0.0.1:36677/upload</code></p></blockquote><p><strong>Delete API URL</strong></p><blockquote><p>这是PicList的删除api URL，默认为<code>http://127.0.0.1:36677/delete</code></p></blockquote><p><strong>Copy Type</strong></p><blockquote><p>默认是 Markdown。</p></blockquote><table><thead><tr><th>类型</th><th>格式</th></tr></thead><tbody><tr><td>url</td><td><code>url</code></td></tr><tr><td>markdown</td><td><code>![alt](url)</code></td></tr><tr><td>html</td><td><code>&lt;img src=url alt=alt&gt;</code></td></tr><tr><td>ubb</td><td><code>[img]url[/img]</code></td></tr><tr><td>自定义</td><td><code>custom</code></td></tr></tbody></table><p><strong>Custom Type</strong></p><blockquote><p>默认是 <code>![$filename]($url)</code></p></blockquote><p><strong>Encode URL</strong></p><blockquote><p>是否在插入文本时编码 URL。默认为 <code>false</code></p></blockquote><p><strong>Enable upload on drop</strong></p><blockquote><p>是否启用拖放上传。默认为 <code>true</code></p></blockquote><p><strong>Remote Server Mode</strong></p><blockquote><p>当您在服务器或其他机器上部署 Piclist 或 Piclist-Core 服务时，您可以启用远程服务器模式，然后通过发送文件来启动上传请求。</p></blockquote><ul><li>详细使用看下方GIF图就能学会。</li></ul><h2 id="Gif-演示教学"><a href="#Gif-演示教学" class="headerlink" title="Gif 演示教学"></a>Gif 演示教学</h2><p><strong>从剪贴板上传图像</strong></p><p><img src="https://img.zrf.me/20250209043708136.gif" alt="20250209043708136.gif"></p><p><strong>从资源管理器上传图像</strong></p><p><img src="https://img.zrf.me/20250209044657724.gif" alt="20250209044657724.gif"></p><p><strong>从本地路径或 URL 上传图像</strong></p><p><img src="https://img.zrf.me/20250209044732033.gif" alt="20250209044732033.gif"></p><p><strong>通过拖放操作上传图像</strong></p><p><img src="https://img.zrf.me/20250209044805821.gif" alt="20250209044805821.gif"></p><p><strong>删除远程托管服务中的图片</strong></p><p><img src="https://img.zrf.me/20250209044834951.gif" alt="20250209044834951.gif"></p><p><strong>上传文件中的所有图像</strong></p><p><img src="https://img.zrf.me/20250209044938826.gif" alt="20250209044938826.gif"></p><p><strong>右键单击上传文件中选定的图像</strong></p><p><img src="https://img.zrf.me/20250209045023293.gif" alt="20250209045023293.gif"></p><h2 id="VSCode-优秀插件推荐"><a href="#VSCode-优秀插件推荐" class="headerlink" title="VSCode 优秀插件推荐"></a>VSCode 优秀插件推荐</h2><p><strong>GitHub Copilot</strong></p><ol><li><p>首先打开 <a href="https://github.com/settings/copilot">GitHub Copilot</a> 进行一些相关设置的开启，其中免费计划：<strong>免费使用 Copilot 响应限制为每月 2,000 个代码完成和 50 条聊天消息。</strong><br><img src="https://img.zrf.me/20250209172512572.webp" alt="GitHub Copilot 设置"></p></li><li><p>打开 <strong>VSCode</strong> 左侧边栏，搜索 <strong>GitHub Copilot</strong> 或链接下载 <a href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot">GitHub Copilot</a> 并点击安装。我已经安装过了，安装完成后，关闭并重启 <strong>VSCode</strong> 使其插件生效。<br><img src="https://img.zrf.me/20250209172710100.webp" alt="GitHub Copilot 安装"></p></li><li><p>内置的 <strong>GitHub Copilot</strong> 我这个让他修改格式后，他的书写格式会更加标准，可以在我们学习书写 markdown 格式中起到很大的帮助作用，右下角可以自行切换<strong>大模型</strong>。生成代码、修复错误、询问有关您代码的问题等等…更多功能等着你自己发掘这里就不多介绍了。<br><img src="https://img.zrf.me/20250209174159420.webp" alt="20250209174159420.webp"><br><img src="https://img.zrf.me/20250209182028597.webp" alt="20250209182028597.webp"></p></li></ol><ul><li>完结撒花</li></ul><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p> 点击前往 <a href="https://marketplace.visualstudio.com/items?itemName=Kuingsmile.vs-piclist">VS-PicList</a></p></blockquote><blockquote><p> 点击前往 <a href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot/">GitHub Copilot</a></p></blockquote><blockquote><p> 点击前往 <a href="https://blog.zrf.me/p/PicList/">PicList - 一款高效的云存储和图片托管平台管理工具</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;VSCode-VS-PicList&quot;&gt;&lt;a href=&quot;#VSCode-VS-PicList&quot; class=&quot;headerlink&quot; title=&quot;VSCode + VS-PicList&quot;&gt;&lt;/a&gt;VSCode + VS-PicList&lt;/h1&gt;&lt;blockquo</summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="办公" scheme="https://blog.zrf.me/tags/%E5%8A%9E%E5%85%AC/"/>
    
    <category term="图像软件" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="AI" scheme="https://blog.zrf.me/tags/AI/"/>
    
    <category term="hexo" scheme="https://blog.zrf.me/tags/hexo/"/>
    
    <category term="图床" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%BA%8A/"/>
    
    <category term="图像处理" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86/"/>
    
    <category term="素材资源" scheme="https://blog.zrf.me/tags/%E7%B4%A0%E6%9D%90%E8%B5%84%E6%BA%90/"/>
    
    <category term="插件推荐" scheme="https://blog.zrf.me/tags/%E6%8F%92%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    <category term="WebP" scheme="https://blog.zrf.me/tags/WebP/"/>
    
    <category term="VS-PicList" scheme="https://blog.zrf.me/tags/VS-PicList/"/>
    
    <category term="图片管理" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E7%89%87%E7%AE%A1%E7%90%86/"/>
    
    <category term="高效书写" scheme="https://blog.zrf.me/tags/%E9%AB%98%E6%95%88%E4%B9%A6%E5%86%99/"/>
    
    <category term="VSCode" scheme="https://blog.zrf.me/tags/VSCode/"/>
    
    <category term="Markdown" scheme="https://blog.zrf.me/tags/Markdown/"/>
    
  </entry>
  
  <entry>
    <title>最低79元起，让你的小米手机满血“复活”，再战个两年吧</title>
    <link href="https://blog.zrf.me/p/news-xiaomi202525/"/>
    <id>https://blog.zrf.me/p/news-xiaomi202525/</id>
    <published>2025-02-05T21:07:55.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="小米科技年货节"><a href="#小米科技年货节" class="headerlink" title="小米科技年货节"></a>小米科技年货节</h1><p><img src="https://img.zrf.me/20250207051601797.webp" alt="小米科技年货节"></p><p><strong>手机电池老化？小米推出电池焕新服务</strong></p><p>随着时间推移，手机电池会逐渐老化，续航时间变短，充电速度也会变慢。这种现象就像人体机能随年龄增长而自然下降一样，无法完全避免。</p><p>除了时间因素，使用习惯也会加速电池老化，比如频繁充电、过度放电、长时间处于高温环境等。面对这些问题，换电池是一个直接的解决办法。</p><p>如果你担心外部维修店的质量和价格问题，可以考虑官方道的服务。近期，小米推出了“科技年货节”活动，提供电池更换服务，价格从79.2元起，具体参与活动的机型如下。</p><p><img src="https://img.zrf.me/20250207052733962.webp" alt="支持机型"></p><p>这项服务可能对需要更换电池的用户有一定的帮助。如果你的旧手机电池老化，但其他功能仍然正常，不妨了解一下这项活动。</p><p><strong>博主评价</strong></p><p>小米官方电池更换服务的一个优点是质量有保障，虽然我这个机型的价格比起当初99元的价格还是不够香，但比起外部维修店，官方服务通常更可靠。我之前也曾通过官方渠道更换过电池，整体体验还不错。如果你的手机电池老化，但机器本身性能还可以，考虑官方换电池是一个不错的选择。</p><h2 id="优惠截止于-2025-2-11-24-00"><a href="#优惠截止于-2025-2-11-24-00" class="headerlink" title="优惠截止于 2025/2/11 24:00"></a><code>优惠截止于 2025/2/11 24:00</code></h2><blockquote><p>小米科技年货节:<a href="https://d.zrf.me/xiaomi202525">https://d.zrf.me/xiaomi202525</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;小米科技年货节&quot;&gt;&lt;a href=&quot;#小米科技年货节&quot; class=&quot;headerlink&quot; title=&quot;小米科技年货节&quot;&gt;&lt;/a&gt;小米科技年货节&lt;/h1&gt;&lt;p&gt;&lt;img src=&quot;https://img.zrf.me/20250207051601797.web</summary>
      
    
    
    
    <category term="资源中心" scheme="https://blog.zrf.me/categories/%E8%B5%84%E6%BA%90%E4%B8%AD%E5%BF%83/"/>
    
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="最新资讯" scheme="https://blog.zrf.me/tags/%E6%9C%80%E6%96%B0%E8%B5%84%E8%AE%AF/"/>
    
    <category term="小米手机" scheme="https://blog.zrf.me/tags/%E5%B0%8F%E7%B1%B3%E6%89%8B%E6%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title>B站视频下载全攻略 - 第三方工具推荐(PC/浏览器插件) - 哔哩哔哩(Bilibili)教程</title>
    <link href="https://blog.zrf.me/p/bilibili-download/"/>
    <id>https://blog.zrf.me/p/bilibili-download/</id>
    <published>2025-02-03T21:16:19.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="B站视频下载全攻略-第三方工具推荐-PC-浏览器插件"><a href="#B站视频下载全攻略-第三方工具推荐-PC-浏览器插件" class="headerlink" title="B站视频下载全攻略 - 第三方工具推荐(PC&#x2F;浏览器插件)"></a>B站视频下载全攻略 - 第三方工具推荐(PC&#x2F;浏览器插件)</h1><p>今天给大家介绍两款，B站视频下载的第三方工具  <strong>Bili23-Downloader</strong> （PC端跨平台工具）和 <strong>bilibili哔哩哔哩下载助手</strong> （浏览器插件）</p><p><strong>Bili23-Downloader</strong>：跨平台的 B 站视频下载工具，支持 Windows、Linux、macOS 三平台，下载 B 站视频&#x2F;番剧&#x2F;电影&#x2F;纪录片 等资源，程序支持多线程下载（最多 8 线程）、并行下载（上限为 8 个，支持动态调整）、断点续传、下载限速、出错重试等功能。</p><p><strong>bilibili哔哩哔哩下载助手</strong>：帮你下载版权受限（能看不能缓存）的 番剧 电影 影视 电视剧 等 视频。</p><hr><h2 id="Bili23-Downloader（PC）"><a href="#Bili23-Downloader（PC）" class="headerlink" title="Bili23-Downloader（PC）"></a>Bili23-Downloader（PC）</h2><h3 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h3><ul><li>支持输入的 URL 链接的格式</li></ul><table><thead><tr><th>类型</th><th>支持的功能</th><th>示例</th></tr></thead><tbody><tr><td><strong>用户投稿视频</strong>（含分P，合集视频）</td><td>解析下载</td><td><a href="https://www.bilibili.com/video/BV1t94y1C7fp">https://www.bilibili.com/video/BV1t94y1C7fp</a></td></tr><tr><td><strong>剧集</strong>（含番剧、电影、纪录片、国创、电视剧、综艺）</td><td>解析下载</td><td><a href="https://www.bilibili.com/bangumi/play/ss45574">https://www.bilibili.com/bangumi/play/ss45574</a></td></tr><tr><td><strong>课程</strong></td><td>解析下载</td><td><a href="https://www.bilibili.com/cheese/play/ep69165">https://www.bilibili.com/cheese/play/ep69165</a></td></tr><tr><td><strong>直播</strong></td><td>m3u8直链解析、录制</td><td><a href="https://live.bilibili.com/1">https://live.bilibili.com/1</a></td></tr><tr><td><strong>b23.tv 短链接</strong></td><td>解析下载</td><td><a href="https://b23.tv/BV1UG411f7K1">https://b23.tv/BV1UG411f7K1</a></td></tr><tr><td><strong>活动页链接</strong></td><td>解析下载</td><td><a href="https://www.bilibili.com/blackboard/topic/activity-jjR1nNRUF.html">https://www.bilibili.com/blackboard/topic/activity-jjR1nNRUF.html</a></td></tr><tr><td>注意：本程序不提供付费视频解析服务，若您需要下载大会员专享内容，请登录大会员账号。程序支持扫码登录、账号密码*登录和验证码登录三种方式。</td><td></td><td></td></tr></tbody></table><ul><li>支持下载的弹幕 &amp; 字幕 &amp; 封面格式</li></ul><table><thead><tr><th>类型</th><th>支持下载的格式</th><th>备注</th></tr></thead><tbody><tr><td><strong>弹幕</strong></td><td><code>xml</code>, <code>protobuf</code></td><td>&#x2F;</td></tr><tr><td><strong>字幕</strong></td><td><code>srt</code>, <code>txt</code>, <code>json</code></td><td>需要登录才可下载</td></tr><tr><td><strong>封面</strong></td><td><code>jpg</code></td><td>&#x2F;</td></tr></tbody></table><ul><li>支持下载的清晰度</li></ul><table><thead><tr><th>类型</th><th>说明</th></tr></thead><tbody><tr><td><strong>超高清 8K</strong></td><td>自行登录大会员账号使用</td></tr><tr><td><strong>杜比视界</strong></td><td>自行登录大会员账号使用</td></tr><tr><td><strong>真彩 HDR</strong></td><td>自行登录大会员账号使用</td></tr><tr><td><strong>超清 4K</strong></td><td>自行登录大会员账号使用</td></tr><tr><td><strong>高清 1080P60</strong></td><td>即 1080P 60帧</td></tr><tr><td><strong>高清 1080P+</strong></td><td>即 1080P 高码率</td></tr><tr><td><strong>智能修复</strong></td><td>部分年代久远的剧集支持</td></tr><tr><td><strong>高清 1080P</strong></td><td>&#x2F;</td></tr><tr><td><strong>高清 720P</strong></td><td>&#x2F;</td></tr><tr><td><strong>清晰 480P</strong></td><td>&#x2F;</td></tr><tr><td><strong>流畅 360P</strong></td><td>&#x2F;</td></tr><tr><td>可在设置中更改默认下载清晰度为 <strong>自动</strong> 程序将自动获取每个视频的最高可用清晰度，避免多个视频最高清晰度不统一，无法同时下载最高清晰度的情况。</td><td></td></tr></tbody></table><h3 id="安装与使用"><a href="#安装与使用" class="headerlink" title="安装与使用"></a>安装与使用</h3><ol><li><p>打开 <a href="https://github.com/ScottSloan/Bili23-Downloader/releases/">Github-Bili23-Downloader</a> 下载应用程序（给开发者顺便点个 <strong>Star</strong> ），解压后运行 <strong>GUI.exe</strong> （注意：管理员身份运行本程序，若仍无法运行，请尝试修复 C++ 运行库。）<br><img src="https://img.zrf.me/20250204163432499.webp" alt="1"></p></li><li><p>由于 <strong>B站</strong> 限制，未登录状态下无法下载高清晰度视频，建议您登录后使用本程序。<br><img src="https://img.zrf.me/20250204165031590.webp" alt="2"></p></li><li><p>推荐这款软件最重要的原因就是 <strong>视频合集下载</strong> 与 <strong>多线程下载</strong> 我们接下来演示一下这两个功能。</p></li></ol><p><strong>视频合集下载</strong></p><ol><li><p>：我们找<a href="https://space.bilibili.com/385805493">自说自话的总裁</a>的视频合集<a href="https://www.bilibili.com/video/BV1zr4y1o7q4">总裁聊聊</a>进行演示，直接复制视频链接。<br><img src="https://img.zrf.me/20250204170044680.webp" alt="视频合集下载1"></p></li><li><p>将视频链接粘贴到地址栏中，点击 <strong>Get</strong> 按钮开始解析视频链接，可在设置中更改默认下载清晰度为 <strong>自动</strong>，程序将自动获取每个视频的最高可用清晰度，避免多个视频最高清晰度不统一，无法同时下载最高清晰度的情况。（部分视频类型可直接输入编号：视频 av、BV 号 剧集 ep、md、ss 号）<br><img src="https://img.zrf.me/20250204172548977.webp" alt="视频合集下载2"></p></li><li><p>可以看到速度还是不错的，但是总裁的视频不是4K或8K,只为测试 <strong>视频合集下载</strong> 功能。<br><img src="https://img.zrf.me/20250204173050579.webp" alt="视频合集下载3"></p></li></ol><p><strong>多线程下载</strong> </p><ol><li><p>我们在软件界面 <strong>工具</strong> → <strong>设置</strong> → <strong>下载</strong> → <strong>多线程数</strong> 调至最高 8<br><img src="https://img.zrf.me/20250204184958750.webp" alt="多线程下载1"></p></li><li><p>换个8K视频测试，可以看到我的清晰度选择的 <strong>自动</strong>  下载时是给我按照最高清晰度进行下载的。<br><img src="https://img.zrf.me/20250204184412566.webp" alt="多线程下载2"> </p></li><li><p>测试下载速度，最快跑到 <strong>60 MB&#x2F;s</strong> 左右，均值在 <strong>55 MB&#x2F;s</strong> 左右，超级快呢，当然下载速度是根据你的网络带宽而定。<br><img src="https://img.zrf.me/20250204184021072.webp" alt="多线程下载3"></p></li></ol><p><strong>到此，这款软件介绍完毕，其他更多使用功能，请自行探索！</strong> </p><hr><h2 id="哔哩哔哩下载助手（浏览器插件）"><a href="#哔哩哔哩下载助手（浏览器插件）" class="headerlink" title="哔哩哔哩下载助手（浏览器插件）"></a>哔哩哔哩下载助手（浏览器插件）</h2><ul><li><p>开发者公告： <strong>注意：收到B站律师函了，近期将会从各商店下架，已经安装的大家应该是可以继续使用的。</strong> </p></li><li><p>开发者既然这么说了，那我不得不保存一下。Github私库部署教程参考：<a href="https://blog.zrf.me/p/Notes-GitHub-PicList-Vercel/">GitHub + PicList + Vercel 免费搭建高速图床，使用 CDN 轻松加速访问！</a></p></li></ul><h3 id="安装与使用-1"><a href="#安装与使用-1" class="headerlink" title="安装与使用"></a>安装与使用</h3><ol><li><p>打开下方地址，根据你使用的浏览器选择，如 <strong>Chrome 内核</strong> 的浏览器基本都可以使用 <strong>Google Chrome</strong> 的安装，都没有选择 <strong>crx文件</strong> 手动安装。(目前最新版3.0.2) </p><blockquote><ul><li><a href="https://chromewebstore.google.com/detail/bfcbfobhcjbkilcbehlnlchiinokiijp">Google Chrome 扩展商店安装</a></li><li><a href="https://microsoftedge.microsoft.com/addons/detail/cagicamgdlbdmonbclkpgiabbldodgae">Microsoft Edge 扩展商店安装</a></li><li><a href="https://images.aizrf.com/bilibili-helper-3.0.2.crx">Github博主私库-下载crx文件</a></li></ul></blockquote></li><li><p>打开B站视频的播放页面，正常可以看到右下角有一个按钮 <strong>打开B站下载助手</strong> ， 右侧点击 <strong>收起</strong> 可以把助手缩小成一个按钮（页面右下角处），下载过程中也可以点 <strong>收起</strong> ，我们在播放器中切换 <strong>视频清晰度</strong> ，下方解析的下载地址也会随着解析。<br><img src="https://img.zrf.me/20250205010159704.webp" alt="哔哩哔哩下载助手1"></p></li></ol><ul><li>其中下载模式又分为 <strong>高级模式</strong> 与 <strong>兼容模式</strong> 两种！</li></ul><p><strong>高级模式</strong></p><ol><li><p><strong>合并下载</strong> ：支持自动重命名（给你重命名为视频资源的标题）和自动合并分段（一般下载视频分为 <strong>音频</strong> 与 <strong>画面</strong> 两个资源或视频分为很多段，帮你自动合并在一起。）一般常用到此功能。<br><img src="https://img.zrf.me/20250204203238116.webp" alt="高级模式1"></p></li><li><p>关闭 <strong>合并下载</strong> ：有些使用者，可能会使用到我只要音频或视频，自己去剪辑一些内容，就可单独选择一个资源去下载！<br><img src="https://img.zrf.me/20250204204642020.webp" alt="高级模式2"></p></li></ol><p><strong>兼容模式</strong></p><ol><li><p>兼容模式直接使用浏览器的默认下载（主要是可以调用多线程下载工具），资源占用很小，但不支持自动重命名和合并下载。必须右键另存为方式下载。<br><img src="https://img.zrf.me/20250204205505405.webp" alt="兼容模式1"></p></li><li><p>浏览器默认的下载速度肯定没多线程下载工具的快！<br><img src="https://img.zrf.me/20250204212138828.webp" alt="兼容模式2"></p></li><li><p>使用<a href="https://blog.zrf.me/p/FileCentipede/">文件蜈蚣</a> ，等截图素材马上都快下完了，峰值在 <strong>120 MB&#x2F;s</strong> 左右，均值在 <strong>90 MB&#x2F;s</strong> 左右，哥们快不快就完事了。<br><img src="https://img.zrf.me/20250204210631695.webp" alt="兼容模式3"></p></li><li><p>使用<a href="https://blog.zrf.me/p/IDM-Crack/">IDM</a> , 右键选择 <strong>使用IDM下载</strong> ，峰值一闪而过没截图到，峰值在 <strong>100 MB&#x2F;s</strong> 左右，均值在 <strong>80 MB&#x2F;s</strong> 左右<br><img src="https://img.zrf.me/20250204213119765.webp" alt="兼容模式4"></p></li></ol><p><strong>到此，这款浏览器插件介绍完毕，其他更多使用功能，请自行探索！</strong> </p><hr><h2 id="博主总结"><a href="#博主总结" class="headerlink" title="博主总结"></a>博主总结</h2><p>下载工具对比</p><table><thead><tr><th>特性</th><th><strong>Bili23-Downloader</strong></th><th><strong>哔哩下载助手插件</strong></th></tr></thead><tbody><tr><td><strong>跨平台兼容性</strong></td><td>✅ Windows&#x2F;Linux&#x2F;macOS</td><td>❌ 仅限浏览器插件</td></tr><tr><td><strong>功能全面性</strong></td><td>✅ 支持直播录制、分P解析、高弹幕字幕格式</td><td>❌ 仅提供基本下载</td></tr><tr><td><strong>下载速度</strong></td><td>✅ 多线程（最高8线程），最高60MB&#x2F;s</td><td>✅ 依赖外部工具（IDM等）提升速度</td></tr><tr><td><strong>使用便捷性</strong></td><td>❌ 需安装、配置</td><td>✅ 浏览器内一键解析</td></tr><tr><td><strong>合并下载</strong></td><td>✅ 自动合并音视频</td><td>✅ 提供合并模式</td></tr><tr><td><strong>版权受限资源下载</strong></td><td>❌ 需自行解决</td><td>❌ 需自行解决</td></tr><tr><td><strong>清晰度限制</strong></td><td>✅ 最高支持 8K（视账号权限）</td><td>✅ 最高支持 8K（视账号权限）</td></tr><tr><td><strong>稳定性</strong></td><td>✅ 受B站策略影响较小</td><td>❌ 可能因B站封锁失效</td></tr><tr><td><strong>法律风险</strong></td><td>✅ 开源项目，风险较低</td><td>❌ 插件作者已收到B站律师函</td></tr><tr><td><strong>适用人群</strong></td><td>适合开发者、大量下载需求者</td><td>适合普通用户、单次快速下载</td></tr><tr><td><strong>未来建议</strong></td><td>优先选择开源项目，关注更新</td><td>备份安装文件，防止插件下架</td></tr></tbody></table><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p>Github-Bili23-Downloader:<a href="https://github.com/ScottSloan/Bili23-Downloader/releases/">https://github.com/ScottSloan/Bili23-Downloader/releases/</a></p></blockquote><blockquote><p>哔哩下载助手插件:<a href="https://chromewebstore.google.com/detail/bfcbfobhcjbkilcbehlnlchiinokiijp">https://chromewebstore.google.com/detail/bfcbfobhcjbkilcbehlnlchiinokiijp</a></p></blockquote><blockquote><p>文件蜈蚣:<a href="https://blog.zrf.me/p/FileCentipede/">https://blog.zrf.me/p/FileCentipede/</a></p></blockquote><blockquote><p>IDM:<a href="https://blog.zrf.me/p/IDM-Crack/">https://blog.zrf.me/p/IDM-Crack/</a></p></blockquote><blockquote><p>GitHub + PicList + Vercel 免费搭建高速图床，使用 CDN 轻松加速访问！:<a href="https://blog.zrf.me/p/Notes-GitHub-PicList-Vercel/">https://blog.zrf.me/p/Notes-GitHub-PicList-Vercel/</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;B站视频下载全攻略-第三方工具推荐-PC-浏览器插件&quot;&gt;&lt;a href=&quot;#B站视频下载全攻略-第三方工具推荐-PC-浏览器插件&quot; class=&quot;headerlink&quot; title=&quot;B站视频下载全攻略 - 第三方工具推荐(PC&amp;#x2F;浏览器插件)&quot;&gt;&lt;/a&gt;</summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="浏览器插件" scheme="https://blog.zrf.me/tags/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8F%92%E4%BB%B6/"/>
    
    <category term="下载工具" scheme="https://blog.zrf.me/tags/%E4%B8%8B%E8%BD%BD%E5%B7%A5%E5%85%B7/"/>
    
    <category term="MacOS" scheme="https://blog.zrf.me/tags/MacOS/"/>
    
    <category term="Linux" scheme="https://blog.zrf.me/tags/Linux/"/>
    
    <category term="影音视听" scheme="https://blog.zrf.me/tags/%E5%BD%B1%E9%9F%B3%E8%A7%86%E5%90%AC/"/>
    
    <category term="bilibili" scheme="https://blog.zrf.me/tags/bilibili/"/>
    
    <category term="chrome" scheme="https://blog.zrf.me/tags/chrome/"/>
    
    <category term="破解" scheme="https://blog.zrf.me/tags/%E7%A0%B4%E8%A7%A3/"/>
    
    <category term="素材资源" scheme="https://blog.zrf.me/tags/%E7%B4%A0%E6%9D%90%E8%B5%84%E6%BA%90/"/>
    
  </entry>
  
  <entry>
    <title>GitHub + PicList + Vercel 免费搭建高速图床，使用 CDN 轻松加速访问！</title>
    <link href="https://blog.zrf.me/p/Notes-GitHub-PicList-Vercel/"/>
    <id>https://blog.zrf.me/p/Notes-GitHub-PicList-Vercel/</id>
    <published>2025-02-01T21:44:09.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="GitHub-PicList-Vercel-免费搭建高速图床，使用-CDN-轻松加速访问！"><a href="#GitHub-PicList-Vercel-免费搭建高速图床，使用-CDN-轻松加速访问！" class="headerlink" title="GitHub + PicList + Vercel 免费搭建高速图床，使用 CDN 轻松加速访问！"></a>GitHub + PicList + Vercel 免费搭建高速图床，使用 CDN 轻松加速访问！</h1><p>在博客中，我偶尔会想分享一些视频资源，但一直没有找到合适的视频图床方案。哔哩哔哩需要审核，而 Cloudflare R2 虽然稳定，但并非所有人都能开通，并且我也不想将视频资源存放在 R2 上。  </p><p>此前，我们曾介绍过如何打造个人图床：<a href="https://blog.zrf.me/p/Notes-CloudflareR2-PicGo/">免费稳定，Cloudflare R2 + PicGo + WebP Cloud，全球畅通无阻！</a> 但这次，我们采用更简单的方案——<strong>利用 GitHub 作为存储</strong>。  </p><p>通常情况下，GitHub 并不会主动审查私有仓库的内容或大小，<strong>只要不影响 GitHub 基础设施或违反服务条款，就不会被干预</strong>。因此，它可以成为一个不错的存储选择。</p><h2 id="效果浏览"><a href="#效果浏览" class="headerlink" title="效果浏览"></a>效果浏览</h2><ol><li><p>金克斯，图片大小为 <strong>19.7 MB</strong><br>直链：<a href="https://images.aizrf.com/20250202154648625.webp">https://images.aizrf.com/20250202154648625.webp</a><br><img src="https://images.aizrf.com/20250202154648625.webp" alt="金克斯"></p></li><li><p>柯洁恶搞视频，视频大小为 <strong>22.8 MB</strong><br>直链：<a href="https://images.aizrf.com/20250202072513106.MP4">https://images.aizrf.com/20250202072513106.MP4</a></p></li></ol><p><video     src="https://images.aizrf.com/20250202072513106.MP4"    title="柯洁恶搞视频"    controls    style="width:100%; height:auto; max-height:90vh; object-fit:cover;"><br></video></p><ol><li><a href="https://space.bilibili.com/15385187">@兔总裁s</a> <a href="https://www.bilibili.com/video/BV1ixFtefE5j">串门路上偶遇学姐跳舞！</a> ，视频大小为  <strong>18.4 MB</strong><br>直链：<a href="https://images.aizrf.com/20250202174408668.mp4">https://images.aizrf.com/20250202174408668.mp4</a></li></ol><p><video src="https://images.aizrf.com/20250202174408668.mp4"       title="兔总裁s"       controls       style="width:100%; height:auto; max-height:90vh; object-fit:cover;"><br></video></p><ol><li>IDM 6.42 ，浏览器直接下载可能报毒，压缩包大小为 <strong>23.3 MB</strong><br>直链：<a href="https://images.aizrf.com/20250202175503956.zip">https://images.aizrf.com/20250202175503956.zip</a></li></ol><hr><h2 id="事前准备"><a href="#事前准备" class="headerlink" title="事前准备"></a>事前准备</h2><ul><li>域名（<strong>非必须</strong>，你也可以使用免费域名，或者<code>Vercel</code>分配的域名也可以）</li><li><a href="https://github.com/">GitHub</a>（<strong>必须</strong>，你需要注册一个GitHub帐号）</li><li><a href="https://vercel.com/">Vercel</a>（<strong>必须</strong>，你需要注册一个Vercel帐号，你也可以直接使用<code>Vercel</code>分配的域名，当然你也可以使用Cloudflare部署，基本步骤流程一样。）</li></ul><h2 id="创建Github私库并获取Token"><a href="#创建Github私库并获取Token" class="headerlink" title="创建Github私库并获取Token"></a>创建Github私库并获取Token</h2><ol><li><p>创建一个Github仓库的私库,打开：<a href="https://github.com/new">https://github.com/new</a>看图设置，项目名称随你设置，最后点击 <strong>Create repository</strong> 完成创建！<br><img src="https://img.zrf.me/20250202054751059.webp" alt="1"></p></li><li><p>获取 <strong>Github Token</strong> 打开：<a href="https://github.com/settings/tokens">https://github.com/settings/tokens</a>，然后点击 <strong>Generate new Token(Classic)</strong> ，把 <strong>repo</strong> 的勾打上，根据自己的需要设定过期时间(我设置的不过期)。然后翻到页面最底部，点击 <strong>Generate Token</strong> 的绿色按钮生成token。<br><img src="https://img.zrf.me/20250202071916748.webp" alt="2"></p></li><li><p>Token只会显示一次，请复制Token后存到安全的地方，稍后设置软件需要用到，Github的相关设置完成！<br><img src="https://img.zrf.me/20250202072039858.webp" alt="3"></p></li></ol><h2 id="Vercel部署"><a href="#Vercel部署" class="headerlink" title="Vercel部署"></a>Vercel部署</h2><ol><li><p>使用Vercel部署 打开：<a href="https://vercel.com/new">https://vercel.com/new</a> 选择你刚创建的私库！<br><img src="https://img.zrf.me/20250202070704251.webp" alt="4"></p></li><li><p>直接点击 <strong>Deploy</strong> 部署即可，项目名称随你设置，我就默认了，等待部署完成。<br><img src="https://img.zrf.me/20250202070834295.webp" alt="5"></p></li><li><p>给项目设置自定义域名，套上 CDN 加速。这里我就不细说了，不想写过于重复的内容，详细教程参考：<a href="https://blog.zrf.me/p/55/">https://blog.zrf.me/p/55/</a> 其实就是设置个自定义域名，然后 <strong>CNAME</strong> 内容设置为 <code>vercel.001315.xyz</code> 。就套上加速了。<br><img src="https://img.zrf.me/20250202161310300.webp" alt="6"><br><img src="https://img.zrf.me/20250202161651346.webp" alt="7"></p></li><li><p>完成上一步操作后你设置的自定义域名，稍后设置软件需要用到，Vercel的相关设置完成！</p></li></ol><h2 id="Cloudflare部署"><a href="#Cloudflare部署" class="headerlink" title="Cloudflare部署"></a>Cloudflare部署</h2><ul><li>可选项！！！这两个部署选一个就行，因为Vercel部署有现成的加速方案，我一般偏向使用Vercel进行部署，Cloudflare部署，我是没有什么好的加速方案，所以就不详细演示了。基本同理操作就是没有上方的套 CDN 加速的步骤。</li></ul><ol><li><p>选择你刚创建的私库。<br><img src="https://img.zrf.me/20250202180755597.webp" alt="8"></p></li><li><p>保存并部署。<br><img src="https://img.zrf.me/20250202071155816.webp" alt="9"></p></li></ol><h2 id="PicList相关设置"><a href="#PicList相关设置" class="headerlink" title="PicList相关设置"></a>PicList相关设置</h2><ol><li><p>下载及详细教程参考：<a href="https://blog.zrf.me/p/PicList/#%E7%AE%80%E5%8D%95%E5%AE%89%E8%A3%85%E5%92%8C%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B">PicList - 一款高效的云存储和图片托管平台管理工具</a> 如果你之前没用过PicGo，忽视 <strong>2.PicGo 迁移</strong> 步骤，忽视 <strong>3.设置 AWS S3</strong> 步骤。其他都可以按照教程设置一下，设置完成我们看下一步。</p></li><li><p>好，默认你已经完成上面的相关设置。点击软件界面中的 <strong>图床</strong> → <strong>Gihub</strong> → <strong>设置修改</strong><br><img src="https://img.zrf.me/20250202073634772.webp" alt="10"></p></li><li><p>按照下方图片进行设置，设置完成最后点击确定保存！</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&quot;图床配置名&quot; = 图床配置名，你自己随意设置</span><br><span class="line">&quot;设定仓库名&quot; = 格式是username/reponame，你的Github用户名/仓库地址，例如:zrf/images</span><br><span class="line">&quot;设定分支名&quot; = 分支名，默认是main</span><br><span class="line">&quot;设定Token&quot; = Github token</span><br><span class="line">&quot;设定储存路径&quot; = 用于指定图片存储位置，不填写则默认存储在默认位置，自定义存储路径，例如:img/</span><br><span class="line">&quot;设定自定义域名&quot; = 用于指定图片自定义域名，一般用于CDN加速。自定义域名，注意要加http://或者https://，域名最后面的/不要加</span><br></pre></td></tr></table></figure><p><img src="https://img.zrf.me/20250202171334535.webp" alt="11"></p></li><li><p>软件首页 <strong>上传区</strong> 切换使用你的Github图床，也可在  <strong>图床</strong> → <strong>Gihub</strong> → <strong>设置为默认图床</strong><br><img src="https://img.zrf.me/20250202171943207.webp" alt="12"></p></li><li><p>你可以使用 <strong>PicList</strong> 上传图片视频以及压缩包等，Github 支持很多上传格式，到此就完成了图床的所有设置！<br><img src="https://img.zrf.me/20250202172328817.webp" alt="13"></p></li></ol><h2 id="博主总结"><a href="#博主总结" class="headerlink" title="博主总结"></a>博主总结</h2><p>选择 Vercel （或 Cloudflare） 进行项目部署并配置自定义域名，实现 CDN 加速，该方案不仅满足了图片、视频和压缩包等多种格式的云存储需求，同时也提高了资源加载速度和使用体验，是面向开发者和站长的实用教程。通过本教程，用户将能够高效构建一个具备完整图床服务的云存储平台，有效提升项目部署和内容分发的效率。</p><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p>Vercel托管站点提速小技巧 :<a href="https://blog.zrf.me/p/55">https://blog.zrf.me/p/55</a></p></blockquote><blockquote><p>PicList - 一款高效的云存储和图片托管平台管理工具 :<a href="https://blog.zrf.me/p/PicList">https://blog.zrf.me/p/PicList</a></p></blockquote><blockquote><p>打造个人图床神器：免费稳定，Cloudflare R2 + PicGo + WebP Cloud，全球畅通无阻！ :<a href="https://blog.zrf.me/p/Notes-CloudflareR2-PicGo">https://blog.zrf.me/p/Notes-CloudflareR2-PicGo</a></p></blockquote><blockquote><p>Fscarmen佬 图床方案 佬的视频我看着想睡觉一直没真正看完过 :<a href="https://www.youtube.com/@fscarmen">https://www.youtube.com/@fscarmen</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;GitHub-PicList-Vercel-免费搭建高速图床，使用-CDN-轻松加速访问！&quot;&gt;&lt;a href=&quot;#GitHub-PicList-Vercel-免费搭建高速图床，使用-CDN-轻松加速访问！&quot; class=&quot;headerlink&quot; title=&quot;Gi</summary>
      
    
    
    
    <category term="教程笔记" scheme="https://blog.zrf.me/categories/%E6%95%99%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="MacOS" scheme="https://blog.zrf.me/tags/MacOS/"/>
    
    <category term="Linux" scheme="https://blog.zrf.me/tags/Linux/"/>
    
    <category term="办公" scheme="https://blog.zrf.me/tags/%E5%8A%9E%E5%85%AC/"/>
    
    <category term="图像软件" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="hexo" scheme="https://blog.zrf.me/tags/hexo/"/>
    
    <category term="Vercel" scheme="https://blog.zrf.me/tags/Vercel/"/>
    
    <category term="图床" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%BA%8A/"/>
    
    <category term="图像处理" scheme="https://blog.zrf.me/tags/%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86/"/>
    
    <category term="素材资源" scheme="https://blog.zrf.me/tags/%E7%B4%A0%E6%9D%90%E8%B5%84%E6%BA%90/"/>
    
  </entry>
  
  <entry>
    <title>ODE 多功能助手 - 百度网盘下载工具 拥有还不错的速率</title>
    <link href="https://blog.zrf.me/p/ODE/"/>
    <id>https://blog.zrf.me/p/ODE/</id>
    <published>2025-01-29T18:17:21.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ODE-多功能助手-百度网盘下载工具-🖥️"><a href="#ODE-多功能助手-百度网盘下载工具-🖥️" class="headerlink" title="ODE 多功能助手 - 百度网盘下载工具 🖥️"></a>ODE 多功能助手 - 百度网盘下载工具 🖥️</h1><h2 id="简单介绍"><a href="#简单介绍" class="headerlink" title="简单介绍"></a>简单介绍</h2><p><strong>ODE 多功能助手</strong> 简称 <strong>ODE</strong> 由 <strong>窝头</strong> 开发者所开发的一款百度网盘下载工具，目前只有百度网盘解析下载功能，开发者称会以多功能生态为主扩展开发此款应用，期待有更多更好的功能。<br>昨天在逛B站的时候发现了这款软件，下载下来还不错。测试下载速度可达到 <strong>10MB&#x2F;s</strong> 比起百度网盘的几十KB速度快了不少了。目前开发者更新到1.1.1版本。</p><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><p><img src="https://img.zrf.me/20250130170825160.webp" alt="界面预览"></p><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li><strong>还不错的速率</strong>：博主测试下载速度可达到 <strong>10MB&#x2F;s</strong>，比起百度网盘的几十KB速度快了不少了。  </li><li><strong>自动解析链接</strong>：粘贴百度网盘分享链接，包含提取码的链接可自动识别。</li></ul><h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h2><ol><li>打开软件，点击左侧的 <strong>「链接解析」</strong> 图标，粘贴百度网盘分享链接（包含提取码的链接可自动识别），点击 <strong>「开始处理」</strong>。<br><img src="https://img.zrf.me/20250130172523829.webp" alt="链接解析"></li><li>解析完成后，勾选你要下载的文件，选择下载存储位置，这你自己随意设置，点击 <strong>「确认」</strong> 。<br><img src="https://img.zrf.me/20250130175204955.webp" alt="选择存储位置"></li><li>阅读 <strong>「ODE下载声明」</strong> ，勾选并同意，点击 <strong>「下一步」</strong> ，再次点击 <strong>「确认」</strong> 。<br><img src="https://img.zrf.me/20250130180112935.webp" alt="ODE下载声明"></li><li>我这里出现了 <strong>「空间满载，正在使用人数过多」</strong> 的提示，如你也出现这样的提示，可多次点击 <strong>「确认」</strong> 或者换个时间段下载，毕竟这个软件是开发者提供的公益服务，你也不能要求太多。<br><img src="https://img.zrf.me/20250130180618608.webp" alt="空间满载"></li><li>最后点击左侧的 <strong>「传输列表」</strong> 中就可以看到你正在下载的任务。我这里测试下载速度可达到 <strong>10MB&#x2F;s</strong> 在这个速度左右，有这个软件备用很不错的，比起百度网盘的几十KB速度快了不少了！！！<br><img src="https://img.zrf.me/20250130181630653.webp" alt="下载文件"></li></ol><h2 id="博主总结"><a href="#博主总结" class="headerlink" title="博主总结"></a>博主总结</h2><p>ODE 多功能助手是一款功能强大且操作简便的百度网盘下载工具，尤其在下载速度方面表现出色。尽管可能会遇到服务器负载问题，但作为一款公益服务，值得考虑作为备用下载工具。期待开发者未来扩展更多功能，为用户提供更全面的服务。</p><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p> ODE 多功能助手 Setup 1.1.0.exe 提取码:vPB0 :<a href="https://caiyun.139.com/m/i?105CqGTCYnoVC">https://caiyun.139.com/m/i?105CqGTCYnoVC</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ODE-多功能助手-百度网盘下载工具-🖥️&quot;&gt;&lt;a href=&quot;#ODE-多功能助手-百度网盘下载工具-🖥️&quot; class=&quot;headerlink&quot; title=&quot;ODE 多功能助手 - 百度网盘下载工具 🖥️&quot;&gt;&lt;/a&gt;ODE 多功能助手 - 百度网盘下载</summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="下载工具" scheme="https://blog.zrf.me/tags/%E4%B8%8B%E8%BD%BD%E5%B7%A5%E5%85%B7/"/>
    
    <category term="破解" scheme="https://blog.zrf.me/tags/%E7%A0%B4%E8%A7%A3/"/>
    
    <category term="百度网盘" scheme="https://blog.zrf.me/tags/%E7%99%BE%E5%BA%A6%E7%BD%91%E7%9B%98/"/>
    
  </entry>
  
  <entry>
    <title>IDM 破解版 - PC电脑端必装的高速下载器，永久免费版安装教程！下载速度超高速提升!</title>
    <link href="https://blog.zrf.me/p/IDM-Crack/"/>
    <id>https://blog.zrf.me/p/IDM-Crack/</id>
    <published>2025-01-27T14:38:03.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="IDM-破解版-🖥️"><a href="#IDM-破解版-🖥️" class="headerlink" title="IDM 破解版 🖥️"></a>IDM 破解版 🖥️</h1><p><strong>Internet Download Manager</strong>（简称 <strong>IDM</strong>）是一款功能强大、下载速度超快的应用程序，可以将下载速度提升至 <strong>5 倍</strong>。作为一款广受欢迎的下载管理工具，IDM 不仅拥有直观的用户界面，还具备多种智能功能，为用户提供高效便捷的下载体验。</p><hr><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><div class="gallery-container waterfall">        <div class="gallery-item"><img class="nolazyload" src=https://img.zrf.me/20250128004827262.webp alt="界面预览" /></div><div class="gallery-item"><img class="nolazyload" src=https://img.zrf.me/20250128004854840.webp alt="界面预览" /></div><div class="gallery-item"><img class="nolazyload" src=https://img.zrf.me/20250128004956068.webp alt="界面预览" /></div><div class="gallery-item"><img class="nolazyload" src=https://img.zrf.me/20250128005126320.gif alt="界面预览" /></div><div class="gallery-item"><img class="nolazyload" src=https://img.zrf.me/20250128005157927.gif alt="界面预览" /></div><div class="gallery-item"><img class="nolazyload" src=https://img.zrf.me/20250128005234989.gif alt="界面预览" /></div>      </div><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li><p><strong>高速下载</strong><br>IDM 可将下载速度提高至 <strong>5 倍</strong>，通过智能加速技术和动态下载文件，优化文件下载过程，确保最大带宽的使用。</p></li><li><p><strong>多协议支持</strong><br>支持 <strong>FTP、HTTP、HTTPS</strong> 协议，兼容代理服务器、防火墙、Cookies 和授权验证等多种功能。</p></li><li><p><strong>支持断点续传</strong><br>IDM 破解版支持从下载停止的地方继续下载，无需重新开始，节省时间并确保文件完整。</p></li><li><p><strong>浏览器集成</strong><br>无缝集成到 <strong>Internet Explorer、Firefox、Chrome</strong>、Opera 等多款浏览器，自动捕获下载链接，无需手动操作。</p></li><li><p><strong>离线浏览器抓取</strong><br>支持下载整个网站或其子集，方便离线浏览。可以定时执行抓取任务，定期同步网页内容。</p></li><li><p><strong>智能下载管理</strong><br>支持批量下载、下载队列管理以及文件分类，自动整理文件，优化下载体验。</p></li></ul><h2 id="高级功能"><a href="#高级功能" class="headerlink" title="高级功能"></a>高级功能</h2><ul><li><p><strong>定时下载与自动操作</strong><br>可以设置在特定时间连接互联网，下载所需的文件，完成后自动断开连接或关闭计算机。</p></li><li><p><strong>多语言支持</strong><br>支持多种语言，包括中文、英文、法语、德语、阿拉伯语等，为全球用户提供便利。</p></li><li><p><strong>Windows 兼容性</strong><br>兼容 <strong>Windows 7、8、8.1、10</strong> 和 <strong>Windows 11</strong>，以及各种浏览器和平台，支持最新的 Windows 系统。</p></li><li><p><strong>带宽控制与配额</strong><br>支持设置下载配额，限制每小时下载的最大文件大小，适用于使用 <strong>FAP</strong>（公平接入策略）等网络环境。</p></li></ul><h2 id="安装与使用"><a href="#安装与使用" class="headerlink" title="安装与使用"></a>安装与使用</h2><ol><li><p><strong>下载安装包</strong>  </p><p>打开 IDM官方下载地址 <a href="https://www.internetdownloadmanager.com/download.html">https://www.internetdownloadmanager.com/download.html</a> 下载 IDM 安装包并进行安装，或使用我提供的安装包直接安装也行<a href="https://blog.zrf.me/p/IDM-Crack/#%E7%9B%B8%E5%85%B3%E9%93%BE%E6%8E%A5">直达相关链接　下载</a>  <strong>（一个以“f”结尾的是零售版，另一个是完整版。选择完整版。）</strong> 安装默认一直下一步就可以了！</p></li></ol><p> <img src="https://img.zrf.me/20250128005710499.webp" alt="下载"></p><ol start="2"><li><p><strong>应用破解补丁</strong>  </p><p>安装完成后，使用并应用 IDM 破解补丁，激活完整版 IDM。</p></li></ol><p> <img src="https://img.zrf.me/20250128010022674.webp" alt="破解补丁"><br> <img src="https://img.zrf.me/20250128004145720.webp" alt="激活"></p><ol start="3"><li><p><strong>开启浏览器扩展</strong>  </p><p>安装完成后，IDM 扩展会自动在 Windows 10、Windows 11 或更高版本的 Chrome 上弹出或安装，并且需要你手动开启一下，打开浏览器 <strong>扩展程序</strong> 找到插件并开启。如果没有安装可以手动安装！</p></li></ol><blockquote><ul><li><a href="https://chromewebstore.google.com/detail/idm-integration-module/ngpampappnmepgilojfohadhhmbhlaek">Google Chrome</a></li><li><a href="https://addons.mozilla.org/en-US/firefox/addon/tonec-idm-integration-module/">Mozilla Firefox</a></li><li><a href="https://microsoftedge.microsoft.com/addons/detail/idm-integration-module/llbjbkhnmlidjebalopleeepgdfgcpec">Microsoft Edge</a></li></ul></blockquote><p> <img src="https://img.zrf.me/20250128020735199.webp" alt="开启浏览器扩展"></p><ol start="4"><li><p><strong>简单设置</strong>  </p><p>破解完成，启动 IDM，打开你的IDM，打开 <strong>下载</strong> &gt; <strong>选项</strong> ，然后点击 <strong>连接</strong> 选项卡。更改<strong>默认最大连接数</strong>到 16、24 或 32。</p></li></ol><p> <img src="https://img.zrf.me/20250128010830465.webp" alt="最大连接数"></p><ol start="5"><li><p><strong>下载微软官方Windows11 ISO 测速</strong>  </p><p>打开视频地址，默认右上角可见 <strong>下载该视频</strong> 按钮点击即可下载。使用 YouTube 视频下载进行测速不太精准。我使用 <strong>Windows11 ISO</strong> 为例，左边为Chrome下载，右边是IDM下载， <strong>（同一网网络，同一资源，微软偶尔抽风很慢，我这就遇到了）</strong> IDM 看到跑满了我的带宽，一个5G的文件，不到一分钟就下载完成了，当然速度是根据你的网络带宽而定。</p></li></ol><p> <img src="https://img.zrf.me/20250128015830134.webp" alt="YouTube"><br> <img src="https://img.zrf.me/20250128023818954.webp" alt="Windows"></p><hr><h2 id="免责声明"><a href="#免责声明" class="headerlink" title="免责声明"></a>免责声明</h2><p>本文所涉及的 Internet Download Manager（IDM）相关内容仅供个人学习、研究和参考使用。文中所提及的任何破解版、序列号或补丁均来源于网络，仅用于技术交流，严禁用于任何商业或非法用途。</p><p>作为博主，我承诺严格遵守相关法律法规，不会利用本项目或博文进行任何违法活动。若因使用本文中提及的内容引发任何纠纷或责任，均由使用者自行承担。博主不对因使用该项目或相关内容造成的任何直接或间接后果负责，同时保留追究违规使用者违法行为的权利。</p><p>请使用者在实践中遵守所在地区的相关法律法规，不得将本文中提及的内容用于任何形式的商业或非法活动。任何因违规操作或不当使用所产生的后果，均由使用者自行负责。同时，使用者应自行承担因使用本文所涉及内容而带来的所有风险和责任。</p><p>博主不对本文中提及的任何破解补丁、序列号或修改版本的完整性、可靠性和合法性作出任何保证。请务必确保您在使用这些内容时完全符合相关法律的要求。</p><p>感谢您的理解与支持！</p><hr><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p>IDM 6.42 提取码:o5bS :<a href="https://caiyun.139.com/m/i?105CpIzPBad8U">https://caiyun.139.com/m/i?105CpIzPBad8U</a></p></blockquote><blockquote><p>InfiniCLOUD（Download）:<a href="https://miya.teracloud.jp/share/11d1e10c7a0a1136">https://miya.teracloud.jp/share/11d1e10c7a0a1136</a></p></blockquote><blockquote><p>IDM 官网 :<a href="https://www.internetdownloadmanager.com/">https://www.internetdownloadmanager.com/</a></p></blockquote><blockquote><p>插件 Google Chrome :<a href="https://chromewebstore.google.com/detail/idm-integration-module/ngpampappnmepgilojfohadhhmbhlaek/">https://chromewebstore.google.com/detail/idm-integration-module/ngpampappnmepgilojfohadhhmbhlaek/</a></p></blockquote><blockquote><p>插件 Mozilla Firefox :<a href="https://addons.mozilla.org/en-US/firefox/addon/tonec-idm-integration-module/">https://addons.mozilla.org/en-US/firefox/addon/tonec-idm-integration-module/</a></p></blockquote><blockquote><p>插件 Microsoft Edge :<a href="https://microsoftedge.microsoft.com/addons/detail/idm-integration-module/llbjbkhnmlidjebalopleeepgdfgcpec/">https://microsoftedge.microsoft.com/addons/detail/idm-integration-module/llbjbkhnmlidjebalopleeepgdfgcpec/</a></p></blockquote><blockquote><p>参考资源 :<a href="https://abbaspc.net/idm-crack/">https://abbaspc.net/idm-crack/</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;IDM-破解版-🖥️&quot;&gt;&lt;a href=&quot;#IDM-破解版-🖥️&quot; class=&quot;headerlink&quot; title=&quot;IDM 破解版 🖥️&quot;&gt;&lt;/a&gt;IDM 破解版 🖥️&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;Internet Download Manager&lt;</summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="浏览器插件" scheme="https://blog.zrf.me/tags/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8F%92%E4%BB%B6/"/>
    
    <category term="下载工具" scheme="https://blog.zrf.me/tags/%E4%B8%8B%E8%BD%BD%E5%B7%A5%E5%85%B7/"/>
    
    <category term="破解" scheme="https://blog.zrf.me/tags/%E7%A0%B4%E8%A7%A3/"/>
    
  </entry>
  
  <entry>
    <title>SPlayer - 一款基于 NeteaseCloudMusicApi 构建的高颜值网易云在线音乐播放器。</title>
    <link href="https://blog.zrf.me/p/SPlayer-NeteaseCloudMusicApi/"/>
    <id>https://blog.zrf.me/p/SPlayer-NeteaseCloudMusicApi/</id>
    <published>2025-01-21T19:17:27.000Z</published>
    <updated>2025-01-21T19:17:27.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="SPlayer"><a href="#SPlayer" class="headerlink" title="SPlayer"></a>SPlayer</h1><p>SPlayer 是一款基于 NeteaseCloudMusicApi 构建的高颜值网易云在线音乐播放器，界面简洁清爽，无广告，在线畅听。</p><p>此项目前端 (SPlayer) 是由 <strong>imsyy</strong>  开发 采用 Vue 3 + TypeScript + Naïve UI + Electron 开发，提供网页版和 Windows 客户端，适配基础的移动端体验。<br>此项目后端API (NeteaseCloudMusicApi) 是由 <strong>Binaryify</strong> 开发 持续维护更新的网易云音乐第三方 API 。</p><h2 id="博主前言"><a href="#博主前言" class="headerlink" title="博主前言"></a>博主前言</h2><p>我的教程偏向小白用户，流程简单易懂，当然你也可以不懂，按教程操作即可轻松上手；大佬等进阶用户请随意探索。</p><h2 id="在线体验："><a href="#在线体验：" class="headerlink" title="在线体验："></a>在线体验：</h2><p>SPlayer:<a href="https://music.zrfme.com/">https://music.zrfme.com</a></p><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a>界面预览</h2><p><img src="https://img.zrf.me/20260302063024086.webp" alt="网页端界面预览"><br><img src="https://img.zrf.me/20260302063147467.webp" alt="移动端界面预览">  </p><h2 id="应用特点"><a href="#应用特点" class="headerlink" title="应用特点"></a>应用特点</h2><ul><li><p><strong>登录功能</strong>：</p><ul><li>支持扫码登录</li><li>支持手机号登录</li></ul></li><li><p><strong>签到功能</strong>：</p><ul><li>自动每日签到</li><li>自动云贝签到</li></ul></li><li><p><strong>桌面歌词</strong>：</p><ul><li>支持桌面歌词显示</li></ul></li><li><p><strong>本地模式</strong>：</p><ul><li>支持切换为本地播放器，无需网络连接</li></ul></li><li><p><strong>主题适配</strong>：</p><ul><li>封面主题色自动适应</li><li>支持全站着色</li></ul></li><li><p><strong>暗黑模式</strong>：</p><ul><li>支持 Light &#x2F; Dark &#x2F; Auto 模式自动切换</li></ul></li><li><p><strong>本地音乐管理</strong>：</p><ul><li>管理及分类本地歌曲</li><li>简易编辑音乐标签及修改封面</li></ul></li><li><p><strong>无版权歌曲播放</strong>：</p><ul><li>支持播放部分无版权歌曲（可能与原曲不匹配，为客户端独占功能）</li></ul></li><li><p><strong>下载功能</strong>：</p><ul><li>支持下载最高 Hi-Res 音质歌曲（需会员账号）</li></ul></li><li><p><strong>歌单管理</strong>：</p><ul><li>新建、编辑歌单</li><li>收藏 &#x2F; 取消收藏歌单或歌手</li></ul></li><li><p><strong>推荐功能</strong>：</p><ul><li>每日推荐歌曲</li><li>私人 FM</li></ul></li><li><p><strong>云盘功能</strong>：</p><ul><li>上传云盘音乐</li><li>播放云盘内歌曲</li><li>纠正云盘内歌曲信息</li><li>删除云盘内歌曲</li></ul></li><li><p><strong>歌词功能</strong>：</p><ul><li>支持逐字歌词</li><li>歌词滚动及翻译</li></ul></li><li><p><strong>视频功能</strong>：</p><ul><li>支持 MV 与视频播放</li></ul></li><li><p><strong>播放效果</strong>：</p><ul><li>音乐频谱显示</li><li>音乐渐入渐出效果</li></ul></li><li><p><strong>PWA 支持</strong>：</p><ul><li>提供渐进式 Web 应用体验</li></ul></li><li><p><strong>评论区支持</strong>：</p><ul><li>支持评论互动</li></ul></li><li><p><strong>移动端适配</strong>：</p><ul><li>提供基础的移动端界面支持</li></ul></li></ul><h2 id="事前准备"><a href="#事前准备" class="headerlink" title="事前准备"></a>事前准备</h2><ul><li>域名（<strong>非必须</strong>，你也可以使用免费域名，或者<code>Vercel</code>分配的域名也可以）</li><li><a href="https://github.com/">GitHub</a>（<strong>必须</strong>，你需要注册一个GitHub帐号）</li><li><a href="https://vercel.com/">Vercel</a>（<strong>必须</strong>，你需要注册一个Vercel帐号，你也可以直接使用<code>Vercel</code>分配的域名，当然你也可以使用Cloudflare部署，基本步骤流程一样。）</li></ul><h2 id="部署教程"><a href="#部署教程" class="headerlink" title="部署教程"></a>部署教程</h2><h3 id="部署网易云音乐-API"><a href="#部署网易云音乐-API" class="headerlink" title="部署网易云音乐 API"></a>部署网易云音乐 API</h3><ul><li><a href="https://d.zrf.me/tgq">加入群组获取</a></li></ul><ol><li><p>在Gitlab Fork 项目，打开：<a href="https://gitlab.com/Binaryify/neteasecloudmusicapi">https://gitlab.com/Binaryify/neteasecloudmusicapi</a> 开发者的地址， <strong>加入群组回复<code>网易云音乐API</code> 获得我修改的 API 版本，在原有的基础上，加入了一些不错的功能</strong> 。<br><img src="https://img.zrf.me/20250122040354601.webp" alt="Gitlab Fork1"><br><img src="https://img.zrf.me/20250122043437358.webp" alt="Gitlab Fork2"></p></li><li><p>首先打开<a href="https://vercel.com/new">https://vercel.com/new</a>去部署 <strong>网易云音乐 API</strong> ，选择 <strong>Gitlab</strong> 并选择你 fork 的此项目并点击 <strong>import</strong> 。<br><img src="https://img.zrf.me/20250122050923389.webp" alt="网易云音乐 API"><br><img src="https://img.zrf.me/20250122051004886.webp" alt="网易云音乐 API2"></p></li><li><p><strong>PROJECT NAME</strong> 自己填，这是项目名称，我就默认了，然后直接点 <strong>Deploy</strong> 接着等部署完成即可。<br><img src="https://img.zrf.me/20250122051602670.webp" alt="网易云音乐 API3"></p></li><li><p>去控制面板， <strong>Domains</strong> 下方的地址可以直接打开，其实这个地址也是你的 <strong>网易云音乐 API</strong> ，但是呢，我们不使用这个地址。因为大陆使用这个vercel提供给你的地址，你基本没法使用被墙的。除非你用科学上网才能正常使用，但你不可能时时刻刻都挂着科学上网吧。<br><img src="https://img.zrf.me/20250122051759283.webp" alt="网易云音乐 API4"><br><img src="https://img.zrf.me/20250122051952002.webp" alt="网易云音乐 API5"></p></li><li><p>给 <strong>网易云音乐 API</strong> 设置 <strong>Vercel-CDN加速</strong> ，使网站项目速度大幅提高，提升国内用户的访问体验，解析成功的域名就是你的 <strong>网易云音乐 API</strong> ，详细教程如下：<a href="https://vercel.001315.xyz/">https://vercel.001315.xyz/</a></p></li></ol><ul><li>到此完成网易云API部署的所有设置，获得 <strong>网易云音乐 API</strong> 地址，如下图中这个地址是下方步骤填写在 <strong>VITE_API_URL</strong> 中的切记别写错。<br><img src="https://img.zrf.me/20250130164040158.webp" alt="获得网易云AIP"></li></ul><h3 id="部署前端-SPlayer"><a href="#部署前端-SPlayer" class="headerlink" title="部署前端 SPlayer"></a>部署前端 SPlayer</h3><ol><li><p>在Github Fork 项目，打开：<a href="https://github.com/imsyy/SPlayer">https://github.com/imsyy/SPlayer</a><br><img src="https://img.zrf.me/20250122040643766.webp" alt="1"></p></li><li><p>打开<a href="https://vercel.com/new">https://vercel.com/new</a>去部署项目前端，选择 <strong>GitHub</strong> 并选择你 fork 的此项目并点击 <strong>import</strong><br><img src="https://img.zrf.me/20250122052112474.webp" alt="项目前端1"><br><img src="https://img.zrf.me/20250122052345051.webp" alt="项目前端2"></p></li><li><p>将 <strong>Build and Output Settings</strong> 中的 <strong>Output Directory</strong> 改为 <strong>out&#x2F;renderer</strong> ， <strong>VITE_API_URL</strong> 改为 <strong>网易云音乐 API 地址</strong> 然后直接点 <strong>Deploy</strong> 这次部署时间较长。等部署完成即可。</p></li></ol><ul><li>变量设置：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">VITE_WEB_PORT = 14558（默认不改）</span><br><span class="line">VITE_SERVER_PORT = 25884（默认不改）</span><br><span class="line">VITE_API_URL = 网易云音乐 API 地址结尾不要加 /（设置这一个就行）</span><br></pre></td></tr></table></figure><img src="https://img.zrf.me/20250122053538220.webp" alt="项目前端3"></li></ul><ol><li><p>出现这个页面就部署成功，点击卡片可以进入浏览，但是这次也建议你按照上方设置 <strong>Vercel-CDN加速</strong> ，我设置的是<a href="https://music.aizrf.com/">https://music.aizrf.com/</a> 将作为公开项目给大家<strong>学习研究使用，禁止用于商业及非法用途</strong>。<br><img src="https://img.zrf.me/20250122054354319.webp" alt="项目前端4"></p></li><li><p>右上角使用扫码登录，手机号登录貌似有问题，或者我不懂设置，登录后你可以看到你自己创建的歌单，收藏的歌单。<br><img src="https://img.zrf.me/20250122054900387.webp" alt="歌单"></p></li><li><p>开始畅享你的音乐生活！<br><img src="https://img.zrf.me/20250122060029189.webp" alt="VIP"></p></li></ol><h2 id="免责声明"><a href="#免责声明" class="headerlink" title="免责声明"></a>免责声明</h2><p>本文所涉及的项目部分功能基于网易云音乐的第三方 API 服务，仅供个人学习和研究使用，严禁用于任何商业或非法用途。</p><p>作为博主，我承诺严格遵守相关法律法规以及网易云音乐 API 的使用协议，不会利用该项目或博文进行任何违法活动。若因使用此项目引发任何纠纷或责任，均由使用者自行承担。博主不对因使用该项目造成的任何直接或间接后果负责，同时保留追究使用者违法行为的权利。</p><p>请使用者在实践中遵守相关法律法规，不得将此项目用于任何商业或非法活动。任何因违规操作而产生的后果均由使用者自行负责。同时，使用者应自行承担因使用此项目而带来的所有风险和责任。博主不对本项目所提供的服务或内容的完整性和可用性做出任何保证。</p><p>感谢您的理解与支持！</p><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><blockquote><p>网易云音乐 在线体验:<a href="https://music.zrfme.com/">https://music.zrfme.com</a></p></blockquote><blockquote><p>加入群组获取:<a href="https://d.zrf.me/tgq">https://d.zrf.me/tgq</a></p></blockquote><blockquote><p>SPlayer项目地址:<a href="https://github.com/imsyy/SPlayer">https://github.com/imsyy/SPlayer</a></p></blockquote><blockquote><p>网易云音乐API:<a href="https://gitlab.com/Binaryify/neteasecloudmusicapi">https://gitlab.com/Binaryify/neteasecloudmusicapi</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;SPlayer&quot;&gt;&lt;a href=&quot;#SPlayer&quot; class=&quot;headerlink&quot; title=&quot;SPlayer&quot;&gt;&lt;/a&gt;SPlayer&lt;/h1&gt;&lt;p&gt;SPlayer 是一款基于 NeteaseCloudMusicApi 构建的高颜值网易云在线音乐播放</summary>
      
    
    
    
    <category term="我的项目" scheme="https://blog.zrf.me/categories/%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="Cloudflare" scheme="https://blog.zrf.me/tags/Cloudflare/"/>
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="Windows" scheme="https://blog.zrf.me/tags/Windows/"/>
    
    <category term="日常" scheme="https://blog.zrf.me/tags/%E6%97%A5%E5%B8%B8/"/>
    
    <category term="音频软件" scheme="https://blog.zrf.me/tags/%E9%9F%B3%E9%A2%91%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="在线工具" scheme="https://blog.zrf.me/tags/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="破解" scheme="https://blog.zrf.me/tags/%E7%A0%B4%E8%A7%A3/"/>
    
    <category term="部署教程" scheme="https://blog.zrf.me/tags/%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/"/>
    
    <category term="DNS" scheme="https://blog.zrf.me/tags/DNS/"/>
    
    <category term="Vercel" scheme="https://blog.zrf.me/tags/Vercel/"/>
    
    <category term="CDN" scheme="https://blog.zrf.me/tags/CDN/"/>
    
    <category term="网易云" scheme="https://blog.zrf.me/tags/%E7%BD%91%E6%98%93%E4%BA%91/"/>
    
  </entry>
  
  <entry>
    <title>PiliPala - 简洁清爽的第三方 B站客户端 让你畅享全新B站体验的神器！</title>
    <link href="https://blog.zrf.me/p/PiliPala/"/>
    <id>https://blog.zrf.me/p/PiliPala/</id>
    <published>2025-01-20T17:28:09.000Z</published>
    <updated>2026-03-02T00:48:53.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="PiliPala"><a href="#PiliPala" class="headerlink" title="PiliPala"></a>PiliPala</h1><p>一款由 Flutter 开发的第三方 B站客户端，基于 B站官网的 API 构建，界面简洁清爽，无广告，体积小巧。</p><p>此项目 (PiliPala) 是个开发者为了人兴趣制作了这款客户端，并为其取名“噼里啪啦”。目前开发者着重移动端 (Android、iOS)，暂时没有适配桌面端、Pad 端、手表端等。</p><h2 id="界面预览"><a href="#界面预览" class="headerlink" title="界面预览"></a><strong>界面预览</strong></h2><p><img src="https://img.zrf.me/20250121014052262.webp" alt="界面预览"><br><img src="https://img.zrf.me/20250121014549068.webp" alt="界面预览"><br><img src="https://img.zrf.me/20250121014601189.webp" alt="界面预览"><br><img src="https://img.zrf.me/20250121014639249.webp" alt="界面预览"></p><h2 id="应用功能"><a href="#应用功能" class="headerlink" title="应用功能"></a><strong>应用功能</strong></h2><h3 id="推荐视频"><a href="#推荐视频" class="headerlink" title="推荐视频"></a><strong>推荐视频</strong></h3><ul><li>应用首页展示了<strong>最热视频列表</strong>和<strong>热门直播</strong>，确保你始终能看到最新的热门内容。同时，你还可以通过<strong>番剧列表</strong>找到自己喜欢的动画系列。如果你不想看到某些用户的视频，<strong>屏蔽黑名单内用户视频</strong>的功能非常实用。</li></ul><h3 id="排行榜"><a href="#排行榜" class="headerlink" title="排行榜"></a><strong>排行榜</strong></h3><ul><li>你可以随时查看视频的<strong>排行榜</strong>，了解当前最受欢迎的内容。</li></ul><h3 id="用户相关功能"><a href="#用户相关功能" class="headerlink" title="用户相关功能"></a><strong>用户相关功能</strong></h3><ul><li>在<strong>用户相关</strong>功能下，你可以方便地查看自己关注的用户、粉丝，或者管理<strong>拉黑用户</strong>。还可以直接访问用户的<strong>主页</strong>，并根据需求<strong>关注</strong>或<strong>取关</strong>某个用户。</li></ul><h3 id="离线缓存"><a href="#离线缓存" class="headerlink" title="离线缓存"></a><strong>离线缓存</strong></h3><ul><li>对于喜欢随时观看视频的朋友来说，<strong>离线缓存</strong>功能非常便捷。你可以将感兴趣的视频<strong>稍后再看</strong>，还可以随时查看你的<strong>观看记录</strong>和<strong>收藏</strong>，并管理自己的黑名单。</li></ul><h3 id="动态相关"><a href="#动态相关" class="headerlink" title="动态相关"></a><strong>动态相关</strong></h3><ul><li>应用提供了非常灵活的<strong>动态相关</strong>功能，支持按<strong>全部</strong>、<strong>投稿</strong>、<strong>番剧</strong>等分类查看动态。你可以查看和回复<strong>动态评论</strong>，并且动态界面还会标记<strong>未读</strong>内容，确保你不错过任何有趣的互动。</li></ul><h3 id="视频播放体验"><a href="#视频播放体验" class="headerlink" title="视频播放体验"></a><strong>视频播放体验</strong></h3><ul><li><p>视频播放方面，应用非常注重细节。你可以通过双击屏幕来实现<strong>快进&#x2F;快退</strong>和<strong>播放&#x2F;暂停</strong>，并且<strong>垂直方向手势</strong>可用来调节亮度和音量。<strong>上下滑动</strong>则可以轻松切换全屏或退出全屏模式，而<strong>水平方向手势</strong>则支持快速快进和快退。</p></li><li><p>此外，应用还提供了<strong>倍速选择</strong>，你可以通过<strong>长按2倍速</strong>按钮来加速播放；<strong>硬件加速</strong>功能（视机型而定）进一步提升了播放流畅度；你也可以根据需要调整视频的<strong>画质</strong>和<strong>音质</strong>（具体根据视频类型和设备不同而有所差异）。</p></li></ul><h3 id="视频详情"><a href="#视频详情" class="headerlink" title="视频详情"></a><strong>视频详情</strong></h3><ul><li><p>在视频详情页，你可以切换<strong>选集</strong>（分P视频），对视频进行<strong>点赞</strong>、<strong>投币</strong>、<strong>收藏&#x2F;取消收藏</strong>等操作。同时，<strong>相关视频</strong>推荐让你轻松发现更多感兴趣的内容。</p></li><li><p>评论部分支持<strong>评论用户身份标识</strong>，你可以查看<strong>主楼</strong>和<strong>二楼</strong>的评论，进行<strong>评论点赞</strong>和回复。还可以查看和保存<strong>评论笔记图片</strong>。</p></li></ul><h3 id="搜索功能"><a href="#搜索功能" class="headerlink" title="搜索功能"></a><strong>搜索功能</strong></h3><ul><li>搜索功能也是这款应用的亮点之一。你可以查看<strong>热搜</strong>，浏览自己的<strong>搜索历史</strong>，并通过<strong>默认搜索词</strong>快速查找视频。支持按<strong>投稿</strong>、<strong>番剧</strong>、<strong>直播间</strong>、<strong>用户</strong>进行搜索，甚至可以按照视频时长进行筛选，确保你快速找到自己想要的内容。</li></ul><h3 id="设置选项"><a href="#设置选项" class="headerlink" title="设置选项"></a><strong>设置选项</strong></h3><ul><li>在设置方面，应用支持灵活的<strong>画质</strong>、<strong>音质</strong>、<strong>解码方式</strong>预设，满足不同设备的需求。你还可以调整<strong>图片质量</strong>和<strong>主题模式</strong>（亮色&#x2F;暗色&#x2F;跟随系统）。对于喜欢震动反馈的用户，应用还提供了<strong>震动反馈</strong>选项，<strong>高帧率</strong>模式也能提供更平滑的观影体验。最后，<strong>自动全屏</strong>功能确保你能更专注于视频内容。</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a><strong>总结</strong></h2><p>PiliPala 是一款由 Flutter 开发的无广告、简洁高效的 B站第三方客户端，专注移动端（Android、iOS）。</p><p>它提供了丰富的功能，包括推荐视频、排行榜、离线缓存、动态管理、倍速播放等。用户可以通过流畅的手势操作调节视频播放，支持多种画质、音质设置，满足不同需求。同时，强大的搜索功能、灵活的评论管理和个性化设置让使用体验更加便捷。</p><p>总体来说，PiliPala 是一款功能全面、界面简洁、体验出色的 B站客户端。</p><h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a><strong>相关链接</strong></h2><blockquote><p>GitHub:<a href="https://github.com/guozhigq/pilipala/releases">https://github.com/guozhigq/pilipala/releases</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;PiliPala&quot;&gt;&lt;a href=&quot;#PiliPala&quot; class=&quot;headerlink&quot; title=&quot;PiliPala&quot;&gt;&lt;/a&gt;PiliPala&lt;/h1&gt;&lt;p&gt;一款由 Flutter 开发的第三方 B站客户端，基于 B站官网的 API 构建，界面简洁清</summary>
      
    
    
    
    <category term="软件推荐" scheme="https://blog.zrf.me/categories/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="开源" scheme="https://blog.zrf.me/tags/%E5%BC%80%E6%BA%90/"/>
    
    <category term="软件" scheme="https://blog.zrf.me/tags/%E8%BD%AF%E4%BB%B6/"/>
    
    <category term="Android" scheme="https://blog.zrf.me/tags/Android/"/>
    
    <category term="iOS" scheme="https://blog.zrf.me/tags/iOS/"/>
    
    <category term="影音视听" scheme="https://blog.zrf.me/tags/%E5%BD%B1%E9%9F%B3%E8%A7%86%E5%90%AC/"/>
    
    <category term="bilibili" scheme="https://blog.zrf.me/tags/bilibili/"/>
    
  </entry>
  
  <entry>
    <title>Epic 游戏喜加一：《逃脱学院》</title>
    <link href="https://blog.zrf.me/p/epic2025-1-17/"/>
    <id>https://blog.zrf.me/p/epic2025-1-17/</id>
    <published>2025-01-17T00:59:33.000Z</published>
    <updated>2025-05-07T17:57:35.000Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.zrf.me/20250117153510869.webp" alt="今日限免"></p><h2 id="今日限免："><a href="#今日限免：" class="headerlink" title="今日限免："></a><strong>今日限免：</strong></h2><blockquote><p>《逃脱学院》:<a href="https://d.zrf.me/epic2025-1-17">https://d.zrf.me/epic2025-1-17</a></p></blockquote><h2 id="优惠截止于-2025-1-24-00-00"><a href="#优惠截止于-2025-1-24-00-00" class="headerlink" title="优惠截止于 2025/1/24 00:00"></a><code>优惠截止于 2025/1/24 00:00</code></h2><h2 id="下周限免："><a href="#下周限免：" class="headerlink" title="下周限免："></a><strong>下周限免：</strong></h2><blockquote><p>《倾听画语: 最美好的景色》</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.zrf.me/20250117153510869.webp&quot; alt=&quot;今日限免&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;今日限免：&quot;&gt;&lt;a href=&quot;#今日限免：&quot; class=&quot;headerlink&quot; title=&quot;今日限免：&quot;&gt;&lt;/a</summary>
      
    
    
    
    <category term="资源中心" scheme="https://blog.zrf.me/categories/%E8%B5%84%E6%BA%90%E4%B8%AD%E5%BF%83/"/>
    
    
    <category term="游戏" scheme="https://blog.zrf.me/tags/%E6%B8%B8%E6%88%8F/"/>
    
    <category term="Epic Games" scheme="https://blog.zrf.me/tags/Epic-Games/"/>
    
    <category term="Epic 喜加一" scheme="https://blog.zrf.me/tags/Epic-%E5%96%9C%E5%8A%A0%E4%B8%80/"/>
    
  </entry>
  
</feed>
