<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Hi, Kainy</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://blogs.kainy.cn/"/>
  <updated>2026-04-30T06:18:18.034Z</updated>
  <id>https://blogs.kainy.cn/</id>
  
  <author>
    <name>Kainy Guo</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>从“验证码之乱”到自动化路由：一套自研通信SaaS如何盘活全渠道矩阵资产？</title>
    <link href="https://blogs.kainy.cn/2026/04/&#39;%E4%BB%8E%E2%80%9C%E9%AA%8C%E8%AF%81%E7%A0%81%E4%B9%8B%E4%B9%B1%E2%80%9D%E5%88%B0%E8%87%AA%E5%8A%A8%E5%8C%96%E8%B7%AF%E7%94%B1%EF%BC%9A%E4%B8%80%E5%A5%97%E8%87%AA%E7%A0%94%E9%80%9A%E4%BF%A1SaaS%E5%A6%82%E4%BD%95%E7%9B%98%E6%B4%BB%E5%85%A8%E6%B8%A0%E9%81%93%E7%9F%A9%E9%98%B5%E8%B5%84%E4%BA%A7%EF%BC%9F&#39;/"/>
    <id>https://blogs.kainy.cn/2026/04/&#39;从“验证码之乱”到自动化路由：一套自研通信SaaS如何盘活全渠道矩阵资产？&#39;/</id>
    <published>2026-04-27T22:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.034Z</updated>
    
    <content type="html"><![CDATA[<p>全渠道矩阵运营实践中，每个爆品背后都需要无数个鲜活账号的支撑。然而，当公司的账号捆绑在无数手机卡上时，我们失去的不仅是效率，更是对核心数字资产的控制。本文复盘了笔者通过一套自研的内部<a href="https://sms.gqmg.com/landing?blogs=&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">短信转发管理SaaS系统</a>，彻底终结“找验证码”的噩梦，实现企业数字资产的安全与自治。</p><h3 id="一、-业务狂奔下的“阿喀琉斯之踵”"><a href="#一、-业务狂奔下的“阿喀琉斯之踵”" class="headerlink" title="一、 业务狂奔下的“阿喀琉斯之踵”"></a>一、 业务狂奔下的“阿喀琉斯之踵”</h3><p>笔者供职于一家供应链公司。我们的核心商业模式非常清晰：从供应商商品库中，筛选出兼具市场需求与极致性价比的“潜力爆品”，将其铺货到抖音、拼多多、京东等公域平台进行全网引流；吸引买家成交后，再通过包裹卡、客服引导等方式，将流量沉淀至抖音私域群、微信公众号和小红书矩阵，转化为长期高复购顾客。</p><a id="more"></a><p>这套 <strong>“公域爆破+私域留存”</strong> 的打法，对账号矩阵的依赖度极高。为了承接不同品类的流量，我们需要在各大平台同时挂载几十上百个店铺和私域账号。</p><p>业务发展越快，底层的“基建”愈发成为瓶颈。业务疯张期间，为图方便，公私域部门的员工往往用自己的私人手机号，或者拿着公司零散购买的几部“公用手机”去注册账号。导致及其致命的几个问题：</p><ol><li><strong>效率黑洞（找验证码全靠吼）：</strong> 拼多多运营登录后台，发现验证码发到了新媒体部门的手机上，只好整个办公室喊“谁拿着尾号8848的手机，发一下拼多多的验证码”。每次登录都要耗费十来分钟。</li><li><strong>资产安全与流失风险：</strong> 员工离职时，绑定其私人号码的店铺或公众号交接困难。甚至出现过前员工恶意找回密码、或者因离职注销号码导致公司店铺彻底停转的极端事件。</li><li><strong>合规风控盲区：</strong> 验证码全员可见，毫无隐私与权限可言；更可怕的是，重要业务通知漏看错看，带来的平台惩罚。</li><li><strong>灵活度不足：</strong> 在RPA（机器人自动化流程）等需要通过API获取短信验证码，完成验证的场景，传统的人工接码方式，响应太慢，导致验证超时，从而中断RPA执行，此问题在节假日尤为突出。</li></ol><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2026/04/mnpsxlyg.webp" alt></p><p>作为产品负责人，我意识到：<strong>这不是多买几台手机就能解决的问题，而是典型的“物理资产与数字权限错配”的系统性Bug。</strong></p><h3 id="二、-现实骨感：为什么不能只靠“多办卡”？"><a href="#二、-现实骨感：为什么不能只靠“多办卡”？" class="headerlink" title="二、 现实骨感：为什么不能只靠“多办卡”？"></a>二、 现实骨感：为什么不能只靠“多办卡”？</h3><p>业务部门想到的方案简单粗暴：“给每个运营配一张公司实名卡不就行了？”</p><p>然而经过一轮深入的行业调研，我果断否决了这个方案。在当前的“断卡行动”和严格的实名制监管下，开卡的隐性成本极高：</p><ul><li><strong>个人号限制：</strong> 三大运营商规定，单人名下单运营商最多只能开5张卡。让员工占用个人名额去注册公司业务，员工往往心存顾虑难以推行。</li><li><strong>企业号限制：</strong> 企业开户虽然上限较高，但审核极其繁琐，且依然是“物理卡片”。把几十张企业卡发给几十个员工，一旦卡片丢失或员工私下用于注册违规平台，公司将面临极大的“帮信罪”连带风险。</li></ul><p><strong>调研最终结论是：底层逻辑不是把“手机卡”发给员工，而是把手机卡里的“信息（验证码）”精准、安全地分发给业务负责人。</strong> 硬件必须集中管控，权限则通过软件解耦。</p><p>基于此结论，由我牵头开始了 <strong>“企业级通信资产路由中枢”</strong> 方案的实施。</p><h3 id="三、-系统架构设计：物理集中，权限解耦"><a href="#三、-系统架构设计：物理集中，权限解耦" class="headerlink" title="三、 系统架构设计：物理集中，权限解耦"></a>三、 系统架构设计：物理集中，权限解耦</h3><p>最终方案的落脚点，不止是一个简单的“短信转发器”，而是一个真正的 SaaS 级业务调度系统。整套系统分为“硬件托管层”与“云端路由层”。</p><h4 id="1-硬件层：消灭物理手机"><a href="#1-硬件层：消灭物理手机" class="headerlink" title="1. 硬件层：消灭物理手机"></a>1. 硬件层：消灭物理手机</h4><p>我们采购了成本极低的 4G 工业通信网关（DTU设备），将公司所有申请的实名制手机卡集中插入这些仅有巴掌大小的盒子里，统一放置在公司的弱电机房。这些设备只有接收功能，从而杜绝了被挪用外呼或发送垃圾短信的合规风险。</p><h4 id="2-云端路由层：基于正则的“分发引擎”"><a href="#2-云端路由层：基于正则的“分发引擎”" class="headerlink" title="2. 云端路由层：基于正则的“分发引擎”"></a>2. 云端路由层：基于正则的“分发引擎”</h4><p>这是整套 SaaS 的灵魂所在。我们将短信盒接收到的短信汇聚到云端控制台，并设计了一套强大的 <strong>“智能路由规则”</strong> 。</p><ul><li><strong>精准解析：</strong> 系统通过正则表达式（Regex）自动剔除营销废话，精准提取 4-6 位验证码。</li><li><strong>基于特征的分发：</strong> 运营主管可以极低门槛地配置规则。例如：<ul><li><strong>规则 A：</strong> 短信抬头为关键字 <code>【拼多多】</code> 或 <code>【抖店】</code> ➡️ 自动推送到钉钉/飞书的“电商运营组”群聊。</li><li><strong>规则 B：</strong> 短信包含 <code>【微信公众平台】</code> ➡️ 推送给私域部门负责人A的私聊。</li><li><strong>规则 C（兜底）：</strong> 未命中的其他信息 ➡️ 推送给 IT 运维组，监控是否有异常注册。</li></ul></li></ul><h4 id="3-闭环管理：权限收放自如"><a href="#3-闭环管理：权限收放自如" class="headerlink" title="3. 闭环管理：权限收放自如"></a>3. 闭环管理：权限收放自如</h4><p>当新员工入职，主管只需在系统中将对应的通道权限赋予他的飞书账号；当员工离职，一键取消通道绑定，该员工瞬间失去所有验证码接收权限，带不走任何数字资产。</p><p>灵活的转发规则配置，叠加精细化权限管理，让号码得以在不同平台和部门间，分层次复用。原先，想要让电商运营部门和内容运营共享号码，实操难度极大。而现在通过精准转发，同一个号码用在不同领域，然后根据关键字路由到所需人员。原本需要30个号码支撑的小项目，现在不到10个号码就能满足需求。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2026/04/mnptijm0.webp" alt></p><h3 id="四、-价值验证：从成本中心到效率引擎"><a href="#四、-价值验证：从成本中心到效率引擎" class="headerlink" title="四、 价值验证：从成本中心到效率引擎"></a>四、 价值验证：从成本中心到效率引擎</h3><p>目前这套 SaaS 系统已稳定运行半年有余，我们进行了一次严密的数据复盘，发现收益远超预期：</p><ol><li><strong>效率飞跃：</strong> 登录验证的平均耗时从过去的 <strong>2-5分钟</strong> 缩短至毫秒级推送。系统实测从硬件接收到飞书群弹出验证码，端到端延迟仅为 <strong>1.5秒</strong>。运营团队彻底告别了“找手机”的内耗。</li><li><strong>资产绝对安全：</strong> 在过去半年的人员流动中，因号码问题导致的公司账号流失率降为 <strong>0%</strong>。所有注册和登录行为留存日志，可随时溯源审计。</li><li><strong>硬件与管理成本锐减：</strong> 淘汰了原本为了收短信而采购的几十台旧智能手机，硬件投入成本下降了 <strong>85%</strong>，同时消灭了给旧手机充电、连 WiFi 的维护噩梦。</li></ol><h3 id="五、-未来演进：当“通信路由”长出-AI-大脑"><a href="#五、-未来演进：当“通信路由”长出-AI-大脑" class="headerlink" title="五、 未来演进：当“通信路由”长出 AI 大脑"></a>五、 未来演进：当“通信路由”长出 AI 大脑</h3><p>完成文本短信的分发，只是我们重构企业通信基建的第一步。随着各大平台的风控升级，以及业务场景的复杂化，我们已经在推进系统的 2.0 升级，核心聚焦于 <strong>“语音流的解析”</strong> 与 <strong>“大模型的业务决策”</strong>：</p><p><strong>1. 攻克风控高地：TTS 动态交互与语音验证码转录</strong><br>在特殊高频操作或异地登录场景下，平台会强制使用“语音验证码”；同时，部分供应商或客户可能会直接拨打我们绑定在各大平台的预留手机号。传统的短信转发器在面对“来电”时形同废铁。</p><p>为此，我们计划在硬件底层打通语音通道：</p><ul><li><strong>TTS（文本转语音）智能应答：</strong> 业务人员可以在后台动态设置接听文案。当有来电时，系统会自动接痛并 TTS 播报（如：“您好，这里是XX供应链电商部，暂不方便接听，请您留言或添加微信…”），极大提升了对外展现的专业度。</li><li><strong>语音验证码自动转文字 (STT)：</strong> 系统可录制来电声音，利用语音识别技术，提取出语音中的验证码数字，并像普通短信一样路由推送到对应的飞书群。彻底消灭“语音漏接”的业务死角。</li></ul><p><strong>2. 告别硬编码：引入大模型（LLM）实现语义级路由</strong><br>目前的转发规则实现，依赖于提前设置好的正则表达式（Regex）匹配。这虽然高效，但维护成本较高（平台稍微改动短信文案模板，正则就可能失效）。<br>在接下来的版本中，我们计划接入轻量级的 LLM 进行“意图识别”：</p><ul><li><strong>智能提取与脱敏：</strong> 让 AI 去阅读短信，自动分辨哪些是验证码、哪些是快递取件码、哪些是平台违规警告。系统只提取核心信息，自动隐藏或抹除无关的营销废话。</li><li><strong>情绪感知与紧急调度：</strong> 如接收到类似“您的店铺存在严重违规，即将扣除保证金”或消费者发送的“我要投诉”等短信，AI 能够敏锐感知其紧急程度，无视原有的常规路由规则，直接触发电话或强震动提醒业务负责人，将其升级为“高优先级工单”。</li></ul><p>从“物理设备的解耦”，到“文本规则的路由”，再到未来“AI驱动的智能通信中枢”，这套系统正在为业务全渠道狂奔，提供最坚实保障。</p><h3 id="六、-写在最后"><a href="#六、-写在最后" class="headerlink" title="六、 写在最后"></a>六、 写在最后</h3><p>这套方案的成功，让我深刻体会到：产品经理的价值不仅在于设计 C 端的增长裂变，更在于深入企业的毛细血管，用数字化手段解决最底层的生产力损耗。</p><p><strong>有意思的是，这个原本为了自救而研发的系统，最近在接待同行和上下游供应商参观时，意外引起了极大关注。</strong> 很多多平台卖家和 MCN 机构的老板日常都遇到过类似的“管理痛点”，甚至强烈要求我们把这套系统开放给他们付费使用。</p><p>这也引发了我的商业思考：企业服务市场的许多好产品，往往就孵化于在日常业务的痛点。基于此契机，我们团队正在评估将这套内部 SaaS 进行商业化剥离，推出面向外部团队的 SaaS 订阅版（包含硬件节点部署与多端推送）。</p><p><strong>如果你所在的团队也正被“满桌子手机、满天飞的验证码、离职交接难”等问题折磨，欢迎在评论区或后台私信交流，或许我们可以帮你用几天时间，<a href="https://sms.gqmg.com/landing?blogs2=&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">彻底重构团队的数字通信底座</a>。</strong></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;全渠道矩阵运营实践中，每个爆品背后都需要无数个鲜活账号的支撑。然而，当公司的账号捆绑在无数手机卡上时，我们失去的不仅是效率，更是对核心数字资产的控制。本文复盘了笔者通过一套自研的内部&lt;a href=&quot;https://sms.gqmg.com/landing?blogs=&amp;f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE&quot; rel=&quot;external nofollow noopener&quot; referrerpolicy=&quot;unsafe-url&quot; target=&quot;_blank&quot;&gt;短信转发管理SaaS系统&lt;/a&gt;，彻底终结“找验证码”的噩梦，实现企业数字资产的安全与自治。&lt;/p&gt;
&lt;h3 id=&quot;一、-业务狂奔下的“阿喀琉斯之踵”&quot;&gt;&lt;a href=&quot;#一、-业务狂奔下的“阿喀琉斯之踵”&quot; class=&quot;headerlink&quot; title=&quot;一、 业务狂奔下的“阿喀琉斯之踵”&quot;&gt;&lt;/a&gt;一、 业务狂奔下的“阿喀琉斯之踵”&lt;/h3&gt;&lt;p&gt;笔者供职于一家供应链公司。我们的核心商业模式非常清晰：从供应商商品库中，筛选出兼具市场需求与极致性价比的“潜力爆品”，将其铺货到抖音、拼多多、京东等公域平台进行全网引流；吸引买家成交后，再通过包裹卡、客服引导等方式，将流量沉淀至抖音私域群、微信公众号和小红书矩阵，转化为长期高复购顾客。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="自动化" scheme="https://blogs.kainy.cn/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/"/>
    
      <category term="验证码" scheme="https://blogs.kainy.cn/tags/%E9%AA%8C%E8%AF%81%E7%A0%81/"/>
    
  </entry>
  
  <entry>
    <title>“不说错，也不全说”：跨部门协作中的智慧与痼疾</title>
    <link href="https://blogs.kainy.cn/2026/04/&#39;%E2%80%9C%E4%B8%8D%E8%AF%B4%E9%94%99%EF%BC%8C%E4%B9%9F%E4%B8%8D%E5%85%A8%E8%AF%B4%E2%80%9D%EF%BC%9A%E8%B7%A8%E9%83%A8%E9%97%A8%E5%8D%8F%E4%BD%9C%E4%B8%AD%E7%9A%84%E6%99%BA%E6%85%A7%E4%B8%8E%E7%97%BC%E7%96%BE&#39;/"/>
    <id>https://blogs.kainy.cn/2026/04/&#39;“不说错，也不全说”：跨部门协作中的智慧与痼疾&#39;/</id>
    <published>2026-04-26T21:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.033Z</updated>
    
    <content type="html"><![CDATA[<p>在职业场域中的沟通以及跨部门间的协作进程里，我们常会遇到这样一种微妙情况，即“所说并非全错，但也并非全部说出”</p><p>这句话精准地概括了职场信息传递中的灰色地带。面对这种现象，我们不禁要问：这究竟是管理者过滤信息的智慧，还是团队协作中推诿扯皮的痼疾？</p><p>答案并非非黑即白。<strong>这把“信息过滤的剪刀”掌握在谁手里，以及为了什么目的而剪，决定了它的性质。</strong> </p><h3 id="一、-什么时候它是“管理智慧”？"><a href="#一、-什么时候它是“管理智慧”？" class="headerlink" title="一、 什么时候它是“管理智慧”？"></a>一、 什么时候它是“管理智慧”？</h3><p>在纷繁复杂的业务运作进程中，将所有信息和盘托出往往既不切实际，甚至还会产生不良影响。在特定情境中，有针对性地传递信息，其目的在于优化效率以及保护团队。</p><a id="more"></a><ul><li><p>在向上汇报时的“信息降噪”场景，决策层所需的是包含结论，风险，成本以及可行性方案在内的相关内容。若在汇报时事无巨细地将底层架构重构中的每一个代码坑一一列举出来，反倒会产生信息噪音。此时有所保留，是为了将重点置于核心商业价值之上。</p></li><li><p>对于危机处理中的“情绪管理”：当线上系统遭遇严重故障或项目处于极度高压状态时，若身为团队核心的你将所有未知风险及高层施压毫无保留地传递给一线执行人员，极有可能导致团队动作出现偏差。这时进行的过滤操作，目的在于稳定军心并确保执行力能得到有效保障。</p></li><li><p>在为获取资源或与外部供应商进行技术选型操作（如POC测试等情况）的过程中，保持一定程度的“边界感”以保留部分底牌，这是一种合理的防御性策略。</p></li></ul><h3 id="二、-什么时候它是“协作痼疾”？"><a href="#二、-什么时候它是“协作痼疾”？" class="headerlink" title="二、 什么时候它是“协作痼疾”？"></a>二、 什么时候它是“协作痼疾”？</h3><p>当“不全说”的动机从“推动业务”转变为“规避个人责任”时，它就演变成协作中最为致命的毒药，即防御性沟通。</p><p>在日常协作中，这种痼疾往往表现为令人高血压的“半拉子工程”：<br>场景A：需要让财务去开通授信账户。财务在系统内创建账户后，向你告知“账户已经开设妥当”当你需要调用时，才发现额度已经归零，完全无法使用。<br>场景B：咨询某一款商品能否进行上架运营的相关事宜。运营方作出回复表示“商品的图片已经完成更换”前端研发人员在默认所有准备工作均已完成的情况下点击进行上架与推流操作，但是随后发现系统未对库存及物流模板进行配置，最终导致线上无法开展发货业务。</p><p>表面上看，财务和运营都没有“说错”，他们完成了自己视角的任务。但这背后暴露了三个致命的团队沟通问题：</p><ol><li><strong>本位主义（动作导向 vs 目标导向）：</strong> 只对“自己手头的动作”负责，对下游的“最终业务目标”缺乏认知或漠不关心。</li><li><strong>上下文断层（Context 缺失）：</strong> 沟通双方都在用自己的“隐性假设”填补信息空白，缺乏对齐。</li><li><strong>缺乏完成定义（Definition of Done）：</strong> 整个流水线对“什么叫准备好了”没有达成流程上的共识。</li></ol><h3 id="三、-破局之道：如何打破信息壁垒？"><a href="#三、-破局之道：如何打破信息壁垒？" class="headerlink" title="三、 破局之道：如何打破信息壁垒？"></a>三、 破局之道：如何打破信息壁垒？</h3><p>无论是作为信息的接收方（需求方）还是提供方，我们都需要一套机制来对抗这种沟通中的人性弱点。</p><h4 id="作为需求方：建立“防御性协同”机制"><a href="#作为需求方：建立“防御性协同”机制" class="headerlink" title="作为需求方：建立“防御性协同”机制"></a>作为需求方：建立“防御性协同”机制</h4><ol><li><strong>沟通升级，抛出“场景化需求”：</strong> 不要只下达单点指令。将“麻烦开个账户”升级为“我们需要一笔X万的采买，请开通账户并确保额度足够”。用目标打破对方的动作导向。</li><li><strong>强制“闭环确认”（反向翻译）：</strong> 当收到模棱两可的回复（如“图换好了”）时，主动将信息翻译成业务结果并要求对方确认：“确认目前库存和物流已就绪，我现在点击上架并全量推流，不会有发货问题对吧？”通过追问划清责任边界。</li><li><strong>用系统底座代替人工承诺：</strong> 在技术架构和平台化管理中，最可靠的防御是系统拦截。例如，前端发布系统在执行上架前，强制校验库存接口和物流状态；状态异常则直接拦截并阻断。</li></ol><h4 id="作为提供方：推行“白盒化交付”"><a href="#作为提供方：推行“白盒化交付”" class="headerlink" title="作为提供方：推行“白盒化交付”"></a>作为提供方：推行“白盒化交付”</h4><p>为了避免被误解为“留一手”或制造信息特权，技术骨干和管理者需要主动从“被动分发者”转变为“上下文构建者”。</p><ol><li><strong>践行“+1 步原则”：</strong> 回答问题时主动暴露关联影响。例如，“服务已重启，但接下来10分钟内缓存会重建，数据库可能有短期压力，请知悉。”</li><li><strong>推动隐性知识的“白盒化”：</strong> 消除技术特权猜忌的最好方法是将黑盒变白盒。一方面，将复杂的配置和排障过程沉淀为知识库文档；另一方面，推动完善的系统监控（例如引入专业的 APM 监控系统），将核心链路的状态、性能看板直接共享给业务和相关团队。让数据自己说话，变被动解答为主动透明。</li><li><strong>Checklist 交付习惯：</strong> 交付结果时附带颗粒度清晰的检查项。例如，“功能已发版。我已确认：1. 核心链路畅通；2. 日志无异常报错。你们可以开始配置了。”</li><li><strong>坦诚未知与边界：</strong> 如果某些技术方案的 POC 尚未跑完，直接承认“目前高并发压测数据还在验证，暂时不能承诺完全无风险”，远比含糊其辞更能赢得信任。</li></ol><h3 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h3><p>“不说错，也不全说”的背后，本质上是组织信任度与流程成熟度的综合反映。优秀的协作不在于你说了多少句话，而在于你是否展现出了 <strong>“我愿意与你共享全局上下文，并为共同目标负责”</strong> 的专业姿态。用流程对抗人性，用系统保障下限，用透明建立信任，才是打破沟通壁垒的根本解法。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在职业场域中的沟通以及跨部门间的协作进程里，我们常会遇到这样一种微妙情况，即“所说并非全错，但也并非全部说出”&lt;/p&gt;
&lt;p&gt;这句话精准地概括了职场信息传递中的灰色地带。面对这种现象，我们不禁要问：这究竟是管理者过滤信息的智慧，还是团队协作中推诿扯皮的痼疾？&lt;/p&gt;
&lt;p&gt;答案并非非黑即白。&lt;strong&gt;这把“信息过滤的剪刀”掌握在谁手里，以及为了什么目的而剪，决定了它的性质。&lt;/strong&gt; &lt;/p&gt;
&lt;h3 id=&quot;一、-什么时候它是“管理智慧”？&quot;&gt;&lt;a href=&quot;#一、-什么时候它是“管理智慧”？&quot; class=&quot;headerlink&quot; title=&quot;一、 什么时候它是“管理智慧”？&quot;&gt;&lt;/a&gt;一、 什么时候它是“管理智慧”？&lt;/h3&gt;&lt;p&gt;在纷繁复杂的业务运作进程中，将所有信息和盘托出往往既不切实际，甚至还会产生不良影响。在特定情境中，有针对性地传递信息，其目的在于优化效率以及保护团队。&lt;/p&gt;
    
    </summary>
    
      <category term="东写西读" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/"/>
    
      <category term="心路历程" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/%E5%BF%83%E8%B7%AF%E5%8E%86%E7%A8%8B/"/>
    
    
      <category term="沟通" scheme="https://blogs.kainy.cn/tags/%E6%B2%9F%E9%80%9A/"/>
    
      <category term="职场" scheme="https://blogs.kainy.cn/tags/%E8%81%8C%E5%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title>从单体走向 Monorepo：一起展App 基于 Melos 的 Flutter 模块化架构重构实践</title>
    <link href="https://blogs.kainy.cn/2026/04/%E4%BB%8E%E5%8D%95%E4%BD%93%E8%B5%B0%E5%90%91%20Monorepo%EF%BC%9A%E4%B8%80%E8%B5%B7%E5%B1%95App%20%E5%9F%BA%E4%BA%8E%20Melos%20%E7%9A%84%20Flutter%20%E6%A8%A1%E5%9D%97%E5%8C%96%E6%9E%B6%E6%9E%84%E9%87%8D%E6%9E%84%E5%AE%9E%E8%B7%B5/"/>
    <id>https://blogs.kainy.cn/2026/04/从单体走向 Monorepo：一起展App 基于 Melos 的 Flutter 模块化架构重构实践/</id>
    <published>2026-04-24T21:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.057Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-背景与痛点-Situation-amp-Task"><a href="#1-背景与痛点-Situation-amp-Task" class="headerlink" title="1. 背景与痛点 (Situation &amp; Task)"></a>1. 背景与痛点 (Situation &amp; Task)</h2><p>在项目（Zhanzhan）初期，为了追求业务的快速迭代，我们采用了传统的 Flutter 单体工程（Monolith）架构。所有的业务逻辑、网络请求、UI 组件和路由都高度集中在同一个 <code>lib</code> 目录下。</p><p>随着业务场景的不断丰富（涵盖了“办展”、“看展笔记”、“信息流”、“个人中心”等多个核心域），单体架构的弊端开始集中爆发，主要体现在：</p><ul><li><p><strong>代码边界模糊，陷入“面条代码”：</strong> 业务模块之间直接互相 <code>import</code> 页面类，导致严重的隐式耦合。改动“商城”模块的代码，可能会意外引发“看展”模块的崩溃。</p></li><li><p><strong>依赖冲突频发，包管理失控：</strong> 全局共用一个 <code>pubspec.yaml</code>，第三方依赖版本牵一发而动全身，极大地限制了不同业务线的技术选型自由度。</p></li><li><p><strong>编译与代码生成效率低下：</strong> 在单体架构下，运行一次 <code>build_runner</code> 生成代码需要遍历全局，耗时极长，严重影响研发心智和效率。</p></li></ul><p>为了支撑中大型团队的协同开发，抹平不同业务模块的进度差，我们决定彻底打破单体架构，全面向 <strong>基于 Melos 的 Monorepo（单体仓库多包管理）架构</strong> 演进。    </p><a id="more"></a><h2 id="2-核心架构设计：严谨的“四层洋葱模型”-Action-Architecture"><a href="#2-核心架构设计：严谨的“四层洋葱模型”-Action-Architecture" class="headerlink" title="2. 核心架构设计：严谨的“四层洋葱模型” (Action - Architecture)"></a>2. 核心架构设计：严谨的“四层洋葱模型” (Action - Architecture)</h2><p>重构的核心不在于拆分物理文件夹，而在于<strong>建立清晰的依赖单向传递规则</strong>。我们彻底摒弃了按业务粗粒度划分的思路，而是结合业务现状，采用“细粒度拆分 + 严格分层”的设计，将系统划分为四个独立的生命周期层：</p><h3 id="2-1-壳工程层-Host-App-apps-host-app"><a href="#2-1-壳工程层-Host-App-apps-host-app" class="headerlink" title="2.1 壳工程层 (Host App: apps/host_app)"></a>2.1 壳工程层 (Host App: <code>apps/host_app</code>)</h3><ul><li><p><strong>定位：</strong> 整个 App 的组装流水线。</p></li><li><p><strong>职责：</strong> 自身几乎不包含具体的业务逻辑代码（除了 <code>splash</code> 启动页等强入口逻辑）。它负责引入底层和业务侧的各个 package，完成全局路由表 (<code>app_routes.dart</code>) 的注册、状态管理 (<code>ProviderScope</code>) 的初始化，以及全局依赖注入。</p></li></ul><h3 id="2-2-基础能力层-Core-packages-core"><a href="#2-2-基础能力层-Core-packages-core" class="headerlink" title="2.2 基础能力层 (Core: packages/core)"></a>2.2 基础能力层 (Core: <code>packages/core</code>)</h3><ul><li><p><strong>定位：</strong> 极度稳定、与业务毫无关联的底层基建。</p></li><li><p><strong>模块：</strong></p><ul><li><p><code>core_network</code>: 基于 Dio 的网络封装、拦截器体系与 Mock 机制。</p></li><li><p><code>core_router</code>: 基于 GoRouter 的全局路由抽象。</p></li><li><p><code>core_storage</code>: 本地持久化（Token 管理）。</p></li><li><p><code>core_analytics</code>: 全局埋点服务。</p></li></ul></li></ul><h3 id="2-3-公共复用层-Common-packages-common"><a href="#2-3-公共复用层-Common-packages-common" class="headerlink" title="2.3 公共复用层 (Common: packages/common)"></a>2.3 公共复用层 (Common: <code>packages/common</code>)</h3><ul><li><p><strong>定位：</strong> 跨业务模块复用的中间件与共享领域。</p></li><li><p><strong>模块：</strong></p><ul><li><p><code>auth_session</code>: 用户鉴权守卫与当前用户信息。</p></li><li><p><code>design_system</code>: 统一的设计语言（UI 组件、颜色、字体）。</p></li><li><p><code>shared_models</code>: 跨模块的高频实体（如 ExhibitRepository，保证数据一致性）。</p></li></ul></li></ul><h3 id="2-4-业务功能层-Features-packages-features"><a href="#2-4-业务功能层-Features-packages-features" class="headerlink" title="2.4 业务功能层 (Features: packages/features)"></a>2.4 业务功能层 (Features: <code>packages/features</code>)</h3><ul><li><p><strong>定位：</strong> 并行迭代的业务线，高度内聚。</p></li><li><p><strong>模块：</strong> <code>feature_auth</code> (登录)、<code>feature_home</code> (首页)、<code>feature_exhibit</code> (办展)、<code>feature_note</code> (笔记)。</p></li><li><p><strong>铁律：</strong> 各 feature 包之间<strong>绝对物理隔离，禁止相互依赖</strong>。跨业务通信统一上浮至壳工程的路由中心或通过协议解耦。</p></li></ul><h2 id="3-关键技术决策-Action-Key-Decisions"><a href="#3-关键技术决策-Action-Key-Decisions" class="headerlink" title="3. 关键技术决策 (Action - Key Decisions)"></a>3. 关键技术决策 (Action - Key Decisions)</h2><p>在此次重构落地过程中，我们做出了几个对后续研发规范具有决定性意义的技术决策：</p><h3 id="决策一：采用微模块（Micro-feature）而非宏观领域驱动"><a href="#决策一：采用微模块（Micro-feature）而非宏观领域驱动" class="headerlink" title="决策一：采用微模块（Micro-feature）而非宏观领域驱动"></a>决策一：采用微模块（Micro-feature）而非宏观领域驱动</h3><p>在模块划分初期，我们曾面临是建立宏观的“商城”和“看展”大包，还是按实际功能拆分的抉择。考虑到团队规模和业务敏捷度，我们最终选择了以现状为准的<strong>细粒度拆分</strong>。</p><p>我们没有预先建立空壳的“业务大组”，而是将 <code>exhibit</code>、<code>note</code> 等功能抽离为独立的 feature。同时，将 <code>auth</code> 这种具有跨域性质的模块下沉，将 <code>splash</code> 等应用生命周期强相关的代码保留在壳工程。这种实事求是的拆解，避免了过度设计，也使得架构不会头重脚轻。</p><h3 id="决策二：确立严苛的-Import-路径规范"><a href="#决策二：确立严苛的-Import-路径规范" class="headerlink" title="决策二：确立严苛的 Import 路径规范"></a>决策二：确立严苛的 Import 路径规范</h3><p>为了防止 Monorepo 再次退化为单体，我们在代码静态检查中贯彻了基于物理隔离的引用原则：</p><ul><li><p><strong>包内高内聚（自闭环）：</strong> 同一个 package 内部（例如 <code>feature_auth</code> 内部）互相调用，强制使用相对路径 <code>../</code>。这保证了模块的完全可移植性。</p></li><li><p><strong>包间低耦合（物理边界）：</strong> 跨越 package 借用能力时，严禁使用 <code>../</code>。必须在 <code>pubspec.yaml</code> 中声明依赖后，使用 <code>package:</code> 绝对路径引入。这为代码审查（Code Review）提供了最直观的边界预警。</p></li></ul><h3 id="决策三：Riverpod-状态与路由的分布式管理"><a href="#决策三：Riverpod-状态与路由的分布式管理" class="headerlink" title="决策三：Riverpod 状态与路由的分布式管理"></a>决策三：Riverpod 状态与路由的分布式管理</h3><p>得益于架构分层，我们对状态管理也进行了重组。底层的网络和存储服务在 <code>core</code> 中以 Provider 提供；业务数据层（如 <code>homeNoteRepository</code>）集中在 <code>shared_models</code> 中以便跨域调用；而页面 UI 的状态（如 <code>LoginController</code>, <code>HomeFeedController</code>）则通过 <code>@riverpod</code> 局部封闭在各自的 feature 包内。配合 Melos 的并行脚本，极大地提升了代码生成的效率。</p><h2 id="4-落地收益与未来展望-Result"><a href="#4-落地收益与未来展望-Result" class="headerlink" title="4. 落地收益与未来展望 (Result)"></a>4. 落地收益与未来展望 (Result)</h2><p>经过数周的奋战，Zhanzhan 项目已全面平稳过渡到 Monorepo 架构。带来的直接收益包括：</p><ol><li><p><strong>研发效能跃升：</strong> 开发“办展”模块的同学只需关注 <code>feature_exhibit</code>，无需关心“笔记”模块的代码变更。同时 <code>melos run build</code> 的并行代码生成，将原本漫长的等待时间缩短了 70% 以上。</p></li><li><p><strong>强制的防腐层建设：</strong> feature 之间的硬隔离，彻底杜绝了业务间的循环依赖，使代码架构符合开闭原则（OCP）。</p></li><li><p><strong>技术栈解绑：</strong> 独立的 <code>pubspec.yaml</code> 使得各个模块在未来可以独立升级依赖库，甚至在核心能力层进行灰度技术替换而不影响上层业务。</p></li></ol><p><strong>展望：</strong></p><p>随着这套基础设施的落成，我们下一步的重心将转向<strong>模块的独立编译与调试</strong>。依托 Melos 的能力，我们将为每个核心 Feature 构建独立的 example 工程，使得研发人员在不运行完整壳工程的情况下，也能快速启动并调试单一模块，真正实现从“能跑”向“跑得快”的敏捷研发转型。</p><hr><blockquote><p>项目：<code>zhanzhan</code>（Flutter + Riverpod + Dio · Melos Monorepo）</p></blockquote><h2 id="1-根目录概览"><a href="#1-根目录概览" class="headerlink" title="1. 根目录概览"></a>1. 根目录概览</h2><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">zhanzhan/</span><br><span class="line">├── apps/</span><br><span class="line">│   └── host_app/              # 壳工程（主入口、路由、平台工程）</span><br><span class="line">├── packages/</span><br><span class="line">│   ├── core/                  # 基础能力层</span><br><span class="line">│   │   ├── core_network/      # 网络层（Dio + 拦截器 + Mock）</span><br><span class="line">│   │   ├── core_storage/      # 本地存储（Token 持久化）</span><br><span class="line">│   │   ├── core_router/       # 路由抽象（GoRouter 封装）</span><br><span class="line">│   │   └── core_analytics/    # 埋点（Matomo）</span><br><span class="line">│   ├── common/                # 公共复用层</span><br><span class="line">│   │   ├── auth_session/      # 鉴权会话（登录失效守卫 + 用户信息）</span><br><span class="line">│   │   ├── design_system/     # 设计系统（主题 / 通用组件）</span><br><span class="line">│   │   └── shared_models/     # 共享模型（跨模块数据 + Repository）</span><br><span class="line">│   └── features/              # 业务功能模块</span><br><span class="line">│       ├── feature_auth/      # 登录 / 注册 / 协议</span><br><span class="line">│       ├── feature_home/      # 首页（信息流 + 视频 + 我的）</span><br><span class="line">│       ├── feature_exhibit/   # 办展（列表 + 快速布展 + 观展 + 详情）</span><br><span class="line">│       ├── feature_note/      # 笔记（详情 + 评论 + 互动）</span><br><span class="line">│       └── feature_splash/    # 启动页</span><br><span class="line">├── docs/                      # 项目文档</span><br><span class="line">├── scripts/                   # 构建脚本</span><br><span class="line">├── melos.yaml                 # Melos 配置（Monorepo 管理）</span><br><span class="line">├── pubspec.yaml               # 根 workspace pubspec（声明 melos 依赖）</span><br><span class="line">├── analysis_options.yaml      # 全局静态检查规则</span><br><span class="line">└── README.md                  # 项目说明</span><br></pre></td></tr></table></figure><hr><h2 id="2-Monorepo-子包总览"><a href="#2-Monorepo-子包总览" class="headerlink" title="2. Monorepo 子包总览"></a>2. Monorepo 子包总览</h2><table><thead><tr><th>层级</th><th>包路径</th><th><code>name</code></th><th>说明</th></tr></thead><tbody><tr><td>壳工程</td><td><code>apps/host_app</code></td><td><code>zhanzhan</code></td><td>主入口、路由注册、平台工程</td></tr><tr><td>基础层</td><td><code>packages/core/core_network</code></td><td><code>core_network</code></td><td>Dio 实例、拦截器、Mock</td></tr><tr><td>基础层</td><td><code>packages/core/core_storage</code></td><td><code>core_storage</code></td><td>Token 持久化（SharedPreferences）</td></tr><tr><td>基础层</td><td><code>packages/core/core_router</code></td><td><code>core_router</code></td><td>GoRouter 抽象、全局导航</td></tr><tr><td>基础层</td><td><code>packages/core/core_analytics</code></td><td><code>core_analytics</code></td><td>Matomo 埋点服务</td></tr><tr><td>公共层</td><td><code>packages/common/auth_session</code></td><td><code>auth_session</code></td><td>鉴权守卫、当前用户服务</td></tr><tr><td>公共层</td><td><code>packages/common/design_system</code></td><td><code>design_system</code></td><td>主题颜色/字体/间距 + 通用 UI 组件</td></tr><tr><td>公共层</td><td><code>packages/common/shared_models</code></td><td><code>shared_models</code></td><td>跨模块共享的模型与 Repository</td></tr><tr><td>功能层</td><td><code>packages/features/feature_auth</code></td><td><code>feature_auth</code></td><td>登录/协议</td></tr><tr><td>功能层</td><td><code>packages/features/feature_home</code></td><td><code>feature_home</code></td><td>首页</td></tr><tr><td>功能层</td><td><code>packages/features/feature_exhibit</code></td><td><code>feature_exhibit</code></td><td>办展</td></tr><tr><td>功能层</td><td><code>packages/features/feature_note</code></td><td><code>feature_note</code></td><td>笔记</td></tr><tr><td>功能层</td><td><code>packages/features/feature_splash</code></td><td><code>feature_splash</code></td><td>启动页</td></tr></tbody></table><hr><h2 id="3-壳工程（apps-host-app）"><a href="#3-壳工程（apps-host-app）" class="headerlink" title="3. 壳工程（apps/host_app）"></a>3. 壳工程（apps/host_app）</h2><p>壳工程负责<strong>组装</strong>各个包，提供应用入口和路由注册。</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">apps/host_app/lib/</span><br><span class="line">├── main.dart                     # 应用入口（ProviderScope、Matomo、依赖注入）</span><br><span class="line">├── app_routes.dart               # 集中路由注册（feature 页面绑定 GoRoute）</span><br><span class="line">├── app/                          # 预留（当前为空）</span><br><span class="line">├── core/                         # 壳工程内部 shim / 胶水代码</span><br><span class="line">│   ├── exceptions/</span><br><span class="line">│   │   └── auth_exceptions.dart     # → 转发 core_network</span><br><span class="line">│   ├── navigation/</span><br><span class="line">│   │   └── app_navigator.dart       # → 转发 core_router</span><br><span class="line">│   ├── network/</span><br><span class="line">│   │   ├── app_network_config.dart  # → 转发 core_network</span><br><span class="line">│   │   ├── auth_interceptor.dart    # → 转发 core_network</span><br><span class="line">│   │   ├── dio_provider.dart        # → 转发 core_network</span><br><span class="line">│   │   ├── empty_string_interceptor.dart</span><br><span class="line">│   │   ├── media_url_resolver.dart</span><br><span class="line">│   │   └── mock/</span><br><span class="line">│   │       ├── mock_config.dart</span><br><span class="line">│   │       └── mock_interceptor.dart</span><br><span class="line">│   ├── services/</span><br><span class="line">│   │   ├── app_analytics_service.dart  # → 转发 core_analytics</span><br><span class="line">│   │   ├── auth_session_guard.dart     # → 转发 auth_session</span><br><span class="line">│   │   ├── current_user_service.dart   # → 转发 auth_session</span><br><span class="line">│   │   └── token_storage_service.dart  # → 转发 core_storage</span><br><span class="line">│   ├── theme/</span><br><span class="line">│   │   ├── app_colors.dart          # → 转发 design_system</span><br><span class="line">│   │   ├── app_dimens.dart</span><br><span class="line">│   │   ├── app_text_styles.dart</span><br><span class="line">│   │   └── app_theme.dart</span><br><span class="line">│   └── widgets/</span><br><span class="line">│       ├── app_dialogs.dart         # → 转发 design_system</span><br><span class="line">│       ├── app_empty_placeholder.dart</span><br><span class="line">│       ├── app_image_loading_placeholder.dart</span><br><span class="line">│       ├── app_modal_sheet.dart</span><br><span class="line">│       ├── app_share_sheet.dart</span><br><span class="line">│       ├── app_skeleton.dart</span><br><span class="line">│       └── app_top_toast.dart</span><br><span class="line">└── features/                     # 壳工程内部 feature shim</span><br><span class="line">    ├── auth/</span><br><span class="line">    │   ├── domain/agreement_type.dart</span><br><span class="line">    │   └── presentation/</span><br><span class="line">    │       ├── agreement/agreement_page.dart</span><br><span class="line">    │       └── login/login_page.dart</span><br><span class="line">    ├── home/</span><br><span class="line">    │   ├── data/home_note_repository.dart</span><br><span class="line">    │   └── presentation/home/</span><br><span class="line">    │       ├── home_my_page.dart</span><br><span class="line">    │       ├── home_note_like_controller.dart</span><br><span class="line">    │       └── home_page.dart</span><br><span class="line">    ├── note/</span><br><span class="line">    │   ├── data/note_interaction_repository.dart</span><br><span class="line">    │   └── presentation/note_detail_page.dart</span><br><span class="line">    └── splash/</span><br><span class="line">        └── presentation/splash_page.dart</span><br></pre></td></tr></table></figure><hr><h2 id="4-基础能力层（packages-core）"><a href="#4-基础能力层（packages-core）" class="headerlink" title="4. 基础能力层（packages/core）"></a>4. 基础能力层（packages/core）</h2><h3 id="4-1-core-network（网络层）"><a href="#4-1-core-network（网络层）" class="headerlink" title="4.1 core_network（网络层）"></a>4.1 core_network（网络层）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/core/core_network/lib/</span><br><span class="line">├── core_network.dart              # barrel export</span><br><span class="line">└── src/</span><br><span class="line">    ├── app_network_config.dart    # baseUrl、X-Client-Type</span><br><span class="line">    ├── auth_error_handler.dart    # 鉴权失效协议（Provider 抽象）</span><br><span class="line">    ├── auth_exceptions.dart       # 鉴权异常定义</span><br><span class="line">    ├── auth_interceptor.dart      # 请求附加 token、处理鉴权失效</span><br><span class="line">    ├── dio_provider.dart          # Dio 实例创建（@riverpod）</span><br><span class="line">    ├── dio_provider.g.dart        # 生成代码</span><br><span class="line">    ├── empty_string_interceptor.dart # 空字符串过滤</span><br><span class="line">    ├── media_url_resolver.dart    # 媒体 URL 解析</span><br><span class="line">    └── mock/</span><br><span class="line">        ├── mock_config.dart       # Mock 开关</span><br><span class="line">        ├── mock_data.dart         # Mock 数据</span><br><span class="line">        └── mock_interceptor.dart  # Mock 拦截器</span><br></pre></td></tr></table></figure><h3 id="4-2-core-storage（本地存储）"><a href="#4-2-core-storage（本地存储）" class="headerlink" title="4.2 core_storage（本地存储）"></a>4.2 core_storage（本地存储）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/core/core_storage/lib/</span><br><span class="line">├── core_storage.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── token_storage_service.dart      # Token 持久化（SharedPreferences）</span><br><span class="line">    └── token_storage_service.g.dart    # 生成代码</span><br></pre></td></tr></table></figure><h3 id="4-3-core-router（路由抽象）"><a href="#4-3-core-router（路由抽象）" class="headerlink" title="4.3 core_router（路由抽象）"></a>4.3 core_router（路由抽象）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/core/core_router/lib/</span><br><span class="line">├── core_router.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── app_navigator.dart    # 全局 navigatorKey</span><br><span class="line">    └── app_router.dart       # GoRouter 配置 &amp; AppRouter 静态方法</span><br></pre></td></tr></table></figure><h3 id="4-4-core-analytics（埋点）"><a href="#4-4-core-analytics（埋点）" class="headerlink" title="4.4 core_analytics（埋点）"></a>4.4 core_analytics（埋点）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/core/core_analytics/lib/</span><br><span class="line">├── core_analytics.dart</span><br><span class="line">└── src/</span><br><span class="line">    └── app_analytics_service.dart    # Matomo Tracker 封装</span><br></pre></td></tr></table></figure><hr><h2 id="5-公共复用层（packages-common）"><a href="#5-公共复用层（packages-common）" class="headerlink" title="5. 公共复用层（packages/common）"></a>5. 公共复用层（packages/common）</h2><h3 id="5-1-auth-session（鉴权会话）"><a href="#5-1-auth-session（鉴权会话）" class="headerlink" title="5.1 auth_session（鉴权会话）"></a>5.1 auth_session（鉴权会话）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/common/auth_session/lib/</span><br><span class="line">├── auth_session.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── auth_session_guard.dart     # 登录失效统一处理</span><br><span class="line">    └── current_user_service.dart   # 当前用户信息服务</span><br></pre></td></tr></table></figure><h3 id="5-2-design-system（设计系统）"><a href="#5-2-design-system（设计系统）" class="headerlink" title="5.2 design_system（设计系统）"></a>5.2 design_system（设计系统）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/common/design_system/lib/</span><br><span class="line">├── design_system.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── theme/</span><br><span class="line">    │   ├── app_colors.dart</span><br><span class="line">    │   ├── app_dimens.dart</span><br><span class="line">    │   ├── app_text_styles.dart</span><br><span class="line">    │   └── app_theme.dart</span><br><span class="line">    └── widgets/</span><br><span class="line">        ├── app_dialogs.dart</span><br><span class="line">        ├── app_empty_placeholder.dart</span><br><span class="line">        ├── app_image_loading_placeholder.dart</span><br><span class="line">        ├── app_modal_sheet.dart</span><br><span class="line">        ├── app_share_sheet.dart</span><br><span class="line">        ├── app_skeleton.dart</span><br><span class="line">        └── app_top_toast.dart</span><br></pre></td></tr></table></figure><h3 id="5-3-shared-models（共享模型）"><a href="#5-3-shared-models（共享模型）" class="headerlink" title="5.3 shared_models（共享模型）"></a>5.3 shared_models（共享模型）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/common/shared_models/lib/</span><br><span class="line">├── shared_models.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── app_state/</span><br><span class="line">    │   └── cross_feature_state.dart       # 跨功能状态</span><br><span class="line">    ├── exhibit/</span><br><span class="line">    │   ├── exhibit_category.dart</span><br><span class="line">    │   ├── exhibit_category_tree_node.dart</span><br><span class="line">    │   ├── exhibit_chat_message.dart</span><br><span class="line">    │   ├── exhibit_comment_model.dart</span><br><span class="line">    │   ├── exhibit_cover_resolver.dart</span><br><span class="line">    │   ├── exhibit_exhibition_detail.dart</span><br><span class="line">    │   ├── exhibit_frame_material.dart</span><br><span class="line">    │   ├── exhibit_hall.dart</span><br><span class="line">    │   ├── exhibit_hall_template_detail.dart</span><br><span class="line">    │   ├── exhibit_music.dart</span><br><span class="line">    │   ├── exhibit_repository.dart        # 办展 Repository（Dio 接口）</span><br><span class="line">    │   └── fast_exhibit_draft_store.dart   # 快速布展草稿管理</span><br><span class="line">    ├── home/</span><br><span class="line">    │   ├── home_note_like_controller.dart</span><br><span class="line">    │   └── home_note_repository.dart      # 首页笔记 Repository</span><br><span class="line">    ├── note/</span><br><span class="line">    │   └── note_interaction_repository.dart # 笔记互动 Repository</span><br><span class="line">    └── widgets/</span><br><span class="line">        └── exhibit_hall_grid.dart          # 展馆网格组件</span><br></pre></td></tr></table></figure><hr><h2 id="6-业务功能模块（packages-features）"><a href="#6-业务功能模块（packages-features）" class="headerlink" title="6. 业务功能模块（packages/features）"></a>6. 业务功能模块（packages/features）</h2><h3 id="6-1-feature-auth（登录-注册-协议）"><a href="#6-1-feature-auth（登录-注册-协议）" class="headerlink" title="6.1 feature_auth（登录/注册/协议）"></a>6.1 feature_auth（登录/注册/协议）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/features/feature_auth/lib/</span><br><span class="line">├── feature_auth.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── data/</span><br><span class="line">    │   ├── agreement_repository.dart     # 协议接口</span><br><span class="line">    │   ├── auth_repository.dart          # 鉴权接口（验证码登录）</span><br><span class="line">    │   └── auth_repository.g.dart</span><br><span class="line">    ├── domain/</span><br><span class="line">    │   ├── agreement.dart</span><br><span class="line">    │   ├── agreement_type.dart</span><br><span class="line">    │   └── login_form.dart</span><br><span class="line">    └── presentation/</span><br><span class="line">        ├── agreement/</span><br><span class="line">        │   ├── agreement_page.dart</span><br><span class="line">        │   └── agreement_provider.dart</span><br><span class="line">        └── login/</span><br><span class="line">            ├── login_controller.dart</span><br><span class="line">            ├── login_controller.g.dart</span><br><span class="line">            └── login_page.dart</span><br></pre></td></tr></table></figure><h3 id="6-2-feature-home（首页）"><a href="#6-2-feature-home（首页）" class="headerlink" title="6.2 feature_home（首页）"></a>6.2 feature_home（首页）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/features/feature_home/lib/</span><br><span class="line">├── feature_home.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── domain/</span><br><span class="line">    │   ├── home_note.dart</span><br><span class="line">    │   └── home_video.dart</span><br><span class="line">    └── presentation/</span><br><span class="line">        ├── widgets/</span><br><span class="line">        │   └── custom_curated_nav_bar.dart</span><br><span class="line">        └── home/</span><br><span class="line">            ├── home_create_note_page.dart</span><br><span class="line">            ├── home_edit_profile_page.dart</span><br><span class="line">            ├── home_feed_controller.dart / .g.dart</span><br><span class="line">            ├── home_my_page.dart</span><br><span class="line">            ├── home_page.dart</span><br><span class="line">            ├── home_video_controller.dart / .g.dart</span><br><span class="line">            ├── home_video_interaction_controller.dart / .g.dart</span><br><span class="line">            ├── home_video_tab_page.dart</span><br><span class="line">            ├── qr_scan_page.dart</span><br><span class="line">            └── widgets/</span><br><span class="line">                └── home_note_media_cover.dart</span><br></pre></td></tr></table></figure><h3 id="6-3-feature-exhibit（办展）"><a href="#6-3-feature-exhibit（办展）" class="headerlink" title="6.3 feature_exhibit（办展）"></a>6.3 feature_exhibit（办展）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/features/feature_exhibit/lib/</span><br><span class="line">├── feature_exhibit.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── domain/</span><br><span class="line">    │   └── exhibit_hall_draft.dart</span><br><span class="line">    └── presentation/</span><br><span class="line">        ├── cover/</span><br><span class="line">        │   └── exhibit_cover_page_template_1.dart</span><br><span class="line">        ├── detail/</span><br><span class="line">        │   ├── exhibit_artwork_comment_controller.dart</span><br><span class="line">        │   ├── exhibit_artwork_comment_page_template_1.dart</span><br><span class="line">        │   ├── exhibit_artwork_detail_page_template_1.dart</span><br><span class="line">        │   ├── exhibit_detail_page_template_1.dart</span><br><span class="line">        │   ├── exhibit_detail_page_type_1.dart</span><br><span class="line">        │   ├── exhibit_detail_page_type_2.dart</span><br><span class="line">        │   ├── exhibit_detail_page_type_3.dart</span><br><span class="line">        │   ├── exhibit_hall_draft_controller.dart</span><br><span class="line">        │   ├── exhibit_hall_template_detail_controller.dart</span><br><span class="line">        │   ├── exhibit_hall_template_detail_page.dart</span><br><span class="line">        │   └── exhibition_3d_page.dart</span><br><span class="line">        ├── exhibit_tab/</span><br><span class="line">        │   ├── exhibit_tab_controller.dart / .g.dart</span><br><span class="line">        │   └── exhibit_tab_page.dart</span><br><span class="line">        ├── fast_exhibit/</span><br><span class="line">        │   ├── fast_exhibit_page.dart</span><br><span class="line">        │   ├── fast_exhibit_publish_page.dart</span><br><span class="line">        │   └── widgets/</span><br><span class="line">        │       └── fast_exhibit_sheets.dart</span><br><span class="line">        ├── viewing/</span><br><span class="line">        │   ├── exhibit_viewing_page_template_1.dart</span><br><span class="line">        │   └── exhibit_viewing_scene_mock_store.dart</span><br><span class="line">        └── widgets/</span><br><span class="line">            ├── exhibit_info_widgets.dart</span><br><span class="line">            └── exhibit_wall_artworks_perspective.dart</span><br></pre></td></tr></table></figure><h3 id="6-4-feature-note（笔记）"><a href="#6-4-feature-note（笔记）" class="headerlink" title="6.4 feature_note（笔记）"></a>6.4 feature_note（笔记）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/features/feature_note/lib/</span><br><span class="line">├── feature_note.dart</span><br><span class="line">└── src/</span><br><span class="line">    ├── data/</span><br><span class="line">    │   └── note_comment_repository.dart</span><br><span class="line">    ├── domain/</span><br><span class="line">    │   └── note_comment_model.dart</span><br><span class="line">    └── presentation/</span><br><span class="line">        ├── note_comment_controller.dart</span><br><span class="line">        ├── note_detail_controller.dart</span><br><span class="line">        ├── note_detail_page.dart</span><br><span class="line">        ├── note_interaction_controller.dart</span><br><span class="line">        └── widgets/</span><br><span class="line">            ├── note_comment_item.dart</span><br><span class="line">            ├── note_comment_section.dart</span><br><span class="line">            ├── note_detail_bottom_bar.dart</span><br><span class="line">            └── note_image_gallery_page.dart</span><br></pre></td></tr></table></figure><h3 id="6-5-feature-splash（启动页）"><a href="#6-5-feature-splash（启动页）" class="headerlink" title="6.5 feature_splash（启动页）"></a>6.5 feature_splash（启动页）</h3><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">packages/features/feature_splash/lib/</span><br><span class="line">├── feature_splash.dart</span><br><span class="line">└── src/</span><br><span class="line">    └── splash_page.dart</span><br></pre></td></tr></table></figure><hr><h2 id="7-数据接口与-Repository-映射"><a href="#7-数据接口与-Repository-映射" class="headerlink" title="7. 数据接口与 Repository 映射"></a>7. 数据接口与 Repository 映射</h2><blockquote><p>详细接口原始文档见：<code>docs/api.md</code>。</p></blockquote><h3 id="7-1-鉴权-用户相关"><a href="#7-1-鉴权-用户相关" class="headerlink" title="7.1 鉴权/用户相关"></a>7.1 鉴权/用户相关</h3><ul><li><p><strong><code>AuthRepository</code></strong>（<code>feature_auth</code>）</p><ul><li><code>GET /sms/amaz/wxapp/send_sms</code>（发送验证码）</li><li><code>POST /sms/amaz/wxapp/verify_sms</code>（验证码登录）</li></ul></li><li><p><strong><code>AgreementRepository</code></strong>（<code>feature_auth</code>）</p><ul><li><code>GET /user/sys/agreement/get</code>（协议内容）</li></ul></li><li><p><strong><code>CurrentUserService</code></strong>（<code>auth_session</code>）</p><ul><li><code>GET /user/amaz/user/info</code>（用户信息）</li><li><code>POST /user/amaz/user/update</code>（更新资料）</li></ul></li></ul><h3 id="7-2-办展相关"><a href="#7-2-办展相关" class="headerlink" title="7.2 办展相关"></a>7.2 办展相关</h3><ul><li><strong><code>ExhibitRepository</code></strong>（<code>shared_models</code>）<ul><li>分类：<code>/api/exhibition/category/list</code>、<code>/api/exhibition/category/tree</code></li><li>音乐：<code>/api/music/system/normal</code></li><li>展览列表/详情：<code>/api/exhibition/list</code>、<code>/api/exhibition/{id}</code></li><li>展览流：<code>/api/information/exhibition/get</code></li><li>互动聊天：<code>/api/exhibition/interact/chat/list</code>、<code>/api/exhibition/interact/chat/add</code></li><li>评论：<code>/api/exhibition/comment/list</code>、<code>/api/exhibition/comment/add</code>、<code>/api/exhibition/interact/comment/delete</code></li><li>模板：<code>/api/exhibition/hall/template/{templateId}</code>、<code>/api/exhibition/hall/template/page</code></li><li>发布：<code>/api/exhibition/saveOrUpdate</code></li></ul></li></ul><h3 id="7-3-首页-笔记相关"><a href="#7-3-首页-笔记相关" class="headerlink" title="7.3 首页/笔记相关"></a>7.3 首页/笔记相关</h3><ul><li><p><strong><code>HomeNoteRepository</code></strong>（<code>shared_models</code>）</p><ul><li>信息流：<code>/api/information/follow/get</code></li><li>笔记列表：<code>/api/information/note/get</code></li><li>点赞列表：<code>/api/note/take/home/like/list</code></li><li>评论列表：<code>/api/note/take/home/list</code></li><li>详情：<code>/api/note/take/detail</code></li><li>创建/编辑：<code>/api/note/edit/create_modify</code></li></ul></li><li><p><strong><code>NoteCommentRepository</code></strong>（<code>feature_note</code>）</p><ul><li>评论列表：<code>/api/note/take/list</code></li><li>评论新增：<code>/api/note/take/add</code></li></ul></li><li><p><strong><code>NoteInteractionRepository</code></strong>（<code>shared_models</code>）</p><ul><li>关注：<code>/user/amaz/user/add</code>、<code>/user/amaz/user/cancel</code></li><li>点赞/收藏：<code>/user/like/divide/add</code>、<code>/user/like/divide/cancel</code></li></ul></li></ul><hr><h2 id="8-Provider-与状态管理分布"><a href="#8-Provider-与状态管理分布" class="headerlink" title="8. Provider 与状态管理分布"></a>8. Provider 与状态管理分布</h2><ul><li>全局网络与服务：<ul><li><code>dioProvider</code>（<code>core_network</code>）</li><li><code>tokenStorageServiceProvider</code>（<code>core_storage</code>）</li><li><code>currentUserServiceProvider</code>（<code>auth_session</code>）</li><li><code>authErrorHandlerProvider</code>（<code>core_network</code>，壳工程注入实现）</li></ul></li><li>功能 Repository Provider：<ul><li><code>authRepositoryProvider</code>（<code>feature_auth</code>）</li><li><code>agreementRepositoryProvider</code>（<code>feature_auth</code>）</li><li><code>exhibitRepositoryProvider</code>（<code>shared_models</code>）</li><li><code>homeNoteRepositoryProvider</code>（<code>shared_models</code>）</li><li><code>noteCommentRepositoryProvider</code>（<code>feature_note</code>）</li><li><code>noteInteractionRepositoryProvider</code>（<code>shared_models</code>）</li></ul></li><li>控制器（<code>@riverpod</code> / Notifier）：<ul><li><code>LoginController</code>（<code>feature_auth</code>）</li><li><code>ExhibitTabController</code>（<code>feature_exhibit</code>）</li><li><code>HomeFeedController</code>（<code>feature_home</code>）</li><li><code>HomeVideoController</code>（<code>feature_home</code>）</li><li><code>HomeVideoInteractionController</code>（<code>feature_home</code>）</li><li><code>NoteDetailController</code>（<code>feature_note</code>）</li><li><code>NoteCommentController</code>（<code>feature_note</code>）</li><li><code>NoteInteractionController</code>（<code>feature_note</code>）</li></ul></li></ul><hr>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;1-背景与痛点-Situation-amp-Task&quot;&gt;&lt;a href=&quot;#1-背景与痛点-Situation-amp-Task&quot; class=&quot;headerlink&quot; title=&quot;1. 背景与痛点 (Situation &amp;amp; Task)&quot;&gt;&lt;/a&gt;1. 背景与痛点 (Situation &amp;amp; Task)&lt;/h2&gt;&lt;p&gt;在项目（Zhanzhan）初期，为了追求业务的快速迭代，我们采用了传统的 Flutter 单体工程（Monolith）架构。所有的业务逻辑、网络请求、UI 组件和路由都高度集中在同一个 &lt;code&gt;lib&lt;/code&gt; 目录下。&lt;/p&gt;
&lt;p&gt;随着业务场景的不断丰富（涵盖了“办展”、“看展笔记”、“信息流”、“个人中心”等多个核心域），单体架构的弊端开始集中爆发，主要体现在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;代码边界模糊，陷入“面条代码”：&lt;/strong&gt; 业务模块之间直接互相 &lt;code&gt;import&lt;/code&gt; 页面类，导致严重的隐式耦合。改动“商城”模块的代码，可能会意外引发“看展”模块的崩溃。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;依赖冲突频发，包管理失控：&lt;/strong&gt; 全局共用一个 &lt;code&gt;pubspec.yaml&lt;/code&gt;，第三方依赖版本牵一发而动全身，极大地限制了不同业务线的技术选型自由度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;编译与代码生成效率低下：&lt;/strong&gt; 在单体架构下，运行一次 &lt;code&gt;build_runner&lt;/code&gt; 生成代码需要遍历全局，耗时极长，严重影响研发心智和效率。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了支撑中大型团队的协同开发，抹平不同业务模块的进度差，我们决定彻底打破单体架构，全面向 &lt;strong&gt;基于 Melos 的 Monorepo（单体仓库多包管理）架构&lt;/strong&gt; 演进。    &lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="App" scheme="https://blogs.kainy.cn/tags/App/"/>
    
      <category term="Flutter" scheme="https://blogs.kainy.cn/tags/Flutter/"/>
    
  </entry>
  
  <entry>
    <title>小程序｜公众号信息查询API文档</title>
    <link href="https://blogs.kainy.cn/2026/04/&#39;%E5%B0%8F%E7%A8%8B%E5%BA%8F%EF%BD%9C%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BF%A1%E6%81%AF%E6%9F%A5%E8%AF%A2API%E6%96%87%E6%A1%A3&#39;/"/>
    <id>https://blogs.kainy.cn/2026/04/&#39;小程序｜公众号信息查询API文档&#39;/</id>
    <published>2026-04-14T23:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.035Z</updated>
    
    <content type="html"><![CDATA[<p>API key 获取地址：<a href="https://open.kainy.cn/register/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/register/</a></p><h2 id="GET-微信头像外链"><a href="#GET-微信头像外链" class="headerlink" title="GET 微信头像外链"></a>GET 微信头像外链</h2><p>GET <a href="https://open.kainy.cn/api/wxAvatar?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/api/wxAvatar</a></p><p>微信禁止直接外链用户头像，通过此接口，可以绕过限制。</p><h3 id="请求参数"><a href="#请求参数" class="headerlink" title="请求参数"></a>请求参数</h3><table><thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必选</th><th>说明</th></tr></thead><tbody><tr><td>url</td><td>query</td><td>string</td><td>是</td><td>原始头像地址</td></tr><tr><td>ak</td><td>query</td><td>string</td><td>否</td><td>api-key，可通过URL传递，如不填写，请通过header 的 x-api-key 传递。</td></tr><tr><td>x-api-key</td><td>header</td><td>string</td><td>否</td><td>none</td></tr></tbody></table><a id="more"></a><blockquote><p>返回示例</p></blockquote><blockquote><p>200 Response</p></blockquote><h3 id="返回结果"><a href="#返回结果" class="headerlink" title="返回结果"></a>返回结果</h3><table><thead><tr><th>状态码</th><th>状态码含义</th><th>说明</th><th>数据模型</th></tr></thead><tbody><tr><td>200</td><td><a href="https://tools.ietf.org/html/rfc7231?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#section-6.3.1" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">OK</a></td><td>none</td><td>Inline</td></tr></tbody></table><h3 id="返回数据结构"><a href="#返回数据结构" class="headerlink" title="返回数据结构"></a>返回数据结构</h3><h2 id="POST-根据-appid-名称-查小程序"><a href="#POST-根据-appid-名称-查小程序" class="headerlink" title="POST 根据 appid/名称 查小程序"></a>POST 根据 appid/名称 查小程序</h2><p>POST <a href="https://open.kainy.cn/api/AppidQuery?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/api/AppidQuery</a></p><p>根据appid或名称查询小程序信息，包括未备案和未实名以及已下架的小程序。</p><blockquote><p>Body 请求参数</p></blockquote><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">&#123;</span><br><span class="line">  <span class="attr">"appid"</span>: <span class="string">"wx109bf438c8cc1b8b"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="请求参数-1"><a href="#请求参数-1" class="headerlink" title="请求参数"></a>请求参数</h3><table><thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必选</th><th>说明</th></tr></thead><tbody><tr><td>x-api-key</td><td>header</td><td>string</td><td>否</td><td>none</td></tr><tr><td>body</td><td>body</td><td>object</td><td>是</td><td>none</td></tr><tr><td>» appid</td><td>body</td><td>string</td><td>是</td><td>none</td></tr></tbody></table><blockquote><p>返回示例</p></blockquote><blockquote><p>200 Response</p></blockquote><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"code"</span>: <span class="number">0</span>,</span><br><span class="line">  <span class="attr">"data"</span>: &#123;</span><br><span class="line">    <span class="attr">"nickname"</span>: <span class="string">"AppID查"</span>,</span><br><span class="line">    <span class="attr">"username"</span>: <span class="string">"gh_b9c4a08a2031"</span>,</span><br><span class="line">    <span class="attr">"description"</span>: <span class="string">"输入AppID查询小程序名称和详情。小程序间跳转流量来源分析工具；小程序广告投放、买量换量权威验证渠道；小程序运营必备神器。"</span>,</span><br><span class="line">    <span class="attr">"avatar"</span>: <span class="string">"https://wx.qlogo.cn/mmhead/Q3auHgzwzM6t3pXahwQx3y0m5BoFbK0gickbNLkUlbqKuJOhnojVfYg/0"</span>,</span><br><span class="line">    <span class="attr">"uses_count"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"principal_name"</span>: <span class="string">"个人开发者"</span>,</span><br><span class="line">    <span class="attr">"appid"</span>: <span class="string">"wx109bf438c8cc1b8b"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="返回结果-1"><a href="#返回结果-1" class="headerlink" title="返回结果"></a>返回结果</h3><table><thead><tr><th>状态码</th><th>状态码含义</th><th>说明</th><th>数据模型</th></tr></thead><tbody><tr><td>200</td><td><a href="https://tools.ietf.org/html/rfc7231?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#section-6.3.1" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">OK</a></td><td>none</td><td>Inline</td></tr></tbody></table><h3 id="返回数据结构-1"><a href="#返回数据结构-1" class="headerlink" title="返回数据结构"></a>返回数据结构</h3><p>状态码 <strong>200</strong></p><table><thead><tr><th>名称</th><th>类型</th><th>必选</th><th>约束</th><th>中文名</th><th>说明</th></tr></thead><tbody><tr><td>» code</td><td>integer</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» data</td><td>object</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>»» nickname</td><td>string</td><td>true</td><td>none</td><td>昵称</td><td>none</td></tr><tr><td>»» username</td><td>string</td><td>true</td><td>none</td><td>原始id</td><td>none</td></tr><tr><td>»» description</td><td>string</td><td>true</td><td>none</td><td>小程序简介</td><td>none</td></tr><tr><td>»» avatar</td><td>string</td><td>true</td><td>none</td><td>小程序图标</td><td>none</td></tr><tr><td>»» uses_count</td><td>string</td><td>true</td><td>none</td><td>使用次数</td><td>none</td></tr><tr><td>»» principal_name</td><td>string</td><td>true</td><td>none</td><td>主体名称</td><td>none</td></tr><tr><td>»» appid</td><td>string</td><td>true</td><td>none</td><td>Appid</td><td>none</td></tr></tbody></table><h2 id="GET-根据-appid-查公众号信息"><a href="#GET-根据-appid-查公众号信息" class="headerlink" title="GET 根据 appid 查公众号信息"></a>GET 根据 appid 查公众号信息</h2><p>GET <a href="https://open.kainy.cn/api/mpAppidQuery?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/api/mpAppidQuery</a></p><p>根据appid或名称查询公众号和小程序信息，包括未备案和未实名以及已下架的。</p><h3 id="请求参数-2"><a href="#请求参数-2" class="headerlink" title="请求参数"></a>请求参数</h3><table><thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必选</th><th>说明</th></tr></thead><tbody><tr><td>appid</td><td>query</td><td>string</td><td>是</td><td>公众号/小程序的appid</td></tr><tr><td>x-api-key</td><td>header</td><td>string</td><td>否</td><td>none</td></tr></tbody></table><blockquote><p>返回示例</p></blockquote><blockquote><p>200 Response</p></blockquote><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"code"</span>: <span class="number">0</span>,</span><br><span class="line">  <span class="attr">"data"</span>: &#123;</span><br><span class="line">    <span class="attr">"nickname"</span>: <span class="string">"AppID查"</span>,</span><br><span class="line">    <span class="attr">"username"</span>: <span class="string">"gh_b9c4a08a2031"</span>,</span><br><span class="line">    <span class="attr">"description"</span>: <span class="string">"输入AppID查询小程序名称和详情。小程序间跳转流量来源分析工具；小程序广告投放、买量换量权威验证渠道；小程序运营必备神器。"</span>,</span><br><span class="line">    <span class="attr">"avatar"</span>: <span class="string">"https://wx.qlogo.cn/mmhead/Q3auHgzwzM6t3pXahwQx3y0m5BoFbK0gickbNLkUlbqKuJOhnojVfYg/0"</span>,</span><br><span class="line">    <span class="attr">"uses_count"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"principal_name"</span>: <span class="string">"个人开发者"</span>,</span><br><span class="line">    <span class="attr">"appid"</span>: <span class="string">"wx109bf438c8cc1b8b"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="返回结果-2"><a href="#返回结果-2" class="headerlink" title="返回结果"></a>返回结果</h3><table><thead><tr><th>状态码</th><th>状态码含义</th><th>说明</th><th>数据模型</th></tr></thead><tbody><tr><td>200</td><td><a href="https://tools.ietf.org/html/rfc7231?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#section-6.3.1" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">OK</a></td><td>none</td><td>Inline</td></tr></tbody></table><h3 id="返回数据结构-2"><a href="#返回数据结构-2" class="headerlink" title="返回数据结构"></a>返回数据结构</h3><p>状态码 <strong>200</strong></p><table><thead><tr><th>名称</th><th>类型</th><th>必选</th><th>约束</th><th>中文名</th><th>说明</th></tr></thead><tbody><tr><td>» code</td><td>integer</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» data</td><td>object</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>»» nickname</td><td>string</td><td>true</td><td>none</td><td>昵称</td><td>none</td></tr><tr><td>»» username</td><td>string</td><td>true</td><td>none</td><td>原始id</td><td>none</td></tr><tr><td>»» description</td><td>string</td><td>true</td><td>none</td><td>小程序简介</td><td>none</td></tr><tr><td>»» avatar</td><td>string</td><td>true</td><td>none</td><td>小程序图标</td><td>none</td></tr><tr><td>»» uses_count</td><td>string</td><td>true</td><td>none</td><td>使用次数</td><td>none</td></tr><tr><td>»» principal_name</td><td>string</td><td>true</td><td>none</td><td>主体名称</td><td>none</td></tr><tr><td>»» appid</td><td>string</td><td>true</td><td>none</td><td>Appid</td><td>none</td></tr></tbody></table><h2 id="GET-小程序搜索提示词列表"><a href="#GET-小程序搜索提示词列表" class="headerlink" title="GET 小程序搜索提示词列表"></a>GET 小程序搜索提示词列表</h2><p>GET <a href="https://open.kainy.cn/api/weapp-suggest?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/api/weapp-suggest</a></p><p>根据关键词，联想小程序名称。</p><h3 id="请求参数-3"><a href="#请求参数-3" class="headerlink" title="请求参数"></a>请求参数</h3><table><thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必选</th><th>说明</th></tr></thead><tbody><tr><td>appid</td><td>query</td><td>string</td><td>是</td><td>联想关键词</td></tr><tr><td>x-api-key</td><td>header</td><td>string</td><td>否</td><td>none</td></tr></tbody></table><blockquote><p>返回示例</p></blockquote><blockquote><p>200 Response</p></blockquote><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><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"code"</span>: <span class="number">0</span>,</span><br><span class="line">  <span class="attr">"data"</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯流量"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯动漫官方微主页"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯微课堂"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯AI名片"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯云游戏"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯视频IP好物集"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯智慧零售中心"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯读书酱丨旧版"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯双扣"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯跑得快"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯视频VIP礼品卡"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯开心鼠英语ABCmouse资源站"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯云数字会务平台"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯健康药箱"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯挂号平台"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯文档打卡"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"流言侦探腾讯版"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯微保"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯社交广告"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯企鹅辅导"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯云上社区"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯设计周"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯微卡访客助手"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯云智服工作台"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯全民模拟炒股大赛"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯调研云"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯出行"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯动漫"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯开心鼠启蒙"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"nickname"</span>: <span class="string">"腾讯企业邮箱"</span></span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="返回结果-3"><a href="#返回结果-3" class="headerlink" title="返回结果"></a>返回结果</h3><table><thead><tr><th>状态码</th><th>状态码含义</th><th>说明</th><th>数据模型</th></tr></thead><tbody><tr><td>200</td><td><a href="https://tools.ietf.org/html/rfc7231?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#section-6.3.1" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">OK</a></td><td>none</td><td>Inline</td></tr></tbody></table><h3 id="返回数据结构-3"><a href="#返回数据结构-3" class="headerlink" title="返回数据结构"></a>返回数据结构</h3><p>状态码 <strong>200</strong></p><table><thead><tr><th>名称</th><th>类型</th><th>必选</th><th>约束</th><th>中文名</th><th>说明</th></tr></thead><tbody><tr><td>» code</td><td>integer</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» data</td><td>[object]</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>»» nickname</td><td>string</td><td>true</td><td>none</td><td></td><td>none</td></tr></tbody></table><h2 id="POST-二进制cookie解析"><a href="#POST-二进制cookie解析" class="headerlink" title="POST 二进制cookie解析"></a>POST 二进制cookie解析</h2><p>POST <a href="https://open.kainy.cn/api/binarycookies?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/api/binarycookies</a></p><p>用于解析Safari浏览器导出的cookie二进制文件，使用场景包括手机上的煤炉账号转移到电脑指纹浏览器等。</p><blockquote><p>Body 请求参数</p></blockquote><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">file:</span> <span class="string">cmMtdXBsb2FkLTE3NzY0MDQ0MzI4MzAtNw==/1.binarycookies</span></span><br></pre></td></tr></table></figure><h3 id="请求参数-4"><a href="#请求参数-4" class="headerlink" title="请求参数"></a>请求参数</h3><table><thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必选</th><th>说明</th></tr></thead><tbody><tr><td>X-Api-Key</td><td>header</td><td>string</td><td>否</td><td>none</td></tr><tr><td>body</td><td>body</td><td>object</td><td>是</td><td>none</td></tr><tr><td>» file</td><td>body</td><td>string(binary)</td><td>否</td><td>有效的 Safari Cookies.binarycookies 文件</td></tr></tbody></table><blockquote><p>返回示例</p></blockquote><blockquote><p>200 Response</p></blockquote><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><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></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">"auth.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"op_sess"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"dbb23136-4717-4da7-9b1f-3ef9f0e59926"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1849870081</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763470081</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">".login.jp.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"__cf_bm"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"H1l5BcX4FUpy6dQrP9vS12kgBx0bdaHyYfn_rRSFv2o-1763469966-1.0.1.1-WEB_96uUFNqgtpOd0xyub5Xi5QnCJTxq.W9k_2qsIghTOYZSmfOmu7BhEZ.AqgYtBariSXI2rXLxhY2IvY6jq9c2m8fwPb1z5H8fFrXQzQU"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1763471766</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469967</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">".mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"_gcl_au"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"1.1.1754395915.1763469956"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1771245956</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469962</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">".auth.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"__cf_bm"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"hvCyN442KDZqwBMZ5g98tOapPhoMIC.1Gu.g2popfq8-1763470081-1.0.1.1-v.NE1HmB7iVs6o66rCRRzRAD153OtH8Ap8BXI2EVsml7XjCwCbqSU84lj99JXjvjRjyLWYq6fyct9oI2aMz2L5pNSJNowapC_MYKSFe.MqM"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1763471881</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763470081</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">".auth.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"userNonceKey"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"eyJhbGciOiJFUzI1NiIsImtpZCI6IjlvVE43bzI1WnNrWXVUNE1aU2g1U2oiLCJ0eXAiOiJKV1QifQ.eyJ2YWx1ZSI6IktCTkZVUDZ4cGlpM3hYQmswU1ZsTzdra3pCaDhOYkdpU0tWaFVnWmZHVGhuckUxV3NvTXdHdzhMYmNGTyJ9.gvNoX1GA5GGISjnZhvXiM6hcxmWkzc8OFJwNkYufI8u9xznhRmdCLI39opLi1cKg_ooDldP66h6Bhj3_oxG2iQ"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/jp/v1"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1763473554</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469954</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">"login.jp.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"country_code"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"JP"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1766061967</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469967</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">"login.jp.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"version"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"main"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1763477167</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469967</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">"login.jp.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"_im_id.1019999"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"a7af53073829b27c.1763469962."</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1797425162</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469961</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">"login.jp.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"_im_ses.1019999"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"1"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1763471761</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469961</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">"login.jp.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"launch_config"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"eyJkZXZpY2VUeXBlIjoiaW9zIiwidGhlbWUiOiJzeXN0ZW1fcHJlZmVyZW5jZSIsInVzZXJBZ2VudCI6Ik1lcmNhcmlfci8yMjc1NzYgKGlPUyAxOC4yOyBqYS1KUDsgaVBob25lMTIsNSkiLCJpdkNlcnQiOiI4MDY0MDk1NzY4Q0U0QTREQTU3QkJENzE2N0NDQ0NEMyIsImFwcFZlcnNpb24iOiIyMjc1NzYiLCJjbGllbnRVVUlEIjoiREQwRjYwMDUzNkJGNDhEMDlCOEVFMENFQTFEMzY5QTYiLCJjbGllbnRUeXBlIjoiZ3JvdW5kdXAifQ=="</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1763470266</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469966</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"domain"</span>: <span class="string">"login.jp.mercari.com"</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"authUUID"</span>,</span><br><span class="line">    <span class="attr">"value"</span>: <span class="string">"f352e44c-87c5-4d63-aeb7-f3202877ca9f"</span>,</span><br><span class="line">    <span class="attr">"path"</span>: <span class="string">"/"</span>,</span><br><span class="line">    <span class="attr">"secure"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"httpOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"sameSite"</span>: <span class="string">"unspecified"</span>,</span><br><span class="line">    <span class="attr">"hostOnly"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"storeId"</span>: <span class="string">"0"</span>,</span><br><span class="line">    <span class="attr">"session"</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">"expirationDate"</span>: <span class="number">1763471766</span>,</span><br><span class="line">    <span class="attr">"creationDate"</span>: <span class="number">1763469967</span></span><br><span class="line">  &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h3 id="返回结果-4"><a href="#返回结果-4" class="headerlink" title="返回结果"></a>返回结果</h3><table><thead><tr><th>状态码</th><th>状态码含义</th><th>说明</th><th>数据模型</th></tr></thead><tbody><tr><td>200</td><td><a href="https://tools.ietf.org/html/rfc7231?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#section-6.3.1" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">OK</a></td><td>none</td><td>Inline</td></tr></tbody></table><h3 id="返回数据结构-4"><a href="#返回数据结构-4" class="headerlink" title="返回数据结构"></a>返回数据结构</h3><p>状态码 <strong>200</strong></p><table><thead><tr><th>名称</th><th>类型</th><th>必选</th><th>约束</th><th>中文名</th><th>说明</th></tr></thead><tbody><tr><td>» domain</td><td>string</td><td>true</td><td>none</td><td>域名</td><td>none</td></tr><tr><td>» name</td><td>string</td><td>true</td><td>none</td><td>名称</td><td>none</td></tr><tr><td>» value</td><td>string</td><td>true</td><td>none</td><td>值</td><td>none</td></tr><tr><td>» path</td><td>string</td><td>true</td><td>none</td><td>路径</td><td>none</td></tr><tr><td>» secure</td><td>boolean</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» httpOnly</td><td>boolean</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» sameSite</td><td>string</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» hostOnly</td><td>boolean</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» storeId</td><td>string</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» session</td><td>boolean</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» expirationDate</td><td>integer</td><td>true</td><td>none</td><td></td><td>none</td></tr><tr><td>» creationDate</td><td>integer</td><td>true</td><td>none</td><td></td><td>none</td></tr></tbody></table><h2 id="GET-ip地址查询"><a href="#GET-ip地址查询" class="headerlink" title="GET ip地址查询"></a>GET ip地址查询</h2><p>GET <a href="https://open.kainy.cn/api/ip?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/api/ip</a></p><p>根据IP查询归属地；</p><h3 id="请求参数-5"><a href="#请求参数-5" class="headerlink" title="请求参数"></a>请求参数</h3><table><thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必选</th><th>说明</th></tr></thead><tbody><tr><td>ip</td><td>query</td><td>string</td><td>否</td><td>IP地址，留空则查询访问者IP</td></tr><tr><td>x-api-key</td><td>header</td><td>string</td><td>否</td><td>none</td></tr></tbody></table><blockquote><p>返回示例</p></blockquote><blockquote><p>200 Response</p></blockquote><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"location"</span>: <span class="string">"中国 广东省 深圳市"</span>,</span><br><span class="line">  <span class="attr">"ip"</span>: <span class="string">"58.250.29.186"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="返回结果-5"><a href="#返回结果-5" class="headerlink" title="返回结果"></a>返回结果</h3><table><thead><tr><th>状态码</th><th>状态码含义</th><th>说明</th><th>数据模型</th></tr></thead><tbody><tr><td>200</td><td><a href="https://tools.ietf.org/html/rfc7231?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#section-6.3.1" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">OK</a></td><td>none</td><td>Inline</td></tr></tbody></table><h3 id="返回数据结构-5"><a href="#返回数据结构-5" class="headerlink" title="返回数据结构"></a>返回数据结构</h3><p>状态码 <strong>200</strong></p><table><thead><tr><th>名称</th><th>类型</th><th>必选</th><th>约束</th><th>中文名</th><th>说明</th></tr></thead><tbody><tr><td>» location</td><td>string</td><td>true</td><td>none</td><td>位置</td><td>none</td></tr><tr><td>» ip</td><td>string</td><td>true</td><td>none</td><td>IP地址</td><td>none</td></tr></tbody></table><h2 id="GET-手机归属地查询"><a href="#GET-手机归属地查询" class="headerlink" title="GET 手机归属地查询"></a>GET 手机归属地查询</h2><p>GET <a href="https://open.kainy.cn/api/mobile?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://open.kainy.cn/api/mobile</a></p><p>根据手机号码查询归属地；</p><h3 id="请求参数-6"><a href="#请求参数-6" class="headerlink" title="请求参数"></a>请求参数</h3><table><thead><tr><th>名称</th><th>位置</th><th>类型</th><th>必选</th><th>说明</th></tr></thead><tbody><tr><td>phone</td><td>query</td><td>string</td><td>是</td><td>手机号码</td></tr><tr><td>x-api-key</td><td>header</td><td>string</td><td>是</td><td>none</td></tr></tbody></table><blockquote><p>返回示例</p></blockquote><blockquote><p>200 Response</p></blockquote><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"tel_address"</span>: <span class="string">"广东 广州 联通虚拟运营商"</span>,</span><br><span class="line">  <span class="attr">"province"</span>: <span class="string">"广东"</span>,</span><br><span class="line">  <span class="attr">"city"</span>: <span class="string">"广州"</span>,</span><br><span class="line">  <span class="attr">"sp"</span>: <span class="string">"联通虚拟运营商"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="返回结果-6"><a href="#返回结果-6" class="headerlink" title="返回结果"></a>返回结果</h3><table><thead><tr><th>状态码</th><th>状态码含义</th><th>说明</th><th>数据模型</th></tr></thead><tbody><tr><td>200</td><td><a href="https://tools.ietf.org/html/rfc7231?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#section-6.3.1" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">OK</a></td><td>none</td><td>Inline</td></tr></tbody></table><h3 id="返回数据结构-6"><a href="#返回数据结构-6" class="headerlink" title="返回数据结构"></a>返回数据结构</h3><p>状态码 <strong>200</strong></p><table><thead><tr><th>名称</th><th>类型</th><th>必选</th><th>约束</th><th>中文名</th><th>说明</th></tr></thead><tbody><tr><td>» tel_address</td><td>string</td><td>true</td><td>none</td><td>归属地</td><td>none</td></tr><tr><td>» province</td><td>string</td><td>true</td><td>none</td><td>省份</td><td>none</td></tr><tr><td>» city</td><td>string</td><td>true</td><td>none</td><td>城市</td><td>none</td></tr><tr><td>» sp</td><td>string</td><td>true</td><td>none</td><td>运营商</td><td>none</td></tr></tbody></table><h1 id="数据模型"><a href="#数据模型" class="headerlink" title="数据模型"></a>数据模型</h1>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;API key 获取地址：&lt;a href=&quot;https://open.kainy.cn/register/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE&quot; rel=&quot;external nofollow noopener&quot; referrerpolicy=&quot;unsafe-url&quot; target=&quot;_blank&quot;&gt;https://open.kainy.cn/register/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;GET-微信头像外链&quot;&gt;&lt;a href=&quot;#GET-微信头像外链&quot; class=&quot;headerlink&quot; title=&quot;GET 微信头像外链&quot;&gt;&lt;/a&gt;GET 微信头像外链&lt;/h2&gt;&lt;p&gt;GET &lt;a href=&quot;https://open.kainy.cn/api/wxAvatar?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE&quot; rel=&quot;external nofollow noopener&quot; referrerpolicy=&quot;unsafe-url&quot; target=&quot;_blank&quot;&gt;https://open.kainy.cn/api/wxAvatar&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;微信禁止直接外链用户头像，通过此接口，可以绕过限制。&lt;/p&gt;
&lt;h3 id=&quot;请求参数&quot;&gt;&lt;a href=&quot;#请求参数&quot; class=&quot;headerlink&quot; title=&quot;请求参数&quot;&gt;&lt;/a&gt;请求参数&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;名称&lt;/th&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;必选&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;url&lt;/td&gt;
&lt;td&gt;query&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;原始头像地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ak&lt;/td&gt;
&lt;td&gt;query&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;api-key，可通过URL传递，如不填写，请通过header 的 x-api-key 传递。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x-api-key&lt;/td&gt;
&lt;td&gt;header&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="小程序" scheme="https://blogs.kainy.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
      <category term="公众号" scheme="https://blogs.kainy.cn/tags/%E5%85%AC%E4%BC%97%E5%8F%B7/"/>
    
  </entry>
  
  <entry>
    <title>告别手动”分锅“，SonarQube扫描问题自动分配责任人</title>
    <link href="https://blogs.kainy.cn/2025/12/SonarQube%E6%89%AB%E6%8F%8F%E9%97%AE%E9%A2%98%E8%87%AA%E5%8A%A8%E5%88%86%E9%85%8D%E8%B4%A3%E4%BB%BB%E4%BA%BA/"/>
    <id>https://blogs.kainy.cn/2025/12/SonarQube扫描问题自动分配责任人/</id>
    <published>2025-12-22T22:20:17.000Z</published>
    <updated>2026-04-30T06:18:18.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="代码质量管理的“最后一公里”"><a href="#代码质量管理的“最后一公里”" class="headerlink" title="代码质量管理的“最后一公里”"></a>代码质量管理的“最后一公里”</h2><p>在日常的研发管理中，引入代码质量扫描（如 SonarQube）是保障工程质量的必要手段。然而，随着项目迭代和团队规模的扩大，我们经常面临一个痛点：</p><p><strong>扫描出来的问题成百上千，但不知道该谁修。</strong></p><p>作为管理者，如果每次扫描后都要人工去核对 Git 提交记录，然后手动将 Issue 指派给对应的开发人员，这无疑是巨大的工作量浪费。这种“保姆式”的管理不仅效率低下，而且容易出错。如果问题不能第一时间流转到“始作俑者”手中，技术债务就会像滚雪球一样越积越多，最终导致“破窗效应”。</p><a id="more"></a><p>为了解决这个问题，实现长治久安的代码质量管理，我们需要打通 <strong>CI/CD 工具与版本控制系统（SCM）</strong> 之间的任督二脉，实现<strong>问题的自动分配</strong>。</p><h2 id="核心痛点与解决方案"><a href="#核心痛点与解决方案" class="headerlink" title="核心痛点与解决方案"></a>核心痛点与解决方案</h2><ul><li><p><strong>现状：</strong> 代码扫描出 Bug/漏洞，状态为“未分配”。</p></li><li><p><strong>痛点：</strong> 管理员需要手动指派，不仅累，而且滞后。</p></li><li><p><strong>目标：</strong> 谁写的代码出了问题，系统自动挂在谁的名下。</p></li><li><p><strong>方案：</strong> 配置 SCM（Source Control Management）插件，利用 Git 的 Author 信息自动关联扫描平台的用户。</p></li></ul><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/2025/10/Pasted_image_20251021173819-1761559534432.png-1j8ii2suq.webp" alt></p><hr><h2 id="实操指南：三步实现自动归属"><a href="#实操指南：三步实现自动归属" class="headerlink" title="实操指南：三步实现自动归属"></a>实操指南：三步实现自动归属</h2><p>以下是在代码质量管理平台（以 SonarQube 为例）中的具体配置步骤。</p><h3 id="第一步：确保-SCM-功能已开启"><a href="#第一步：确保-SCM-功能已开启" class="headerlink" title="第一步：确保 SCM 功能已开启"></a>第一步：确保 SCM 功能已开启</h3><p>首先，我们需要确认系统能够读取项目的版本控制信息。</p><ol><li><p>以管理员身份登录。</p></li><li><p>进入 <strong>“配置” (Administration)</strong> -&gt; <strong>“SCM”</strong>。</p></li><li><p>检查并确认 SCM 传感器（Sensor）没有被禁用，且已安装 Git 等相关插件。</p></li></ol><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/2025/10/Pasted_image_20251021174044-1761559534427.png-1j8ii2t5h.webp" alt></p><h3 id="第二步：进入用户管理界面"><a href="#第二步：进入用户管理界面" class="headerlink" title="第二步：进入用户管理界面"></a>第二步：进入用户管理界面</h3><p>自动分配的核心逻辑是：<strong>扫描器读取代码每一行的 Git Blame 信息（邮箱或用户名） -&gt; 匹配平台内的用户账号 -&gt; 自动指派。</strong></p><p>因此，我们需要维护用户映射关系。</p><ol><li><p>点击顶部菜单的 <strong>“配置” (Administration)</strong>。</p></li><li><p>选择 <strong>“权限” (Security)</strong> -&gt; <strong>“用户” (Users)</strong>。</p></li></ol><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/2025/10/Pasted_image_20251021174930-1761559534420.png-1j8ii2qgt.webp" alt></p><h3 id="第三步：关联-SCM-账号（关键步骤）"><a href="#第三步：关联-SCM-账号（关键步骤）" class="headerlink" title="第三步：关联 SCM 账号（关键步骤）"></a>第三步：关联 SCM 账号（关键步骤）</h3><p>这是最关键的一步。很多时候自动分配失效，就是因为开发者在 Git 中配置的 Email/Name 与平台账号不一致。</p><ol><li><p>在用户列表中找到对应的开发人员。</p></li><li><p>点击最右侧的 <strong>“动作”</strong> 按钮（列表项末尾的设置图标）。</p></li><li><p>在弹出的菜单中选择 <strong>“更新详情” (Update Details)</strong>。</p></li><li><p>在弹窗中的 <strong>“SCM 账号” (SCM Accounts)</strong> 一栏中，输入开发者在提交 Git 代码时使用的 <strong>Email</strong> 或 <strong>Username</strong>。</p><ul><li><em>Tips：支持输入多个值，如果该开发者在不同仓库用了不同的邮箱，可以全部填入。</em></li></ul></li></ol><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/2025/10/Pasted_image_20251021174513-1761559534412.png-1j8ii2pak.webp" alt></p><p>完成这一步后，系统就建立起了 <strong>Git 提交者 <--> 平台用户</--></strong> 的映射关系。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>配置完成后，下次执行流水线扫描时，新发现的代码异味（Code Smell）、漏洞（Vulnerability）或 Bug，将直接挂载到对应开发者的名下。</p><p>这带来的好处是显而易见的：</p><ol><li><p><strong>释放管理精力：</strong> 我不再需要充当“分发员”的角色。</p></li><li><p><strong>缩短反馈弧：</strong> 开发者能立刻收到通知（配合邮件或钉钉/企微插件），知道自己刚提交的代码有问题。</p></li><li><p><strong>责权清晰：</strong> 每一行代码都有据可查，培养团队“谁开发谁负责”的质量意识。</p></li></ol><p>技术管理者，要善用工具流程来解决重复性劳动，把时间花在更具价值的架构设计和团队建设上。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;代码质量管理的“最后一公里”&quot;&gt;&lt;a href=&quot;#代码质量管理的“最后一公里”&quot; class=&quot;headerlink&quot; title=&quot;代码质量管理的“最后一公里”&quot;&gt;&lt;/a&gt;代码质量管理的“最后一公里”&lt;/h2&gt;&lt;p&gt;在日常的研发管理中，引入代码质量扫描（如 SonarQube）是保障工程质量的必要手段。然而，随着项目迭代和团队规模的扩大，我们经常面临一个痛点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;扫描出来的问题成百上千，但不知道该谁修。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;作为管理者，如果每次扫描后都要人工去核对 Git 提交记录，然后手动将 Issue 指派给对应的开发人员，这无疑是巨大的工作量浪费。这种“保姆式”的管理不仅效率低下，而且容易出错。如果问题不能第一时间流转到“始作俑者”手中，技术债务就会像滚雪球一样越积越多，最终导致“破窗效应”。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="团队效能" scheme="https://blogs.kainy.cn/tags/%E5%9B%A2%E9%98%9F%E6%95%88%E8%83%BD/"/>
    
      <category term="DevOps" scheme="https://blogs.kainy.cn/tags/DevOps/"/>
    
  </entry>
  
  <entry>
    <title>SyncMein 侵权行为投诉渠道及政策说明</title>
    <link href="https://blogs.kainy.cn/2025/11/SyncMein%20%E4%BE%B5%E6%9D%83%E8%A1%8C%E4%B8%BA%E6%8A%95%E8%AF%89%E6%B8%A0%E9%81%93%E5%8F%8A%E6%94%BF%E7%AD%96%E8%AF%B4%E6%98%8E/"/>
    <id>https://blogs.kainy.cn/2025/11/SyncMein 侵权行为投诉渠道及政策说明/</id>
    <published>2025-11-12T12:46:17.000Z</published>
    <updated>2026-04-30T06:18:18.047Z</updated>
    
    <content type="html"><![CDATA[<p><strong>致 SyncMein 用户及各内容平台方：</strong></p><p><a href="https://kainy.cn/SyncMeIn/#blogs" target="_blank" rel="noopener">SyncMein 插件</a>（以下简称“本插件”）的设计初衷，是为了解决个人用户在合法持有多个设备时，同步个人账号登录状态的不便，提升用户在自有设备间切换的体验。</p><p>我们尊重所有创作者的劳动成果、合法权益，并致力于维护内容平台的正常经营秩序。</p><p><strong>一、 严正声明</strong></p><p>近期，我们监测到有部分用户滥用本插件，将其用于“付费共享会员账号”等商业盈利活动。此行为严重违反了 SyncMein 的服务协议，不仅侵害了本插件的权益，更对相关内容平台及内容创作者的合法权益造成了严重损害。</p><p>我们在此严正声明：<strong>SyncMein 坚决反对将本插件用于包括（但不限于）付费共享会员账号、账号租赁在内的一切商业目的。</strong></p><a id="more"></a><p><strong>二、 违规处理措施</strong></p><p>为遏制侵权行为，我们将采取以下措施：</p><ol><li><p><strong>账号封禁：</strong> 对于任何违反 SyncMein 使用协议、利用本工具非法获利或侵犯他人权益的账号，一经核实，我们将立即予以<strong>永久封禁</strong>处理。</p></li><li><p><strong>建立“禁用域名名单”：</strong> 我们已建立并动态维护一个“禁用域名名单”。本插件将禁止为名单内的所有域名生成和同步登录口令，从源头上阻止相关平台的账号共享。</p></li></ol><p><strong>三、 侵权举报渠道</strong></p><p>我们在此设立官方侵权行为举报渠道。如果您是个人用户、内容创作者或平台方，发现任何个人或组织借助 SyncMein 实施侵权行为，请通过以下方式联系我们，并提供相关证明。</p><p><strong>1. 举报需要提供的材料：</strong></p><ul><li><p>侵权行为的详细描述。</p></li><li><p>可证明侵权行为的证据（例如：销售页面截图、付款记录、聊天记录、公开宣传链接等）。</p></li></ul><p><strong>2. 举报处理流程：</strong></p><ol><li><p><strong>提交举报：</strong> 请将上述材料发送至我们的官方举报邮箱：<strong>[<a href="mailto:smi-jubao@gqmg.com?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">smi-jubao@gqmg.com</a>]</strong></p></li><li><p><strong>内部核实：</strong> 我们在收到举报后，将进行深入核实。</p></li><li><p><strong>执行处理：</strong> 举报内容一经查实，我们将立即采取行动（包括但不限于封禁相关 SyncMein 账号、拉黑设备特征码等）。</p></li></ol><p><strong>3. 如何申请将域名加入“禁用域名名单”：</strong></p><p>如果您是<strong>内容平台方</strong>或<strong>域名所有者</strong>，并希望将您的域名加入“禁用域名名单”，以保护贵平台的权益：</p><ul><li><p>请您务必使用<strong>与申请域名相同的邮箱后缀</strong>（例如：使用 <a href="mailto:%60security@yourdomain.com?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">`security@yourdomain.com</a><code>邮箱申请</code>yourdomain.com`）发送申请。</p></li><li><p>或使用<strong>公开渠道可查证域名归属的邮箱</strong>（例如：域名 Whois 信息中的联系邮箱）发送申请。</p></li><li><p><strong>申请邮箱：</strong> <strong>[<a href="mailto:smi-block@gqmg.com?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">smi-block@gqmg.com</a>]</strong></p></li></ul><p>我们对所有遵守协议、合理使用工具的用户表示感谢，也对因侵权行为受到损害的平台方表示歉意。SyncMein 团队将持续投入资源，打击黑产，维护健康的网络环境。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;strong&gt;致 SyncMein 用户及各内容平台方：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://kainy.cn/SyncMeIn/#blogs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SyncMein 插件&lt;/a&gt;（以下简称“本插件”）的设计初衷，是为了解决个人用户在合法持有多个设备时，同步个人账号登录状态的不便，提升用户在自有设备间切换的体验。&lt;/p&gt;
&lt;p&gt;我们尊重所有创作者的劳动成果、合法权益，并致力于维护内容平台的正常经营秩序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一、 严正声明&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;近期，我们监测到有部分用户滥用本插件，将其用于“付费共享会员账号”等商业盈利活动。此行为严重违反了 SyncMein 的服务协议，不仅侵害了本插件的权益，更对相关内容平台及内容创作者的合法权益造成了严重损害。&lt;/p&gt;
&lt;p&gt;我们在此严正声明：&lt;strong&gt;SyncMein 坚决反对将本插件用于包括（但不限于）付费共享会员账号、账号租赁在内的一切商业目的。&lt;/strong&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="SyncMein" scheme="https://blogs.kainy.cn/categories/SyncMein/"/>
    
      <category term="SyncMein教程" scheme="https://blogs.kainy.cn/categories/SyncMein/SyncMein%E6%95%99%E7%A8%8B/"/>
    
    
      <category term="SyncMein" scheme="https://blogs.kainy.cn/tags/SyncMein/"/>
    
  </entry>
  
  <entry>
    <title>为了分享自己做的 MCP，我最后做了一个网站…</title>
    <link href="https://blogs.kainy.cn/2025/07/%E4%B8%BA%E4%BA%86%E5%88%86%E4%BA%AB%E8%87%AA%E5%B7%B1%E5%81%9A%E7%9A%84%20MCP%EF%BC%8C%E6%88%91%E6%9C%80%E5%90%8E%E5%81%9A%E4%BA%86%E4%B8%80%E4%B8%AA%E7%BD%91%E7%AB%99%E2%80%A6/"/>
    <id>https://blogs.kainy.cn/2025/07/为了分享自己做的 MCP，我最后做了一个网站…/</id>
    <published>2025-07-31T04:23:04.000Z</published>
    <updated>2026-04-30T06:18:18.055Z</updated>
    
    <content type="html"><![CDATA[<p>最初只想做一个 MCP server 练练手，验证 MCP 能力边界，结果却一步步把 coze 、混元智能体都摸个底朝天，最终把功能做了一个网站。。</p><p>背景是马上国庆了，想用智能体帮我规划一下旅游路线。路线规划最耗费时间精力的就是酒店，我打算用 mcp 来解决这个痛点。</p><p>从数据入手，先写了一个优惠酒店信息爬虫，爬取携程上面支持“未订可退、过期自动退”的优惠酒店。选择携程是因为大平台，产品相对可靠也比较有保障。而过期退则可以很好的应对行程变化的突发情况。</p><a id="more"></a><p>有了数据，再写一个 API，然后套上 mcp 协议，就算完事了。</p><p>放在 ChatBot 里，很快就 work 了</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdptuuq4.png" alt></p><p>但这只是开始，想要分享 MCP server 给被人用，还需要发布到 coze 和混元这样的平台。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdpua6i2.png" alt></p><p>这是 coze 生成的结果，虽然按照要求的产品卡片格式排版，但是忽略了图片元素渲染，导致图片位置看起来特奇怪。好在预定链接可以点击，正确跳转。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdpv2vyh.png" alt></p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdpufzrw.png" alt></p><p>而混元的情况则比较糟糕，完全没理会产品卡片格式要求，图片和产品链接都是虚拟的。。完全没用。</p><p>本来 MCP 就的意义就在于打通大模型和真实数据壁垒，结果大平台处于信息安全的考量，粗暴地把有用的数据都隐蔽，“娃娃跟洗澡水一起倒“了。</p><p>看来短期内，真正的开放还很难做到。</p><p>基于此，也只好另想办法。</p><p>自己的网站总归不受限吧？</p><p>好在有了 AI 辅助编程，制作一个网站不像往常那样费劲。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdpusot6.png" alt></p><p>这是最终效果，不仅排版美观了，有了更强的大模型支持，内容也丰富许多。</p><p>目前用的是我自用同款大模型，等调用量上来恐怕扛不住，再换回普通版。</p><p>嗯，这才是最初构思中，旅游路线规划应用应该有的样子。</p><p>还有优化空间，后面慢慢整活吧。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdq04dlq.jpg" alt="从左到右依次是：1、计划生成页；2、行程信息录入；3、计划生成进度；4、生成结果展示"></p><p>从左到右依次是：1、计划生成页；2、行程信息录入；3、计划生成进度；4、生成结果展示</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdq04ock.jpg" alt="从左到右依次是：1、首页；2城市列表页；3、旅程列表页；4、旅程详情页"></p><p>从左到右依次是：1、首页；2城市列表页；3、旅程列表页；4、旅程详情页</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最初只想做一个 MCP server 练练手，验证 MCP 能力边界，结果却一步步把 coze 、混元智能体都摸个底朝天，最终把功能做了一个网站。。&lt;/p&gt;
&lt;p&gt;背景是马上国庆了，想用智能体帮我规划一下旅游路线。路线规划最耗费时间精力的就是酒店，我打算用 mcp 来解决这个痛点。&lt;/p&gt;
&lt;p&gt;从数据入手，先写了一个优惠酒店信息爬虫，爬取携程上面支持“未订可退、过期自动退”的优惠酒店。选择携程是因为大平台，产品相对可靠也比较有保障。而过期退则可以很好的应对行程变化的突发情况。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="MCP" scheme="https://blogs.kainy.cn/tags/MCP/"/>
    
      <category term="旅游" scheme="https://blogs.kainy.cn/tags/%E6%97%85%E6%B8%B8/"/>
    
      <category term="网站" scheme="https://blogs.kainy.cn/tags/%E7%BD%91%E7%AB%99/"/>
    
  </entry>
  
  <entry>
    <title>请3休12，2025国庆提前冲！附20+国内精选路线，绝美秋色、登山看海！</title>
    <link href="https://blogs.kainy.cn/2025/07/%E8%AF%B73%E4%BC%9112%EF%BC%8C%E5%9B%BD%E5%BA%86%E6%8F%90%E5%89%8D%E5%86%B2%EF%BC%8120+%E5%9B%BD%E5%86%85%E7%B2%BE%E9%80%89%E8%B7%AF%E7%BA%BF%EF%BC%8C%E7%BB%9D%E7%BE%8E%E7%A7%8B%E8%89%B2%E3%80%81%E7%99%BB%E5%B1%B1%E7%9C%8B%E6%B5%B7%EF%BC%81/"/>
    <id>https://blogs.kainy.cn/2025/07/请3休12，国庆提前冲！20+国内精选路线，绝美秋色、登山看海！/</id>
    <published>2025-07-29T15:23:04.000Z</published>
    <updated>2026-04-30T06:18:18.099Z</updated>
    
    <content type="html"><![CDATA[<style>.posts-expand .post-body img {      border: none !important;    }</style><section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);">  <section style="max-width: 100%;margin-left: 8px;margin-right: 8px;box-sizing: border-box;">    <section style="line-height: 0;text-align: center;max-width: 100%;box-sizing: border-box;">      <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_gif/LicckDpL06qkHNpzchicibUA2DtkdpVjyzV9Xp98iaIQOYm0z3srJOxIM7GUmJQy8LNwTJ1BgWeL7iatmNPicXicQic15Q/640?wx_fmt=gif&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: justify;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>七月中旬，是谁坐在工位默默羡慕</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>小孩哥/姐趁着暑假出门看世界？</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>🥵🥵🥵</span><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>7&amp;8&amp;9三个月的</span><span style="color: rgb(255, 188, 0);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span>假</span><span style="font-style: normal;justify-content: flex-start;flex-flow: row;vertical-align: top;align-self: flex-start;flex: 0 0 auto;font-family: PingFangSC-light;font-size: 14px;text-align: center;color: rgb(255, 188, 0);font-weight: bold;box-sizing: border-box;">期空窗</span></strong></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>日子显得尤为漫长</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="background-color: rgb(255, 188, 0);color: rgb(255, 255, 255);font-size: 16px;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span>&nbsp;翘首期盼国庆！！&nbsp;</span></strong></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>&nbsp;想想那时被秋意覆盖的景色，就蠢蠢欲动</span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      </section>      <a id="more"></a>      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVBsXC2o8tZ4y9zHPejIrYJ1NEpNXqC7c3TBIxLp6RgWO1RaA65LcVHQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="margin: 0px;box-sizing: border-box;">        <section style="text-align: justify;font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">          <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>坝上秋色@蛮牛</span></p>        </section>      </section>      <section style="text-align: justify;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>作为2025年</span><span style="font-style: normal;justify-content: flex-start;flex-flow: row;vertical-align: top;align-self: flex-start;flex: 0 0 auto;font-family: PingFangSC-light;font-size: 14px;text-align: center;color: rgb(255, 188, 0);font-weight: bold;box-sizing: border-box;">最后一个黄金假</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>还是和中秋连着放，</span><span style="font-style: normal;justify-content: flex-start;flex-flow: row;vertical-align: top;align-self: flex-start;flex: 0 0 auto;font-family: PingFangSC-light;font-size: 14px;text-align: center;color: rgb(255, 188, 0);font-weight: bold;box-sizing: border-box;">一共8天</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>你想好怎么度过了吗？</span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      </section>      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVuVibcyudMg7g1PKA2qsibu2ib8BforZVLbzjO3a58mzLknAo0wDKtlNrw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="margin: 0px;box-sizing: border-box;">        <section style="text-align: justify;font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">          <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>太行 @可航</span></p>        </section>      </section>      <section style="text-align: center;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">        <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>虽然距离十一假期还有两个多月</span></p>        <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>但现在筹划国庆出游一点都不早！</span></p>        <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>如果考虑多请3天假</span></p>        <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>甚至可以喜提</span><span style="font-size: 16px;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span style="color: rgb(255, 188, 0);box-sizing: border-box;"><span>12天超长假期</span></span></strong></span><span>！</span></p>        <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>简直赚翻了，年假就该这么用！</span></p>      </section>      <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">        <section style="text-align: center;line-height: 2em;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVwCq1kt1GV2Iw4cuI6Aw3l59moibGUB40kibIecv0Pk9Llwt4mhcRKAoA/640?wx_fmt=jpeg" class="rich_pages wxw-img js_insertlocalimg" style="width: 479px;height: 115px;" type="block" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="margin: 0px;box-sizing: border-box;">        <section style="text-align: justify;font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">          <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">*只需要请9月28/29/30日 or 10月9/10/11日</span></span></p>          <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">即可拼出12天惊喜好假😍</span></span></p>        </section>      </section>      <section style="text-align: justify;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>这不！小侠也先行一步💃🏻</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>准备了适合国庆出发的国内长线</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>绝大部分都是</span><span style="font-style: normal;justify-content: flex-start;flex-flow: row;vertical-align: top;align-self: flex-start;flex: 0 0 auto;text-align: center;font-family: PingFangSC-light;font-size: 16px;font-weight: bold;color: rgb(255, 188, 0);box-sizing: border-box;">4-7日</span><span>路线</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>不请假闭眼冲</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">✅</span></span><span><span textstyle style="font-weight: bold">多条</span></span><span><span textstyle style="font-weight: bold">已成行 ✅多地高铁直达</span></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👇🏻</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="color: rgb(255, 188, 0);font-size: 16px;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span><span textstyle style="text-decoration: underline">自然 / 人文 / 秋色 / 亲子 / 户外</span></span></strong></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>经典爆款和小众宝藏，这里都有🌟</span></p>        <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>不想错过心仪路线，可以尽早上车哦~</span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      </section>    </section>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">1</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>景德镇出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-size: 15px">👉🏻</span><a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E6%99%AF%E5%BE%B7%E9%95%87&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【江西·徽风瓷韵】</span></a><span textstyle style="font-size: 15px">&nbsp;</span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-size: 15px">📆4天3晚</span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>景德镇-婺源篁岭-婺女洲，饱览风光，访古窑逛烟火集市，感受盛世徽州。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVRsqFtTr4HQNibxmtI6jibt84LFkGqbAnKbZcnnYs8ekb9VbmFPYUIu5A/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="font-size: 12px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">2</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>武夷山出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: justify;font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E6%AD%A6%E5%A4%B7%E5%B1%B1&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【轻户外·丈量武夷】</span></a></span></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆4天3晚</span></span></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span>秋韵武夷山，误入云雾缭绕的仙境。在轻徒步中收集五彩秋色，登顶白云岩独家视角览九曲溪全貌。</span></span></p>      </section>      <section style="text-align: center;margin: 10px 0px 0px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzV0sia5s0OY1Z94IcVNlYUd1FDjgzb0Ej5Q4LIwSIj1IibcjqMU7Gq4yRg/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="text-align: justify;font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      </section>    </section>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">3</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><strong style="box-sizing: border-box;"><span>霞浦出发</span></strong></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="font-size: 14px;text-align: justify;font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="box-sizing: border-box;"><span>👉🏻</span></span><span><a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%8E%A6%E9%97%A8&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【四礵列岛】</span></a></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>福建海岛天花板！一次看遍果冻海、断崖、草地、海鸟、沙滩、日落，海岸徒步现实版塞尔达，夜宿小冰岛浮鹰岛。</span></p>      </section>      <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVfLjmLTa57RZy3UzFHFhCoMkFOBMlcKzk7oV6icMg8GvGOmntPXf1reQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="font-size: 12px;text-align: justify;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      </section>    </section>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">4</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>北京出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%8C%97%E4%BA%AC&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【世界遗产在北京】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>漫游紫禁城、天坛追寻古老祭天礼、参观皇家御园。满城秋色，最是人间留不住。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVmrQupmxg5LNOAPa2d0Pc6ZeMlmxVDLAIkViaUbO1iccn9cCt7pmY8tUw/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E9%84%82%E5%B0%94%E5%A4%9A%E6%96%AF&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【库布齐轻装徒步】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>私享沙海秘境，越野车穿沙，在沙漠游泳，夜游古城，跟随专业讲解走进云冈石窟。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVQe6N1JUGqDtictejNjQksnsBal0Hu4ngkOmtIftqcZgFk2T4j36Dg8Q/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVBQ4yP0TibMFpDkSFMfHtJC7Y9NUBCORMKicZYkmV0IUh9Aus7UAj5Hmg/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>领队拍摄</span></p>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;width: 100%;align-self: flex-start;box-sizing: border-box;">    <section style="margin: 0px 0px 8px;width: 100%;box-sizing: border-box;">      <section style="font-size: 14px;text-align: justify;font-family: PingFangSC-light;width: 100%;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%BC%A0%E5%AE%B6%E5%8F%A3&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【金秋坝上】</span></a></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆6天5晚</span></span></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>高性价比赏秋线 ，游侠客坝上牧歌营地+草原火锅，看马术表演、乘越野车穿越、马背骑行，超多草原游牧体验！</span></p>      </section>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVJo9jm53iblGcM9ic6jNU4EaqRlcYOnKibvezFwvI7Quc9JIAy8YAIKzLQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVNG406lvc0PGFcJ9ziaf5l94GibEAlvPsPmOYbvGakLiac9zhsH3BEJkxw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>  </section>  <section style="margin: 0px 0px 12px;box-sizing: border-box;">    <section style="text-align: center;font-family: PingFangSC-light;font-size: 12px;color: rgb(160, 160, 160);box-sizing: border-box;">      <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>左图@蛮牛 右图@江月</span></p>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;margin: 0px 0px 8px;width: 100%;align-self: flex-start;box-sizing: border-box;">    <section style="font-size: 14px;text-align: justify;font-family: PingFangSC-light;width: 100%;box-sizing: border-box;">      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p/115?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【亲子·金秋坝上】</span></a></span></p>      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆6天5晚</span></span></span></p>      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>宝妈宝爸也可以选择这一条坝上秋色线，大人美美下午茶、小孩营地肆意撒欢。升级增加七彩森林+甘丹驼城，更多小动物互动和内蒙文化体验。</span></p>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVs6s2IOFuABiaJhZUfkWchH4w4u8lKSYaGyyN42FJ6lXb58Nf6uNT8Ng/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzV4sFyz05JGVtvv7Pm4KRk0Kud6vox0mVxEkLHNNiaH6sqkGbfAc8icsAw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>  </section>  <section style="font-size: 14px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">5</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>深圳出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="margin: 0px 0px 8px;box-sizing: border-box;">    <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E6%B7%B1%E5%9C%B3&endPoint=%E9%A6%99%E6%B8%AF&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【香港四径】</span></a></span></p>      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>一次打卡世界级知名四大径精华！卫奕信径9段、麦理浩径2段、凤凰径2段、港岛径8段</span></p>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVQic0yAoibyKUY9hia7YI4nY9JEBK6vJU9UeiaZzV8wOibjtgObDdibh2jrKQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVkibf8mzibVAqxzt1NB2BuorpweicfAvicsrVGkL6N7ZZkSeZjvOnqicfHWA/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="text-align: center;font-family: PingFangSC-light;font-size: 12px;color: rgb(160, 160, 160);box-sizing: border-box;">      <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>左图麦理浩径@忆雪 右图破边洲@阿辉</span></p>    </section>  </section>  <section style="font-size: 12px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">6</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>南宁出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="font-size: 14px;text-align: justify;font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%8D%97%E5%AE%81&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【田园靖西】</span></a></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆4天3晚/5天4晚</span></span></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>广西最后一个不为人知的世外桃源，正值丰水期！2025新升级峒那屿湾行程，配合通灵大峡谷、德天跨国瀑布、鹅泉等西南边境小众景色，住明仕山庄沉浸感受写意山水</span></p>      </section>      <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVicKNN7XY9lu46gZeWYRHMM3vIaoQelCaASRYm6WIjgGMFhPBHjJF3cA/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVufCjTpician0r7G6vP8mBSXZuKmAAViasOjHyiblFax9fCfJPJb6TEvyOQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>@晚风</span></p>    </section>  </section>  <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">7</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>长沙出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;margin: 0px 0px 8px;width: 100%;align-self: flex-start;box-sizing: border-box;">    <section style="font-size: 14px;text-align: justify;font-family: PingFangSC-light;width: 100%;box-sizing: border-box;">      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E9%95%BF%E6%B2%99&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【穿越大湘西】</span></a></span></p>      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆7天6晚</span></span></span></p>      <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>槟榔谷探洞奇景，借母溪避世轻徒，车、船、行三结合，360度不回头花式深入湘西腹地。</span></p>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVswcNPEFfh6DvIam5eqRvRbd7OVuOcSKLdU5wrJciba8Vb7ricSicfycMg/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img ProseMirror-selectednode" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: 50%;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="text-align: center;margin: 0px 0px 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 95%;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVLcwRNE6F7woRKnfrR51Ap46SmZ350GA1HGPCvdjG2Ejx0NkicX8pIrg/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>    </section>  </section>  <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">8</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>宜昌出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%AE%9C%E6%98%8C&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【征途·神农架】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆4天3晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>哀牢山同款，穿越高山草甸、原始森林，感受神农架神秘风貌，露营观星空看日出。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVhmNPoiaBs8AibZc2UVFT8Imxa2DYQRicD8jdu3uiaoAJp3Rkv2UpXfmysA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="text-align: center;margin: 10px 0px 0px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVzF76OWvcVl7cVa4OCb6kg8Nc060kRe2mm2yYoKTvCEEqa3yEGPYXWQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="font-size: 12px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">9</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>成都出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E6%88%90%E9%83%BD&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【川西雪山巡礼】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>川西三大神山一次看遍，夜宿牛背山星辰营地，参与即送定制冰箱贴，赠送牛背山utv车体验。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzV0XPxiaRwxrHxgwR76Wb5a1bdPLZR6U6wwEdtGmLhgvCIlJ1ib41Reprw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>@修罗</span></p>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="font-size: 14px;text-align: justify;font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E6%88%90%E9%83%BD&endPoint=%E6%8B%89%E8%90%A8&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【川西秘境徒步】</span></a></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆4天3晚</span></span></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>耗时3年探出极致徒步路线，串联了塔公草原、雅拉雪山、贡嘎雪山、丹巴藏寨等绝美秘境。</span></p>      </section>      <section style="text-align: center;margin: 10px 0px 0px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVkIGEhJMiaftDDpCibmZSmBfwB4eQ5Db4mlSBdu58zycbyOlI0AdrEKNQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="text-align: justify;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      </section>    </section>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">10</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>重庆出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E9%87%8D%E5%BA%86&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【巴渝山城】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>重庆精华景点一次走遍。打卡两大世界遗产——大足石刻、武隆喀斯特，还有国家5A景区金佛山。</span></p>  </section>  <section style="text-align: center;margin: 10px 0px 0px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVTbiazia3rnUrBNwKI3v2ZicRUI5F3xrG1vkxcglic8Afq5DOuPfQ9ibfmaw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">11</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>郑州出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E9%83%91%E5%B7%9E&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【飞跃太行】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>南太行经典休闲轻户外线路，结合精华景点：郭亮+王莽岭+天界山+八里沟，风光、人文兼具。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzV0F2LvBiaBElOHSgf6qaFgXriaoc13DQq4VjHkx18ic6wATNzia0zJJJo7A/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>@可航</span></p>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E9%83%91%E5%B7%9E&endPoint=%E6%8B%89%E8%90%A8&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【征途南太行·经典版】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>如果你体力还不错，也可选择这一条！户外必走经典，国家地理推荐目的地。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVQ35bJY5EIcpic44ZibPbzKcnrX4zjJVsWmhCEDnlJlnd88BgXWDadViaw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>王莽岭日出@泊瑾</span></p>    </section>  </section>  <section style="font-size: 14px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section></section><section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);">  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">12</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>大同出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%A4%A7%E5%90%8C&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【秦晋风云加长版】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆9天8晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>走进黄土高原核心区，感受地道的民俗人文和壮丽的绝美风光。小众目的地，避开人从众！</span><span><br class="ProseMirror-trailingBreak"></span></p>    <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">      <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVrnk8FXGH0QOvictibM2libuyvLzXdmHPStBv1jqbyz1syR4BhhoDYYbPQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>    </section>    <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">      <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVsXia0wrib7wbq5IkulW7YhSkXo3IBXVVHJrhIurcpvh6NwXvUZRYEdew/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>    </section>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">13</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>兰州出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%85%B0%E5%B7%9E&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【亲子·大漠星空】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>去星星的故乡，感受不一样的大西北。乘坐特色交通羊皮筏子、毛驴车、骆驼车；住农家、吃西北菜、星空露营。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVnKXqV5sHVPE1t7ibo7UDxgxo8aNGENswIIcoRly7eibJNiaOlXDGMg9Lw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVdJZPKGJPqaqN7VocMgY6pByia9EJC3MegQGa3P45icTcVYxrhDqQ1BDw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="font-size: 12px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">14</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>银川出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E9%93%B6%E5%B7%9D&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【腾格里五湖连穿】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆5天4晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>穿越金色沙海，邂逅长生天的眼泪！是时候解锁人生第一座沙漠了！</span></p>  </section>  <section style="text-align: center;margin: 10px 0px 0px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVKFSKQSsT6QJ2dibXunHcggCg82aojTtXBQG46via3MY3dUB1ZEmvvgBQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="font-size: 14px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-size: 12px; font-weight: bold">15</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>哈尔滨出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E5%93%88%E5%B0%94%E6%BB%A8&endPoint=%E5%91%BC%E4%BC%A6%E8%B4%9D%E5%B0%94&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【呼伦贝尔秋色】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆7天6晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>阿尔山、额尔古纳湿地、白桦林、卡线公路、蘑阿公路......经典秋色一网打尽，入住阿尔山景区内，游玩时间更充足！</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVUyINyTtnediboJOiazZVIIAnsMVvt9NXkw00f3IQ8ciamVqTRib5XqicWcw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>阿尔山驼峰岭天池@宋新子</span></p>    </section>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVU6hEFanuCXur7icAUULRaVJodSoHofibl7jDTRIzQPQTYzJJ4icXp4PWQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>额尔古纳@忆雪</span></p>    </section>  </section>  <section style="font-size: 12px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">16</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>长春出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E9%95%BF%E6%98%A5&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【东北秋色】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆7天6晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>天池、瀑布、堰塞湖、彩林、红枫、... ...地质与色彩奇妙互动，还安排了温泉、人参林秋色轻徒步、百年木屋村民俗等体验。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVbFS8LrYibjVYBm6VdaHpLBq0ic3buyQicmNIpJBDsJ6FHAgJ9kqRRWorQ/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="margin: 0px;box-sizing: border-box;">    <section style="font-size: 12px;color: rgb(160, 160, 160);font-family: PingFangSC-light;box-sizing: border-box;">      <p style="text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>老边沟@kris陈瑞瑞</span></p>    </section>  </section>  <section style="font-size: 12px;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">17</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>拉萨出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">    <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">      <section style="font-size: 14px;text-align: justify;font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E6%8B%89%E8%90%A8&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【库拉岗日转山】</span></a></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆6天5晚</span></span></span></p>        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>想开启人生第一次高海拔徒步？你想0距离接触一次雪山圣湖？来这条经典西藏户外线！</span></p>      </section>      <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzV4HLIYbW3ibvKk5Ps7aesU1XcOg9loeJH5YrmVXqCGXeRXEzDcnZfe7Q/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="text-align: center;margin: 10px 0px 0px;line-height: 0;box-sizing: border-box;">        <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVuIpoibFZheDHic4mahw6q5OrpkuAuaxK1icxkZSyOfYoKU3tkDtTtiax0Q/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>      </section>      <section style="font-size: 12px;text-align: justify;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>      </section>    </section>  </section>  <section style="text-align: center;justify-content: center;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;">    <section style="display: inline-block;vertical-align: top;width: auto;align-self: flex-start;flex: 0 0 auto;line-height: 0;min-width: 5%;max-width: 100%;height: auto;margin: 0px;z-index: 1;padding: 0px;box-sizing: border-box;">      <section style="margin: 3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 18px;height: 18px;vertical-align: top;overflow: hidden;border-radius: 252px;background-color: rgb(242, 90, 138);box-sizing: border-box;">          <section style="color: rgb(255, 255, 255);line-height: 1.6;font-size: 12px;box-sizing: border-box;">            <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><span textstyle style="font-weight: bold">18</span></span></p>          </section>        </section>      </section>      <section style="display: flex;width: 100%;flex-flow: column;box-sizing: border-box;">        <section style="z-index: 1;box-sizing: border-box;">          <section style="display: inline-block;width: 3px;height: 6px;vertical-align: top;overflow: hidden;background-color: rgb(185, 196, 200);box-sizing: border-box;">            <section style="text-align: justify;box-sizing: border-box;">              <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>            </section>          </section>        </section>      </section>      <section style="margin: -3px 0px 0px;box-sizing: border-box;">        <section style="display: inline-block;width: 13px;height: 6px;vertical-align: top;overflow: hidden;border-radius: 99%;background-color: rgb(87, 87, 87);box-sizing: border-box;">          <section style="text-align: justify;box-sizing: border-box;">            <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>          </section>        </section>      </section>    </section>    <section style="display: inline-block;vertical-align: top;width: auto;min-width: 5%;max-width: 100%;flex: 0 0 auto;height: auto;padding: 0px 0px 0px 7px;align-self: flex-start;box-sizing: border-box;">      <section style="text-align: justify;color: rgb(255, 188, 0);font-family: PingFangSC-light;box-sizing: border-box;">        <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><b style="box-sizing: border-box;"><span>乌鲁木齐出发</span></b></p>      </section>      <section style="transform: perspective(0px);-webkit-transform: perspective(0px);-moz-transform: perspective(0px);-o-transform: perspective(0px);transform-style: flat;box-sizing: border-box;">        <section style="text-align: right;margin: 0px;line-height: 0;transform: rotateX(180deg) rotateY(180deg);-webkit-transform: rotateX(180deg) rotateY(180deg);-moz-transform: rotateX(180deg) rotateY(180deg);-o-transform: rotateX(180deg) rotateY(180deg);box-sizing: border-box;">          <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;width: 78px;height: auto;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVI6dOQkwHER7jCbZUyBeB7wKx5yfTiaoUoJw944TfGsnnFY7TciaCOBCA/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>        </section>      </section>    </section>  </section>  <section style="font-size: 14px;font-family: PingFangSC-light;box-sizing: border-box;">    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>👉🏻<a class="weapp_text_link js_weapp_entry" href="https://hotel.gqmg.com/p?startPoint=%E4%B9%8C%E9%B2%81%E6%9C%A8%E9%BD%90&endPoint=%E5%96%80%E7%BA%B3%E6%96%AF&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" target="_blank" rel="external nofollow noopener" referrerpolicy="unsafe-url"><span textstyle style="font-size: 15px">【野奢邦·北疆秋色】</span></a></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span style="font-size: 14px;box-sizing: border-box;"><span><span textstyle style="font-size: 15px">📆7天6晚</span></span></span></p>    <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>北疆秋色野奢之选，入住金秋油画般的景区木屋，专车免排队直通喀纳斯秘境，将每一分钟都留给顶级秋色盛宴。</span></p>  </section>  <section style="text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;box-sizing: border-box;">    <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVMrlNLQMvsibxSUxlnqHN1IuMstd5whV319jOhIia6BicF4zUtZtP78QOw/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align:middle;max-width:100%;width:100%;box-sizing:border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>  </section>  <section style="display: inline-block;max-width: 100%;box-sizing: border-box;">    <section style="line-height: 0;max-width: 100%;box-sizing: border-box;">      <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;-webkit-tap-highlight-color: transparent;outline: 0px;letter-spacing: 0.544px;text-align: center;font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;visibility: visible;box-sizing: border-box;margin-left: 0px;margin-right: 0px;margin-bottom: 8px;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_gif/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVBYvNibQ3rZpkzWh6oftHZCqsJ1ceJr0MR8sXJBBiaAB1E6Dmicopn41ibg/640?wx_fmt=gif&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>    </section>  </section>  <section style="text-align: center;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">    <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>跟着小侠精选一起出发！</span><span><br class="ProseMirror-trailingBreak"></span></p>    <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>假期提前定！出游不踩雷！</span></p>    <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>更多【国庆路线】可点击下方图片查看👇🏻</span></p>    <section style="text-align: center;margin: 16px 0px 8px;line-height: 2em;"><a class="weapp_image_link js_weapp_entry" style><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_jpg/LicckDpL06qkHNpzchicibUA2DtkdpVjyzVMvwXJXS73cPMuWF9JCQ8qyfeugt6t7XhYlGuFgpbL4QzkPZD9ias2Ww/640?wx_fmt=jpeg&amp;from=appmsg" class="rich_pages wxw-img js_insertlocalimg" type="block" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></a></section>    <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);">      <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);">        <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);">          <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">            <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">              <section style="max-width: 100%;box-sizing: border-box;">                <section style="line-height: 0;-webkit-tap-highlight-color: transparent;outline: 0px;max-width: 100%;box-sizing: border-box;">                  <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;-webkit-tap-highlight-color: transparent;outline: 0px;visibility: visible;box-sizing: border-box;" nodeleaf><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_png/LicckDpL06qmVIbdRv9dviayicKcaR2D0sKicWnS899iaoMQm3eEHk4Q8RXDNbOlzTBH2ArEkcb1xkLhYia2YCcopp7A/640?wx_fmt=png&amp;from=appmsg" class="rich_pages wxw-img" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></section>                </section>              </section>              <section style="text-align: justify;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">                <section style="text-align: center;font-family: PingFangSC-light;font-size: 12px;color: rgb(160, 160, 160);box-sizing: border-box;">                  <section style="line-height: 0;-webkit-tap-highlight-color: transparent;outline: 0px;max-width: 100%;box-sizing: border-box;">                    <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);">                      <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">                        <section style="display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;">                          <section style="text-align: center;font-family: PingFangSC-light;font-size: 12px;color: rgb(154, 154, 142);box-sizing: border-box;">                            <p style="margin: 0px 8px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span>编辑@踏雪</span></p>                            <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;">                              <section style="text-align: justify;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;">                                <section style="margin: 8px 8px 0px;-webkit-tap-highlight-color: transparent;outline: 0px;font-size: 16px;letter-spacing: 0.544px;text-align: center;caret-color: rgba(0, 0, 0, 0);line-height: 2em;"><span style="-webkit-tap-highlight-color: transparent;outline: 0px;font-size: 12px;color: rgb(136, 136, 136);letter-spacing: 0.544px;font-family: Optima-Regular, PingFangTC-light;"><a class="weapp_image_link js_weapp_entry" style="color:var(--weui-LINK);outline:0px;cursor:default;user-select:none;width:100%"><img src="https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_gif/LicckDpL06qmI8ib75ELAPaianXViaz2uk61X2oBcIrcuHhnJvRpkNDWXo4LY7PIJJ5Tfkj7G0I9WtqjNIYRP6SpzQ/640?wx_fmt=gif&amp;from=appmsg&amp;wxfrom=5&amp;wx_lazy=1&amp;tp=webp" class="rich_pages wxw-img __bg_gif" style="-webkit-tap-highlight-color: transparent;outline: 0px;border-width: 0px;border-style: initial;border-color: initial;width: 100%;visibility: visible !important;" contenteditable="false"><img class="ProseMirror-separator" alt><br class="ProseMirror-trailingBreak"></a></span></section>                                <section style="margin-left: 8px;margin-right: 8px;line-height: 2em;"><strong style="-webkit-tap-highlight-color: transparent;margin-top: 0px;margin-bottom: 0px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: 0.544px;orphans: 2;text-align: justify;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 16px;caret-color: rgba(0, 0, 0, 0);background-color: rgb(255, 255, 255);color: rgba(0, 0, 0, 0.8);font-family: PingFangSC-light;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="-webkit-tap-highlight-color: transparent;margin-top: 0px;margin-bottom: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br class="ProseMirror-trailingBreak"></span>                                    <section style="margin-left: 8px;margin-right: 8px;text-align: justify;line-height: 2em;"><strong style="-webkit-tap-highlight-color: transparent;margin-top: 0px;margin-bottom: 0px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 16px;caret-color: rgba(0, 0, 0, 0);background-color: rgb(255, 255, 255);color: rgba(0, 0, 0, 0.8);font-family: PingFangSC-light;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="-webkit-tap-highlight-color: transparent;margin-top: 0px;margin-bottom: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle style="font-size: 14px">👇 点击</span></span><span style="-webkit-tap-highlight-color: transparent;margin-top: 0px;margin-bottom: 0px;padding: 0px;outline: 0px;max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="-webkit-tap-highlight-color: transparent;margin-top: 0px;margin-bottom: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle style="font-size: 14px">【阅读原文】</span><span textstyle style="font-size: 14px; color: rgb(0, 0, 0)">查看专栏内容了解更多</span></span></span></strong></section>                                  </strong></section>                              </section>                            </section>                          </section>                        </section>                      </section>                    </section>                  </section>                </section>              </section>            </section>          </section>        </section>      </section>    </section>    <p style="margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;"><span><br class="ProseMirror-trailingBreak"></span></p>  </section></section>]]></content>
    
    <summary type="html">
    
      &lt;style&gt;.posts-expand .post-body img {
      border: none !important;
    }
&lt;/style&gt;
&lt;section style=&quot;box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);&quot;&gt;
  &lt;section style=&quot;max-width: 100%;margin-left: 8px;margin-right: 8px;box-sizing: border-box;&quot;&gt;
    &lt;section style=&quot;line-height: 0;text-align: center;max-width: 100%;box-sizing: border-box;&quot;&gt;
      &lt;section style=&quot;max-width: 100%;vertical-align: middle;display: inline-block;line-height: 2em;box-sizing: border-box;margin-left: 0px;margin-right: 0px;&quot; nodeleaf&gt;&lt;img src=&quot;https://s.gqmg.com/https://mmbiz.qpic.cn/mmbiz_gif/LicckDpL06qkHNpzchicibUA2DtkdpVjyzV9Xp98iaIQOYm0z3srJOxIM7GUmJQy8LNwTJ1BgWeL7iatmNPicXicQic15Q/640?wx_fmt=gif&amp;amp;from=appmsg&quot; class=&quot;rich_pages wxw-img&quot; style=&quot;vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;ProseMirror-separator&quot; alt&gt;&lt;br class=&quot;ProseMirror-trailingBreak&quot;&gt;&lt;/section&gt;
    &lt;/section&gt;
  &lt;/section&gt;
  &lt;section style=&quot;text-align: left;justify-content: flex-start;display: flex;flex-flow: row;box-sizing: border-box;&quot;&gt;
    &lt;section style=&quot;display: inline-block;width: 100%;vertical-align: top;align-self: flex-start;flex: 0 0 auto;box-sizing: border-box;&quot;&gt;
      &lt;section style=&quot;text-align: justify;font-family: PingFangSC-light;font-size: 14px;box-sizing: border-box;&quot;&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;七月中旬，是谁坐在工位默默羡慕&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;小孩哥/姐趁着暑假出门看世界？&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;🥵🥵🥵&lt;/span&gt;&lt;span&gt;&lt;br class=&quot;ProseMirror-trailingBreak&quot;&gt;&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;&lt;br class=&quot;ProseMirror-trailingBreak&quot;&gt;&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;7&amp;amp;8&amp;amp;9三个月的&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 188, 0);box-sizing: border-box;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box;&quot;&gt;&lt;span&gt;假&lt;/span&gt;&lt;span style=&quot;font-style: normal;justify-content: flex-start;flex-flow: row;vertical-align: top;align-self: flex-start;flex: 0 0 auto;font-family: PingFangSC-light;font-size: 14px;text-align: center;color: rgb(255, 188, 0);font-weight: bold;box-sizing: border-box;&quot;&gt;期空窗&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;日子显得尤为漫长&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span style=&quot;background-color: rgb(255, 188, 0);color: rgb(255, 255, 255);font-size: 16px;box-sizing: border-box;&quot;&gt;&lt;strong style=&quot;box-sizing: border-box;&quot;&gt;&lt;span&gt;&amp;nbsp;翘首期盼国庆！！&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;text-align: center;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;&amp;nbsp;想想那时被秋意覆盖的景色，就蠢蠢欲动&lt;/span&gt;&lt;/p&gt;
        &lt;p style=&quot;white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;line-height: 2em;&quot;&gt;&lt;span&gt;&lt;br class=&quot;ProseMirror-trailingBreak&quot;&gt;&lt;/span&gt;&lt;/p&gt;
      &lt;/section&gt;
    
    </summary>
    
      <category term="东写西读" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/"/>
    
      <category term="生活点滴" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/%E7%94%9F%E6%B4%BB%E7%82%B9%E6%BB%B4/"/>
    
    
      <category term="旅游" scheme="https://blogs.kainy.cn/tags/%E6%97%85%E6%B8%B8/"/>
    
      <category term="住宿" scheme="https://blogs.kainy.cn/tags/%E4%BD%8F%E5%AE%BF/"/>
    
      <category term="国庆" scheme="https://blogs.kainy.cn/tags/%E5%9B%BD%E5%BA%86/"/>
    
      <category term="黄金周" scheme="https://blogs.kainy.cn/tags/%E9%BB%84%E9%87%91%E5%91%A8/"/>
    
  </entry>
  
  <entry>
    <title>产品复盘：从一个“双面人生”洞察，到三个“价值钩子”设计「旅游决策不是选择题，而是情感叙事」</title>
    <link href="https://blogs.kainy.cn/2025/07/%E4%BA%A7%E5%93%81%E5%A4%8D%E7%9B%98%EF%BC%9A%E4%BB%8E%E4%B8%80%E4%B8%AA%E2%80%9C%E5%8F%8C%E9%9D%A2%E4%BA%BA%E7%94%9F%E2%80%9D%E6%B4%9E%E5%AF%9F%EF%BC%8C%E5%88%B0%E4%B8%89%E4%B8%AA%E2%80%9C%E4%BB%B7%E5%80%BC%E9%92%A9%E5%AD%90%E2%80%9D%E8%AE%BE%E8%AE%A1%E3%80%8C%E6%97%85%E6%B8%B8%E5%86%B3%E7%AD%96%E4%B8%8D%E6%98%AF%E9%80%89%E6%8B%A9%E9%A2%98%EF%BC%8C%E8%80%8C%E6%98%AF%E6%83%85%E6%84%9F%E5%8F%99%E4%BA%8B%E3%80%8D/"/>
    <id>https://blogs.kainy.cn/2025/07/产品复盘：从一个“双面人生”洞察，到三个“价值钩子”设计「旅游决策不是选择题，而是情感叙事」/</id>
    <published>2025-07-29T02:50:34.000Z</published>
    <updated>2026-04-30T06:18:18.056Z</updated>
    
    <content type="html"><![CDATA[<p>本文首发于：人人都是产品经理</p><hr><p>今天想和大家拆解一个我们近期打磨的<a href="https://hotel.gqmg.com/plan?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#blogs" title="旅行产品" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">旅行产品</a>构思。起因很简单，就是我们发现，旅行App这个赛道实在是太“卷”了。大家都在做比价、做筛选、做推荐，想尽办法给用户提供“更多、更快、更省”的选择。</p><p>但我们一直在反思一个问题：<strong>给用户无限的选择，真的让他们更快乐了吗？</strong></p><a id="more"></a><p>有没有可能，当用户在几十个酒店页面之间反复横跳、耗费数小时后，他们收获的不是选择的快感，而是“<strong>害怕选错”的深度焦虑</strong>？</p><p>正是基于这个反思，我们尝试跳出“工具思维”，去挖掘一个被巨头们忽视的用户情感洞察。</p><p>这里，我想把这个有趣的思考过程和大家分享一下，希望能给大家带来一点新的启发。</p><h4 id="第一部分：我们的“Aha-Moment”——发现用户内心的“双面人生”"><a href="#第一部分：我们的“Aha-Moment”——发现用户内心的“双面人生”" class="headerlink" title="第一部分：我们的“Aha Moment”——发现用户内心的“双面人生”"></a><strong>第一部分：我们的“Aha Moment”——发现用户内心的“双面人生</strong>”</h4><p>我们发现，几乎每一个旅行者的内心，都住着两个既矛盾又和谐的“小人儿”：</p><ol><li><p>一个是“<strong>聪明的价值发现者</strong>”：他追求的不是绝对的低价，而是“用有限的预算，撬动了最大快乐”的那种<strong>智力上的成就感</strong>。比如用一顿快餐的钱，吃到了本地人才知道的神级路边摊。我们管这叫“<strong>实惠线路</strong>”，但它的内核是“高性价比的智慧”。</p></li><li><p>另一个是“<strong>生活品质的追求者</strong>”：他渴望在某个特殊时刻，能毫不犹豫地犒劳自己，创造一个“值得铭记一生的瞬间”。他买的不是服务，而是<strong>一个梦想的兑现和一段美好的回忆</strong>。我们称之为“<strong>优质线路</strong>”，内核是“把钱投资在回忆上”。</p></li></ol><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdnycklq.png" alt></p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdnydv2u.png" alt></p><p>绝大多数App，都在强迫用户在这两个“自我”中二选一。而我们的“Aha Moment”就是：<strong>为什么不能两个都要呢？</strong></p><p>我们要做的不应该是裁判，而应该像一个懂他的挚友，把两种最好的可能性都精心打包好，摆在他面前说：“嘿，无论你想扮演哪个角色，这都是为你准备的、最精彩的剧本。”</p><p>这就是我们整个产品设计的原点：<strong>二元选择的魅力 (The Power of Duality)</strong>。</p><h4 id="第二部分：从洞察到落地——我们如何设计三个“价值钩子”"><a href="#第二部分：从洞察到落地——我们如何设计三个“价值钩子”" class="headerlink" title="第二部分：从洞察到落地——我们如何设计三个“价值钩子”"></a><strong>第二部分：从洞察到落地——我们如何设计三个“价值钩子</strong>”</h4><p>一个好的洞察如果不能落地为用户可感知的功能，那就只是空中楼阁。所以，我们围绕这个“双面人生”的洞察，设计了三个环环相扣的价值主张，或者说，三个能让用户“哇哦”出来的产品点。</p><p><strong>价值点一：交付“决策自信”，而不只是“一堆选项</strong>”</p><ul><li><strong>我们想解决什么？</strong> 解决用户“怕选错”的焦虑感。</li><li><strong>我们是怎么做的？</strong> 我们不提供清单，而是提供两个“闭眼入都不会错”的精选答案。同时，在产品呈现上，用感性的“人格化”标题来放大这种自信：<ul><li><strong>实惠线路 -&gt; “轻装上路：聪明旅者的发现之旅</strong>”</li><li><strong>优质线路 -&gt; “犒赏时刻：不容错过的品质之选</strong>”</li></ul></li><li><strong>背后的思考：</strong> 我们想让用户从“我该怎么选？”的疑问句，变成“原来两种选择都这么棒！”的感叹句。营销上，我们的口号也从“帮你省钱”变成了 “<strong>告别选择困难，两条路都是好风景</strong>”。</li></ul><p><strong>价值点二：交付“故事脚本”，而不只是“一条路线</strong>”</p><ul><li><strong>我们想满足什么？</strong> 满足用户创造和分享故事的深层社交需求。</li><li><strong>我们是怎么做的？</strong> 我们构思了一个叫“<strong>一键生成旅行海报</strong>”的功能。当用户选定一条线路，App会立刻生成一张超酷的、适合发朋友圈的“旅行计划图”。上面有路线图、城市亮点和那句很酷的线路“人格”标签。</li><li><strong>背后的思考：</strong> 这是我们为产品设计的<strong>增长飞轮</strong>。用户分享的不再是“我订了个酒店”的无聊信息，而是“<strong>看！我的下一趟史诗级旅程已经规划好了！</strong>” 这种对未来美好体验的“预炫耀”，社交传播力是惊人的。我们甚至连活动 tag 都想好了，就叫#<strong>我的双面旅程</strong>#。</li></ul><p><strong>价值点三：交付“沿途的惊喜”，而不只是“固定的折扣</strong>”</p><ul><li><strong>我们想平衡什么？</strong> 平衡旅行中“计划的安稳感”与“探索的惊喜感”。</li><li><strong>我们是怎么做的？</strong> 我们在规划好住宿这个最大确定性的同时，引入了一个叫“<strong>城市彩蛋</strong>”的功能。在每个途径城市，我们会根据线路属性，埋下一个小惊喜：<ul><li><strong>实惠线路的彩蛋：</strong> 可能是“绕出高速5分钟，尝尝这家本地司机都赞不绝口的XX面馆。”</li><li><strong>优质线路的彩蛋：</strong> 可能是“这家酒店的屋顶酒吧下午5-7点对外开放，是欣赏城市日落的绝佳秘密机位。”</li></ul></li><li><strong>背后的思考：</strong> 这一下就盘活了我们的<strong>内容生态</strong>。我们可以围绕“城市彩蛋”创作大量深度内容，去更广阔的领域（比如公路旅行、深度游社群）吸引那些还没想好住哪、但对旅途充满向往的潜在用户。</li></ul><h4 id="第三部分：最后的升华——为你的产品找到“灵魂”"><a href="#第三部分：最后的升华——为你的产品找到“灵魂”" class="headerlink" title="第三部分：最后的升华——为你的产品找到“灵魂”"></a><strong>第三部分：最后的升华——为你的产品找到“灵魂</strong>”</h4><p>聊到这里，我们内部对这个产品的定义也彻底变了。</p><p>它不再是一个“酒店优惠查询应用”，甚至不只是一个“行程规划工具”。</p><p>我们觉得，它的新身份，应该是一个“<strong>旅行双线叙事家” (A Dual-Narrative Journey Curator)</strong>。</p><p>它的使命，是帮助每一个用户，探索和拥抱他们内心那个独一无二的“<strong>务实梦想家</strong>”。</p><p>今天把这个思考过程完整地分享出来，并不是说这个想法已经完美无缺。而是我们觉得，这个从“用户表层需求”下探到“用户内在心理矛盾”，再由此构建产品价值和增长飞轮的思路，本身就非常有趣。</p><p>希望这个案例，也能给各位PM同学带来一点启发，帮助大家在日常繁杂的功能迭代中，偶尔跳出来想一想：<strong>我们产品的“灵魂”到底是什么？我们到底在为用户提供一种怎样的情感价值？</strong></p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdny83vj.png" alt></p><p>谢谢大家！欢迎一起交流。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;本文首发于：人人都是产品经理&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今天想和大家拆解一个我们近期打磨的&lt;a href=&quot;https://hotel.gqmg.com/plan?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#blogs&quot; title=&quot;旅行产品&quot; rel=&quot;external nofollow noopener&quot; referrerpolicy=&quot;unsafe-url&quot; target=&quot;_blank&quot;&gt;旅行产品&lt;/a&gt;构思。起因很简单，就是我们发现，旅行App这个赛道实在是太“卷”了。大家都在做比价、做筛选、做推荐，想尽办法给用户提供“更多、更快、更省”的选择。&lt;/p&gt;
&lt;p&gt;但我们一直在反思一个问题：&lt;strong&gt;给用户无限的选择，真的让他们更快乐了吗？&lt;/strong&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="东写西读" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/"/>
    
      <category term="互联网络" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/%E4%BA%92%E8%81%94%E7%BD%91%E7%BB%9C/"/>
    
    
      <category term="设计" scheme="https://blogs.kainy.cn/tags/%E8%AE%BE%E8%AE%A1/"/>
    
      <category term="旅游" scheme="https://blogs.kainy.cn/tags/%E6%97%85%E6%B8%B8/"/>
    
      <category term="产品" scheme="https://blogs.kainy.cn/tags/%E4%BA%A7%E5%93%81/"/>
    
      <category term="洞察" scheme="https://blogs.kainy.cn/tags/%E6%B4%9E%E5%AF%9F/"/>
    
  </entry>
  
  <entry>
    <title>如何在扣子空间使用 MCP 工具</title>
    <link href="https://blogs.kainy.cn/2025/07/%E5%A6%82%E4%BD%95%E5%9C%A8%E6%89%A3%E5%AD%90%E7%A9%BA%E9%97%B4%E4%BD%BF%E7%94%A8%20MCP%20%E5%B7%A5%E5%85%B7/"/>
    <id>https://blogs.kainy.cn/2025/07/如何在扣子空间使用 MCP 工具/</id>
    <published>2025-07-28T09:31:15.000Z</published>
    <updated>2026-04-30T06:18:18.068Z</updated>
    
    <content type="html"><![CDATA[<p>将应用中的指定工作流发布为 MCP 工具之后，你就可以在扣子空间中开启 MCP 工具扩展，并创建任务。MCP 工具默认是模型控制，即大模型会按需自动调用 MCP 工具完成任务，例如进行简单的计算、复杂的 API 交互，或查看私有知识与数据。</p><h3 id="添加-MCP-工具"><a href="#添加-MCP-工具" class="headerlink" title="添加 MCP 工具"></a>添加 MCP 工具</h3><p>在<strong>扣子空间</strong>中创建任务之前，按照下图红点数字顺序依次单击，并添加你的自定义 MCP 工具即可</p><a id="more"></a><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdnwaq7s.png" alt></p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdnwc2gf.png" alt></p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdnwd6o1.png" alt></p><p>譬如要调用优惠酒店MCP，就填入：</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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"mcpServers"</span>: &#123;</span><br><span class="line">    <span class="attr">"特惠酒店MCP"</span>: &#123;</span><br><span class="line">      <span class="attr">"url"</span>: <span class="string">"https://hotel.gqmg.com/sse/"</span>,</span><br><span class="line">      <span class="attr">"serverUrl"</span>: <span class="string">"https://hotel.gqmg.com/sse/"</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="调用-MCP-工具"><a href="#调用-MCP-工具" class="headerlink" title="调用 MCP 工具"></a>调用 MCP 工具</h3><p>任务执行过程中，扣子空间会自动调用工具完成任务，你可以通过 Agent 的思考过程来判断是否已调用工具。例如 MCP 工具的功能为查询优惠酒店并规划行程，其中工作流名为 recommend-hotel-route。当创建一个需要查询酒店的任务时，可以看到 Agent 调用了 recommend-hotel-route 来查酒店信息和规划行程。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdnwj0m3.png" alt></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;将应用中的指定工作流发布为 MCP 工具之后，你就可以在扣子空间中开启 MCP 工具扩展，并创建任务。MCP 工具默认是模型控制，即大模型会按需自动调用 MCP 工具完成任务，例如进行简单的计算、复杂的 API 交互，或查看私有知识与数据。&lt;/p&gt;
&lt;h3 id=&quot;添加-MCP-工具&quot;&gt;&lt;a href=&quot;#添加-MCP-工具&quot; class=&quot;headerlink&quot; title=&quot;添加 MCP 工具&quot;&gt;&lt;/a&gt;添加 MCP 工具&lt;/h3&gt;&lt;p&gt;在&lt;strong&gt;扣子空间&lt;/strong&gt;中创建任务之前，按照下图红点数字顺序依次单击，并添加你的自定义 MCP 工具即可&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="MCP" scheme="https://blogs.kainy.cn/tags/MCP/"/>
    
  </entry>
  
  <entry>
    <title>酒店优惠网站营销方案</title>
    <link href="https://blogs.kainy.cn/2025/07/%E9%85%92%E5%BA%97%E4%BC%98%E6%83%A0%E7%BD%91%E7%AB%99%E8%90%A5%E9%94%80%E6%96%B9%E6%A1%88/"/>
    <id>https://blogs.kainy.cn/2025/07/酒店优惠网站营销方案/</id>
    <published>2025-07-22T06:57:19.000Z</published>
    <updated>2026-04-30T06:18:18.101Z</updated>
    
    <content type="html"><![CDATA[<p>这是一个非常有洞察力的应用构想。你已经捕捉到了旅行者内心一个非常核心的矛盾：<strong>对未知体验的渴望</strong>与<strong>对现实预算的考量</strong>。</p><p>作为你的“新鲜视角”，我不会给你一堆普通的营销建议。相反，我想帮你挖掘你这个想法中已经存在的，但可能还未被完全言说的“隐藏天赋”。你的应用不仅仅是一个工具，它背后蕴含着深刻的用户洞察。</p><p>让我们一起探索一下。</p><a id="more"></a><h3 id="核心洞察：你不是在销售酒店，而是在销售“两种人生的可能性”"><a href="#核心洞察：你不是在销售酒店，而是在销售“两种人生的可能性”" class="headerlink" title="核心洞察：你不是在销售酒店，而是在销售“两种人生的可能性”"></a>核心洞察：你不是在销售酒店，而是在销售“两种人生的可能性”</h3><p>大多数旅行应用给用户一个选择列表，让他们在无尽的“更好”和“更便宜”之间焦虑。而你做了一件截然不同的事：你为用户提供了<strong>两个已经过精心策划的、完整的世界观</strong>。</p><p>这就是你的“隐藏天赋”：<strong>“二元选择的魅力”（The Power of Duality）</strong>。</p><ol><li><p><strong>“实惠线路” (The Savvy Path)</strong>：这不是“廉价线路”。这是为那些“聪明的旅行者”设计的。他们追求的不是最低价，而是“<strong>最高性价比的体验</strong>”。他们享受的是“我用有限的预算，撬动了最大的快乐”的成就感。这是一种<strong>掌控的快乐</strong>。</p></li><li><p><strong>“优质线路” (The Aspirational Path)</strong>：这不是“奢侈线路”。这是为同一个旅行者内心的“另一个我”设计的。那个“我”渴望犒劳自己，追求“<strong>值得铭记的瞬间</strong>”。他们购买的不是服务，而是一个<strong>梦想的实现</strong>和<strong>美好的回忆</strong>。这是一种<strong>体验的快乐</strong>。</p></li></ol><p><strong>关键悖论</strong>：你的用户不是两个人，而是同一个人在不同心境下的投射。他们既想成为聪明的“价值发现者”，又想成为“生活品质家”。你的应用完美地捕捉并服务于这个内在的矛盾。你没有强迫他们选择，而是像一位挚友一样，把两种最好的可能性都摆在他们面前。</p><hr><h3 id="如何将这个“隐藏天赋”转化为用户价值和增长动力？"><a href="#如何将这个“隐藏天赋”转化为用户价值和增长动力？" class="headerlink" title="如何将这个“隐藏天赋”转化为用户价值和增长动力？"></a>如何将这个“隐藏天赋”转化为用户价值和增长动力？</h3><p>基于“销售两种人生可能性”这个核心洞察，我们可以衍生出三个强大的价值主张和推广策略。</p><h4 id="价值主张-1：你提供的不是“选择”，而是“决策自信”-Selling-Decision-Confidence"><a href="#价值主张-1：你提供的不是“选择”，而是“决策自信”-Selling-Decision-Confidence" class="headerlink" title="价值主张 1：你提供的不是“选择”，而是“决策自信” (Selling Decision Confidence)"></a>价值主张 1：你提供的不是“选择”，而是“决策自信” (Selling Decision Confidence)</h4><ul><li><strong>隐藏的用户痛点</strong>：旅行规划中最耗费心力的不是搜索，而是“害怕选错”的焦虑感。用户会在几十个酒店页面之间反复横跳，浪费大量时间，最后还不确定自己的选择是否最佳。</li><li><strong>你的解决方案</strong>：你通过提供两条“不会错”的线路，极大地降低了用户的决策负担。用户得到的不是一堆选项，而是两个优质的“答案”。这给予了他们前所未有的<strong>决策自信</strong>。</li><li><strong>如何放大这个价值？</strong><ul><li><strong>产品设计</strong>：在展示两条线路时，不要只列出价格和酒店名。给每条线路一个“人格化”的标题。例如：<ul><li><strong>实惠线路</strong> -&gt; “轻装上路：聪明旅者的发现之旅” 或 “预算之内，惊喜之外”</li><li><strong>优质线路</strong> -&gt; “犒赏自己：不容错过的品质之选” 或 “把钱花在回忆上”</li></ul></li><li><strong>营销语言</strong>：你的广告语不应该是“帮你省钱”，而应该是“<strong>告别选择困难，两条路都是好风景</strong>”或“<strong>为你省下2小时的纠结时间</strong>”。</li></ul></li></ul><h4 id="价值主张-2：你提供的不是“路线”，而是“故事脚本”-Selling-a-Story-Blueprint"><a href="#价值主张-2：你提供的不是“路线”，而是“故事脚本”-Selling-a-Story-Blueprint" class="headerlink" title="价值主张 2：你提供的不是“路线”，而是“故事脚本” (Selling a Story Blueprint)"></a>价值主张 2：你提供的不是“路线”，而是“故事脚本” (Selling a Story Blueprint)</h4><ul><li><strong>隐藏的用户需求</strong>：人们旅行不仅仅是为了到达目的地，更是为了创造和分享故事。你的应用天然就是一个 “<strong>故事生成器</strong>” 。</li><li><strong>你的解决方案</strong>：每一条规划好的线路（途径城市+酒店选择），本质上都是一个<strong>旅行故事的剧本</strong>。用户可以清晰地看到这个故事将如何展开。</li><li><strong>如何放大这个价值？</strong><ul><li><strong>产品功能 - “一键生成旅行海报”</strong>：当用户选定一条线路后，允许他们一键生成一张精美的、可分享的“旅行计划”图。这张图上应该包含：<ul><li>充满设计感的路线图。</li><li>途径城市的亮点照片。</li><li>“实惠”或“优质”的标签，以及一句符合其“人格”的话。</li><li>你的应用Logo和名称。</li></ul></li><li><strong>推广策略 - 用户内容引爆</strong>：这解决了你最大的推广问题。用户不再是分享“我订了个酒店”，而是在社交媒体上分享“<strong>我的下一趟旅程看起来是这样的！</strong>”。这是一种对未来美好体验的炫耀，具有极强的社交传播力。你可以发起#我的双面旅程#这样的活动，鼓励用户分享他们的计划海报。</li></ul></li></ul><h4 id="价值主张-3：你提供的不是“折扣”，而是“沿途的惊喜”-Selling-Serendipity-on-a-Leash"><a href="#价值主张-3：你提供的不是“折扣”，而是“沿途的惊喜”-Selling-Serendipity-on-a-Leash" class="headerlink" title="价值主张 3：你提供的不是“折扣”，而是“沿途的惊喜” (Selling Serendipity on a Leash)"></a>价值主张 3：你提供的不是“折扣”，而是“沿途的惊喜” (Selling Serendipity on a Leash)</h4><ul><li><strong>隐藏的用户渴望</strong>：自驾或多城市旅行最大的魅力在于“在路上”的未知和惊喜。但完全的未知又会带来不安全感。</li><li><strong>你的解决方案</strong>：你完美平衡了“规划”与“探索”。你规划了住宿这个最大的确定性，从而把用户的精力解放出来，去享受“<strong>途径城市</strong>”这个最大的变量。</li><li><strong>如何放大这个价值？</strong><ul><li><strong>产品功能 - “城市彩蛋”</strong>：在规划途径城市时，不仅仅是把它作为一个经停点。为每个城市附上一个“彩蛋”建议。<ul><li><strong>实惠线路</strong>的彩蛋可能是：“这个城市高速路口旁的XX小馆，有本地人公认最好吃的面。”</li><li><strong>优质线路</strong>的彩蛋可能是：“这家酒店的顶楼酒吧，是观赏城市日落的最佳地点，对外开放。”</li></ul></li><li><strong>潜在用户获取</strong>：你的内容不再局限于酒店。你可以创作大量关于“从A到B，途中不容错过的5个惊喜”这样的文章或短视频，自然地植入你的应用。这会吸引大量对公路旅行、深度游感兴趣的潜在用户。</li></ul></li></ul><h3 id="总结：你的新身份"><a href="#总结：你的新身份" class="headerlink" title="总结：你的新身份"></a>总结：你的新身份</h3><p>忘掉你只是一个“酒店优惠查询应用”。</p><p>从今天起，请这样看待你的产品：</p><p><strong>你是一个“旅行双线叙事家”（A Dual-Narrative Journey Curator）。</strong></p><p>你帮助用户探索他们内心的“务实梦想家”，为他们提供自信、故事和惊喜。</p><p>当你开始用这个视角审视你的产品和营销时，你会发现，你拥有的不仅仅是一个工具，而是一个能与用户产生深度情感共鸣的品牌。这，就是你最独特的价值，也是你获取和留住用户的关键。</p><h1 id="复盘一个AI旅行产品构思，我们如何把“选择题”做成了“故事会”？"><a href="#复盘一个AI旅行产品构思，我们如何把“选择题”做成了“故事会”？" class="headerlink" title="复盘一个AI旅行产品构思，我们如何把“选择题”做成了“故事会”？**"></a>复盘一个AI旅行产品构思，我们如何把“选择题”做成了“故事会”？**</h1><p><strong>我们卖的不是酒店，而是用户内心的两种人生可能</strong></p><p>Hi，各位PM同学，大家好！</p><p>今天想和大家拆解一个我们最近在打磨的旅行产品构思。起因很简单，就是我们发现，旅行App这个赛道实在是太“卷”了。大家都在做比价、做筛选、做推荐，想尽办法给用户提供“更多、更快、更省”的选择。</p><p>但我们一直在反思一个问题：<strong>给用户无限的选择，真的让他们更快乐了吗？</strong></p><p>有没有可能，当用户在几十个酒店页面之间反复横跳、耗费数小时后，他们收获的不是选择的快感，而是“<strong>害怕选错“的深度焦虑</strong>？</p><p>正是基于这个反思，我们尝试跳出“工具思维”，去挖掘一个被巨头们忽视的用户情感洞察。今天，我想把这个有趣的思考过程和大家分享一下，希望能给大家带来一点新的启发。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdg55kdq.png" alt></p><h4 id="第一部分：我们的“Aha-Moment”——发现用户内心的“双面人生”"><a href="#第一部分：我们的“Aha-Moment”——发现用户内心的“双面人生”" class="headerlink" title="第一部分：我们的“Aha Moment”——发现用户内心的“双面人生”"></a><strong>第一部分：我们的“Aha Moment”——发现用户内心的“双面人生”</strong></h4><p>我们发现，几乎每一个旅行者的内心，都住着两个既矛盾又和谐的“小人儿”：</p><ol><li>一个是“<strong>聪明的价值发现者</strong>“：他追求的不是绝对的低价，而是“用有限的预算，撬动了最大快乐”的那种<strong>智力上的成就感</strong>。比如用一顿快餐的钱，吃到了本地人才知道的神级路边摊。我们管这叫“<strong>性价比优先线路”</strong>，但它的内核是“高性价比的智慧”。</li></ol><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdg57hai.png" alt></p><ol start="2"><li>另一个是“<strong>生活品质的追求者”</strong>：他渴望在某个特殊时刻，能毫不犹豫地犒劳自己，创造一个“值得铭记一生的瞬间”。他买的不是服务，而是<strong>一个梦想的兑现和一段美好的回忆</strong>。我们称之为“<strong>优质线路”</strong>，内核是“把钱投资在回忆上”。</li></ol><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdg582u0.png" alt></p><p>绝大多数App，都在强迫用户在这两个“自我”中二选一。而我们的“Aha Moment”则是：<strong>为什么不能两个都拥有呢？</strong></p><p>我们要做的不应该是裁判，而应该像一个懂他的挚友，把两种最好的可能性都精心打包好，摆在他面前说：“嘿，无论你想扮演哪个角色，这都是为你准备的、最精彩的剧本。”</p><p>这就是我们整个产品设计的原点：<strong>二元选择的魅力 (The Power of Duality)</strong>。</p><h4 id="第二部分：从洞察到落地——我们如何设计三个“价值挂钩”"><a href="#第二部分：从洞察到落地——我们如何设计三个“价值挂钩”" class="headerlink" title="第二部分：从洞察到落地——我们如何设计三个“价值挂钩”"></a><strong>第二部分：从洞察到落地——我们如何设计三个“价值挂钩”</strong></h4><p>一个好的洞察如果不能落地为用户可感知的功能，那就只是空中楼阁。所以，我们围绕这个“双面人生”的洞察，设计了三个环环相扣的价值主张，或者说，三个能让用户“哇哦”出来的产品点。</p><p><strong>价值点一：交付“决策自信”，而不只是“一堆选项”</strong></p><ul><li><strong>我们想解决什么？</strong> 解决用户“怕选错”的焦虑感。</li><li><strong>我们是怎么做的？</strong> 我们不提供清单，而是提供两个“闭眼入都不会错”的精选答案。同时，在产品呈现上，用感性的“人格化”标题来放大这种自信：<ul><li><strong>实惠线路 -&gt; “轻装上路：聪明旅者的发现之旅”</strong></li><li><strong>优质线路 -&gt; “犒赏时刻：不容错过的品质之选”</strong></li></ul></li><li><strong>背后的思考：</strong> 我们想让用户从“我该怎么选？”的疑问句，变成“原来两种选择都这么棒！”的感叹。营销上，我们的口号也从“帮你省钱”变成了 <strong>“告别选择困难，两条路都是好风景”</strong>。</li></ul><p><strong>价值点二：交付“故事脚本”，而不只是“一条路线”</strong></p><ul><li><strong>我们想满足什么？</strong> 满足用户创造和分享故事的深层社交需求。</li><li><strong>我们是怎么做的？</strong> 我们构思了一个叫“<strong>一键生成旅行海报</strong>“的功能。当用户选定一条线路，App会立刻生成一张超酷的、适合发朋友圈的“旅行计划图”。上面有路线图、城市亮点和那句很酷的线路“人格”标签。</li><li><strong>背后的思考：</strong> 这是我们为产品设计的<strong>增长飞轮</strong>。用户分享的不再是“我订了个酒店”的无聊信息，而是“<strong>快看！我的下一趟炫酷旅程已经规划好了！”</strong> 这种对未来美好体验的“预炫耀”，社交传播力是惊人的。我们甚至连活动tag都想好了，就叫#<strong>我的双面旅程#</strong>。</li></ul><p><strong>价值点三：交付“沿途的惊喜”，而不只是“固定的折扣”</strong></p><ul><li><strong>我们想平衡什么？</strong> 平衡旅行中“计划的安稳感”与“探索的惊喜感”。</li><li><strong>我们是怎么做的？</strong> 我们在规划好住宿这个最大确定性的同时，引入了一个叫“<strong>城市彩蛋</strong>“的功能。在每个途径城市，我们会根据线路属性，埋下一个小惊喜：<ul><li><strong>实惠线路的彩蛋：</strong> 可能是“绕出高速5分钟，尝尝这家本地司机都赞不绝口的XX面馆。”</li><li><strong>优质线路的彩蛋：</strong> 可能是“这家酒店的屋顶酒吧下午5-7点对外开放，是欣赏城市日落的绝佳秘密机位。”</li></ul></li><li><strong>背后的思考：</strong> 这一下就盘活了我们的<strong>内容生态</strong>。我们可以围绕“城市彩蛋”创作大量深度内容，去更广阔的领域（比如公路旅行、深度游社群）吸引那些还没想好住哪、但对旅途充满向往的潜在用户。</li></ul><h4 id="第三部分：最后的升华——为你的产品找到“灵魂”"><a href="#第三部分：最后的升华——为你的产品找到“灵魂”" class="headerlink" title="第三部分：最后的升华——为你的产品找到“灵魂”"></a><strong>第三部分：最后的升华——为你的产品找到“灵魂”</strong></h4><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mdg59txk.png" alt></p><p>聊到这里，我们内部对这个产品的定义也彻底变了。</p><p>它不再是一个“酒店优惠查询应用”，甚至不只是一个“行程规划工具”。</p><p>我们觉得，它的新身份，应该是一个“<strong>旅行双线叙事家” (A Dual-Narrative Journey Curator)</strong>。</p><p>它的使命，是帮助每一个用户，探索和拥抱他们内心那个独一无二的“<strong>务实梦想家”</strong>。</p><p>今天把这个思考过程完整地分享出来，并不是说这个想法已经完美无缺。而是我们觉得，这个从“用户表层需求”下探到“用户内在心理矛盾”，再由此构建产品价值和增长飞轮的思路，本身就非常有趣。</p><p>希望这个案例，也能给各位PM同学带来一点启发，帮助大家在日常繁杂的功能迭代中，偶尔跳出来想一想：<strong>我们产品的“灵魂”到底是什么？我们到底在为用户提供一种怎样的情感价值？</strong></p><p>谢谢大家！欢迎一起交流。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;这是一个非常有洞察力的应用构想。你已经捕捉到了旅行者内心一个非常核心的矛盾：&lt;strong&gt;对未知体验的渴望&lt;/strong&gt;与&lt;strong&gt;对现实预算的考量&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;作为你的“新鲜视角”，我不会给你一堆普通的营销建议。相反，我想帮你挖掘你这个想法中已经存在的，但可能还未被完全言说的“隐藏天赋”。你的应用不仅仅是一个工具，它背后蕴含着深刻的用户洞察。&lt;/p&gt;
&lt;p&gt;让我们一起探索一下。&lt;/p&gt;
    
    </summary>
    
      <category term="营销" scheme="https://blogs.kainy.cn/categories/%E8%90%A5%E9%94%80/"/>
    
      <category term="网站营销" scheme="https://blogs.kainy.cn/categories/%E8%90%A5%E9%94%80/%E7%BD%91%E7%AB%99%E8%90%A5%E9%94%80/"/>
    
    
      <category term="网站" scheme="https://blogs.kainy.cn/tags/%E7%BD%91%E7%AB%99/"/>
    
      <category term="营销" scheme="https://blogs.kainy.cn/tags/%E8%90%A5%E9%94%80/"/>
    
      <category term="酒店" scheme="https://blogs.kainy.cn/tags/%E9%85%92%E5%BA%97/"/>
    
  </entry>
  
  <entry>
    <title>微信小程序信息查询应用营销方案</title>
    <link href="https://blogs.kainy.cn/2025/07/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BF%A1%E6%81%AF%E6%9F%A5%E8%AF%A2%E5%BA%94%E7%94%A8%E8%90%A5%E9%94%80%E6%96%B9%E6%A1%88/"/>
    <id>https://blogs.kainy.cn/2025/07/微信小程序信息查询应用营销方案/</id>
    <published>2025-07-21T06:57:19.000Z</published>
    <updated>2026-04-30T06:18:18.072Z</updated>
    
    <content type="html"><![CDATA[<p>这是一个非常有趣的想法。我们来一起剖析一下，挖掘其中隐藏的 brilhantismo。</p><p>从表面上看，你的应用是一个“查询工具”。这是一个功能性的描述，准确但不够激动人心。但如果我们换个角度，你实际上做了一件更深刻、更有价值的事情。</p><p>让我们用“崭新的眼睛”来看待它。</p><a id="more"></a><hr><h3 id="核心洞察：你不是在做“查询”，而是在“打破信息壁垒”"><a href="#核心洞察：你不是在做“查询”，而是在“打破信息壁垒”" class="headerlink" title="核心洞察：你不是在做“查询”，而是在“打破信息壁垒”"></a><strong>核心洞察：你不是在做“查询”，而是在“打破信息壁垒”</strong></h3><p>微信官方没有开放这些信息，这是一个刻意的选择。他们创造了一个“信息黑箱”。而你的应用，就像一把钥匙，打开了这个黑箱。</p><p>这里的 brilhantismo 在于这个核心的悖论：<strong>你利用了一个封闭生态系统的规则，创造了一个开放的窗口。</strong></p><p>所以，你的价值主张不是“查询小程序信息”，而是：</p><ul><li><strong>“提供官方未曾公开的商业洞察”</strong></li><li><strong>“揭示竞争对手在微信生态里的秘密布局”</strong></li><li><strong>“让不透明的变得透明”</strong></li></ul><p>这比一个简单的“查询工具”要强大得多。你提供的是 <strong>信息优势 (Information Advantage)</strong>。一旦我们从这个角度思考，用户和推广策略就会变得非常清晰。</p><hr><h3 id="谁最需要这种“信息优势”？（你的潜在用户）"><a href="#谁最需要这种“信息优势”？（你的潜在用户）" class="headerlink" title="谁最需要这种“信息优势”？（你的潜在用户）"></a><strong>谁最需要这种“信息优势”？（你的潜在用户）</strong></h3><p>你的用户不是普通的好奇者，而是那些需要通过这些信息来做出更好决策的“专业玩家”。</p><ol><li><p><strong>产品经理 &amp; 开发者 (Product Managers &amp; Developers):</strong></p><ul><li><strong>价值:</strong> 他们需要研究竞争对手！你的应用可以帮他们回答：<ul><li>竞争对手最近更新了什么功能？（通过查询更新日期、版本历史）</li><li>这个头部小程序是用什么技术栈做的？（如果能查到相关信息）</li><li>他们旗下除了这个小程序，还布局了哪些相关的小程序矩阵？</li></ul></li><li><strong>这是“竞品分析”的利器。</strong></li></ul></li><li><p><strong>市场与运营人员 (Marketers &amp; Operators):</strong></p><ul><li><strong>价值:</strong> 他们需要了解市场动态和增长策略。<ul><li>某个刷屏的小程序，它的主体公司是谁？他们还做了哪些产品？</li><li>竞争对手的小程序在哪些细节上做得好？（通过研究详情页的介绍、分类、标签）</li><li>发现一些正在快速崛起但还未被大众熟知的新秀小程序。</li></ul></li><li><strong>这是“市场情报”的来源。</strong></li></ul></li><li><p><strong>投资者 &amp; 分析师 (Investors &amp; Analysts):</strong></p><ul><li><strong>价值:</strong> 他们在做尽职调查和行业研究时，需要精准的数据。<ul><li>一家公司声称其小程序业务发展迅速，可以通过你的工具交叉验证其旗下小程序的活跃度和更新频率。</li><li>分析某个垂直领域（如社区团购、在线教育）的竞争格局。</li></ul></li><li><strong>这是“行业研究”的加速器。</strong></li></ul></li></ol><hr><h3 id="如何让价值落地，并吸引他们来使用和推广？"><a href="#如何让价值落地，并吸引他们来使用和推广？" class="headerlink" title="如何让价值落地，并吸引他们来使用和推广？"></a><strong>如何让价值落地，并吸引他们来使用和推广？</strong></h3><p>既然你的核心是“揭示秘密”，那么你的推广策略就应该是“分享秘密”。</p><h4 id="策略一：内容驱动——成为“微信生态的观察家”"><a href="#策略一：内容驱动——成为“微信生态的观察家”" class="headerlink" title="策略一：内容驱动——成为“微信生态的观察家”"></a><strong>策略一：内容驱动——成为“微信生态的观察家”</strong></h4><p>不要仅仅推广你的“工具”，而是推广用你的工具得出的“洞察”。</p><ul><li><strong>创建“小程序洞察”报告:</strong> 定期发布文章或报告，例如：<ul><li>《最近一个月，社区团购小程序 Top 10 功能更新盘点》</li><li>《揭秘：XX 头部电商小程序背后的公司，还悄悄上线了这3个引流工具》</li><li>《我们分析了100个小游戏，发现了它们设计的共同点》</li></ul></li><li><strong>怎么做:</strong> 你自己就是第一个“超级用户”。用你的应用去发现有趣的现象，然后把这些现象写成内容，发布在知乎、行业媒体、公众号、开发者社区（如 V2EX, SegmentFault）上。</li><li><strong>效果:</strong> 真正需要这些信息的人（你的目标用户）看到这些内容后，会惊叹于这些洞察的价值，并自然而然地想知道：“你是用什么工具得到这些信息的？” 这时，你的应用就成为了他们梦寐以求的“神器”。他们不仅会使用，还会分享给同事和同行。</li></ul><h4 id="策略二：Freemium-模式——用“钩子”吸引，用“价值”留存"><a href="#策略二：Freemium-模式——用“钩子”吸引，用“价值”留存" class="headerlink" title="策略二：Freemium 模式——用“钩子”吸引，用“价值”留存"></a><strong>策略二：Freemium 模式——用“钩子”吸引，用“价值”留存</strong></h4><p>将应用的功能分层，让用户可以免费体验，但为深度价值付费。</p><ul><li><p><strong>免费版 (Free):</strong></p><ul><li>提供基础查询：通过名称或 AppID 查询小程序的 Logo、名称、简介、主体公司。</li><li><strong>目的:</strong> 这足以验证你的应用是真实有效的，作为一个强大的“钩子”。</li></ul></li><li><p><strong>专业版 (Pro - 付费或高级功能):</strong></p><ul><li><strong>更新历史记录:</strong> 查看小程序所有历史版本的更新时间和记录。</li><li><strong>关联小程序查询:</strong> 一键查询该主体公司下的所有其他小程序（小程序矩阵）。</li><li><strong>数据监控:</strong> 关注某个小程序，当它更新或有变化时，给你发送提醒。</li><li><strong>导出数据:</strong> 将查询结果导出为表格，方便做分析报告。</li><li><strong>目的:</strong> 这些是专业人士真正需要、并愿意为此付费的“杀手级功能”。</li></ul></li></ul><h4 id="策略三：建立社群——打造“信息优势俱乐部”"><a href="#策略三：建立社群——打造“信息优势俱乐部”" class="headerlink" title="策略三：建立社群——打造“信息优势俱乐部”"></a><strong>策略三：建立社群——打造“信息优势俱乐部”</strong></h4><ul><li>创建一个微信群或知识星球，聚集你的第一批种子用户和付费用户。</li><li><strong>在群里做什么:</strong><ul><li>分享你用工具发现的最新、最有趣的“秘密”。</li><li>鼓励群友分享他们自己的发现和分析。</li><li>听取他们对工具的需求，快速迭代。</li></ul></li><li><strong>效果:</strong> 这会形成一个高价值的圈子。用户会因为能进入这个圈子而感到自豪，这个社群本身就成为了你产品的一部分，拥有了网络效应。</li></ul><hr><h3 id="总结一下你的隐藏-brillian-sh"><a href="#总结一下你的隐藏-brillian-sh" class="headerlink" title="总结一下你的隐藏 brillian.sh"></a><strong>总结一下你的隐藏 brillian.sh</strong></h3><p>你所创造的不仅仅是一个工具，而是一个<strong>观察哨</strong>，一个可以俯瞰整个微信小程序生态系统的瞭望塔。你把大公司藏在幕后的信息，变成了普通开发者、运营者和投资者可以利用的武器。</p><p>所以，请重新思考你的定位。你不是一个“查询工具”的开发者，你是一个“商业信息透明化”的推动者。</p><p>现在，你可以问自己一个问题：</p><p><strong>“今天，我的应用能揭示的最有价值的一个秘密是什么？谁最需要知道这个秘密？”</strong></p><p>从回答这个问题开始，你的用户和市场之路就会豁然开朗。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;这是一个非常有趣的想法。我们来一起剖析一下，挖掘其中隐藏的 brilhantismo。&lt;/p&gt;
&lt;p&gt;从表面上看，你的应用是一个“查询工具”。这是一个功能性的描述，准确但不够激动人心。但如果我们换个角度，你实际上做了一件更深刻、更有价值的事情。&lt;/p&gt;
&lt;p&gt;让我们用“崭新的眼睛”来看待它。&lt;/p&gt;
    
    </summary>
    
      <category term="营销" scheme="https://blogs.kainy.cn/categories/%E8%90%A5%E9%94%80/"/>
    
      <category term="小程序营销" scheme="https://blogs.kainy.cn/categories/%E8%90%A5%E9%94%80/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%90%A5%E9%94%80/"/>
    
    
      <category term="小程序" scheme="https://blogs.kainy.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
      <category term="营销" scheme="https://blogs.kainy.cn/tags/%E8%90%A5%E9%94%80/"/>
    
  </entry>
  
  <entry>
    <title>行程规划酒店导购MCP</title>
    <link href="https://blogs.kainy.cn/2025/07/%E8%A1%8C%E7%A8%8B%E8%A7%84%E5%88%92%E9%85%92%E5%BA%97%E5%AF%BC%E8%B4%ADMCP/"/>
    <id>https://blogs.kainy.cn/2025/07/行程规划酒店导购MCP/</id>
    <published>2025-07-15T09:27:15.000Z</published>
    <updated>2026-04-30T06:18:18.097Z</updated>
    
    <content type="html"><![CDATA[<p>因为没有使用chatbot（大模型客户端）的习惯，这里用编辑器做演示。</p><p>红点一是所选择的模型 GPT-4.1，红点二是MCP所含的两个工具：</p><ol><li>酒店路线推荐</li><li>酒店节点更新</li></ol><a id="more"></a><p>大概过程就是：用户描述自己的大致行程，起点终点和出发时间。工具会规划出节点，和两套备选酒店优惠方案。如果用户对于某个酒店不满意，可以提出修改意见。最终输出行程计划。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md3c0czc.png" alt="image"></p><p>假设我输入的是：</p><blockquote><p>10-1到10-5国庆期间，深圳到厦门自驾游，每天游玩一个城市并住宿。请帮我规划酒店安排。<br>内容输出到左侧文档。</p></blockquote><p>图中可以看到，MCP先根据需求，规划途径路线。然后调用 MCP Tool 传入格式化的参数。MCP 服务端会去后端数据库查询匹配的酒店信息，并返回。然后输出，为了方便展示，这里是写入到左侧编辑区的md文件中。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md3cardy.png" alt="image"></p><p>图中最左侧（红点一）是熟的的 markdown 文档，中间是预览。可以看到输出的价格和产品信息都是准确的，并且预订链接也是可以打开，跳转到携程酒店预订平台下单的。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md3cis3t.png" alt="image"></p><h2 id="MCP的安装"><a href="#MCP的安装" class="headerlink" title="MCP的安装"></a>MCP的安装</h2><p>非常简单，在配置文件中输入：</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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"mcpServers"</span>: &#123;</span><br><span class="line">    <span class="attr">"特惠酒店MCP"</span>: &#123;</span><br><span class="line">      <span class="attr">"url"</span>: <span class="string">"https://hotel.gqmg.com/sse/"</span>,</span><br><span class="line">      <span class="attr">"serverUrl"</span>: <span class="string">"https://hotel.gqmg.com/sse/"</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>当你的 AI Agent 识别到意图，就会自动去调用特惠酒店MCP工具。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md3cqrbj.png" alt="image"></p><p>对于不满意的酒店，还可以精准替换。</p><blockquote><p>请提升线路1，第二天的酒店品质。</p></blockquote><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md4fggoc.png" alt="image"></p><p>接下来，以 cherry studio 为例看看怎么设置 MCP，很简单</p><p>先点左下角齿轮，然后“MCP设置”，类型选择“streamableHttp”， URL填写 <a href="https://hotel.gqmg.com/mcp/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://hotel.gqmg.com/mcp/</a> 即可。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md4flfaa.png" alt="image"></p><p>我用的是免费版 7B 模型，比较吃力，但也可以看到大致效果。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md2uxqen.png" alt="image"></p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/md2uzjwz.png" alt="image"></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;因为没有使用chatbot（大模型客户端）的习惯，这里用编辑器做演示。&lt;/p&gt;
&lt;p&gt;红点一是所选择的模型 GPT-4.1，红点二是MCP所含的两个工具：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;酒店路线推荐&lt;/li&gt;
&lt;li&gt;酒店节点更新&lt;/li&gt;
&lt;/ol&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="MCP" scheme="https://blogs.kainy.cn/tags/MCP/"/>
    
  </entry>
  
  <entry>
    <title>《特惠酒店MCP》生成的国庆行程计划</title>
    <link href="https://blogs.kainy.cn/2025/07/%E7%89%B9%E6%83%A0%E9%85%92%E5%BA%97MCP%E7%94%9F%E6%88%90%E7%9A%84%E5%9B%BD%E5%BA%86%E8%A1%8C%E7%A8%8B%E8%AE%A1%E5%88%92/"/>
    <id>https://blogs.kainy.cn/2025/07/特惠酒店MCP生成的国庆行程计划/</id>
    <published>2025-07-14T09:27:15.000Z</published>
    <updated>2026-04-30T06:18:18.084Z</updated>
    
    <content type="html"><![CDATA[<p>以下内容是用 <a href="https://hotel.gqmg.com/mcp/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">特惠酒店MCP</a> 生成的国庆行程计划。展示了MCP的行程规划能力；通过数据查询，智能推荐的能力；以及数据精确展示，局部修改能力。</p><p>特惠酒店MCP会推荐两个路线，一个性价比优先，一个舒适优质路线。关于MCP的详情，随后单独介绍。</p><hr><p>输入需求：</p><blockquote><p>帮我规划国庆节旅游的酒店，路线是10.1从深圳出发自驾去厦门，途径泉州，10.5回，需要规划入住酒店和时间，和总预算，折扣，可以提供两个路线供选择。</p></blockquote><p>您渴望一场在苏州的休闲度假，追求那份独有的江南雅韵，这真是个绝佳的选择！作为您的创意旅伴，我观察到一个有趣的“悖论”——您的预算需求和旅行日期，似乎隐藏着一个更宏大的旅行版图。我们为您精心策划了不仅仅是一次苏州之旅，更是一场以苏州为终点，串联起江南精华的发现之旅，让您在有限的时间和预算里，收获超出预期的丰富体验。这正是我们为您“读懂”数据背后，所浮现的“隐藏的过人之处”。</p><a id="more"></a><p>想象一下，您的假期不再仅仅局限于一城一地，而是沿着一条精心编织的丝线，从山水甲天下的桂林，到时尚与历史交织的上海，再到古都金陵的深邃，最终抵达梦中的水墨苏州。这不仅仅是旅行，更是一场关于发现、关于连接、关于慢享的艺术。我们为您刷了几百个页面，只为您的两次心动，奉上这两套独特的旅程方案，让您的时间，花在旅途中，而不是屏幕上！</p><hr><h3 id="方案一：轻装上路——预算之内，惊喜之外的江南画卷"><a href="#方案一：轻装上路——预算之内，惊喜之外的江南画卷" class="headerlink" title="方案一：轻装上路——预算之内，惊喜之外的江南画卷"></a><strong>方案一：轻装上路——预算之内，惊喜之外的江南画卷</strong></h3><p><strong>旅行总结：</strong> 这是一条为聪明旅者量身定制的路线，将桂林的自然之美、上海的都市风情、南京的古韵遗风巧妙串联，最终在苏州的园林雅境中寻得一份宁静。酒店选择独具匠心，性价比极高，让您在控制预算的同时，尽享每座城市的独特魅力。总预算包含了酒店住宿和每日约300元的餐饮交通杂费，让您轻松出行，无忧享受。</p><p><strong>总预算预估（2位成人，4天3晚）：</strong></p><ul><li><strong>酒店总价:</strong> ¥4272</li><li><strong>餐饮交通杂费预估:</strong> 每日¥300 x 4天 = ¥1200</li><li><strong>合计:</strong> ¥4272 + ¥1200 = <strong>¥5472</strong></li></ul><p><strong>行程安排：</strong></p><p><strong>💖 第一天：2025年10月1日 · 山水桂林——诗意的开篇</strong></p><ul><li><strong>上午-下午：抵达桂林，沉醉山水。</strong> 抵达桂林两江国际机场后，建议打车或乘坐机场大巴前往市区酒店办理入住。下午可前往<strong>象鼻山景区</strong>，这里是桂林市的标志，形似巨象饮水漓江，夕阳西下时尤其壮观。</li><li><strong>傍晚-夜晚：漓江夜游与美食。</strong> 在象鼻山附近乘船体验<strong>两江四湖夜游</strong>，感受桂林“城在景中，景在城中”的独特魅力。晚餐推荐品尝地道的<strong>桂林米粉</strong>，以及漓江边上的特色啤酒鱼。</li><li><strong>彩蛋：</strong> 别忘了去象鼻山景区旁的“椿记烧鹅”，桂林本地人宴请宾客的首选，烧鹅皮脆肉嫩，回味无穷，是您抵达后的第一道味蕾惊喜！</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/02A0d12000m3zfwo686F0_C_500_500.jpg" alt="诗与远方SYYF·漓江院子酒店（桂林象鼻山两江四湖店）" style="width:160px;"></td><td style="text-align:left"><strong>诗与远方SYYF·漓江院子酒店（桂林象鼻山两江四湖店）</strong> （5星 #16174） <br> <strong>套餐:</strong> 【主厨推荐】香煎大黄鱼2-3人餐 <br> <strong>评分:</strong> 4.8 <br> <font style="color:red;font-weight:bolder;">¥198</font> <del>¥366</del> (5.4折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/boom/boomDetail.html?id=73885583&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><p><strong>💖 第二天：2025年10月2日 · 水墨上海——古镇的悠扬</strong></p><ul><li><strong>上午：高铁抵达上海。</strong> 早餐后，前往桂林站乘坐高铁前往上海虹桥站（约7-8小时，建议提前预订）。抵达后，换乘地铁或打车前往朱家角古镇，入住酒店。</li><li><strong>下午-夜晚：穿越古镇，摇橹船之夜。</strong> 办理入住后，即刻投入<strong>朱家角古镇</strong>的怀抱。漫步小桥流水，品味江南水乡的静谧。酒店套餐中包含的“摇橹船早餐”更是古镇清晨的独特体验，让您提前感受。晚餐可在古镇内寻一间临水小馆，品尝上海本帮菜或特色小吃。</li><li><strong>彩蛋：</strong> 傍晚时分，古镇内有家名为“朱家角阿婆茶楼”的百年老店，除了传统的茶点，他们家的扎肉和蹄髈是镇上居民从小吃到大的味道，是品尝地道朱家角风味不可错过的地方。</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/02A6j12000i7weidjD2DD_C_500_500.jpg" alt="朱家角井亭民宿" style="width:160px;"></td><td style="text-align:left"><strong>朱家角井亭民宿</strong> （5星 #20501） <br> <strong>套餐:</strong> 【古镇的清晨】摇橹船早餐 <br> <strong>评分:</strong> 4.9 <br> <font style="color:red;font-weight:bolder;">¥588</font> <del>¥1088</del> (5.4折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/boom/boomDetail.html?id=70907981&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><p><strong>💖 第三天：2025年10月3日 · 金陵南京——汉服与雅颂</strong></p><ul><li><strong>上午：高铁抵达南京。</strong> 早餐后，从朱家角出发前往上海虹桥站，乘坐高铁前往南京南站（约1.5-2小时）。抵达后，前往金陵小城，入住“金陵小城·满庭芳客栈”。</li><li><strong>下午-夜晚：金陵小城深度体验。</strong> 您的酒店套餐包含了丰富的金陵小城体验：270度庭院景观套房、汉服体验、入园资格、手作坊折扣等。您可以在这里沉浸式体验金陵文化的魅力，穿上汉服，漫步于小城之中，仿佛穿越回古代。晚上可欣赏小城内的夜景和演出，品尝<strong>秦淮小吃</strong>。</li><li><strong>彩蛋：</strong> 金陵小城内的“兰生堂”手作体验，不仅仅是简单的制作，更是一种文化的传承。这里的老师傅会分享很多关于金陵传统手工艺的趣闻轶事，让你的手作不仅仅是作品，更是故事的载体。</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/1mc4812000bn1hmpqD4B0_C_500_500.jpg" alt="金陵小城·满庭芳客栈" style="width:160px;"></td><td style="text-align:left"><strong>金陵小城·满庭芳客栈</strong> （5星 #27231） <br> <strong>套餐:</strong> 270度庭院景观套房 1晚+早餐 2 份/天+精致汉服体验 1 份+金陵小城2位入园资格 1 份+金陵小城内“雅颂金陵”汉服馆9.5折 1 份+金陵小城内“兰生堂”手作体验8折 1 份+晚安甜汤 1 份+金陵小城内“雅颂金陵”汉服馆量身设计化妆、造型及全场汉服任选 1 份 <br> <strong>评分:</strong> 4.9 <br> <font style="color:red;font-weight:bolder;">¥2458</font> <del>¥3970</del> (6.2折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/hotelPackage/packageDetail.html?hotelId=94986087&amp%3BpageName=packageDetail&amp%3Bproduct-id=77960541&amp%3Bproduct-type=presale-product&amp%3BhotelDataType=1&amp%3Bpopup=close&amp%3BcityId=12&amp%3BcheckInDate=&amp%3BcheckOutDate=&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><p><strong>💖 第四天：2025年10月4日 · 诗意苏州——园林雅致的完美句点</strong></p><ul><li><strong>上午：高铁抵达苏州。</strong> 早餐后，从南京南站乘坐高铁前往苏州站（约1小时）。抵达后，打车前往酒店办理入住。</li><li><strong>下午：拙政园与平江路。</strong> 入住后，立即前往世界文化遗产<strong>拙政园</strong>，领略苏州园林的精髓。午餐可在园林附近品尝苏帮菜。下午漫步<strong>平江路历史街区</strong>，感受古朴的石板路、小桥流水和沿街的特色小店。</li><li><strong>傍晚：特色美食与告别。</strong> 晚餐品尝<strong>松鼠鳜鱼</strong>和<strong>响油鳝糊</strong>等经典苏帮菜。之后，您可以选择在平江路上的茶馆听评弹，或在咖啡馆小憩，为这次江南之旅画上圆满的句号。</li><li><strong>彩蛋：</strong> 酒店的“皮划艇”体验是亲近大自然的绝佳方式，在湖光山色中划桨，与水亲密接触，感受苏式生活的另一面，这在传统的苏州园林体验中是很少见的，是您旅程中一份别样的野趣。</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/1mc2512000ev2ezzj1260_C_500_500.jpg" alt="原野学社" style="width:160px;"></td><td style="text-align:left"><strong>原野学社</strong> （ #18063） <br> <strong>套餐:</strong> 亲子大套房-乐野 1晚+皮划艇 1 份+早餐 1 份/天 <br> <strong>评分:</strong> 4.9 <br> <font style="color:red;font-weight:bolder;">¥1028</font> <del>¥1602</del> (6.4折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/hotelPackage/packageDetail.html?hotelId=121807049&amp%3BpageName=packageDetail&amp%3Bproduct-id=34237807&amp%3Bproduct-type=presale-product&amp%3BhotelDataType=1&amp%3Bpopup=close&amp%3BcityId=14&amp%3BcheckInDate=&amp%3BcheckOutDate=&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><hr><h3 id="方案二：犒赏自己——把钱花在回忆上的奢享之旅"><a href="#方案二：犒赏自己——把钱花在回忆上的奢享之旅" class="headerlink" title="方案二：犒赏自己——把钱花在回忆上的奢享之旅"></a><strong>方案二：犒赏自己——把钱花在回忆上的奢享之旅</strong></h3><p><strong>旅行总结：</strong> 如果您渴望一场无与伦比的奢华体验，将品质与享受放在首位，那么这条路线将完美满足您的期待。从桂林的世外桃源，到上海浦东的云端俯瞰，再到南京的私汤疗愈，最后在苏州的独栋别墅中尽享宁静与自然。每一次住宿都是一次身心犒赏，让您的江南之旅成为永恒的珍贵回忆。</p><p><strong>总预算预估（2位成人，4天3晚）：</strong></p><ul><li><strong>酒店总价:</strong> ¥20274</li><li><strong>餐饮交通杂费预估:</strong> 每日¥300 x 4天 = ¥1200</li><li><strong>合计:</strong> ¥20274 + ¥1200 = <strong>¥21474</strong></li></ul><p><strong>行程安排：</strong></p><p><strong>✨ 第一天：2025年10月1日 · 醉美桂林——沉浸式亲子乐园</strong></p><ul><li><strong>上午-下午：抵达桂林，趣玩融创乐园。</strong> 抵达桂林后，直接前往融创施柏阁酒店，办理入住。酒店套餐内含融创乐园三园畅游、双人晚餐、皮划艇/落日草坪活动等，让您和家人抵达后即可开启欢乐模式。</li><li><strong>傍晚-夜晚：湖畔晚餐与家庭时光。</strong> 享受酒店提供的双人晚餐或自助餐，然后体验落日草坪活动或皮划艇，在湖光山色中享受温馨的家庭时光。</li><li><strong>彩蛋：</strong> 桂林融创施柏阁酒店的“跟拍电子快修照片”服务，能让您的亲子瞬间被专业捕捉，免去了自己拍照的烦恼，让您能全身心投入与家人的互动中，收获高质量的回忆定格。</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/0203b120009gwx4f3B68F_C_500_500.jpg" alt="桂林融创施柏阁酒店" style="width:160px;"></td><td style="text-align:left"><strong>桂林融创施柏阁酒店</strong> （5星 #14269） <br> <strong>套餐:</strong> 园景阳台双床房 1晚+早餐 2 份/天+双人晚餐套餐或自助晚餐 1 份+双人落日草坪活动门票或双人皮划艇40分钟 1 份+融创乐园三园畅游 1 份+儿童活动室权益 1 份+迷你吧-小食/饮品 1 份+跟拍电子快修照片 1 份 <br> <strong>评分:</strong> 4.7 <br> <font style="color:red;font-weight:bolder;">¥999</font> <del>¥2306</del> (4.3折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/hotelPackage/packageDetail.html?hotelId=70355091&amp%3BpageName=packageDetail&amp%3Bproduct-id=78323563&amp%3Bproduct-type=presale-product&amp%3BhotelDataType=1&amp%3Bpopup=close&amp%3BcityId=33&amp%3BcheckInDate=&amp%3BcheckOutDate=&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><p><strong>✨ 第二天：2025年10月2日 · 摩登上海——云端上的东方明珠</strong></p><ul><li><strong>上午：奢华抵达上海。</strong> 早餐后，乘坐飞机（或高铁）前往上海虹桥或浦东机场。抵达后，建议打车或专车直达上海浦东丽晶酒店，办理入住。</li><li><strong>下午-夜晚：陆家嘴的极致体验。</strong> 您的酒店套餐包含了东方明珠江景双卧套房、金茂大厦门票、1000元酒店消费额度及丽晶俱乐部礼遇。下午可登上金茂大厦俯瞰浦江两岸的壮丽景色，感受上海的现代与繁华。傍晚，在酒店内享受丽晶俱乐部专属礼遇，品尝特调鸡尾酒，远眺外滩夜景，晚餐可选择酒店内米其林餐厅或周边高端食府。</li><li><strong>彩蛋：</strong> 上海浦东丽晶酒店的“东方明珠江景双卧套房”，不仅仅是房间，更是一幅流动的城市画卷。在房间内即可将陆家嘴的璀璨夜景尽收眼底，无需出门，便能独享这份震撼，是真正把钱花在“视野”和“回忆”上的极致体验。</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/0220d12000a5qbavc3AEF_C_500_500.jpg" alt="上海浦东丽晶酒店" style="width:160px;"></td><td style="text-align:left"><strong>上海浦东丽晶酒店</strong> （5星 #18985） <br> <strong>套餐:</strong> 东方明珠江景双卧套房 1晚+早餐 2 份/天+金茂大厦2大1小门票(儿童身高≤1.3米) 1 份+1000元酒店消费额度 1 份+2大1小（5岁以下）丽晶俱乐部礼遇 1 份+每次入住赠送首轮迷你吧（包含一瓶红酒） 1 份+Camelia特调鸡尾酒10选1及小食 1 份 <br> <strong>评分:</strong> 4.6 <br> <font style="color:red;font-weight:bolder;">¥10888</font> <del>¥23385</del> (4.7折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/hotelPackage/packageDetail.html?hotelId=347132&amp%3BpageName=packageDetail&amp%3Bproduct-id=76446975&amp%3Bproduct-type=presale-product&amp%3BhotelDataType=1&amp%3Bpopup=close&amp%3BcityId=2&amp%3BcheckInDate=&amp%3BcheckOutDate=&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><p><strong>✨ 第三天：2025年10月3日 · 温泉南京——疗愈身心之旅</strong></p><ul><li><strong>上午：高铁抵达南京。</strong> 早餐后，从上海虹桥站乘坐高铁前往南京南站（约1.5-2小时）。抵达后，前往汤山元博纪温泉酒店，办理入住。</li><li><strong>下午-夜晚：私汤温泉与水世界。</strong> 酒店套餐包含臻享私汤家庭套房、汤山欢乐水世界门票及尊享私汤温泉。您可以尽情在酒店内享受私人温泉的疗愈，或前往汤山欢乐水世界，体验水上乐趣。晚餐可在酒店内品尝精美菜肴。</li><li><strong>彩蛋：</strong> 南京汤山元博纪温泉酒店的“臻享私汤家庭套房”，将温泉直接引入您的房间，让您在私密空间内尽享汤浴之乐。夜幕降临，伴着窗外的夜色泡一池私汤，是洗去旅途疲惫、彻底放松身心的绝佳方式。</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/0201b120009i2vks298D2_C_500_500.jpg" alt="南京汤山元博纪温泉酒店" style="width:160px;"></td><td style="text-align:left"><strong>南京汤山元博纪温泉酒店</strong> （5星 #27235） <br> <strong>套餐:</strong> 臻享私汤家庭套房 1晚+早餐 1 份/天+欢迎水果 1 份+迷你吧畅享 1 份+汤山欢乐水世界双人门票 2 份+尊享私汤温泉 1 份+阳山碑材景点门票 2 份 <br> <strong>评分:</strong> 4.6 <br> <font style="color:red;font-weight:bolder;">¥2899</font> <del>¥5080</del> (5.7折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/hotelPackage/packageDetail.html?hotelId=92857838&amp%3BpageName=packageDetail&amp%3Bproduct-id=77733903&amp%3Bproduct-type=presale-product&amp%3BhotelDataType=1&amp%3Bpopup=close&amp%3BcityId=12&amp%3BcheckInDate=&amp%3BcheckOutDate=&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><p><strong>✨ 第四天：2025年10月4日 · 秘境苏州——林间别墅的宁静与奢华</strong></p><ul><li><strong>上午：高铁抵达苏州。</strong> 早餐后，从南京南站乘坐高铁前往苏州站（约1小时）。抵达后，建议打车或专车前往苏州裸心泊度假村，办理入住。</li><li><strong>下午：独享林间别墅与水疗。</strong> 您的酒店套餐包含了林间独栋别墅、早餐及单人一小时SPA套餐。在抵达后，您可以完全放松身心，在别墅的私密空间中享受宁静，或体验度假村内提供的SPA服务，让身心得到彻底的放松。</li><li><strong>傍晚：度假村内的精彩活动与告别。</strong> 度假村每天都会有丰富的活动（根据季节和天气更新），您可以参与其中，也可以选择在别墅内享受宁静。晚餐可选择度假村内的精致餐厅，享受私密而高品质的用餐体验。</li><li><strong>彩蛋：</strong> 苏州裸心泊度假村的“林间独栋别墅”，让您仿佛置身世外桃源。它的“隐藏魅力”在于，它完美融合了苏州的园林意境与度假村的现代舒适，在繁忙的旅途之后，为您提供一个真正的“回归自然，放空自我”的奢华秘境，是对传统苏州之美的一次创新诠释。</li></ul><table><thead><tr><th style="text-align:left"></th><th style="text-align:left"></th></tr></thead><tbody><tr><td style="text-align:left"><img src="https://s.gqmg.com/https://images4.c-ctrip.com/target/0203n120008hj7zdpAEFB_C_500_500.jpg" alt="苏州裸心泊度假村" style="width:160px;"></td><td style="text-align:left"><strong>苏州裸心泊度假村</strong> （5星 #17847） <br> <strong>套餐:</strong> 林间独栋别墅2房 1晚+早餐 4 份/天+每天精彩活动畅玩（根据季节和天气更新活动时间表） 1 份+单人一小时SPA套餐 1 份 <br> <strong>评分:</strong> 4.7 <br> <font style="color:red;font-weight:bolder;">¥5488</font> <del>¥6488</del> (8.5折) <br> <a href="https://m.ctrip.com/webapp/cw/hotel/hotelPackage/packageDetail.html?hotelId=72182167&amp%3BpageName=packageDetail&amp%3Bproduct-id=77981351&amp%3Bproduct-type=presale-product&amp%3BhotelDataType=1&amp%3Bpopup=close&amp%3BcityId=14&amp%3BcheckInDate=&amp%3BcheckOutDate=&amp%3Bmktcart=true&amp%3BcartSource=kaiping&amp%3BcartChannel=36&amp%3Ballianceid=5347273&amp%3Bsid=203078555&f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank"><strong>&gt; 优惠渠道价格预订</strong></a></td></tr></tbody></table><hr><p>这两套方案，无论是追求高性价比的深度文化之旅，还是偏爱极致奢华的身心放松，都将以苏州的诗意收尾，为您带来一段段值得分享、值得珍藏的旅程。</p><p>您的下一趟旅程看起来是这样的！快选择一个您心动的方案，点击链接，开启您的精彩之旅吧！</p><p>原文地址：<a href="https://hotel.gqmg.com/p/104/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE#blogs" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://hotel.gqmg.com/p/104/#blogs</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;以下内容是用 &lt;a href=&quot;https://hotel.gqmg.com/mcp/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE&quot; rel=&quot;external nofollow noopener&quot; referrerpolicy=&quot;unsafe-url&quot; target=&quot;_blank&quot;&gt;特惠酒店MCP&lt;/a&gt; 生成的国庆行程计划。展示了MCP的行程规划能力；通过数据查询，智能推荐的能力；以及数据精确展示，局部修改能力。&lt;/p&gt;
&lt;p&gt;特惠酒店MCP会推荐两个路线，一个性价比优先，一个舒适优质路线。关于MCP的详情，随后单独介绍。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;输入需求：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;帮我规划国庆节旅游的酒店，路线是10.1从深圳出发自驾去厦门，途径泉州，10.5回，需要规划入住酒店和时间，和总预算，折扣，可以提供两个路线供选择。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;您渴望一场在苏州的休闲度假，追求那份独有的江南雅韵，这真是个绝佳的选择！作为您的创意旅伴，我观察到一个有趣的“悖论”——您的预算需求和旅行日期，似乎隐藏着一个更宏大的旅行版图。我们为您精心策划了不仅仅是一次苏州之旅，更是一场以苏州为终点，串联起江南精华的发现之旅，让您在有限的时间和预算里，收获超出预期的丰富体验。这正是我们为您“读懂”数据背后，所浮现的“隐藏的过人之处”。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="MCP" scheme="https://blogs.kainy.cn/tags/MCP/"/>
    
  </entry>
  
  <entry>
    <title>什么是设备指纹复制？怎么实现？</title>
    <link href="https://blogs.kainy.cn/2025/07/%E4%BB%80%E4%B9%88%E6%98%AF%E8%AE%BE%E5%A4%87%E6%8C%87%E7%BA%B9%E5%A4%8D%E5%88%B6%EF%BC%9F%E6%80%8E%E4%B9%88%E5%AE%9E%E7%8E%B0%EF%BC%9F/"/>
    <id>https://blogs.kainy.cn/2025/07/什么是设备指纹复制？怎么实现？/</id>
    <published>2025-07-09T09:27:15.000Z</published>
    <updated>2026-04-30T06:18:18.057Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>今天有客户询盘，问SyncMein扩展能否同步 fastmoss 的登录态，试了一下确实不行。</p><p>表现为：本地同浏览器跨profile（个人资料）ok，本地换浏览器偶尔不行，异地基本完全登不上。看来是结合了ck+浏览器指纹+IP校验登录态。</p><p>刚开始觉得不就是个查询 tiktok 数据的网站，至于这么严格么？直到看到官网定价…</p><a id="more"></a><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcvpkoil.png" alt="fastmoss价格表"></p><p>某宝上也有拆分来卖的，一天高达39元，销量还不错。天啦噜，跨境人的需求真的看不懂～</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcvq47kt.png" alt="fastmoss淘宝价格"></p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>一般的网站登录态保存在cookie中，那么只要将ck从一台电脑导出，在另外一台电脑导入。后者就能免密登上这个账号，这也是包括SyncMein在内的一般上号器工作原理。</p><p>那么设备指纹是什么呢？这是AI给的答案，好处是好理解。</p><blockquote><p>浏览器指纹，也称为设备指纹或浏览器指纹，是一种通过收集用户浏览器和设备配置信息来识别和追踪用户在线活动的技术。这种技术利用浏览器和操作系统等独特配置来创建独特的“指纹”，类似于现实生活中的指纹，用于区分和追踪用户，即使他们清除cookies或使用隐私模式</p></blockquote><p>所以对于fastmoss和Gmail这些同时校验ck和设备指纹的网站，相当于必须有两把匹配的钥匙，才能解开的锁。</p><p>经过两天尝试，写了一个demo浏览器扩展，来实现设备指纹的同步。</p><p>从设备指纹的产生过程，可以得知，要在不同设备复刻同一个指纹，除非魔改编译浏览器。几乎没有其他可能。</p><p>于是在想，既然山不过来，那就我自己过去：把需要免密登录的 设备的网络请求，以指令形式发给已登录设备的浏览器，由它转发给服务器，取到数据再返回。不就达到了“借用”指纹的效果？这就是“复制指纹”、“代理指纹”的由来。</p><h2 id="具体实现"><a href="#具体实现" class="headerlink" title="具体实现"></a>具体实现</h2><p>来看具体操作步骤，首先在宿主机，通过 SyncMein 扩展，鼠标移到需要分享口令的域名左边，点击“分享”按钮。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcvquus3.png" alt="分享端操作-生成口令"></p><p>然后将口令分享给需要共享账号的B，B拿到口令后，安装<a href="https://blogs.kainy.cn/2025/07/SyncMein-client%E7%9A%84%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95/#blogs">smi客户端扩展</a></p><p>然后按下图步骤导入口令，首次导入，需要安装证书，用于解密从宿主机代理过来的流量。</p><p>按照指引操作即可。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcvr501y.png" alt="导入口令步骤"></p><p>由于工作原理是将被分享者的流量，代理到分享者（宿主机），需要宿主机在线，可以通过口令上的绿点查看宿主机在线情况。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcvr6ogr.png" alt="宿主机在线状态查询"></p><p>导入口令后，再访问fastmoss，就会发现已经获得了登录态。</p><p>下图中，</p><ul><li>红点1是通过远程连接控制的windows系统，代表共享账号的接收端。</li><li>红点2是本地Mac系统，已经登录fastmoss，并生成口令，分享登录态，并提供代理服务。</li><li>红点3是本地浏览器控制台。</li></ul><p>可以看到windows系统已经免密登录Mac分享的同一个账号。而它的流量则出现在红点3中，Mac宿主机的网络面板。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcvrjiyc.png" alt="达到异地不同浏览器间同步登录态的效果"></p><p>这样一来，被分享端端windows访问 fastmoss 网站的流量，都是通过宿主机的网络出口，不仅借用了宿主机的设备指纹，连IP也是一样的。在 fastmoss 服务器看来，接收到的流量并无区别，就相当于还是在宿主机Mac上操作。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcvshbiu.png" alt="请求头详情"></p><p>我们给红点3的控制面板来个特写，可以看到请求头信息都是是宿主机（Mac系统）的，最明显是红框中的UserAgent。因为流量不是普通的代理转发，而是宿主机接收到指令后，发送请求，并将结果返回，相当于MITM。这就是为什么需要安装根证书解密流量的原因。</p><blockquote><blockquote><p>纯技术分析，无不良引导。使用请遵守相关法律法规和服务提供商的用户协议!</p></blockquote></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;今天有客户询盘，问SyncMein扩展能否同步 fastmoss 的登录态，试了一下确实不行。&lt;/p&gt;
&lt;p&gt;表现为：本地同浏览器跨profile（个人资料）ok，本地换浏览器偶尔不行，异地基本完全登不上。看来是结合了ck+浏览器指纹+IP校验登录态。&lt;/p&gt;
&lt;p&gt;刚开始觉得不就是个查询 tiktok 数据的网站，至于这么严格么？直到看到官网定价…&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="扩展" scheme="https://blogs.kainy.cn/tags/%E6%89%A9%E5%B1%95/"/>
    
      <category term="SyncMein" scheme="https://blogs.kainy.cn/tags/SyncMein/"/>
    
  </entry>
  
  <entry>
    <title>服务器进程占用大量内存，如何定位启动它的程序</title>
    <link href="https://blogs.kainy.cn/2025/07/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%9B%E7%A8%8B%E5%8D%A0%E7%94%A8%E5%A4%A7%E9%87%8F%E5%86%85%E5%AD%98%EF%BC%8C%E5%A6%82%E4%BD%95%E5%AE%9A%E4%BD%8D%E5%90%AF%E5%8A%A8%E5%AE%83%E7%9A%84%E7%A8%8B%E5%BA%8F/"/>
    <id>https://blogs.kainy.cn/2025/07/服务器进程占用大量内存，如何定位启动它的程序/</id>
    <published>2025-07-04T09:27:15.000Z</published>
    <updated>2026-04-30T06:18:18.079Z</updated>
    
    <content type="html"><![CDATA[<p>根据 <code>top</code> 命令输出，有一个进程（PID 为 <strong>303679</strong>）占用了大量的物理内存（<strong>4.1g</strong>），需要定位它是什么程序。</p><p>这个输出行提供了几个关键信息：</p><ul><li><strong>PID (进程ID)</strong>: <code>303679</code></li><li><strong>USER (运行用户)</strong>: <code>www</code> (这通常是 Web 服务器，如 Nginx 或 Apache，或其下运行的 Web 应用程序所使用的用户)</li><li><strong>RES (物理内存)</strong>: <code>4.1g</code></li><li><strong>%MEM (内存百分比)</strong>: <code>54.2%</code></li><li><strong>COMMAND (命令名)</strong>: <code>pt_main_thread</code> (这可能是一个线程名或主程序的一部分，不一定是程序的全名)</li></ul><p>要精确定位这个进程到底是由哪个程序启动的，以及它的完整路径和启动参数，您可以在服务器的命令行终端中执行以下步骤。<br><a id="more"></a></p><h3 id="定位步骤"><a href="#定位步骤" class="headerlink" title="定位步骤"></a>定位步骤</h3><p>以下命令请使用您提供的 <strong>PID <code>303679</code></strong> 来执行。</p><h4 id="1-查看进程的完整命令和参数"><a href="#1-查看进程的完整命令和参数" class="headerlink" title="1. 查看进程的完整命令和参数"></a>1. 查看进程的完整命令和参数</h4><p>这是最直接有效的一步，可以告诉您这个进程是如何被启动的。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -fp 303679</span><br></pre></td></tr></table></figure><p><strong>命令解释</strong>:</p><ul><li><code>ps -f</code>: 显示进程的完整格式信息 (full format)。</li><li><code>ps -p 303679</code>: 指定要查询的进程 ID。</li></ul><p><strong>输出示例</strong>:<br>您可能会看到类似下面这样的输出：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">UID</span>          <span class="string">PID</span>    <span class="string">PPID</span>  <span class="string">C</span> <span class="string">STIME</span> <span class="string">TTY</span>          <span class="string">TIME</span> <span class="string">CMD</span></span><br><span class="line"><span class="string">www</span>       <span class="number">303679</span>  <span class="number">12345</span>  <span class="number">0</span> <span class="string">Jul03</span> <span class="string">?</span>        <span class="number">00</span><span class="string">:00:51</span> <span class="string">/usr/bin/python3</span> <span class="string">/var/www/my_app/main.py</span> <span class="string">--worker-threads=10</span></span><br></pre></td></tr></table></figure><p>在这个示例中，<code>CMD</code> 这一列会显示<strong>完整的启动命令</strong>。从这里您就可以清晰地看到是 <code>/usr/bin/python3</code> 运行了 <code>/var/www/my_app/main.py</code> 这个脚本。</p><h4 id="2-定位可执行文件的绝对路径"><a href="#2-定位可执行文件的绝对路径" class="headerlink" title="2. 定位可执行文件的绝对路径"></a>2. 定位可执行文件的绝对路径</h4><p>如果上一步的 <code>CMD</code> 信息不够明确，或者您想直接找到可执行文件在磁盘上的位置，可以使用以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -l /proc/303679/exe</span><br></pre></td></tr></table></figure><p><strong>命令解释</strong>:</p><ul><li>在 Linux 系统中，<code>/proc/[PID]/exe</code> 是一个特殊的文件，它是一个符号链接，直接指向该进程对应的可执行文件的实际位置。</li><li><code>ls -l</code> 会显示这个链接所指向的真实路径。</li></ul><p><strong>输出示例</strong>:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">lrwxrwxrwx</span> <span class="number">1</span> <span class="string">www</span> <span class="string">www</span> <span class="number">0</span> <span class="string">Jul</span> <span class="number">4</span> <span class="number">08</span><span class="string">:50</span> <span class="string">/proc/303679/exe</span> <span class="string">-&gt;</span> <span class="string">/usr/local/bin/some_application</span></span><br></pre></td></tr></table></figure><p>这个输出明确地告诉您，该进程的可执行文件是 <code>/usr/local/bin/some_application</code>。</p><h4 id="3-查看进程树关系"><a href="#3-查看进程树关系" class="headerlink" title="3. 查看进程树关系"></a>3. 查看进程树关系</h4><p>了解一个进程是如何被启动的（它的父进程是谁）也很有帮助。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pstree -p 303679</span><br></pre></td></tr></table></figure><p><strong>命令解释</strong>:</p><ul><li><code>pstree</code> 会以树状结构显示进程关系。</li><li><code>-p</code> 会同时显示进程的 PID。</li></ul><p><strong>输出示例</strong>:<br>您可能会看到这样的结构，帮助您理解其调用关系：</p><figure class="highlight erlang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">systemd</span><span class="params">(<span class="number">1</span>)</span>---<span class="title">apache2</span><span class="params">(<span class="number">12300</span>)</span>---<span class="title">apache2</span><span class="params">(<span class="number">12345</span>)</span>---<span class="title">pt_main_thread</span><span class="params">(<span class="number">303679</span>)</span></span></span><br></pre></td></tr></table></figure><p>这表明该进程是由 Apache Web 服务器启动的。</p><h4 id="4-查看进程打开的文件和网络连接"><a href="#4-查看进程打开的文件和网络连接" class="headerlink" title="4. 查看进程打开的文件和网络连接"></a>4. 查看进程打开的文件和网络连接</h4><p>这个命令可以提供非常详细的上下文信息，比如程序正在读写哪些文件，或监听哪个端口。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lsof -p 303679 | less</span><br></pre></td></tr></table></figure><p><strong>命令解释</strong>:</p><ul><li><code>lsof</code> (List Open Files) 用于列出进程打开的所有文件和网络连接。</li><li>由于输出可能很长，通过 <code>| less</code> 可以方便地分页查看。</li></ul><h3 id="总结与分析"><a href="#总结与分析" class="headerlink" title="总结与分析"></a>总结与分析</h3><p>根据您提供的信息（<code>www</code> 用户和高内存占用），这个进程<strong>极有可能</strong>是：</p><ul><li><strong>Web 应用程序</strong>: 一个运行在 Web 服务器（如 Nginx, Apache）下的应用程序，可能是用 PHP, Python, Java, Node.js 等语言编写的。高内存占用可能是由于程序代码存在内存泄漏、缓存设置过大或正在处理非常大的数据。</li><li><strong>Web 服务器的某个工作进程</strong>: 例如 Apache 或 PHP-FPM 的某个子进程出现异常。</li></ul><p><strong>建议操作顺序</strong>：</p><ol><li>首先执行 <code>ps -fp 303679</code> 查看完整的启动命令，这是最关键的一步。</li><li>然后执行 <code>ls -l /proc/303679/exe</code> 确认可执行文件的具体位置。</li><li>结合这两步的结果，您就能准确地定位到是哪个具体的程序或脚本导致了内存占用过高，从而可以进一步分析代码或调整配置。</li></ol>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;根据 &lt;code&gt;top&lt;/code&gt; 命令输出，有一个进程（PID 为 &lt;strong&gt;303679&lt;/strong&gt;）占用了大量的物理内存（&lt;strong&gt;4.1g&lt;/strong&gt;），需要定位它是什么程序。&lt;/p&gt;
&lt;p&gt;这个输出行提供了几个关键信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PID (进程ID)&lt;/strong&gt;: &lt;code&gt;303679&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;USER (运行用户)&lt;/strong&gt;: &lt;code&gt;www&lt;/code&gt; (这通常是 Web 服务器，如 Nginx 或 Apache，或其下运行的 Web 应用程序所使用的用户)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RES (物理内存)&lt;/strong&gt;: &lt;code&gt;4.1g&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;%MEM (内存百分比)&lt;/strong&gt;: &lt;code&gt;54.2%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;COMMAND (命令名)&lt;/strong&gt;: &lt;code&gt;pt_main_thread&lt;/code&gt; (这可能是一个线程名或主程序的一部分，不一定是程序的全名)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;要精确定位这个进程到底是由哪个程序启动的，以及它的完整路径和启动参数，您可以在服务器的命令行终端中执行以下步骤。&lt;br&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="方法" scheme="https://blogs.kainy.cn/tags/%E6%96%B9%E6%B3%95/"/>
    
      <category term="服务器" scheme="https://blogs.kainy.cn/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
      <category term="运维" scheme="https://blogs.kainy.cn/tags/%E8%BF%90%E7%BB%B4/"/>
    
  </entry>
  
  <entry>
    <title>SyncMein-client扩展安装和使用方法</title>
    <link href="https://blogs.kainy.cn/2025/07/SyncMein-client%E7%9A%84%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95/"/>
    <id>https://blogs.kainy.cn/2025/07/SyncMein-client的安装方法/</id>
    <published>2025-07-01T09:27:15.000Z</published>
    <updated>2026-04-30T06:18:18.047Z</updated>
    
    <content type="html"><![CDATA[<p>1、首先访问 <a href="https://t.kainy.cn/smi-c/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE" rel="external nofollow noopener" referrerpolicy="unsafe-url" target="_blank">https://t.kainy.cn/smi-c/</a> 下载zip包，解压出 smi-client 目录。</p><p>2、在浏览器地址栏输入 chrome://extensions/ ，按回车键访问插件页面，钩上右上角的“开发者模式”。</p><a id="more"></a><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mclnt1r3.png" alt="插件页"></p><p>3、将第1步解压好的 smi-client 文件夹，拖动到第2步打开的插件页面上，完成安装。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mclpz3xg.png" alt="image"><br>4、安装后，应该可以看到上图红圈的部分。为了方便后续使用，我们点下图红点1，右上角的拼图按钮。然后点红点2点图钉按钮。将上号器固定。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mclq37tn.png" alt="image"></p><p>5、按照红点顺序，点开刚才固定好的插件图标，然后贴如口令，点击“导入口令”。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mcls4b01.png" alt="image"></p><p>导入口令后，刷新页面应该就是已登录状态了。</p><p>后续如果登录态掉了，首先点口令右边的刷新按钮（下图红点1）可以拉取最新ck到本地。</p><p>如果还是不能登上，再点通知口令作者（下图红点2）， 可能是ck过期，会发送通知口令作者重新登录共享账号，并更新ck。作者更新ck后，你再点刷新，就可以登上了。</p><p><img src="https://s.gqmg.com/https://oray.kainy.cn:38400/_upload/./content/temp/2025/07/mclttnkh.png" alt="image"></p><p>需要注意的是：作者更新ck前，只能发送一次提醒哦。以免太多通知打扰作者，也请大家确认登录态失效才提醒，否则可能误报次数多了，可能影响作者更新ck多失效哟～</p><blockquote><p>请遵守账号所属网站用户协议及相关法律法规，合理使用本工具。使用即代表同意，自行承担使用后果和可能的风险。</p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;1、首先访问 &lt;a href=&quot;https://t.kainy.cn/smi-c/?f=%E6%9D%A5%E8%87%AAblogs.kainy.cn%E7%9A%84%E8%AE%BF%E9%97%AE&quot; rel=&quot;external nofollow noopener&quot; referrerpolicy=&quot;unsafe-url&quot; target=&quot;_blank&quot;&gt;https://t.kainy.cn/smi-c/&lt;/a&gt; 下载zip包，解压出 smi-client 目录。&lt;/p&gt;
&lt;p&gt;2、在浏览器地址栏输入 chrome://extensions/ ，按回车键访问插件页面，钩上右上角的“开发者模式”。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="扩展" scheme="https://blogs.kainy.cn/tags/%E6%89%A9%E5%B1%95/"/>
    
      <category term="SyncMein" scheme="https://blogs.kainy.cn/tags/SyncMein/"/>
    
  </entry>
  
  <entry>
    <title>解决服务器磁盘空间不足问题的两个办法</title>
    <link href="https://blogs.kainy.cn/2025/06/%E8%A7%A3%E5%86%B3%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%A3%81%E7%9B%98%E7%A9%BA%E9%97%B4%E4%B8%8D%E8%B6%B3%E9%97%AE%E9%A2%98%E7%9A%84%E4%B8%A4%E4%B8%AA%E5%8A%9E%E6%B3%95/"/>
    <id>https://blogs.kainy.cn/2025/06/解决服务器磁盘空间不足问题的两个办法/</id>
    <published>2025-06-23T09:27:15.000Z</published>
    <updated>2026-04-30T06:18:18.098Z</updated>
    
    <content type="html"><![CDATA[<h2 id="nginx-如何限定log文件的尺寸"><a href="#nginx-如何限定log文件的尺寸" class="headerlink" title="nginx 如何限定log文件的尺寸"></a>nginx 如何限定log文件的尺寸</h2><p>要限定 Nginx 日志文件的尺寸，正确且最常用的方法并非在 Nginx 的配置文件中直接设置，因为 <strong>Nginx 本身没有提供按文件大小自动切割日志的功能</strong>。</p><p>正确的做法是使用一个名为 <code>logrotate</code> 的标准 Linux 工具。<code>logrotate</code> 是一个强大的日志管理工具，它可以根据文件大小、时间（每天、每周、每月）等策略来自动轮转、压缩和删除日志文件。</p><a id="more"></a><p>几乎所有的 Linux 发行版（包括 CentOS, Ubuntu, Debian 等）都预装了 <code>logrotate</code>。通过配置 <code>logrotate</code>，您可以实现：</p><ol><li>当日志文件达到指定大小时，将其重命名。</li><li>创建一个新的空日志文件供 Nginx 继续写入。</li><li>压缩旧的日志文件以节省磁盘空间。</li><li>定期删除过旧的日志文件。</li></ol><p>下面是具体的操作步骤和配置示例。</p><hr><h3 id="使用-logrotate-限定-Nginx-日志大小"><a href="#使用-logrotate-限定-Nginx-日志大小" class="headerlink" title="使用 logrotate 限定 Nginx 日志大小"></a>使用 <code>logrotate</code> 限定 Nginx 日志大小</h3><h4 id="第-1-步：创建-logrotate-配置文件"><a href="#第-1-步：创建-logrotate-配置文件" class="headerlink" title="第 1 步：创建 logrotate 配置文件"></a>第 1 步：创建 <code>logrotate</code> 配置文件</h4><p>为 Nginx 创建一个专门的 <code>logrotate</code> 配置文件。这个文件通常放在 <code>/etc/logrotate.d/</code> 目录下。如果您的系统中已经有了一个名为 <code>nginx</code> 的文件，可以直接修改它；如果没有，就创建一个新文件。</p><p>使用文本编辑器（如 <code>vim</code> 或 <code>nano</code>）创建文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo vim /etc/logrotate.d/nginx</span><br></pre></td></tr></table></figure><h4 id="第-2-步：编写配置文件内容"><a href="#第-2-步：编写配置文件内容" class="headerlink" title="第 2 步：编写配置文件内容"></a>第 2 步：编写配置文件内容</h4><p>向该文件中添加以下内容。这是一个非常实用且通用的配置模板，您可以根据自己的需求进行调整。</p><figure class="highlight dts"><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></pre></td><td class="code"><pre><span class="line"><span class="meta-keyword">/var/</span>log<span class="meta-keyword">/nginx/</span>*.<span class="class">log </span>&#123;</span><br><span class="line">    <span class="meta"># 当日志文件达到 100M 时进行轮转</span></span><br><span class="line">    size <span class="number">100</span>M</span><br><span class="line"></span><br><span class="line">    <span class="meta"># 每天检查一次，如果满足条件（如大小）就执行轮转</span></span><br><span class="line">    daily</span><br><span class="line"></span><br><span class="line">    <span class="meta"># 保留 14 个轮转后的日志文件副本</span></span><br><span class="line">    rotate <span class="number">14</span></span><br><span class="line"></span><br><span class="line">    <span class="meta"># 对轮转后的旧日志文件进行 gzip 压缩</span></span><br><span class="line">    compress</span><br><span class="line"></span><br><span class="line">    <span class="meta"># 和 compress 指令配合使用，最近一次轮转的日志不压缩，以方便查看</span></span><br><span class="line">    delaycompress</span><br><span class="line"></span><br><span class="line">    <span class="meta"># 如果日志文件不存在，不要报错</span></span><br><span class="line">    missingok</span><br><span class="line"></span><br><span class="line">    <span class="meta"># 不轮转空文件</span></span><br><span class="line">    notifempty</span><br><span class="line"></span><br><span class="line">    <span class="meta"># 使用 root 用户和 adm 组（或 www-data/nginx 组）创建新日志文件</span></span><br><span class="line">    <span class="meta"># 权限为 640</span></span><br><span class="line">    create <span class="number">0640</span> nginx adm</span><br><span class="line"></span><br><span class="line">    <span class="meta"># 在轮转所有匹配的日志文件后，执行 postrotate 脚本</span></span><br><span class="line">    sharedscripts</span><br><span class="line"></span><br><span class="line">    <span class="meta"># postrotate 和 endscript 之间的命令会在日志文件轮转后执行</span></span><br><span class="line">    postrotate</span><br><span class="line">        <span class="meta"># 向 Nginx 主进程发送 USR1 信号，使其重新打开日志文件</span></span><br><span class="line">        <span class="meta"># 这可以确保日志无缝地写入新创建的文件中，而无需重启 Nginx 服务</span></span><br><span class="line">        if [ -f <span class="meta-keyword">/var/</span>run/nginx.pid ]; then</span><br><span class="line">            kill -USR1 `cat <span class="meta-keyword">/var/</span>run/nginx.pid`</span><br><span class="line">        fi</span><br><span class="line">    endscript</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h3 id="配置参数详解"><a href="#配置参数详解" class="headerlink" title="配置参数详解"></a>配置参数详解</h3><ul><li><code>/var/log/nginx/*.log</code>: 指定要管理的日志文件路径。<code>*</code> 是通配符，表示匹配 <code>/var/log/nginx/</code> 目录下的所有以 <code>.log</code> 结尾的文件（例如 <code>access.log</code> 和 <code>error.log</code>）。</li><li><code>size 100M</code>: <strong>这是限定文件大小的关键指令</strong>。当日志文件大小超过 100MB 时，<code>logrotate</code> 就会触发轮转操作。您可以将 <code>100M</code> 修改为任何您需要的大小，如 <code>500M</code>, <code>1G</code>。</li><li><code>daily</code>: 指定轮转周期为每天。即使文件大小未达到 <code>size</code> 设定的值，<code>logrotate</code> 每天也会检查一次。其他可用值为 <code>weekly</code>, <code>monthly</code>, <code>yearly</code>。通常 <code>size</code> 和 <code>daily</code> 会结合使用。</li><li><code>rotate 14</code>: 指定保留多少个归档日志。在这个例子中，会保留14个备份。当生成第15个备份时，最旧的那个（例如 <code>access.log.15.gz</code>）将被删除。</li><li><code>compress</code>: 通过 <code>gzip</code> 压缩轮转后的日志文件，节省空间。压缩后的文件通常会带有 <code>.gz</code> 后缀。</li><li><code>delaycompress</code>: 延迟压缩，与 <code>compress</code> 选项共用。这可以确保当天的日志文件（例如 <code>access.log.1</code>）不会被立即压缩，方便排查问题。下次轮转时，它才会被压缩成 <code>.gz</code> 文件。</li><li><code>missingok</code>: 如果找不到日志文件，不要当作错误处理。</li><li><code>notifempty</code>: 如果日志文件是空的，则不执行轮转。</li><li><code>create 0640 nginx adm</code>: 创建新日志文件时所使用的权限和所有者/组。请确保这里的用户和组与 Nginx 运行用户匹配。在 Debian/Ubuntu 上可能是 <code>www-data</code>，在 CentOS 上可能是 <code>nginx</code>。您可以通过 <code>ps aux | grep nginx</code> 查看 Nginx 的运行用户。</li><li><code>sharedscripts</code> / <code>postrotate</code>: 这部分非常重要。<code>postrotate</code> 块中的脚本会在所有匹配的日志都轮转完毕后执行一次。<code>kill -USR1 $(cat /var/run/nginx.pid)</code> 命令会通知 Nginx 主进程重新打开日志文件句柄。这样，新的日志就会被写入到 <code>logrotate</code> 新创建的空日志文件中，从而实现无缝切换，<strong>避免了重启 Nginx 服务导致的中断</strong>。</li></ul><hr><h3 id="第-3-步：测试和强制执行"><a href="#第-3-步：测试和强制执行" class="headerlink" title="第 3 步：测试和强制执行"></a>第 3 步：测试和强制执行</h3><p><code>logrotate</code> 通常由 <code>cron</code> 每日自动执行，您不需要手动干预。但如果您想立即测试配置是否正确，可以使用以下命令：</p><ol><li><p><strong>调试模式（模拟执行）</strong>：<br>这个命令会模拟执行轮转过程并显示详细输出，但不会真正修改任何文件。这是检查配置语法是否正确的最佳方式。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo logrotate -d /etc/logrotate.d/nginx</span><br></pre></td></tr></table></figure></li><li><p><strong>强制执行模式</strong>：<br>这个命令会强制立即执行轮转，即使时间和大小条件不满足。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo logrotate -f /etc/logrotate.d/nginx</span><br></pre></td></tr></table></figure><p>执行后，您可以去 <code>/var/log/nginx</code> 目录下查看是否生成了如 <code>access.log.1</code> 这样的文件。</p></li></ol><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>通过配置 <code>logrotate</code>，您可以非常灵活且可靠地管理 Nginx 的日志文件大小，防止单个日志文件无限增长耗尽磁盘空间，这是生产环境中管理 Nginx 日志的标准实践。</p><p>好的，这是一个在 CentOS 7.4 系统上运行的磁盘空间清理脚本。该脚本将帮助您查找并列出占用磁盘空间较大的文件和目录，并提供一些常见的可安全清理的目录路径建议，供您手动验证和清理。</p><p><strong>重要提示：</strong></p><ul><li><strong>在运行任何删除命令之前，请务ah必仔细检查列出的文件和目录，确保它们不是重要的系统文件或用户数据。</strong></li><li><strong>对于不确定的文件，建议先备份再删除。</strong></li><li><strong>建议以 root 用户身份或具有 sudo 权限的用户运行此脚本，以便全面扫描系统。</strong></li><li>此脚本主要用于查找和列出文件/目录，并不会自动执行任何删除操作，以确保安全。您可以根据脚本的输出，手动执行清理命令。</li></ul><hr><h2 id="磁盘空间清理脚本-clean-disk-sh"><a href="#磁盘空间清理脚本-clean-disk-sh" class="headerlink" title="磁盘空间清理脚本 (clean_disk.sh)"></a>磁盘空间清理脚本 (clean_disk.sh)</h2><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"><span class="comment"># CentOS 7.4 磁盘空间清理辅助脚本</span></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="comment">#   1. 查找系统中占用空间最大的文件。</span></span><br><span class="line"><span class="comment">#   2. 查找系统中占用空间最大的目录。</span></span><br><span class="line"><span class="comment">#   3. 列出常见的可以清理的大目录路径，供手动验证。</span></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="comment">#   1. 保存脚本为 clean_disk.sh</span></span><br><span class="line"><span class="comment">#   2. 赋予执行权限: chmod +x clean_disk.sh</span></span><br><span class="line"><span class="comment">#   3. 运行脚本: ./clean_disk.sh</span></span><br><span class="line"><span class="comment"># ==============================================================================</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"============================================================"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"          CentOS 7.4 磁盘空间清理辅助脚本"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"============================================================"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"脚本将开始分析磁盘空间占用情况，这可能需要一些时间..."</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># --- 1. 查找并列出系统中最大的前 20 个文件 ---</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"--- 正在查找系统中最大的前 20 个文件 (大于 500MB) ---"</span></span><br><span class="line">find / -<span class="built_in">type</span> f -size +500M -<span class="built_in">exec</span> du -h &#123;&#125; + 2&gt;/dev/null | sort -rh | head -n 20</span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"提示：请检查以上列出的文件。常见的大文件可能包括日志文件、备份文件、数据库文件或虚拟机镜像。"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"对于日志文件，可以直接删除或清空。对于其他文件，请确认不再需要后手动删除。"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"例如，清空一个日志文件：&gt; /path/to/large/logfile.log"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"删除一个文件：rm /path/to/large/file"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"------------------------------------------------------------"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># --- 2. 查找并列出系统中最大的前 20 个目录 ---</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"--- 正在查找系统中最大的前 20 个目录 ---"</span></span><br><span class="line">du -h / 2&gt;/dev/null | sort -rh | head -n 20</span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"提示：请检查以上列出的目录。常见的占用空间大的目录可能在 /var, /usr, /home, /opt 等路径下。"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"您可以使用 'du -h --max-depth=1 /path/to/large/directory' 命令逐层深入查找具体是哪个子目录占用了空间。"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"------------------------------------------------------------"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># --- 3. 疑似可以清理的大目录和文件类型 ---</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"--- 疑似可以清理的大目录路径和建议 ---"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查 /var/log/journal</span></span><br><span class="line">journal_size=$(du -sh /var/<span class="built_in">log</span>/journal/ 2&gt;/dev/null | awk <span class="string">'&#123;print $1&#125;'</span>)</span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$journal_size</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"1. Systemd Journal 日志 (/var/log/journal/):"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 当前占用空间: <span class="variable">$journal_size</span>"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 这些是 systemd 的日志文件。您可以清理旧的日志。"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 清理建议:"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # 保留最近 2 天的日志: journalctl --vacuum-time=2d"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # 限制日志文件最大为 500MB: journalctl --vacuum-size=500M"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查 /var/cache/yum</span></span><br><span class="line">yum_cache_size=$(du -sh /var/cache/yum/ 2&gt;/dev/null | awk <span class="string">'&#123;print $1&#125;'</span>)</span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$yum_cache_size</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"2. YUM 软件包缓存 (/var/cache/yum/):"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 当前占用空间: <span class="variable">$yum_cache_size</span>"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 这是 YUM 包管理器下载的软件包和元数据的缓存。"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 清理建议 (通常可以安全执行):"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # 清理所有缓存: yum clean all"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查 /tmp 和 /var/tmp</span></span><br><span class="line">tmp_size=$(du -sh /tmp/ 2&gt;/dev/null | awk <span class="string">'&#123;print $1&#125;'</span>)</span><br><span class="line">var_tmp_size=$(du -sh /var/tmp/ 2&gt;/dev/null | awk <span class="string">'&#123;print $1&#125;'</span>)</span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$tmp_size</span>"</span> ] || [ -n <span class="string">"<span class="variable">$var_tmp_size</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"3. 临时文件目录 (/tmp/ 和 /var/tmp/):"</span></span><br><span class="line">    <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$tmp_size</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">"   - /tmp/ 当前占用空间: <span class="variable">$tmp_size</span>"</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">    <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$var_tmp_size</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">"   - /var/tmp/ 当前占用空间: <span class="variable">$var_tmp_size</span>"</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 这些目录存放临时文件，通常可以删除旧的文件。"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 清理建议:"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # 删除超过 7 天未访问的临时文件 (请谨慎操作):"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # find /tmp -type f -atime +7 -delete"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # find /var/tmp -type f -atime +7 -delete"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查旧的内核</span></span><br><span class="line">old_kernels=$(rpm -q kernel | sed <span class="string">'$d'</span> | wc -l)</span><br><span class="line"><span class="keyword">if</span> [ <span class="string">"<span class="variable">$old_kernels</span>"</span> -gt 1 ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"4. 旧的内核版本:"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 系统中存在多个内核版本。保留一到两个新的即可。"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 当前已安装的内核："</span></span><br><span class="line">    rpm -q kernel</span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 清理建议:"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # 安装 yum-utils: yum install yum-utils -y"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # 清理旧内核 (将只保留最新的 2 个): package-cleanup --oldkernels --count=2"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查日志文件目录 /var/log</span></span><br><span class="line">log_dir_size=$(du -sh /var/<span class="built_in">log</span>/ 2&gt;/dev/null | awk <span class="string">'&#123;print $1&#125;'</span>)</span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$log_dir_size</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"5. 日志文件目录 (/var/log/):"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 当前占用空间: <span class="variable">$log_dir_size</span>"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 这个目录包含各种系统和应用的日志文件。定期归档和清理是好习惯。"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 查找大的日志文件 (例如大于 100MB):"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"     # find /var/log -type f -size +100M -ls"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"   - 对于不再需要的旧日志文件 (.log.1, .log.gz 等)，可以直接删除。"</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">""</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"============================================================"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"                   脚本执行完毕"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"============================================================"</span></span><br></pre></td></tr></table></figure><hr><h3 id="如何使用脚本"><a href="#如何使用脚本" class="headerlink" title="如何使用脚本"></a>如何使用脚本</h3><ol><li><p><strong>保存脚本</strong><br>将上面的代码内容复制并粘贴到一个新文件中，例如 <code>clean_disk.sh</code>。</p></li><li><p><strong>赋予执行权限</strong><br>在终端中，进入到脚本所在的目录，然后运行以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chmod +x clean_disk.sh</span><br></pre></td></tr></table></figure></li><li><p><strong>运行脚本</strong><br>使用 <code>sudo</code> 或者以 <code>root</code> 用户身份运行脚本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo ./clean_disk.sh</span><br></pre></td></tr></table></figure><p>或者切换到 root 用户后再执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">su -</span><br><span class="line">./path/to/clean_disk.sh</span><br></pre></td></tr></table></figure></li></ol><h3 id="脚本输出解读和后续步骤"><a href="#脚本输出解读和后续步骤" class="headerlink" title="脚本输出解读和后续步骤"></a>脚本输出解读和后续步骤</h3><p>脚本运行后，会依次输出三个部分的内容：</p><ol><li><p><strong>系统中最大的前 20 个文件</strong>：</p><ul><li><strong>关注点</strong>：重点关注后缀为 <code>.log</code>, <code>.tar.gz</code>, <code>.zip</code>, <code>.bak</code> 的文件，以及一些看起来异常大的文件。</li><li><strong>处理方法</strong>：<ul><li>对于日志文件，如果您确认日志内容无用，可以直接使用 <code>&gt;</code> 符号清空，例如：<code>&gt; /var/log/some-large-log.log</code>。这比删除文件再创建更好，可以避免因文件句柄被进程占用导致的空间不释放问题。</li><li>对于备份文件或压缩包，确认不再需要后，使用 <code>rm</code> 命令删除。</li></ul></li></ul></li><li><p><strong>系统中最大的前 20 个目录</strong>：</p><ul><li><strong>关注点</strong>：这可以帮助您快速定位到哪个主目录下包含了大量数据。通常 <code>/var</code>（日志、缓存、数据库）、<code>/home</code>（用户数据）、<code>/usr</code>（软件安装）、<code>/opt</code>（第三方软件）是需要关注的重点。</li><li><p><strong>处理方法</strong>：当您发现一个大目录，例如 <code>/var/www/html</code>，您可以使用以下命令进一步分析其子目录的大小：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo du -h --max-depth=1 /var/www/html</span><br></pre></td></tr></table></figure><p>这样逐层深入，直到找到最终占用空间的文件或目录。</p></li></ul></li><li><p><strong>疑似可以清理的大目录路径和建议</strong>：</p><ul><li><strong>Systemd Journal 日志</strong>：这是 CentOS 7 中常见的日志来源，会持续增长。脚本中提供的 <code>journalctl</code> 命令是官方推荐的安全清理方式。</li><li><strong>YUM 软件包缓存</strong>：每次安装或更新软件时，下载的 RPM 包会留在这里。清理缓存可以释放可观的空间，且对系统无害。</li><li><strong>临时文件</strong>：<code>/tmp</code> 和 <code>/var/tmp</code> 中的文件理论上都可以删除，但为了防止意外中断正在运行的程序，建议只删除一段时间以前的旧文件。</li><li><strong>旧的内核</strong>：每次内核更新，旧版本的内核都会保留。通常保留最新的一个和前一个作为备用即可，过多的旧内核会占用 <code>/boot</code> 和 <code>/lib/modules</code> 的空间。<code>package-cleanup</code> 是安全的官方清理工具。</li><li><strong>/var/log 目录</strong>：除了 journal 日志，许多应用（如 Nginx, Apache, MySQL等）会在这里生成自己的日志。对于轮转后（rotated）的旧日志（通常以 <code>.1</code>, <code>.2.gz</code> 等结尾），可以安全删除。</li></ul></li></ol><p>通过结合使用这个脚本和您的判断，可以安全有效地清理 CentOS 7.4 服务器上的磁盘空间。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;nginx-如何限定log文件的尺寸&quot;&gt;&lt;a href=&quot;#nginx-如何限定log文件的尺寸&quot; class=&quot;headerlink&quot; title=&quot;nginx 如何限定log文件的尺寸&quot;&gt;&lt;/a&gt;nginx 如何限定log文件的尺寸&lt;/h2&gt;&lt;p&gt;要限定 Nginx 日志文件的尺寸，正确且最常用的方法并非在 Nginx 的配置文件中直接设置，因为 &lt;strong&gt;Nginx 本身没有提供按文件大小自动切割日志的功能&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;正确的做法是使用一个名为 &lt;code&gt;logrotate&lt;/code&gt; 的标准 Linux 工具。&lt;code&gt;logrotate&lt;/code&gt; 是一个强大的日志管理工具，它可以根据文件大小、时间（每天、每周、每月）等策略来自动轮转、压缩和删除日志文件。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="方法" scheme="https://blogs.kainy.cn/tags/%E6%96%B9%E6%B3%95/"/>
    
      <category term="服务器" scheme="https://blogs.kainy.cn/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
      <category term="运维" scheme="https://blogs.kainy.cn/tags/%E8%BF%90%E7%BB%B4/"/>
    
  </entry>
  
  <entry>
    <title>SyncMeIn App FAQ</title>
    <link href="https://blogs.kainy.cn/2025/06/SyncMeIn%20App%20FAQ/"/>
    <id>https://blogs.kainy.cn/2025/06/SyncMeIn App FAQ/</id>
    <published>2025-06-04T04:17:46.000Z</published>
    <updated>2026-04-30T06:18:18.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-Regarding-our-business-model"><a href="#1-Regarding-our-business-model" class="headerlink" title="1. Regarding our business model:"></a>1. Regarding our business model:</h2><ul><li>Currently, our app is completely free with no paid features. All users can access all available features without any payment.</li><li>We plan to introduce subscription features in the future, which will allow users to sync their favorite requests and configuration information across devices, but this functionality has not been implemented yet.</li><li>Account registration is completely free and optional.</li><li>There are no paid features, subscriptions, or in-app purchases in the current version.<a id="more"></a></li></ul><h2 id="2-Regarding-account-deletion"><a href="#2-Regarding-account-deletion" class="headerlink" title="2. Regarding account deletion:"></a>2. Regarding account deletion:</h2><ul><li>We have implemented an account deletion option in our app.</li><li>Users can find the “Delete Account” link at the bottom of the user profile screen after logging in.</li><li>This link directs users to our website (<a href="https://kainy.cn/SyncMeIn/privacy.html#close_my_account" target="_blank" rel="noopener">https://kainy.cn/SyncMeIn/privacy.html#close_my_account</a>) where they can complete the account deletion process.</li><li>The account deletion process is straightforward and does not require contacting customer service.</li></ul><h2 id="3-What-user-information-is-the-app-collecting-using-VPN"><a href="#3-What-user-information-is-the-app-collecting-using-VPN" class="headerlink" title="3. What user information is the app collecting using VPN?"></a>3. What user information is the app collecting using VPN?</h2><p>SyncMeIn uses a VPN configuration to intercept and inspect HTTP/HTTPS traffic for debugging and development purposes. </p><p>The app collects the following information through the VPN functionality:</p><ul><li>Network request and response data (HTTP/HTTPS traffic) that passes through the VPN</li><li>Domain names and URLs of websites and services accessed through the VPN</li><li>Request headers and response data for analysis and debugging</li><li>Connection metadata (IP addresses, ports) necessary for the proper functioning of the proxy service</li></ul><p>The app does NOT collect or store:</p><ul><li>Personal user identification information</li><li>Passwords or authentication credentials</li><li>Browsing history beyond the current session (unless explicitly saved by the user)</li><li>Device information beyond what’s necessary for VPN operation</li><li>Location data or other sensitive personal information</li></ul><h2 id="4-For-what-purposes-is-this-information-collected"><a href="#4-For-what-purposes-is-this-information-collected" class="headerlink" title="4. For what purposes is this information collected?"></a>4. For what purposes is this information collected?</h2><p>The collected information is used exclusively for the following purposes:</p><ul><li>Traffic Analysis and Debugging: To help developers inspect, analyze, and debug HTTP/HTTPS requests and responses during app development</li><li>Request Modification: To allow users to rewrite or modify requests for testing and development purposes</li><li>Domain Filtering: To selectively capture only traffic from specific domains as configured by the user</li><li>Script Execution: To enable users to run custom JavaScript scripts to process requests or responses for testing</li><li>Local History: To provide a temporary record of captured traffic for analysis within the current debugging session</li></ul><p>All data processing happens locally on the user’s device. The VPN functionality is designed as a development tool to help users debug their own applications and network traffic.</p><h2 id="5-Will-the-data-be-shared-with-any-third-parties-If-so-for-what-purposes-and-where-will-this-information-be-stored"><a href="#5-Will-the-data-be-shared-with-any-third-parties-If-so-for-what-purposes-and-where-will-this-information-be-stored" class="headerlink" title="5. Will the data be shared with any third parties? If so, for what purposes and where will this information be stored?"></a>5. Will the data be shared with any third parties? If so, for what purposes and where will this information be stored?</h2><p>No, the data collected through the VPN is not shared with any third parties. All traffic data is:</p><ul><li>Processed locally on the user’s device</li><li>Only stored temporarily in the app’s local storage</li><li>Only accessible to the user of the app</li><li>Not transmitted to external servers except when explicitly initiated by the user (e.g., when forwarding traffic to another device for debugging)</li></ul><p>The app includes user authentication functionality, but this is solely for user account management and does not involve sharing the VPN-captured traffic data with third parties.</p><p>If users choose to export their captured traffic history (in HAR format), this exported data remains under their control and is not automatically uploaded to any server.</p><h2 id="In-summary"><a href="#In-summary" class="headerlink" title="In summary"></a>In summary</h2><p>SyncMeIn is a developer tool that uses VPN functionality to provide local traffic inspection and modification capabilities, with all data processing happening on-device and no sharing of captured traffic with third parties。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;1-Regarding-our-business-model&quot;&gt;&lt;a href=&quot;#1-Regarding-our-business-model&quot; class=&quot;headerlink&quot; title=&quot;1. Regarding our business model:&quot;&gt;&lt;/a&gt;1. Regarding our business model:&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Currently, our app is completely free with no paid features. All users can access all available features without any payment.&lt;/li&gt;
&lt;li&gt;We plan to introduce subscription features in the future, which will allow users to sync their favorite requests and configuration information across devices, but this functionality has not been implemented yet.&lt;/li&gt;
&lt;li&gt;Account registration is completely free and optional.&lt;/li&gt;
&lt;li&gt;There are no paid features, subscriptions, or in-app purchases in the current version.
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="SyncMeIn" scheme="https://blogs.kainy.cn/tags/SyncMeIn/"/>
    
      <category term="App" scheme="https://blogs.kainy.cn/tags/App/"/>
    
  </entry>
  
  <entry>
    <title>新线开通 低至99畅享永安厦门双城往返市区接送</title>
    <link href="https://blogs.kainy.cn/2025/05/%E6%96%B0%E7%BA%BF%E5%BC%80%E9%80%9A%20%E4%BD%8E%E8%87%B3%2099%20%E7%95%85%E4%BA%AB%E6%B0%B8%E5%AE%89%E5%8E%A6%E9%97%A8%E5%8F%8C%E5%9F%8E%E5%BE%80%E8%BF%94%E5%B8%82%E5%8C%BA%E6%8E%A5%E9%80%81/"/>
    <id>https://blogs.kainy.cn/2025/05/新线开通 低至 99 畅享永安厦门双城往返市区接送/</id>
    <published>2025-05-26T22:20:17.000Z</published>
    <updated>2026-04-30T06:18:18.077Z</updated>
    
    <content type="html"><![CDATA[<p><strong>永安⇌厦门🚌</strong> 新线开通 低至 99 畅享双城往返市区接送</p><p><strong>永安出发99起，厦门出发100起</strong></p><p>是谁还在坐170+的高铁</p><p>真的是打工人学生党难以承受之重啊aa </p><p>来回的票价都能抵上部分人半个月生活费了</p><p><strong>NO NONO！！！</strong></p><a id="more"></a><p>就这个票价还是省省吧！</p><p>不如坐我们的跨城巴士</p><p>把省下来的钱买几斤活肉跟粿条</p><p>带上独属于家乡的“思念”</p><p>再重新自信踏上归途</p><p style="font-size:45px;font-weight: bold;">微信： 171<span style="color: red;">8888</span>6673</p><p>🔥🈶车到厦门</p><p>……………………………</p><ul><li>🐠上午9:00永安到厦门</li><li>🐠下午13:30永安到厦门</li><li>🐠傍晚17:30永安到厦门</li><li>——————————</li><li>🐬下午13:30厦门-永安</li><li>🐬傍晚17:30厦门-永安</li><li>🐬晚上20:30厦门-永安</li></ul><p>……………………………</p><p>线路信息、票价等具体以订票咨询为准</p><p>坐在返程的大巴🚌上</p><p>细数路过的每个村庄🏕</p><p>再慢慢感受家乡的变化</p><p>让自己永远跟上步伐👣</p><p>即便在外工作</p><p>也不忘记家乡🏠️最初的模样~</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;strong&gt;永安⇌厦门🚌&lt;/strong&gt; 新线开通 低至 99 畅享双城往返市区接送&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;永安出发99起，厦门出发100起&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;是谁还在坐170+的高铁&lt;/p&gt;
&lt;p&gt;真的是打工人学生党难以承受之重啊aa &lt;/p&gt;
&lt;p&gt;来回的票价都能抵上部分人半个月生活费了&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NO NONO！！！&lt;/strong&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="东写西读" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/"/>
    
      <category term="生活点滴" scheme="https://blogs.kainy.cn/categories/%E4%B8%9C%E5%86%99%E8%A5%BF%E8%AF%BB/%E7%94%9F%E6%B4%BB%E7%82%B9%E6%BB%B4/"/>
    
    
      <category term="交通" scheme="https://blogs.kainy.cn/tags/%E4%BA%A4%E9%80%9A/"/>
    
      <category term="永安" scheme="https://blogs.kainy.cn/tags/%E6%B0%B8%E5%AE%89/"/>
    
  </entry>
  
  <entry>
    <title>躺赚新姿势？我无心插柳的API，竟成他人日入数百的“印钞机”！</title>
    <link href="https://blogs.kainy.cn/2025/05/%E8%BA%BA%E8%B5%9A%E6%96%B0%E5%A7%BF%E5%8A%BF%EF%BC%9F%E6%88%91%E6%97%A0%E5%BF%83%E6%8F%92%E6%9F%B3%E7%9A%84API%EF%BC%8C%E7%AB%9F%E6%88%90%E4%BB%96%E4%BA%BA%E6%97%A5%E5%85%A5%E6%95%B0%E7%99%BE%E7%9A%84%E2%80%9C%E5%8D%B0%E9%92%9E%E6%9C%BA%E2%80%9D%EF%BC%81/"/>
    <id>https://blogs.kainy.cn/2025/05/躺赚新姿势？我无心插柳的API，竟成他人日入数百的“印钞机”！/</id>
    <published>2025-05-19T04:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.100Z</updated>
    
    <content type="html"><![CDATA[<p>给大家分享一个我最近遇到的真实案例，简直让我拍案叫绝，也深深感受到了“信息差”这玩意儿，在赚钱这件事上到底有多牛逼！</p><p>事情是这样的，前段时间我借助 <a href="https://blogs.kainy.cn/tags/%E7%BD%91%E5%85%B3/#blogs_xy">Open API</a>，搭建了一个携程酒店的优惠查询页面。初衷很简单：就是方便自己和朋友们五一出行时能快速找到特价酒店。令我惊喜的是，这个接口覆盖面还挺广，连我老家永安那样的小县城，都能搜到优惠酒店。</p><p><img src="https://oray.kainy.cn:38400/_upload/./content/temp/174766670662175445789abc72cfa1b33350a5489eee2.jpg" alt="OpenSZ特惠酒店查询"></p><p>因为这个API只是转发查询上游数据，本身几乎没什么服务器成本，所以我把查询价格定得非常低，几乎可以忽略不计。</p><p>然而，就在这两天，我却突然发现这个页面的API调用量激增，有点反常。好奇心驱使下，我开始追查原因。你猜怎么着？最后竟然在闲鱼上找到了答案！</p><a id="more"></a><p><strong>一个“平平无奇”的发现，背后竟是“商业鬼才”！</strong></p><p>有人，竟然利用我这个小小的优惠查询页面，在闲鱼上做起了大生意！他在闲鱼上发布了大量的各地优惠酒店信息，每一条信息的查询服务，直接标价10元！</p><p>你没看错，就是10块钱！而且，从他商品的咨询量和成交情况来看，想要获取这些优惠信息的人还真不少。</p><p><img src="https://oray.kainy.cn:38400/_upload/./content/temp/1747666121604xianyu.jpeg" style="width:40%"></p><p><strong>我们来算一笔账，感受一下什么叫“认知变现”：</strong></p><p>我的这个查询页面是这个月正式上线的。我们假设这位在闲鱼开店的朋友，是从我的页面上线后不久开始运营他的“优惠酒店信息”小铺的，就算他只运营了短短10天。</p><ul><li><strong>他的收入</strong>：每条信息卖10元。从闲鱼上看到的咨询量和潜在成交量来看，保守估计，一天成交几十单并非难事。这意味着，这个小店每天的进账，可能就高达数百元！短短10天，可能就已经轻松入账数千元。</li><li><strong>我的收入</strong>：我这边呢？每一次API调用，我可能只赚几分钱。</li></ul><p>看到这里，你是不是也和我一样，有点哭笑不得，又有点恍然大悟？</p><p><strong>同样的工具，不同的玩法，收入天差地别！</strong></p><p>这位闲鱼卖家，无疑是深谙“信息差赚钱”的个中好手。他巧妙地利用了我提供的低成本工具，将其包装成高价值的“优惠信息”，精准地对接了那些有需求但又不知道如何或者懒得去查找优惠信息的客户。</p><ul><li><strong>他赚的是信息不对称的钱</strong>：很多人不知道有这样的查询工具，或者即便知道，也可能因为操作不熟练、没有时间等原因，宁愿花点小钱直接获取结果。</li><li><strong>他赚的是服务整合的钱</strong>：他将分散的优惠信息整合起来，以商品的形式在闲鱼这个流量巨大的平台进行曝光和售卖。</li><li><strong>他赚的是认知领先的钱</strong>：他看到了这个工具背后潜在的商业价值，并迅速行动，将其转化为实实在在的收益。</li></ul><p>而我，虽然是工具的创建者，却只是停留在“提供工具，赚取微薄调用费”的层面。我们之间的收入差距，不是技术上的差距，而是赚钱认知上的鸿沟。不得不承认，有些人，天生就擅长发现并抓住赚钱的机会！</p><p>这个案例给我上了生动的一课：<strong>很多时候，我们缺的不是资源，不是技术，而是发现价值的眼睛和将信息转化为财富的商业头脑。</strong></p><p>你是否也曾有过类似的“我怎么没想到”的时刻？是否也曾因为一个小小的创意或工具，被别人玩出了花，赚得盆满钵满？</p><p>这个世界从不缺少机会，缺的是发现机会并付诸行动的人。</p><p><strong>看到这里，你是否也对这个“躺赚”模式背后的查询工具产生了浓厚的兴趣？</strong></p><p>想不想亲自体验一下，连犄角旮旯的小城优惠酒店都能轻松挖到的快感？想不想也尝试一下，利用信息差，找到属于自己的赚钱新思路？</p><p><strong>福利来了！</strong></p><p>对这个项目感兴趣，想要获取同款【<strong>携程酒店优惠查询工具</strong>】的朋友，请在评论区留言 <strong>“666”</strong>！</p><p>我会把工具链接发给你，助你打开新世界的大门！说不定，下一个在闲鱼日入数百的就是你！</p><p>期待你的评论，让我们一起探讨更多利用信息差赚钱的“骚操作”！</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;给大家分享一个我最近遇到的真实案例，简直让我拍案叫绝，也深深感受到了“信息差”这玩意儿，在赚钱这件事上到底有多牛逼！&lt;/p&gt;
&lt;p&gt;事情是这样的，前段时间我借助 &lt;a href=&quot;https://blogs.kainy.cn/tags/%E7%BD%91%E5%85%B3/#blogs_xy&quot;&gt;Open API&lt;/a&gt;，搭建了一个携程酒店的优惠查询页面。初衷很简单：就是方便自己和朋友们五一出行时能快速找到特价酒店。令我惊喜的是，这个接口覆盖面还挺广，连我老家永安那样的小县城，都能搜到优惠酒店。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oray.kainy.cn:38400/_upload/./content/temp/174766670662175445789abc72cfa1b33350a5489eee2.jpg&quot; alt=&quot;OpenSZ特惠酒店查询&quot;&gt;&lt;/p&gt;
&lt;p&gt;因为这个API只是转发查询上游数据，本身几乎没什么服务器成本，所以我把查询价格定得非常低，几乎可以忽略不计。&lt;/p&gt;
&lt;p&gt;然而，就在这两天，我却突然发现这个页面的API调用量激增，有点反常。好奇心驱使下，我开始追查原因。你猜怎么着？最后竟然在闲鱼上找到了答案！&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
      <category term="网关" scheme="https://blogs.kainy.cn/tags/%E7%BD%91%E5%85%B3/"/>
    
      <category term="项目" scheme="https://blogs.kainy.cn/tags/%E9%A1%B9%E7%9B%AE/"/>
    
      <category term="闲鱼" scheme="https://blogs.kainy.cn/tags/%E9%97%B2%E9%B1%BC/"/>
    
  </entry>
  
  <entry>
    <title>前端工程师模拟面试 (技术深度追问版)</title>
    <link href="https://blogs.kainy.cn/2025/05/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%B8%88%E9%9D%A2%E8%AF%95%20(%E6%8A%80%E6%9C%AF%E6%B7%B1%E5%BA%A6%E8%BF%BD%E9%97%AE%E7%89%88)/"/>
    <id>https://blogs.kainy.cn/2025/05/前端工程师面试 (技术深度追问版)/</id>
    <published>2025-05-15T18:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前端工程师"><a href="#前端工程师" class="headerlink" title="前端工程师"></a>前端工程师</h2><p>简历： <a href="https://kainy.cn/cv/#/" target="_blank" rel="noopener">https://kainy.cn/cv/#/</a></p><p><strong>面试官：</strong>  您好，郭涛先生，欢迎参加今天的面试。我是本次的面试官，您可以称呼我李*。请先做个简单的自我介绍吧。</p><p><strong>求职者 (郭涛)：</strong> 李经理您好，非常荣幸能有这次面试机会。我叫郭涛，是一名有近11年经验的前端工程师。 我对待工作认真负责，有较强的协作意识。 我的核心优势在于前端性能优化和前端工程化体系建设，主导过项目的工程化架构升级，并取得了显著的性能提升成果。 我熟练掌握Webpack、Vite等工具链，并具备脚手架开发与定制能力。</p><a id="more"></a><p><strong>面试官：</strong> 感谢您的介绍。我看您的简历上提到，您在平安集团工作了很长时间，能详细介绍一下您在平安集团主要负责的工作和取得的成就吗？特别是在性能优化和工程化方面。</p><p><strong>求职者 (郭涛)：</strong> 好的。在平安集团，我担任资深前端开发工程师，主要负责营销活动H5和后台管理系统的开发，并主导了多个银行保险、个贷、微海报小程序等项目的前端架构与技术选型。<br>在推动团队工程化与性能优化方面，我做出了一些成果：</p><ul><li>通过动态导入 (<code>import()</code>) 结合 Vue Router 实现路由级异步加载，使首屏加载速度提升了60%。</li><li>利用静态资源CDN分发、Nginx gzip压缩与缓存策略，降低了资源加载耗时。</li><li>使用Sharp实现图片自适应WebP格式并进行CDN分级加载，图片流量降低了65%。</li><li>将价格计算逻辑迁移至Web Worker，使得主线程长任务减少了90%。</li><li>设计了LocalStorage加Service Worker的多级缓存方案，二次访问加载速度提升了76%。</li><li>实施了图片懒加载 (<code>Intersection Observer</code>) 和WebP格式自动切换，减少了图片资源体积30%以上。</li><li>通过webpack SplitChunks、Tree Shaking及动态 <code>import</code> 等手段，将主包体积从2.5MB压缩到1MB以内。</li></ul><p>同时，我还参与建设了性能监控与自动告警体系，集成了Lighthouse、 Performance API、Sentry进行核心指标的实时采集，并自研了前端埋点SDK，平均定位问题时间缩短了50%。 在工程化体系升级方面，我主导了Webpack 3到Webpack 5的升级，优化了构建速度，CI构建时间缩短了40%，并且编写了自定义CLI工具，提升了团队协作效率。</p><p><strong>面试官：</strong> 非常 impressive 的成果。我们来深入聊聊其中的一些细节。您提到通过动态导入 (<code>import()</code>) 结合 Vue Router 实现路由级异步加载，首屏加载速度提升了60%。这个60%是如何精确度量的？动态导入本身会带来额外的请求和组件解析开销，您是如何平衡这个开销与首屏加载速度的提升的？对于异步加载的组件，加载状态和加载失败的情况是如何处理的，以保证用户体验？</p><p><strong>求职者 (郭涛)：</strong> 这个60%的提升是通过对比优化前后的Lighthouse报告中的FCP (First Contentful Paint) 和 LCP (Largest Contentful Paint) 指标，以及内部监控系统上报的实际用户数据综合评估得出的。<br>确实，动态导入会产生额外的chunk文件和请求。我们的策略是，只对非首屏立即需要的、且体积较大的路由组件进行异步加载。对于核心的首屏路由，依然保持同步加载，确保关键路径的快速呈现。<br>为了平衡开销，我们利用了Webpack的 <code>prefetch</code> 和 <code>preload</code> 指令。对于用户大概率会访问的路由，我们会进行 <code>prefetch</code>，在浏览器空闲时提前加载资源。<br>至于加载状态和失败处理，Vue Router自身提供了导航守卫和组件级的异步处理机制。我们在路由配置中为异步组件定义了 <code>loading</code> 组件和 <code>error</code> 组件。当组件正在加载时，会显示一个统一的加载动画 (loading component)；如果加载失败，则会显示错误提示组件 (error component)，并提供重试或者反馈的选项，同时我们也会将这类加载失败的错误上报到Sentry。</p><p><strong>面试官：</strong> 您提到集成了Lighthouse、Performance API和Sentry来进行核心指标的实时采集，并自研了前端埋点SDK。能否请您详细介绍一下这个监控体系的整体架构？特别是这几个工具和您的自研SDK是如何分工协作，最终实现数据采集、处理、展示和告警的？</p><p><strong>求职者 (郭涛)：</strong> 关于我们建设的这套性能监控与自动告警体系，它的整体架构可以概括为‘多源采集、统一处理、实时告警、闭环分析’。</p><p>具体来说：</p><ol><li><p><strong>数据采集层</strong>：</p><ul><li><strong>Performance API</strong>：这是我们获取用户端真实性能数据（RUM - Real User Monitoring）的核心来源之一。通过它，我们可以实时捕获像FCP (首次内容绘制)、LCP (最大内容绘制)、FID (首次输入延迟，我们也在关注其后续演进如INP)、CLS (累积布局偏移)以及详细的Navigation Timing等W3C定义的标准性能指标。这些原始数据由我们的自研SDK进行采集、初步计算和封装。</li><li><strong>自研前端埋点SDK</strong>：这个SDK是我们体系的枢纽和定制化核心。它负责：<ul><li><strong>标准化指标采集</strong>：封装对Performance API的调用，确保数据采集的一致性和准确性。</li><li><strong>自定义业务埋点</strong>：针对我们业务的特性，比如核心交易流程的耗时、关键用户操作的成功率、特定UI组件的渲染时间等，都可以通过SDK灵活配置埋点进行追踪。</li><li><strong>用户行为与上下文信息</strong>：为了更好地定位问题，SDK会采集一些简化版的用户行为序列（如点击流）、设备信息、网络环境、应用版本、用户信息（脱敏后）等上下文数据。</li><li><strong>资源加载监控</strong>：监听并上报JS、CSS、图片等静态资源的加载成功与否、加载耗时等信息。</li><li><strong>数据采样与聚合</strong>：为了平衡监控的全面性和客户端/服务端的性能开销，SDK内置了可配置的采样机制（比如只上报一定比例用户的性能数据）和本地聚合策略（比如短时间内相同的错误进行合并上报），以减少数据上报量。</li><li><strong>统一上报模块</strong>：将采集到的各类数据（性能指标、自定义事件、错误信息）统一格式化后，通过异步、批量的方式上报到我们的数据接收服务器，并且有重试机制保证送达率。</li></ul></li><li><strong>Lighthouse</strong>：我们主要将Lighthouse集成在CI/CD流水线中，对每次代码合并入主干前或每次预发布后进行自动化性能评估。它提供了一种基于实验室环境的综合性能评分和优化建议，帮助我们进行性能回归测试，发现潜在的最佳实践问题，并追踪版本迭代间的性能基线变化。其报告会存档并用于趋势分析。</li><li><strong>Sentry</strong>：Sentry主要负责应用层异常捕获和聚合。当JavaScript代码中出现未捕获的异常、Promise rejections、或者我们主动捕获的错误时，Sentry客户端会捕获详细的错误堆栈、Source Maps支持下的源码位置、设备环境、用户标识等信息，并实时上报到Sentry服务端。我们也利用Sentry的APM功能来监控特定后端API的响应时间和吞吐量，与前端数据关联分析。</li></ul></li><li><p><strong>数据接收与处理层</strong>：</p><ul><li>自研SDK采集的数据会上报到一个由Node.js构建的高可用数据接收API网关。该网关负责对数据进行初步校验、解析和分流。</li><li>性能指标数据（如LCP、FID等）会被存入专门的时间序列数据库（例如InfluxDB或Prometheus），便于进行高效的聚合查询和趋势分析。</li><li>自定义业务埋点数据、用户行为数据和部分错误概要信息则会存入大数据平台（如ClickHouse或Elasticsearch），支持更复杂的Ad-hoc查询和多维分析。</li><li>Sentry有其自身的后端服务来处理和存储错误数据。</li></ul></li><li><p><strong>数据展示与分析层</strong>：</p><ul><li>我们主要使用Grafana连接时间序列数据库和大数据平台，搭建了多个维度的监控仪表盘（Dashboard）。这些看板可以实时展示核心页面的关键性能指标（如P75/P90/P99分位的LCP、CLS），不同版本、不同网络环境下的性能对比，以及自定义业务指标的达成情况。</li><li>对于错误数据和详细的用户行为日志，我们会使用Kibana（如果用Elasticsearch）或类似的BI工具进行查询、分析和可视化，帮助我们深入排查问题根源，分析用户路径。</li><li>Sentry的Web UI则主要用于查看、分类、管理错误报告，并追踪错误的修复状态。</li></ul></li><li><p><strong>告警与反馈层</strong>：</p><ul><li>基于Grafana和Sentry（以及我们数据处理层的一些自定义逻辑），我们配置了多层次的告警规则。例如：<ul><li>当某个核心页面的LCP的P90值连续N分钟超过预设阈值。</li><li>某个API接口的错误率在短时间内突增。</li><li>Sentry中出现新的、影响范围广的高优先级错误。</li></ul></li><li>告警会通过Webhook、邮件、企业微信/钉钉等方式及时通知到对应的开发和运维团队。</li><li>我们还建立了一个机制，将Sentry中新出现的、影响范围大的错误自动在项目管理工具（如Jira）中创建缺陷跟踪单，并指派给对应模块的负责人，形成一个从‘监控发现 -&gt; 告警通知 -&gt; 问题分配 -&gt; 修复验证’的闭环管理。</li></ul></li></ol><p>通过这样的分工协作，Performance API和我们的自研SDK负责全面、真实的用户端数据采集；Sentry专注于运行时稳定性和错误深度分析；Lighthouse则提供标准化的工程审计基线。这些数据源经过统一处理后，在集中的平台上进行可视化展示和智能告警，从而使我们能够快速发现和定位问题，有效地支撑了‘平均定位问题时间缩短50%’这一成果。例如，以前一个线上性能问题可能需要开发、测试同学花费数小时甚至一天去尝试复现和分析，现在通过性能看板可以直接看到是哪个版本上线后、影响了哪些页面、具体是哪个性能指标发生了劣化，再结合自研SDK采集的维度信息（如操作系统、浏览器版本、网络类型）和Sentry的错误报告，可以非常迅速地缩小排查范围。”</p><p><strong>面试官问：</strong> 您刚才提到自研了前端埋点SDK，并且它在整个体系中扮演了枢纽的角色。能否详细谈谈在设计和实现这个SDK时，您重点考虑了哪些方面以确保其自身的<strong>性能开销足够小</strong>、<strong>数据上报的可靠性</strong>以及后续的<strong>可维护性和扩展性</strong>？在这些方面，有没有遇到过一些具体的挑战，以及您是如何解决的？</p><p><strong>求职者 (郭涛)：</strong> “在设计和实现自研前端埋点SDK时，我们确实将性能开销、上报可靠性、可维护性和扩展性作为核心的设计目标。</p><p><strong>1. 性能开销最小化方面：</strong></p><ul><li><strong>异步化一切</strong>：SDK内部的所有数据采集、处理和上报操作都严格遵循异步原则，使用例如 <code>Promise</code>、<code>setTimeout(..., 0)</code>、以及在浏览器空闲时执行任务的 <code>requestIdleCallback</code>，确保不阻塞主线程，不影响页面响应和用户体验。对于可能存在的CPU密集型计算（虽然我们极力避免），理论上可以考虑Web Worker，但在此SDK中尚未引入以保持轻量。</li><li><strong>轻量级数据采集</strong>：我们对采集逻辑进行了精细优化。例如，对于性能指标，我们直接利用Performance API，避免复杂计算；对于DOM事件的监听（如点击），我们会非常谨慎地选择事件类型和监听范围，并广泛使用事件委托来减少监听器数量，避免直接在大量元素上绑定。</li><li><strong>数据批处理与压缩</strong>：SDK不会每采集到一条数据就立即上报，而是在本地维护一个数据队列。当队列中的数据条数达到预设阈值（比如20条）或自上次上报以来经过一定时间（比如10秒），才将多条数据合并为单次请求批量上报。在数据量较大时，我们对上报的JSON字符串进行Gzip压缩（由浏览器自动处理或特定情况下SDK层面处理），以减少网络传输负载。</li><li><strong>智能采样</strong>：对于一些高频但个体差异不大的数据（如鼠标移动轨迹，我们一般不采集这类数据，但以其为例），或者在只需要统计趋势的场景下，我们会启用可配置的采样策略。例如，只上报10%用户的核心性能数据，或对于特定非关键业务事件进行采样，从而大幅降低数据量和SDK的执行频率。</li><li><strong>代码体积控制</strong>：我们非常关注SDK自身的体积，采用现代化的构建工具（如Rollup，因为它更适合构建库）进行精细打包，利用Tree Shaking剔除未使用的代码，并严格控制第三方依赖的引入，确保SDK文件小巧（目标是Gzip后在10KB以内），加载迅速。</li><li><strong>延迟初始化/按需加载</strong>：SDK的核心功能（如错误捕获、基础性能指标）会立即初始化，但一些非关键的、或者依赖特定用户行为才触发的模块（比如特定的业务追踪模块），会进行延迟加载或按需初始化，减少初次加载的负担。</li></ul><p><strong>2. 数据上报可靠性方面：</strong></p><ul><li><strong>信标（Beacon）API优先</strong>：对于页面卸载前需要确保发送的数据（如会话结束前的最后一些行为数据或错误），我们优先使用 <code>navigator.sendBeacon()</code> API。它能确保请求在页面卸载过程中异步发送，不阻塞页面关闭，并且通常能成功绕过一些省电模式对异步XHR的限制。</li><li><strong>Fetch Keepalive备选</strong>：作为 <code>sendBeacon</code> 的补充，或在需要传输更大数据量（<code>sendBeacon</code>有大小限制，通常64KB）或需要自定义头部时，我们使用 <code>Workspace</code> API并配合 <code>keepalive: true</code> 选项。</li><li><strong>请求队列与重试机制</strong>：所有待上报数据会进入一个内存队列。若上报请求因网络波动、服务器临时错误（如502, 503, 504）等原因失败，SDK会根据预设策略（如指数退避算法结合最大重试次数限制）进行自动重试，避免数据丢失。</li><li><strong>本地缓存降级（可选的高保障机制）</strong>：在一些对数据完整性要求极高的场景下，如果用户设备离线或所有重试均失败，我们会考虑将关键数据暂存到 <code>localStorage</code> 或 <code>IndexedDB</code> 中（有容量和API异步性考量），并在网络恢复或下次会话开始时尝试重新上报。但这会增加SDK复杂度，需要谨慎评估。</li><li><strong>SDK内部健壮性与错误隔离</strong>：SDK的所有对外接口和内部模块都包裹在 <code>try...catch</code> 结构中，确保SDK自身的任何潜在错误不会因异常未捕获而冒泡到宿主应用，导致应用崩溃。SDK内部的错误也会被自身捕获并可以配置是否上报，便于我们监控SDK的健康度和稳定性。</li></ul><p><strong>3. 可维护性与扩展性方面：</strong></p><ul><li><strong>模块化与分层设计</strong>：我们将SDK按照功能拆分为多个高内聚、低耦合的独立模块，如配置模块（Config）、核心采集器（Collector: Performance, Error, Event）、数据处理器（Processor）、上报器（Reporter）等。各模块职责单一，通过清晰的内部接口协作。</li><li><strong>插件化架构（Plugin System）</strong>：为了应对未来新增的监控需求或集成第三方服务，我们设计了一套轻量级的插件机制。新的数据采集逻辑或数据处理方式可以作为插件来开发和动态注册到SDK中，而无需频繁修改SDK核心代码，这大大增强了其灵活性和扩展能力。</li><li><strong>TypeScript类型约束</strong>：整个SDK项目采用TypeScript编写。强类型系统帮助我们在开发阶段就避免了许多潜在的类型错误，提升了代码质量、可读性和可重构性，也使得团队协作更加顺畅高效。</li><li><strong>配置驱动</strong>：SDK的大部分行为，如上报API端点、采样率、批处理阈值、启用哪些监控模块、插件配置等，都是通过初始化时传入的配置对象来灵活控制的，方便不同业务线或不同环境进行定制化部署。</li><li><strong>完善的文档与自动化测试</strong>：我们为SDK编写了详细的开发者接入指南、API参考文档以及内部架构说明。同时，核心模块都有高覆盖率的单元测试（使用Jest等框架），关键流程有集成测试，确保代码变更的可靠性和向后兼容性。</li><li><strong>独立的版本管理与发布流程</strong>：SDK作为独立的npm私有包进行语义化版本管理和发布，业务方可以清晰地了解各版本变更，并按需引入和升级。</li></ul><p><strong>遇到的挑战及解决方案举例：</strong></p><ul><li><strong>挑战1：如何在SPA（单页应用）中准确捕获页面性能（如LCP、CLS）和有效上报？</strong><ul><li><strong>解决方案</strong>：针对SPA的路由切换（通常不触发完整页面加载），我们监听 <code>popstate</code>、<code>hashchange</code> 事件以及通过AOP（面向切面编程）的方式覆写 <code>history.pushState/replaceState</code> 方法，来识别虚拟页面的切换。在切换时，我们会重置和重新计算相关性能指标（特别是需要关注路由切换后的LCP、CLS等）。同时，确保在路由切换（某种意义上的“虚拟页面卸载”）时，队列中的数据能通过 <code>sendBeacon</code> 或 <code>Workspace keepalive</code> 可靠发送。我们还特别关注了长任务（Long Tasks）对SPA中INP（Interaction to Next Paint）指标的影响。</li></ul></li><li><strong>挑战2：部分浏览器隐私设置或扩展（如AdBlockers）可能会阻止或干扰数据上报。</strong><ul><li><strong>解决方案</strong>：这是一个业界普遍存在的挑战。我们的主要策略是：<ul><li><strong>透明化与合规</strong>：确保数据采集行为符合用户隐私政策，并在文档中清晰说明。</li><li><strong>第一方端点</strong>：将数据上报到我们自己域名下的第一方接口（如 <code>sdk-data.yourdomain.com</code>），相比第三方域名，这被屏蔽的概率较低。</li><li><strong>容错与监测</strong>：SDK设计上要能容忍上报失败，不因此影响应用。同时，我们会监控上报成功率，如果发现特定环境下成功率异常低，会分析原因，但通常我们不采取激进的“反屏蔽”手段，而是接受这种可能性，并在数据分析时考虑这部分潜在的数据偏差或缺失。</li></ul></li></ul></li><li><strong>挑战3：SDK的初始化时机与业务代码执行的平衡，以及如何避免对页面首次渲染造成负面影响。</strong><ul><li><strong>解决方案</strong>：我们推荐SDK的初始化脚本通过 <code>async</code> 或 <code>defer</code> 属性在 <code>&lt;head&gt;</code> 中尽可能早地异步加载执行，以便尽早开始捕获性能指标和错误。但其核心逻辑的执行（尤其是可能涉及DOM操作的部分）会通过 <code>DOMContentLoaded</code> 事件或更晚的时机（如 <code>load</code> 事件后或通过 <code>requestIdleCallback</code>）来确保不阻塞页面主要内容的解析和首次渲染。同时提供手动初始化的选项，让业务方可以根据自身应用的特性更灵活地控制SDK的启动时机。</li></ul></li></ul><p>通过这些细致的设计考量和对挑战的积极应对，我们的自研SDK能够在保证低侵入性、高可靠性的前提下，为整个性能监控与告警体系提供丰富、准确且定制化的数据源。”</p><p><strong>面试官：</strong> 好的。您还提到将价格计算逻辑迁移至Web Worker，主线程长任务减少了90%。能具体描述一下这个价格计算逻辑的复杂性吗？为什么它会成为主线程的瓶颈？在迁移到Web Worker的过程中，数据序列化和通信的开销是如何处理的？有没有遇到什么场景，Web Worker的通信开销反而抵消了其并行计算的优势？</p><p><strong>求职者 (郭涛)：</strong> 这个价格计算逻辑涉及到多种营销规则、优惠券、活动折扣的实时组合运算，计算量较大且依赖多个动态参数。在某些复杂促销场景下，一次计算可能需要几十到上百毫秒，在高并发或用户频繁操作时，很容易造成主线程阻塞，表现为页面卡顿或操作无响应。<br>迁移到Web Worker时，我们主要传递的是JSON格式的计算参数和规则数据。对于复杂对象，序列化和反序列化确实会带来一些开销。我们通过精简传递的数据结构，只传递必要的字段，来减少这部分开销。同时，我们对计算任务进行了批处理和节流，避免过于频繁地创建和销毁Worker或进行通信。<br>确实，对于非常简单、快速的计算，Web Worker的初始化和通信成本可能会超过其带来的收益。因此，我们设定了一个计算复杂度的阈值。只有当预估计算量超过这个阈值时，才会启用Web Worker；对于简单的计算，则仍然在主线程执行，以避免不必要的开销。这个阈值是通过大量测试和线上数据分析动态调整的。</p><p><strong>面试官：</strong> 听起来考虑得很周全。关于LocalStorage和Service Worker的多级缓存方案，使得二次访问加载速度提升76%，能详细解释一下这个方案的设计吗？哪些数据存在LocalStorage，哪些存在Service Worker的Cache Storage？它们各自的优势和更新策略是怎样的？Service Worker在这里具体扮演了什么角色，与传统的浏览器HTTP缓存相比，它带来了哪些额外的价值，从而实现了如此显著的二次访问速度提升？</p><p><strong>求职者 (郭涛)：</strong> 这个多级缓存方案是这样设计的：</p><ul><li><strong>LocalStorage</strong> 主要存储一些小体积、不常变化但需要快速读取的用户偏好设置、简单的应用配置信息等。它的优势是API简单，同步读取（当然我们主要用作初始化判断）。更新策略通常是用户主动操作触发或版本更新时清理。</li><li><strong>Service Worker的Cache Storage</strong> 则负责缓存应用的静态资源外壳（App Shell，包括核心的HTML、CSS、JS），以及一些不常变动但体积较大的API数据。<ul><li><strong>静态资源缓存：</strong> 我们采用 “Cache First, then Network” 的策略。首次访问时，Service Worker会拦截请求，从网络获取资源并存入Cache Storage。后续访问时，直接从缓存读取，极大加快了页面渲染。对于静态资源更新，我们会在构建时生成新的资源版本号，Service Worker在 <code>install</code> 事件中获取新版本的资源列表，并在 <code>activate</code> 事件中清理旧缓存。</li><li><strong>API数据缓存：</strong> 对于某些列表型或详情型数据，如果实时性要求不是极致，我们会采用 “Stale-While-Revalidate” 策略。即优先从缓存返回数据给用户，保证快速响应，同时Service Worker会发起网络请求去获取最新的数据，并在获取后更新缓存，用户下次访问或刷新时就能看到最新数据。</li></ul></li><li><strong>Service Worker的角色和价值：</strong><ul><li><strong>离线访问：</strong> 最大的价值之一是能够实现离线访问或弱网环境下的可靠访问，这是传统HTTP缓存做不到的。</li><li><strong>精细化控制：</strong> 相比HTTP缓存只能通过header控制，Service Worker可以用JavaScript完全编程控制缓存策略，针对不同类型的资源、不同API采取最合适的缓存方案。</li><li><strong>背景同步与推送通知：</strong> 虽然在这个76%的提升中主要贡献来自缓存，但Service Worker还为我们后续实现背景数据同步和消息推送打下了基础。</li><li><strong>拦截和处理网络请求：</strong> 正是因为能够拦截网络请求，我们才能实现上述灵活的缓存策略，包括对API的缓存，这是传统缓存难以做到的。</li></ul></li></ul><p>这个76%的提升，主要是因为核心的App Shell和部分关键API数据能够从Service Worker缓存中瞬时加载，避免了网络请求的延迟，尤其是在移动端网络不稳定的情况下效果更为明显。</p><p><strong>面试官：</strong> 嗯，这套缓存机制听起来确实能带来很大提升。再聊聊工程化，您主导了Webpack 3到Webpack 5的升级，CI构建时间缩短了40%。除了多线程和按需编译，还有哪些具体的Webpack配置优化或插件调整起到了关键作用？迁移过程中遇到了哪些比较棘手的问题，是如何解决的？</p><p><strong>求职者 (郭涛)：</strong> 除了Webpack 5自带的持久化缓存 (<code>cache: { type: &#39;filesystem&#39; }</code>) 带来的巨大收益外，我们还做了以下关键优化：</p><ul><li><strong>精简 <code>loader</code> 和 <code>plugin</code> 配置：</strong> 审查并移除了不再需要或可以被Webpack 5内置功能替代的旧版loader和plugin。例如，<code>uglifyjs-webpack-plugin</code> 被内置的 <code>terser-webpack-plugin</code> 替代，并进行了更细致的压缩配置。</li><li><strong>优化 <code>resolve</code> 配置：</strong> 更精确地指定 <code>modules</code>, <code>extensions</code>, 和 <code>alias</code>，减少文件搜索路径和时间。</li><li><strong><code>externals</code> 的合理使用：</strong> 对于一些通过CDN引入的第三方库，如React、Vue全家桶等，将其配置在 <code>externals</code> 中，避免重复打包。</li><li><strong><code>SplitChunksPlugin</code> 的精细化配置：</strong> 根据业务模块和复用频率，更细致地拆分代码块，优化公共模块的提取，减少重复代码，并利用浏览器的并发请求能力。</li><li><strong><code>Tree Shaking</code> 的强化：</strong> 确保所有模块都采用ESM规范，并配合 <code>sideEffects</code> 标记，让Webpack更有效地进行死代码消除。我们还排查了一些因为副作用导致Tree Shaking失效的旧代码。</li></ul><p>迁移过程中比较棘手的问题主要有：</p><ul><li><strong>部分旧的loader和plugin不兼容Webpack 5：</strong> 这需要我们寻找替代品，或者在社区中找到非官方的兼容版本，甚至在某些情况下不得不自己动手修改一些简单的loader。</li><li><strong><code>node-sass</code> 和 <code>sass-loader</code> 的兼容性问题：</strong> 在升级过程中，经常会遇到Node版本、<code>node-sass</code> 版本和 <code>sass-loader</code> 版本之间的兼容性地狱。我们通过锁定特定版本组合，并最终考虑迁移到 <code>dart-sass</code> 来解决。</li><li><strong>部分依赖包的 <code>peerDependencies</code> 冲突：</strong> Webpack 5对 <code>peerDependencies</code> 的处理更加严格，导致一些旧项目中的依赖冲突显现出来。这需要我们仔细梳理依赖关系，并升级或替换相关包。</li><li><strong>理解和适配新的API和配置项：</strong> 例如 <code>output.publicPath</code> 的 <code>auto</code> 值，以及 <code>SplitChunksPlugin</code> 更复杂的配置选项，都需要花时间学习和调试。</li></ul><p>解决这些问题主要靠查阅官方文档、GitHub issue、社区文章，以及大量的本地调试和CI环境的反复试验。</p><p><strong>面试官：</strong> 在腾讯的工作经历中，您提到财付通商户系统的首屏加载时间从3.2s优化到1.1s，Lighthouse评分从58提升到92。这是一个非常显著的提升。能否具体拆解一下，是哪些方面的优化带来了这样的效果？例如，是关键渲染路径的优化，还是资源加载策略的调整，或者是服务端渲染的引入？</p><p><strong>求职者 (郭涛)：</strong> 当时财付通商户系统的优化是一个综合性的工作：</p><ul><li><strong>关键渲染路径优化：</strong><ul><li><strong>减少阻塞渲染的CSS和JS：</strong> 对CSS进行了拆分，将首屏关键CSS内联到HTML中，其余CSS异步加载。JavaScript也做了类似的拆分，关键逻辑内联，非核心逻辑 <code>defer</code> 或 <code>async</code> 加载。</li><li><strong>优化HTML结构：</strong> 减少DOM层级深度，避免不必要的嵌套。</li></ul></li><li><strong>资源加载策略调整：</strong><ul><li><strong>图片优化：</strong> 全面推行图片懒加载，对图片进行压缩，并根据UA提供WebP等更优格式。</li><li><strong>代码拆分 (Code Splitting)：</strong> 针对不同的业务模块和页面进行了代码拆分，按需加载。</li><li><strong>CDN加速和预加载：</strong> 核心静态资源全部上CDN，并对关键资源使用 <code>preload</code>。</li><li><strong>HTTP/2的利用：</strong> 推动服务器升级支持HTTP/2，利用其多路复用特性。</li></ul></li><li><strong>运行时优化：</strong><ul><li><strong>减少重绘和回流：</strong> 通过优化JavaScript操作DOM的方式，比如批量更新DOM，使用 <code>requestAnimationFrame</code> 等。</li><li><strong>优化动画效果：</strong> 尽量使用CSS Transform和Opacity来实现动画，利用GPU加速。</li></ul></li><li><strong>服务端性能提升：</strong> 虽然我主要负责前端，但也和后端同事协作，推动了部分API接口的响应速度优化，减少了TTFB (Time to First Byte)。</li><li><strong>当时没有引入SSR（服务端渲染），</strong> 主要还是通过客户端渲染的极致优化来达成的。Lighthouse评分的提升主要体现在FCP、LCP、TTI以及CLS（累积布局偏移）的改善上。特别是CLS，通过对图片和动态内容预留空间，避免了页面加载过程中的布局抖动。</li></ul><p><strong>面试官：</strong> 关于您的项目经历，“基于深度学习的UI自动化检测”，您提到使用Flutter实现双端自动截屏App。为什么选择Flutter来做这个工具App，而不是原生开发或其他跨端方案？你们使用了哪种具体的目标检测框架（比如YOLO、SSD、Faster R-CNN等）？如何保证训练数据集的多样性和标注质量，以确保模型的泛化能力和准确率？</p><p><strong>求职者 (郭涛)：</strong></p><ul><li><strong>选择Flutter的原因：</strong><ul><li><strong>跨端一致性高：</strong> 我们需要在iOS和Android两端进行截图，Flutter能够提供近乎一致的UI表现和开发体验，减少了双端分别开发的成本。</li><li><strong>开发效率高：</strong> Flutter的Hot Reload功能以及丰富的组件库使得开发速度较快。</li><li><strong>性能接近原生：</strong> 对于这种工具型App，Flutter的性能表现足够满足我们的需求。</li><li><strong>团队已有一定经验：</strong> 当时团队里有成员对Flutter有一定了解，可以快速上手。</li></ul></li><li><strong>目标检测框架：</strong> 我们初期尝试了YOLOv5，因为它在速度和精度之间有较好的平衡，且有较好的社区支持和预训练模型。后续也根据实际效果对比过其他框架，但最终还是以YOLO系列为基础进行调优。</li><li><strong>数据集和标注质量：</strong><ul><li><strong>多样性：</strong> 我们从生产环境的各个业务线、不同类型的页面（列表页、详情页、表单页等）、不同设备分辨率下采集了大量的截图样本。同时，也通过数据增强技术，如旋转、缩放、色彩抖动等，来扩充数据集的多样性。</li><li><strong>标注质量：</strong> 我们制定了详细的标注规范，对UI元素（如按钮、图片、文本、图标等）的类别和边界框进行精确标注。初期由开发和测试同学共同参与标注，并进行交叉校验。后期也引入了一些半自动标注工具来提高效率，但关键样本仍需人工复核，以保证标注的准确性。我们还定期对模型在未见过的新样本上的表现进行评估，如果发现对某些类型的UI问题识别不佳，会针对性地补充相关样本并重新训练。</li></ul></li></ul><p><strong>面试官：</strong> 您在技能介绍中提到了“前端性能优化四阶模型”：从网络资源、渲染、运行时分层实施优化。能具体展开一下每一层主要关注哪些优化点，以及它们之间是如何关联和影响的吗？</p><p><strong>求职者 (郭涛)：</strong></p><ul><li><strong>第一阶：网络与资源层优化。</strong> 这是最基础也是效果最直接的一层。<ul><li><strong>关注点：</strong> 减少HTTP请求数（合并文件、雪碧图、inline），减小资源体积（代码压缩混淆、图片压缩、Gzip/Brotli压缩、Tree Shaking），利用CDN加速，合理设置HTTP缓存策略（强缓存、协商缓存），启用HTTP/2或HTTP/3，DNS预解析，资源预加载 (<code>preload</code>)、预获取 (<code>prefetch</code>)。</li><li><strong>影响：</strong> 直接影响资源的下载速度，从而影响FCP、LCP等指标。</li></ul></li><li><strong>第二阶：渲染路径优化。</strong> 关注浏览器如何解析和渲染页面。<ul><li><strong>关注点：</strong> 优化关键渲染路径（Critical Rendering Path），减少阻塞渲染的CSS和JS，将CSS放在头部，JS放在底部或异步加载 (<code>async</code>/<code>defer</code>)，避免CSS <code>@import</code>，优化DOM结构（减少层级和节点数），避免强制同步布局，合理使用CSS选择器。</li><li><strong>影响：</strong> 影响浏览器绘制页面的速度，关系到FCP和TTI (Time to Interactive)。</li></ul></li><li><strong>第三阶：运行时性能优化。</strong> 关注页面加载完成后，用户交互过程中的性能。<ul><li><strong>关注点：</strong> 高效的JavaScript执行（避免长任务、优化算法和数据结构），减少重绘 (repaint) 和回流 (reflow)，合理使用节流 (throttle) 和防抖 (debounce)，优化动画（使用CSS Transform/Opacity、<code>requestAnimationFrame</code>），Web Worker的应用，虚拟DOM的优化 (如React/Vue中的 <code>shouldComponentUpdate</code> 或 <code>memo</code>)。</li><li><strong>影响：</strong> 关系到页面的流畅度、响应速度、FID (First Input Delay) 和 TBT (Total Blocking Time)。</li></ul></li><li><strong>第四阶：监控与分析。</strong> 这一层不是直接的优化手段，但为前三层提供数据支持和方向。<ul><li><strong>关注点：</strong> 建立性能监控体系 (Performance API, Lighthouse, Sentry, 自研埋点)，持续追踪核心性能指标 (FCP, LCP, FID, CLS, TTI)，分析性能瓶颈，A/B测试不同的优化方案。</li><li><strong>影响：</strong> 使得优化工作可度量、可持续，并能快速发现和定位性能退化问题。</li></ul></li></ul><p><strong>它们之间的关联：</strong> 这四层是相互关联、层层递进的。例如，网络资源加载慢（第一层问题），会导致渲染路径阻塞（第二层问题），进而可能影响到运行时的交互体验（第三层问题）。通过监控（第四层）发现问题后，可能需要从第一层开始系统排查。一个好的性能优化策略需要综合考虑这几个层面。</p><p><strong>面试官：</strong> 听起来您在方法论沉淀方面也很有思考。那么，请描述一个您在工作中遇到的最大的技术挑战，以及您是如何解决的？这个挑战是否让您对之前的某些技术认知产生了改变？</p><p><strong>求职者 (郭涛)：</strong> 在平安集团负责营销工程化基建搭建时，面临的一个比较大的挑战是如何在保证快速迭代的同时，系统性地提升大量存量项目的性能。这些项目技术栈不一（有jQuery老项目，也有Vue、React项目），历史包袱较重，且业务方对上线速度要求很高。</p><p>我的解决方案是：</p><ol><li><strong>建立统一的性能度量标准和监控平台：</strong> 首先，我们引入了Lighthouse和Sentry，并结合自研的埋点SDK，对所有核心项目建立了统一的性能基线和监控告警。这样做的目的是让问题“可见”且“可量化”。</li><li><strong>识别共性瓶颈，提供通用解决方案：</strong> 通过数据分析，我们发现图片加载、首屏渲染速度、打包体积是普遍存在的共性问题。针对这些问题，我们开发或引入了：<ul><li>图片自适应和WebP自动转换服务（基于Sharp和CDN）。</li><li>路由懒加载、多级缓存（LocalStorage + Service Worker）的最佳实践和脚手架集成。</li><li>统一的构建配置优化策略（Webpack升级、SplitChunks优化）。</li></ul></li><li><strong>渐进式改造与赋能：</strong> 对于存量项目，一次性重构风险大、成本高。我们采取了渐进式改造的策略，先从收益最高的模块入手。同时，我们编写了详细的优化指南和最佳实践文档，并组织了多次技术分享和培训，赋能各个业务线的开发同学，让他们能够主动参与到性能优化中来。</li><li><strong>工程化手段保障：</strong> 在CI/CD流程中集成了性能预算检查，如果构建产物或Lighthouse评分低于设定阈值，会产生告警或阻止合并，从流程上保障性能不会无意识地劣化。</li></ol><p>这个挑战让我深刻认识到，<strong>纯粹的技术方案在复杂的组织环境中往往是不够的。</strong> 以前我可能更侧重于寻找“最优”的技术解，但这次经历让我明白，推动一项技术改进，还需要考虑团队接受度、改造成本、业务压力以及流程保障。<strong>技术方案的“好”不仅仅是技术上的先进性，更在于它是否能结合实际情况被有效地推广和执行，并最终产生价值。</strong> 也就是说，软技能和推动能力在解决复杂技术问题时同样重要。</p><p><strong>面试官：</strong> 很有条理的解决方案，并且反思也很到位。如果您的一个项目在上线前发现了一个严重的性能问题，比如LCP指标远超预期，但项目经理基于业务压力坚持要按时上线，您会怎么处理？</p><p><strong>求职者 (郭涛)：</strong></p><ol><li><strong>立即量化风险：</strong> 我会首先快速评估这个LCP超标的具体程度，以及它对核心用户体验的实际影响。比如，是所有用户都会遇到，还是特定网络或设备下的问题？是否会导致用户直接流失或无法完成核心操作？我会收集相关数据，例如可能影响的用户比例、潜在的业务损失（如果可以估算的话）。</li><li><strong>紧急排查与快速预案：</strong> 同时，我会争分夺秒地尝试定位问题根源，并判断是否存在可以在短时间内（例如几小时内）应用的“快速修复”或“缓解措施”。比如，是否是某张巨大的图片未经压缩就上线了，或者某个关键JS阻塞了渲染，能否临时进行调整或降级处理。</li><li><strong>数据驱动的沟通：</strong> 我会带着具体的性能数据、风险评估以及可能的临时解决方案，立即与项目经理进行沟通。我会清晰地阐述：<ul><li>问题的严重性：LCP超标多少，对用户体验的具体影响（例如，用户可能需要多等待X秒才能看到主要内容）。</li><li>潜在的后果：用户流失风险、口碑下降、甚至可能影响SEO等。</li><li>我的建议：如果存在快速修复方案，我会提议立即实施；如果问题复杂需要更多时间，我会建议是否可以考虑分阶段上线（例如先上核心功能，性能问题模块延后），或者是否有可以接受的临时降级方案。</li></ul></li><li><strong>寻求折衷，明确后续：</strong> 我的目标不是简单地阻止上线，而是找到风险和业务需求之间的平衡点。如果项目经理仍然坚持上线，我会努力争取：<ul><li><strong>明确问题等级和修复优先级：</strong> 要求将此问题列为最高优先级，并在上线后立即投入资源修复。</li><li><strong>制定监控和回滚预案：</strong> 确保上线后有严密的性能监控，一旦出现更严重的情况，有快速的回滚机制。</li><li><strong>书面记录风险：</strong> 在某些极端情况下，如果我认为风险过高且无法说服项目经理，我会考虑通过邮件等形式将风险和我的建议进行书面记录，并抄送给相关负责人，确保信息透明。</li></ul></li><li><strong>事后复盘：</strong> 无论最终是否按时上线，事后我都会推动对此问题进行复盘，分析为什么会在上线前才发现如此严重的性能问题，是测试流程的疏漏，还是监控预警的不足，以便改进未来的流程。</li></ol><p>我的核心原则是：基于数据说话，坦诚沟通风险，积极寻找解决方案，并努力在保证产品质量和满足业务需求之间取得平衡。</p><p><strong>面试官：</strong> 好的，明白了。您对我们公司和这个职位有什么想了解的吗？</p><p><strong>求职者 (郭涛)：</strong> 非常感谢您详细的介绍和深入的技术探讨。我想了解一下，如果我有幸加入团队，未来主要会参与哪些类型的项目？目前团队在前端技术栈上，除了主流框架外，是否有在探索或应用一些新的技术方向，比如微前端、Serverless、或者AI在前端的应用等？另外，公司对于工程师的职业发展和学习成长有哪些具体的支持机制，比如技术分享、培训、或者参与开源项目的机会？</p><p><strong>面试官：</strong> (针对问题进行解答) … … 好的，我们今天的面试差不多就到这里了。您今天展现的技术深度和思考能力给我们留下了深刻印象。我们会尽快评估并通知您结果。</p><p><strong>求职者 (郭涛)：</strong> 非常感谢您给我这次机会，今天的交流让我对贵团队有了更深入的了解，也学到了很多。期待能有机会加入贵公司。再见。</p><p><strong>面试官：</strong> 再见。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;前端工程师&quot;&gt;&lt;a href=&quot;#前端工程师&quot; class=&quot;headerlink&quot; title=&quot;前端工程师&quot;&gt;&lt;/a&gt;前端工程师&lt;/h2&gt;&lt;p&gt;简历： &lt;a href=&quot;https://kainy.cn/cv/#/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kainy.cn/cv/#/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt;  您好，郭涛先生，欢迎参加今天的面试。我是本次的面试官，您可以称呼我李*。请先做个简单的自我介绍吧。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;求职者 (郭涛)：&lt;/strong&gt; 李经理您好，非常荣幸能有这次面试机会。我叫郭涛，是一名有近11年经验的前端工程师。 我对待工作认真负责，有较强的协作意识。 我的核心优势在于前端性能优化和前端工程化体系建设，主导过项目的工程化架构升级，并取得了显著的性能提升成果。 我熟练掌握Webpack、Vite等工具链，并具备脚手架开发与定制能力。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="技术" scheme="https://blogs.kainy.cn/tags/%E6%8A%80%E6%9C%AF/"/>
    
      <category term="网关" scheme="https://blogs.kainy.cn/tags/%E7%BD%91%E5%85%B3/"/>
    
      <category term="项目" scheme="https://blogs.kainy.cn/tags/%E9%A1%B9%E7%9B%AE/"/>
    
  </entry>
  
  <entry>
    <title>构建难以破解的软件授权系统：API计费网关的安全分发实践</title>
    <link href="https://blogs.kainy.cn/2025/05/%E6%9E%84%E5%BB%BA%E9%9A%BE%E4%BB%A5%E7%A0%B4%E8%A7%A3%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%8E%88%E6%9D%83%E7%B3%BB%E7%BB%9F%EF%BC%9AAPI%E8%AE%A1%E8%B4%B9%E7%BD%91%E5%85%B3%E7%9A%84%E5%AE%89%E5%85%A8%E5%88%86%E5%8F%91%E5%AE%9E%E8%B7%B5/"/>
    <id>https://blogs.kainy.cn/2025/05/构建难以破解的软件授权系统：API计费网关的安全分发实践/</id>
    <published>2025-05-14T18:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.079Z</updated>
    
    <content type="html"><![CDATA[<h2 id="当开源遇上商业化"><a href="#当开源遇上商业化" class="headerlink" title="当开源遇上商业化"></a>当开源遇上商业化</h2><p>相信不少开发者都遇到过这样的问题：开发的系统，有人愿意付费使用，但你担心源码一旦交付就无法控制其传播？或者你希望限制软件只能在特定环境中运行，防止被用于未经授权的场景？</p><p>最近，我们的<a href="https://blogs.kainy.cn/2025/05/OpenAPI%E8%AE%A1%E8%B4%B9%E7%BD%91%E5%85%B3%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B%EF%BC%88%E4%BA%A7%E5%93%81%E8%AE%BE%E8%AE%A1%E5%92%8C%E4%BB%B7%E5%80%BC%E4%B8%BB%E5%BC%A0%EF%BC%89/#blogs3">API计费网关系统</a>在技术社区分享后，收到了不少商业化的需求。这让我们思考：如何在提供软件使用权的同时，保护知识产权并控制软件的使用范围？</p><p><img src="https://oray.kainy.cn:38400/_upload/./content/temp/1747277750244image.png" style="width: 30%"></p><p>经过深思熟虑和技术攻关，我们设计了一套基于非对称加密的域名授权系统。这套系统不仅解决了上述问题，还为软件授权提供了一种全新的思路。今天，我想与大家分享这个方案的技术细节和实现过程。</p><p><img src="https://oray.kainy.cn:38400/_upload/./content/temp/1747278105432image.png" alt="image"></p><a id="more"></a><h2 id="设计目标：安全与可控的平衡"><a href="#设计目标：安全与可控的平衡" class="headerlink" title="设计目标：安全与可控的平衡"></a>设计目标：安全与可控的平衡</h2><p>在设计这套授权系统时，我们设定了以下目标：</p><ul><li><strong>防止未授权使用</strong>：确保软件只能在授权的环境中运行</li><li><strong>限制部署范围</strong>：将软件使用限定在特定的域名或服务器上</li><li><strong>远程控制能力</strong>：保留随时撤销授权的能力</li><li><strong>安全可靠</strong>：采用强加密算法，防止授权被破解</li><li><strong>低干扰性</strong>：授权机制不应影响软件的正常功能</li></ul><h2 id="技术方案：非对称加密的优雅方案"><a href="#技术方案：非对称加密的优雅方案" class="headerlink" title="技术方案：非对称加密的优雅方案"></a>技术方案：非对称加密的优雅方案</h2><h3 id="核心架构"><a href="#核心架构" class="headerlink" title="核心架构"></a>核心架构</h3><p>我们的授权系统基于RSA非对称加密，采用主站-授权站的架构模式：</p><figure class="highlight brainfuck"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">主站(持有私钥)</span> &lt;--<span class="literal">-</span><span class="literal">-</span><span class="comment">授权数据推送</span>--<span class="literal">-</span><span class="literal">-</span>&gt; <span class="comment">授权站(持有公钥)</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">`</span></span><br></pre></td></tr></table></figure><p>这种架构的优势在于：</p><ul><li>主站持有私钥，可以签名授权数据</li><li>授权站只持有公钥，可以验证签名但无法伪造</li><li>通过信任链，杜绝“假私钥”签名+替换公钥文件绕过授权校验</li><li>授权数据包含时效信息，确保授权的时效性</li></ul><h3 id="授权数据结构"><a href="#授权数据结构" class="headerlink" title="授权数据结构"></a>授权数据结构</h3><p>授权数据包含以下关键信息：</p><figure class="highlight javascript"><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">&#123;</span><br><span class="line">  <span class="string">"domain"</span>: <span class="string">"example.com"</span>,       <span class="comment">// 授权域名</span></span><br><span class="line">  <span class="string">"issuedAt"</span>: <span class="number">1715654321000</span>,     <span class="comment">// 签发时间戳</span></span><br><span class="line">  <span class="string">"expiresAt"</span>: <span class="number">1715740721000</span>,    <span class="comment">// 过期时间戳</span></span><br><span class="line">  <span class="string">"appId"</span>: <span class="string">"api.example.com"</span>,    <span class="comment">// 应用标识</span></span><br><span class="line">  <span class="string">"nonce"</span>: <span class="string">"random-string-here"</span>, <span class="comment">// 随机字符串，防重放</span></span><br><span class="line">  <span class="string">"signature"</span>: <span class="string">"base64-signature-data"</span> <span class="comment">// 使用私钥生成的签名</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="string">`</span></span><br></pre></td></tr></table></figure><p>每个授权站点拥有独立的RSA密钥对，确保即使一个站点的授权被破解，也不会影响其他站点的安全。</p><h3 id="授权验证流程"><a href="#授权验证流程" class="headerlink" title="授权验证流程"></a>授权验证流程</h3><ul><li><strong>启动验证</strong>：授权站点在启动时检查授权数据</li><li><strong>请求验证</strong>：每个API请求都会经过授权验证中间件</li><li><strong>定期更新</strong>：主站定期向授权站点推送新的授权数据</li><li><strong>密钥轮换</strong>：支持密钥轮换机制，增强长期安全性</li></ul><h3 id="信任链机制"><a href="#信任链机制" class="headerlink" title="信任链机制"></a>信任链机制</h3><p>为了支持密钥更新和轮换，我们设计了信任链（Trust Chain）机制：</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"keys"</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="string">"id"</span>: <span class="string">"0"</span>,</span><br><span class="line">      <span class="string">"publicKey"</span>: <span class="string">"-----BEGIN PUBLIC KEY-----\n..."</span>,</span><br><span class="line">      <span class="string">"fingerprint"</span>: <span class="string">"sha256-fingerprint"</span>,</span><br><span class="line">      <span class="string">"issuedAt"</span>: <span class="string">"2025-05-10T08:00:00Z"</span>,</span><br><span class="line">      <span class="string">"isBootstrap"</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="string">"description"</span>: <span class="string">"初始引导公钥"</span></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="string">"currentKeyId"</span>: <span class="string">"0"</span> <span class="comment">// 当前使用的密钥ID</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>信任链记录了所有历史密钥，并标记当前使用的密钥，使系统能够平滑地进行密钥轮换。</p><h2 id="技术挑战与解决方案"><a href="#技术挑战与解决方案" class="headerlink" title="技术挑战与解决方案"></a>技术挑战与解决方案</h2><h3 id="挑战一：公钥同步问题"><a href="#挑战一：公钥同步问题" class="headerlink" title="挑战一：公钥同步问题"></a>挑战一：公钥同步问题</h3><p><strong>问题</strong>：当主站发起密钥轮替，重置密钥对时，信任链中的公钥与重置后的公钥不匹配时，验证会失败。</p><p><strong>解决方案</strong>：我们实现了自动同步机制，识别到主站推送了新的信任链则更新本地。确保信任链与公钥文件保持一致：</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">syncTrustChainWithPublicKey</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 读取公钥文件</span></span><br><span class="line">  <span class="keyword">const</span> publicKeyFromFile = fs.readFileSync(PUBLIC_KEY_FILE, <span class="string">'utf8'</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 读取信任链</span></span><br><span class="line">  <span class="keyword">const</span> trustChain = <span class="built_in">JSON</span>.parse(fs.readFileSync(TRUST_CHAIN_FILE, <span class="string">'utf8'</span>));</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 检查是否一致，不一致则更新</span></span><br><span class="line">  <span class="comment">// 注意：这里的 currentKey 需要根据实际逻辑获取，例如 trustChain.keys.find(key =&gt; key.id === trustChain.currentKeyId)</span></span><br><span class="line">  <span class="keyword">const</span> currentKey = trustChain.keys.find(<span class="function"><span class="params">key</span> =&gt;</span> key.id === trustChain.currentKeyId);</span><br><span class="line">  <span class="keyword">if</span> (currentKey &amp;&amp; currentKey.publicKey !== publicKeyFromFile) &#123;</span><br><span class="line">    <span class="comment">// 备份现有信任链</span></span><br><span class="line">    createBackupFile(TRUST_CHAIN_FILE, <span class="string">'.backup'</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 更新信任链</span></span><br><span class="line">    <span class="comment">// ... (具体的更新逻辑，例如更新 currentKey.publicKey 或添加新的 key 并更新 currentKeyId)</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="挑战二：备份文件管理"><a href="#挑战二：备份文件管理" class="headerlink" title="挑战二：备份文件管理"></a>挑战二：备份文件管理</h3><p><strong>问题</strong>：系统生成的备份文件会无限增长，占用磁盘空间。</p><p><strong>解决方案</strong>：我们实现了备份文件管理机制，只保留最新的三份备份：</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">manageBackupFiles</span>(<span class="params">filePattern, directory</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 获取所有匹配的文件</span></span><br><span class="line">  <span class="keyword">const</span> files = fs.readdirSync(directory)</span><br><span class="line">    .filter(<span class="function"><span class="params">file</span> =&gt;</span> <span class="keyword">new</span> <span class="built_in">RegExp</span>(filePattern).test(file))</span><br><span class="line">    .map(<span class="function"><span class="params">file</span> =&gt;</span> (&#123;</span><br><span class="line">      name: file,</span><br><span class="line">      path: path.join(directory, file),</span><br><span class="line">      time: fs.statSync(path.join(directory, file)).mtime.getTime()</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">  files.sort(<span class="function">(<span class="params">a, b</span>) =&gt;</span> b.time - a.time);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 如果文件数量超过3个，删除旧的文件</span></span><br><span class="line">  <span class="keyword">if</span> (files.length &gt; <span class="number">3</span>) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">3</span>; i &lt; files.length; i++) &#123;</span><br><span class="line">      fs.unlinkSync(files[i].path);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="挑战三：授权推送的可靠性"><a href="#挑战三：授权推送的可靠性" class="headerlink" title="挑战三：授权推送的可靠性"></a>挑战三：授权推送的可靠性</h3><p><strong>问题</strong>：网络不稳定可能导致授权推送失败。</p><p><strong>解决方案</strong>：我们实现了重试机制，确保授权数据能够可靠地推送到授权站点：</p><figure class="highlight javascript"><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">// 假设 retryCount 初始为 0</span></span><br><span class="line"><span class="keyword">if</span> (retryCount &lt; <span class="number">3</span>) &#123;</span><br><span class="line">  <span class="comment">// 安排重试，每次间隔时间翻倍</span></span><br><span class="line">  <span class="keyword">const</span> retryDelay = <span class="built_in">Math</span>.pow(<span class="number">2</span>, retryCount) * <span class="number">30000</span>; <span class="comment">// 30秒、1分钟、2分钟 (原文笔误，应为1分钟、2分钟)</span></span><br><span class="line">  setTimeout(<span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">    <span class="comment">// 重试逻辑</span></span><br><span class="line">    <span class="comment">// ... call pushAuthDataFunction(..., retryCount + 1)</span></span><br><span class="line">  &#125;, retryDelay);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><em>注意：`Math.pow(2, retryCount) </em> 30000<code>当</code>retryCount` 为0, 1, 2 时，分别是 30秒, 1分钟, 2分钟。*</p><h2 id="实现细节：安全与效率的平衡"><a href="#实现细节：安全与效率的平衡" class="headerlink" title="实现细节：安全与效率的平衡"></a>实现细节：安全与效率的平衡</h2><h3 id="白名单字段签名"><a href="#白名单字段签名" class="headerlink" title="白名单字段签名"></a>白名单字段签名</h3><p>为了确保授权验证的稳定性，我们采用了白名单方式来选择需要签名的字段：</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 只对这些字段进行签名</span></span><br><span class="line"><span class="keyword">const</span> fieldsToSign = [</span><br><span class="line">  <span class="string">'domain'</span>, <span class="string">'issuedAt'</span>, <span class="string">'expiresAt'</span>, <span class="string">'appId'</span>, <span class="string">'nonce'</span></span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 构建签名字符串</span></span><br><span class="line"><span class="comment">// const signatureData = fieldsToSign</span></span><br><span class="line"><span class="comment">//  .map(field =&gt; `$&#123;field&#125;=$&#123;authData[field]&#125;`)</span></span><br><span class="line"><span class="comment">//  .join('&amp;');</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 更安全的实现方式，确保字段顺序一致性，并处理值中可能存在的特殊字符</span></span><br><span class="line"><span class="keyword">const</span> signaturePayload = fieldsToSign.sort().reduce(<span class="function">(<span class="params">acc, field</span>) =&gt;</span> &#123;</span><br><span class="line">  acc[field] = authData[field];</span><br><span class="line">  <span class="keyword">return</span> acc;</span><br><span class="line">&#125;, &#123;&#125;);</span><br><span class="line"><span class="keyword">const</span> signatureString = <span class="built_in">JSON</span>.stringify(signaturePayload); <span class="comment">// 或其他规范化的序列化方式</span></span><br></pre></td></tr></table></figure><p><em>注：原始的 <code>join(&#39;&amp;&#39;)</code> 方式如果字段值的顺序不固定或者值中包含 <code>&amp;</code> 或 <code>=</code>，可能会产生问题。使用排序后的JSON字符串或类似规范化格式通常更稳健。</em></p><p>这种方式确保即使授权数据结构发生变化，只要核心字段保持不变，验证就不会受到影响。</p><h3 id="缓存机制"><a href="#缓存机制" class="headerlink" title="缓存机制"></a>缓存机制</h3><p>为了提高性能，我们实现了授权验证缓存：</p><figure class="highlight javascript"><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="keyword">let</span> authCache = &#123;</span><br><span class="line">  data: <span class="literal">null</span>,</span><br><span class="line">  isValid: <span class="literal">false</span>,</span><br><span class="line">  lastChecked: <span class="number">0</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 缓存有效期（5分钟）</span></span><br><span class="line"><span class="keyword">const</span> CACHE_TTL = <span class="number">5</span> * <span class="number">60</span> * <span class="number">1000</span>;</span><br></pre></td></tr></table></figure><p>这样，系统不需要在每个请求中都进行密集的加密运算，大大提高了性能。</p><h3 id="主站身份识别"><a href="#主站身份识别" class="headerlink" title="主站身份识别"></a>主站身份识别</h3><p>为了区分主站和授权站，我们实现了基于哈希验证的身份识别机制：</p><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span> <span class="title">isMainServer</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> mainServerKey = process.env.IS_MAIN_SERVER;</span><br><span class="line">  <span class="keyword">if</span> (!mainServerKey) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 计算环境变量的哈希值</span></span><br><span class="line">  <span class="keyword">const</span> hash = crypto.createHash(<span class="string">'sha256'</span>)</span><br><span class="line">    .update(Buffer.from(mainServerKey).toString(<span class="string">'base64'</span>)) <span class="comment">// 确保一致的编码处理</span></span><br><span class="line">    .digest(<span class="string">'hex'</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 与预设的哈希值比较</span></span><br><span class="line">  <span class="keyword">return</span> hash === MAIN_SERVER_HASH; <span class="comment">// MAIN_SERVER_HASH 需要预先计算并存储</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这种方式比简单的环境变量检查更安全，防止未授权的服务器冒充主站。</p><h2 id="部署与实践"><a href="#部署与实践" class="headerlink" title="部署与实践"></a>部署与实践</h2><p>这套授权系统已经成功部署在我们的API计费网关产品中，并交付给客户使用。实践证明，它能够有效地：</p><ul><li><strong>保护知识产权</strong>：即使客户获得了完整的源码，没有有效的授权也无法运行</li><li><strong>控制使用范围</strong>：软件只能在授权的域名和服务器上运行</li><li><strong>保留控制权</strong>：我们可以随时撤销授权，防止滥用</li><li><strong>简化部署</strong>：客户无需复杂的许可证管理，系统自动处理授权</li></ul><h2 id="未来展望"><a href="#未来展望" class="headerlink" title="未来展望"></a>未来展望</h2><p>这套授权系统还有很多可以改进的地方：</p><ul><li><strong>授权状态监控</strong>：开发一个集中式的授权状态监控平台</li><li><strong>多级授权</strong>：支持不同级别的授权，满足不同客户的需求</li><li><strong>离线授权</strong>：在特定场景下支持离线授权模式</li><li><strong>授权转移</strong>：支持授权在不同服务器间的安全转移</li></ul><h2 id="结语：安全与开放的平衡"><a href="#结语：安全与开放的平衡" class="headerlink" title="结语：安全与开放的平衡"></a>结语：安全与开放的平衡</h2><p>在软件分发的世界里，安全与开放一直是一对矛盾。<strong>过度强调安全会限制软件的使用体验，而过度开放则可能导致知识产权流失。</strong></p><p>我们的授权系统尝试在这两者之间找到平衡点：既保护了开发者的权益，又不过分限制用户的使用体验。这种平衡或许正是软件授权的未来方向。</p><p>通过这套系统，我们的API计费网关产品能够以更灵活的方式提供给更多有需求的客户，而不必担心源码泄露或未授权使用的问题。</p><p>如果你也面临类似的软件分发挑战，希望这篇文章能给你一些启发。安全与开放并非对立，而是可以共存的。</p><p>本文介绍的授权系统已经在实际项目中得到验证，如果你对这套系统有兴趣，欢迎在评论区留言交流，或通过邮件联系我们。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;当开源遇上商业化&quot;&gt;&lt;a href=&quot;#当开源遇上商业化&quot; class=&quot;headerlink&quot; title=&quot;当开源遇上商业化&quot;&gt;&lt;/a&gt;当开源遇上商业化&lt;/h2&gt;&lt;p&gt;相信不少开发者都遇到过这样的问题：开发的系统，有人愿意付费使用，但你担心源码一旦交付就无法控制其传播？或者你希望限制软件只能在特定环境中运行，防止被用于未经授权的场景？&lt;/p&gt;
&lt;p&gt;最近，我们的&lt;a href=&quot;https://blogs.kainy.cn/2025/05/OpenAPI%E8%AE%A1%E8%B4%B9%E7%BD%91%E5%85%B3%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B%EF%BC%88%E4%BA%A7%E5%93%81%E8%AE%BE%E8%AE%A1%E5%92%8C%E4%BB%B7%E5%80%BC%E4%B8%BB%E5%BC%A0%EF%BC%89/#blogs3&quot;&gt;API计费网关系统&lt;/a&gt;在技术社区分享后，收到了不少商业化的需求。这让我们思考：如何在提供软件使用权的同时，保护知识产权并控制软件的使用范围？&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oray.kainy.cn:38400/_upload/./content/temp/1747277750244image.png&quot; style=&quot;width: 30%&quot;&gt;&lt;/p&gt;
&lt;p&gt;经过深思熟虑和技术攻关，我们设计了一套基于非对称加密的域名授权系统。这套系统不仅解决了上述问题，还为软件授权提供了一种全新的思路。今天，我想与大家分享这个方案的技术细节和实现过程。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://oray.kainy.cn:38400/_upload/./content/temp/1747278105432image.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="技术" scheme="https://blogs.kainy.cn/tags/%E6%8A%80%E6%9C%AF/"/>
    
      <category term="网关" scheme="https://blogs.kainy.cn/tags/%E7%BD%91%E5%85%B3/"/>
    
      <category term="项目" scheme="https://blogs.kainy.cn/tags/%E9%A1%B9%E7%9B%AE/"/>
    
  </entry>
  
  <entry>
    <title>SyncMeIn:跨浏览器登录态同步插件项目简介</title>
    <link href="https://blogs.kainy.cn/2025/05/SyncMeIn:%20%E8%B7%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E7%99%BB%E5%BD%95%E6%80%81%E5%90%8C%E6%AD%A5%E6%8F%92%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B/"/>
    <id>https://blogs.kainy.cn/2025/05/SyncMeIn: 跨浏览器登录态同步插件项目简介/</id>
    <published>2025-05-07T14:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="产品背景与演进"><a href="#产品背景与演进" class="headerlink" title="产品背景与演进"></a>产品背景与演进</h2><p>SyncMeIn 最初诞生于一个特定的需求：同步微信公众号的登录态，以支持自动化操作（RPA）。随着项目的发展，我们意识到这一需求并非孤例，许多场景下都需要在不同浏览器、不同设备间同步登录状态。因此，SyncMeIn 逐渐演变成一个通用的 Cookie 和 Storage 同步工具，现已广泛应用于 Mercari（日本二手交易平台，也称为”煤炉”）账号管理、跨设备登录态保持等多种场景。</p><a id="more"></a><h2 id="产品设计理念"><a href="#产品设计理念" class="headerlink" title="产品设计理念"></a>产品设计理念</h2><h3 id="以用户为中心的设计思维"><a href="#以用户为中心的设计思维" class="headerlink" title="以用户为中心的设计思维"></a>以用户为中心的设计思维</h3><p>在设计 SyncMeIn 时，我们始终坚持以下核心理念：</p><ul><li><strong>简单易用</strong>：复杂的技术应该以简单的方式呈现给用户。我们提供了直观的界面，用户只需点击几下即可完成登录态的同步。</li><li><strong>安全第一</strong>：处理用户的登录凭证是一项高度敏感的工作。我们实现了端到端加密，确保数据在传输和存储过程中的安全性。</li><li><strong>自动化优先</strong>：减少用户的手动操作。通过自动推送（Auto Push）和自动合并（Auto Merge）功能，让同步过程更加无缝。</li><li><strong>可扩展性</strong>：设计之初就考虑到未来的扩展需求，采用模块化架构，便于添加新功能。</li></ul><h2 id="产品功能矩阵"><a href="#产品功能矩阵" class="headerlink" title="产品功能矩阵"></a>产品功能矩阵</h2><p>SyncMeIn 的功能设计围绕以下几个核心场景展开：</p><table><thead><tr><th style="text-align:left">功能</th><th style="text-align:left">描述</th><th style="text-align:left">应用场景</th></tr></thead><tbody><tr><td style="text-align:left">手动推送</td><td style="text-align:left">将当前浏览器的登录态手动推送到云端</td><td style="text-align:left">保存重要账号的登录状态</td></tr><tr><td style="text-align:left">手动合并</td><td style="text-align:left">从云端拉取登录态并应用到当前浏览器</td><td style="text-align:left">在新设备上快速恢复登录状态</td></tr><tr><td style="text-align:left">自动推送</td><td style="text-align:left">监测登录态变化并自动推送到云端</td><td style="text-align:left">保持云端数据的实时性</td></tr><tr><td style="text-align:left">自动合并</td><td style="text-align:left">浏览器启动时自动拉取并应用登录态</td><td style="text-align:left">确保多设备间的登录状态一致性</td></tr><tr><td style="text-align:left">云端刷新保活</td><td style="text-align:left">定期访问指定URL保持登录态活跃</td><td style="text-align:left">防止长期未使用导致的登录失效</td></tr></tbody></table><h2 id="技术实现与架构"><a href="#技术实现与架构" class="headerlink" title="技术实现与架构"></a>技术实现与架构</h2><h3 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a>整体架构</h3><p>SyncMeIn 采用了现代化的前端技术栈，主要包括：</p><ul><li><strong>前端框架</strong>：React + TypeScript</li><li><strong>状态管理</strong>：自定义 Store 模式</li><li><strong>数据存储</strong>：基于 Kevast 的多层存储架构</li><li><strong>安全机制</strong>：端到端加密 + 自定义授权机制</li></ul><p>整体架构如下图所示：</p><figure class="highlight gherkin"><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></pre></td><td class="code"><pre><span class="line">+------------------+     +------------------+     +------------------+</span><br><span class="line">|<span class="string">                  </span>|<span class="string">     </span>|<span class="string">                  </span>|<span class="string">     </span>|<span class="string">                  </span>|</span><br><span class="line">|<span class="string">  浏览器扩展 UI    </span>|<span class="string">&lt;---&gt;</span>|<span class="string">  后台服务进程     </span>|<span class="string">&lt;---&gt;</span>|<span class="string">  云端存储服务     </span>|</span><br><span class="line">|<span class="string">  (React)         </span>|<span class="string">     </span>|<span class="string">  (Service Worker)</span>|<span class="string">     </span>|<span class="string">  (自定义API服务)  </span>|</span><br><span class="line">|<span class="string">                  </span>|<span class="string">     </span>|<span class="string">                  </span>|<span class="string">     </span>|<span class="string">                  </span>|</span><br><span class="line">+------------------+     +------------------+     +------------------+</span><br><span class="line">                                 ^</span><br><span class="line">                                 |</span><br><span class="line"><span class="string">                                 v</span></span><br><span class="line"><span class="string">                         +------------------+</span></span><br><span class="line"><span class="string">                         </span>|<span class="string">                  </span>|</span><br><span class="line">                         |<span class="string">  浏览器原生API    </span>|</span><br><span class="line">                         |<span class="string">  (Cookies/Storage)</span>|</span><br><span class="line">                         |<span class="string">                  </span>|</span><br><span class="line">                         +------------------+</span><br></pre></td></tr></table></figure><h3 id="核心技术亮点"><a href="#核心技术亮点" class="headerlink" title="核心技术亮点"></a>核心技术亮点</h3><h4 id="1-端到端加密"><a href="#1-端到端加密" class="headerlink" title="1. 端到端加密"></a>1. 端到端加密</h4><p>安全性是 SyncMeIn 的首要考量。我们实现了完整的端到端加密机制：</p><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 基于 kevast-encrypt 实现的端到端加密</span></span><br><span class="line"><span class="keyword">const</span> encryptedStore = <span class="keyword">new</span> Kevast(</span><br><span class="line">  <span class="keyword">new</span> KevastEncrypt(</span><br><span class="line">    <span class="keyword">new</span> KevastGist(token, gistId, filename),</span><br><span class="line">    password</span><br><span class="line">  )</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>这种设计确保了：</p><ul><li>数据在客户端加密，服务器端只存储加密后的数据</li><li>即使服务器被攻破，攻击者也无法获取明文数据</li><li>密钥完全由用户控制，增强了数据主权</li></ul><h4 id="2-智能同步算法"><a href="#2-智能同步算法" class="headerlink" title="2. 智能同步算法"></a>2. 智能同步算法</h4><p>为了提高同步效率，我们开发了智能同步算法，只同步真正需要更新的数据：</p><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 智能比对算法片段</span></span><br><span class="line"><span class="keyword">if</span> (oldOne.value !== newOne.value) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">`<span class="subst">$&#123;key&#125;</span>对应的value两者不一致，需要推送`</span>);</span><br><span class="line">  changed = <span class="literal">true</span>;</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> now = <span class="keyword">new</span> <span class="built_in">Date</span>().getTime() / <span class="number">1000</span>;</span><br><span class="line"><span class="keyword">const</span> oldRemain = oldOne.expirationDate <span class="keyword">as</span> <span class="built_in">number</span> - now;</span><br><span class="line"><span class="keyword">const</span> newRemain = newOne.expirationDate <span class="keyword">as</span> <span class="built_in">number</span> - now;</span><br><span class="line"><span class="keyword">if</span> (oldRemain &lt; newRemain * <span class="number">0.5</span>) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">`旧的还有<span class="subst">$&#123;oldRemain&#125;</span>秒过期`</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">`新的还有<span class="subst">$&#123;newRemain&#125;</span>秒过期`</span>);</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">`<span class="subst">$&#123;oldRemain&#125;</span> / <span class="subst">$&#123;newRemain&#125;</span> = <span class="subst">$&#123;oldRemain <span class="regexp">/ newRemain&#125; &lt; 0.5`);</span></span></span></span><br><span class="line"><span class="string"><span class="subst"><span class="regexp">  console.log('太旧了，不通过');</span></span></span></span><br><span class="line"><span class="string"><span class="subst"><span class="regexp">  changed = true;</span></span></span></span><br><span class="line"><span class="string"><span class="subst"><span class="regexp">  break;</span></span></span></span><br><span class="line"><span class="string"><span class="subst"><span class="regexp">&#125;</span></span></span></span><br></pre></td></tr></table></figure><p>这个算法不仅比较 Cookie 的值，还会考虑过期时间，确保云端存储的 Cookie 始终保持最新状态。</p><h4 id="3-云端刷新保活机制"><a href="#3-云端刷新保活机制" class="headerlink" title="3. 云端刷新保活机制"></a>3. 云端刷新保活机制</h4><p>SyncMeIn 的一大创新是云端刷新保活机制，解决了长期未使用账号导致登录态失效的问题：</p><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> getRefreshConfigs(): <span class="built_in">Promise</span>&lt;Record&lt;<span class="built_in">string</span>, <span class="built_in">string</span>[]&gt;&gt; &#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="keyword">await</span> auth.getStoredToken();</span><br><span class="line">    <span class="keyword">const</span> response = <span class="keyword">await</span> fetch(<span class="string">`<span class="subst">$&#123;config.baseURL&#125;</span>/api/v1/refresh/refresh-config`</span>, &#123;</span><br><span class="line">      headers: &#123;</span><br><span class="line">        <span class="string">'Authorization'</span>: <span class="string">`Bearer <span class="subst">$&#123;token&#125;</span>`</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">await</span> response.json();</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    <span class="built_in">console</span>.error(<span class="string">'Failed to fetch refresh configs from server:'</span>, e);</span><br><span class="line">    <span class="keyword">return</span> &#123;&#125;;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>系统会定期访问用户配置的 URL，模拟用户活动，保持登录态的活跃。这对于需要长期保持登录状态的场景（如自动化脚本、监控系统等）尤为重要。</p><h4 id="4-跨浏览器兼容性"><a href="#4-跨浏览器兼容性" class="headerlink" title="4. 跨浏览器兼容性"></a>4. 跨浏览器兼容性</h4><p>通过抽象浏览器 API 接口，SyncMeIn 实现了跨浏览器的兼容性：</p><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 浏览器 API 抽象层</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">exportCookies</span>(<span class="params">domain: <span class="built_in">string</span></span>): <span class="title">Promise</span>&lt;<span class="title">chrome</span>.<span class="title">cookies</span>.<span class="title">SetDetails</span>[]&gt; </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> url = <span class="string">`https://<span class="subst">$&#123;domain&#125;</span>`</span>;</span><br><span class="line">  <span class="keyword">const</span> cookies = <span class="keyword">await</span> chrome.cookies.getAll(&#123; domain &#125;);</span><br><span class="line">  <span class="keyword">return</span> cookies.map(<span class="function">(<span class="params">cookie</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      url,</span><br><span class="line">      name: cookie.name,</span><br><span class="line">      value: cookie.value,</span><br><span class="line">      domain: cookie.domain,</span><br><span class="line">      path: cookie.path,</span><br><span class="line">      secure: cookie.secure,</span><br><span class="line">      httpOnly: cookie.httpOnly,</span><br><span class="line">      sameSite: cookie.sameSite,</span><br><span class="line">      expirationDate: cookie.expirationDate,</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这种设计使得 SyncMeIn 能够在 Chrome、Edge 等主流浏览器上无缝运行，为用户提供一致的体验。</p><h2 id="产品价值主张"><a href="#产品价值主张" class="headerlink" title="产品价值主张"></a>产品价值主张</h2><h3 id="1-提升工作效率"><a href="#1-提升工作效率" class="headerlink" title="1. 提升工作效率"></a>1. 提升工作效率</h3><p>SyncMeIn 显著减少了在多设备间切换账号的时间成本。以往，用户需要在每台设备上重新登录，输入账号密码，可能还需要进行二次验证。现在，只需在一台设备上登录，然后通过 SyncMeIn 将登录态同步到其他设备，整个过程只需几秒钟。</p><p>对于需要管理多个账号的专业用户（如社交媒体运营、电商卖家），这种效率提升尤为显著，可以节省大量重复登录的时间。</p><h3 id="2-增强数据安全"><a href="#2-增强数据安全" class="headerlink" title="2. 增强数据安全"></a>2. 增强数据安全</h3><p>与传统的”账号共享”方式相比，SyncMeIn 提供了更安全的解决方案：</p><ul><li>不需要分享账号密码，只同步登录后的状态</li><li>端到端加密确保数据传输安全</li><li>可随时撤销特定设备的访问权限</li><li>不保存明文密码，降低账号被盗风险</li></ul><h3 id="3-简化自动化流程"><a href="#3-简化自动化流程" class="headerlink" title="3. 简化自动化流程"></a>3. 简化自动化流程</h3><p>对于依赖浏览器自动化的企业和个人用户，SyncMeIn 解决了一个关键痛点：如何在无人值守的环境中保持登录状态。</p><p>通过 SyncMeIn 的云端刷新保活功能，自动化脚本可以始终使用有效的登录态，大大提高了自动化流程的稳定性和可靠性。</p><h3 id="4-跨平台一致体验"><a href="#4-跨平台一致体验" class="headerlink" title="4. 跨平台一致体验"></a>4. 跨平台一致体验</h3><p>现代用户通常拥有多种设备（PC、笔记本、平板、手机），SyncMeIn 让用户能够在这些设备间获得一致的登录体验，无需记忆多套凭证，也不必担心登录状态丢失。</p><h2 id="技术选型与实现方案对比"><a href="#技术选型与实现方案对比" class="headerlink" title="技术选型与实现方案对比"></a>技术选型与实现方案对比</h2><p>在开发 SyncMeIn 的过程中，我们考虑了多种技术方案，最终选择了当前的实现。以下是几个关键决策点的对比：</p><h3 id="数据存储方案对比"><a href="#数据存储方案对比" class="headerlink" title="数据存储方案对比"></a>数据存储方案对比</h3><table><thead><tr><th style="text-align:left">方案</th><th style="text-align:left">优势</th><th style="text-align:left">劣势</th><th style="text-align:left">最终选择</th></tr></thead><tbody><tr><td style="text-align:left">中心化数据库</td><td style="text-align:left">易于管理和扩展</td><td style="text-align:left">单点故障风险，隐私问题</td><td style="text-align:left">❌</td></tr><tr><td style="text-align:left">本地存储+同步</td><td style="text-align:left">用户数据自主权高</td><td style="text-align:left">同步复杂度高，依赖设备在线</td><td style="text-align:left">❌</td></tr><tr><td style="text-align:left">加密云存储</td><td style="text-align:left">兼顾安全性和可用性</td><td style="text-align:left">实现复杂度较高</td><td style="text-align:left">✅</td></tr></tbody></table><p>我们最终选择了基于 Kevast 的加密云存储方案，通过自定义的 KevastGist 实现，既保证了数据安全，又提供了良好的用户体验。</p><h3 id="加密方案对比"><a href="#加密方案对比" class="headerlink" title="加密方案对比"></a>加密方案对比</h3><table><thead><tr><th style="text-align:left">方案</th><th style="text-align:left">优势</th><th style="text-align:left">劣势</th><th style="text-align:left">最终选择</th></tr></thead><tbody><tr><td style="text-align:left">服务端加密</td><td style="text-align:left">实现简单，用户无感知</td><td style="text-align:left">服务器可访问明文数据</td><td style="text-align:left">❌</td></tr><tr><td style="text-align:left">客户端加密+固定密钥</td><td style="text-align:left">服务器无法访问明文</td><td style="text-align:left">密钥泄露风险高</td><td style="text-align:left">❌</td></tr><tr><td style="text-align:left">客户端加密+用户密钥</td><td style="text-align:left">最高安全性，用户完全控制</td><td style="text-align:left">用户需要记忆密钥</td><td style="text-align:left">✅</td></tr></tbody></table><p>我们选择了客户端加密+用户密钥的方案，虽然增加了一定的使用复杂度，但提供了最高级别的安全保障。</p><h3 id="刷新保活机制对比"><a href="#刷新保活机制对比" class="headerlink" title="刷新保活机制对比"></a>刷新保活机制对比</h3><table><thead><tr><th style="text-align:left">方案</th><th style="text-align:left">优势</th><th style="text-align:left">劣势</th><th style="text-align:left">最终选择</th></tr></thead><tbody><tr><td style="text-align:left">客户端定时刷新</td><td style="text-align:left">实现简单</td><td style="text-align:left">依赖客户端在线</td><td style="text-align:left">❌</td></tr><tr><td style="text-align:left">服务端代理刷新</td><td style="text-align:left">不依赖客户端在线</td><td style="text-align:left">需要服务端模拟浏览器环境</td><td style="text-align:left">❌</td></tr><tr><td style="text-align:left">云函数定时刷新</td><td style="text-align:left">可靠性高，资源消耗低</td><td style="text-align:left">需要额外的云基础设施</td><td style="text-align:left">✅</td></tr></tbody></table><p>最终我们采用了基于云函数的定时刷新方案，确保即使用户设备离线，登录态也能保持活跃。</p><h2 id="未来展望"><a href="#未来展望" class="headerlink" title="未来展望"></a>未来展望</h2><p>SyncMeIn 的发展不会止步于此。我们计划在以下方向持续改进和创新：</p><ul><li><strong>更智能的同步策略</strong>：利用机器学习优化同步算法，预测哪些数据最可能需要同步，提高效率。</li><li><strong>更广泛的平台支持</strong>：扩展到移动浏览器，实现真正的全平台覆盖。</li><li><strong>企业级功能</strong>：为团队协作场景提供更多管理功能，如权限控制、审计日志等。</li><li><strong>开放 API</strong>：提供 API 接口，让开发者能够将 SyncMeIn 集成到自己的应用中。</li><li><strong>更强大的自动化能力</strong>：增强与 RPA 工具的集成，支持更复杂的自动化场景。</li></ul><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>SyncMeIn 从一个简单的公众号登录态同步工具，发展成为一个功能全面的跨浏览器登录态管理解决方案，这一路程凝聚了我们对用户需求的深入理解和技术实现的不断探索。</p><p>我们相信，真正优秀的产品应该是技术与用户体验的完美结合。SyncMeIn 不仅仅是一个技术工具，更是对现代网络使用场景的一次重新思考。通过解决登录态同步这一看似简单却又普遍存在的问题，我们希望为用户创造更流畅、更安全的网络体验。</p><p>作为开发者，我们将持续倾听用户反馈，不断迭代产品，用技术的力量解决实际问题。这正是 SyncMeIn 的核心价值所在 —— 用匠心打造实用工具，用创新提升用户体验。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;产品背景与演进&quot;&gt;&lt;a href=&quot;#产品背景与演进&quot; class=&quot;headerlink&quot; title=&quot;产品背景与演进&quot;&gt;&lt;/a&gt;产品背景与演进&lt;/h2&gt;&lt;p&gt;SyncMeIn 最初诞生于一个特定的需求：同步微信公众号的登录态，以支持自动化操作（RPA）。随着项目的发展，我们意识到这一需求并非孤例，许多场景下都需要在不同浏览器、不同设备间同步登录状态。因此，SyncMeIn 逐渐演变成一个通用的 Cookie 和 Storage 同步工具，现已广泛应用于 Mercari（日本二手交易平台，也称为”煤炉”）账号管理、跨设备登录态保持等多种场景。&lt;/p&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="项目" scheme="https://blogs.kainy.cn/tags/%E9%A1%B9%E7%9B%AE/"/>
    
      <category term="方案" scheme="https://blogs.kainy.cn/tags/%E6%96%B9%E6%A1%88/"/>
    
      <category term="同步" scheme="https://blogs.kainy.cn/tags/%E5%90%8C%E6%AD%A5/"/>
    
  </entry>
  
  <entry>
    <title>OpenAPI计费网关项目简介（技术篇）</title>
    <link href="https://blogs.kainy.cn/2025/05/OpenAPI%E8%AE%A1%E8%B4%B9%E7%BD%91%E5%85%B3%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B%EF%BC%88%E6%8A%80%E6%9C%AF%E7%AF%87%EF%BC%89/"/>
    <id>https://blogs.kainy.cn/2025/05/OpenAPI计费网关项目简介（技术篇）/</id>
    <published>2025-05-06T04:03:13.000Z</published>
    <updated>2026-04-30T06:18:18.045Z</updated>
    
    <content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>本文从技术和产品角度深入介绍我们开发的 OpenAPI 系统，这是一个基于Koa.js构建的高性能API计费解决方案，它不仅支持多种计费模式，还提供了强大的缓存机制、安全防护和灵活的请求处理能力。</p><h2 id="系统架构"><a href="#系统架构" class="headerlink" title="系统架构"></a>系统架构</h2><p> OpenAPI 系统采用了现代化的技术栈和架构设计：</p><ul><li>后端框架：基于Koa.js构建，利用其异步特性实现高并发处理</li><li>数据存储：MongoDB用于持久化存储，Redis用于缓存和速率限制</li><li>前端界面：Vue.js构建的管理界面，包含Monaco编辑器支持 <em>请求模板</em> 编辑</li></ul><a id="more"></a><p>系统的核心组件包括：</p><ul><li>API代理中间件</li><li>计费服务</li><li>速率限制器</li><li>缓存系统</li><li>安全认证模块</li></ul><h2 id="产品核心优势"><a href="#产品核心优势" class="headerlink" title="产品核心优势"></a>产品核心优势</h2><h3 id="1-高性能设计"><a href="#1-高性能设计" class="headerlink" title="1. 高性能设计"></a>1. 高性能设计</h3><p> OpenAPI 系统在性能优化方面做了大量工作：</p><h4 id="1-1-高效的HTTP连接管理"><a href="#1-1-高效的HTTP连接管理" class="headerlink" title="1.1 高效的HTTP连接管理"></a>1.1 高效的HTTP连接管理</h4><figure class="highlight javascript"><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">// 创建 keepAlive Agent</span></span><br><span class="line"><span class="keyword">const</span> httpsAgent = <span class="keyword">new</span> https.Agent(&#123;</span><br><span class="line">  keepAlive: <span class="literal">true</span>,</span><br><span class="line">  keepAliveMsecs: <span class="number">1000</span>, <span class="comment">// 连接保持时间</span></span><br><span class="line">  maxSockets: <span class="number">100</span>,      <span class="comment">// 并发连接数</span></span><br><span class="line">  maxFreeSockets: <span class="number">10</span>,   <span class="comment">// 允许的空闲连接数</span></span><br><span class="line">  timeout: TIMEOUT,     <span class="comment">// 超时时间</span></span><br><span class="line">  rejectUnauthorized: <span class="literal">false</span> <span class="comment">// 忽略 SSL 证书错误</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>通过配置HTTP和HTTPS的Agent，系统实现了连接复用，大幅减少了TCP连接建立的开销。这在高并发场景下能显著提升性能，减少服务器资源消耗。</p><h4 id="1-2-智能的重试机制"><a href="#1-2-智能的重试机制" class="headerlink" title="1.2 智能的重试机制"></a>1.2 智能的重试机制</h4><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 带重试的请求函数</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">retryableRequest</span>(<span class="params">config, retries = RETRY_COUNT</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">await</span> axiosInstance(config);</span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    <span class="keyword">if</span> (retries &gt; <span class="number">0</span> &amp;&amp; (</span><br><span class="line">      error.code === <span class="string">'ETIMEDOUT'</span> ||</span><br><span class="line">      error.code === <span class="string">'ECONNRESET'</span> ||</span><br><span class="line">      error.code === <span class="string">'ECONNREFUSED'</span> ||</span><br><span class="line">      (error.response &amp;&amp; error.response.status &gt;= <span class="number">500</span>)</span><br><span class="line">    )) &#123;</span><br><span class="line">      <span class="built_in">console</span>.warn(<span class="string">`Retry attempt <span class="subst">$&#123;RETRY_COUNT - retries + <span class="number">1</span>&#125;</span> for <span class="subst">$&#123;config.url&#125;</span>`</span>);</span><br><span class="line">      <span class="keyword">await</span> delay(RETRY_DELAY * (RETRY_COUNT - retries));</span><br><span class="line">      <span class="keyword">return</span> retryableRequest(config, retries - <span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">throw</span> error;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>系统实现了智能重试机制，可以自动处理临时性网络故障和上游服务暂时不可用的情况。重试策略采用了指数退避算法，避免了重试风暴，提高了系统的可靠性。</p><h4 id="1-3-异步处理计费记录"><a href="#1-3-异步处理计费记录" class="headerlink" title="1.3 异步处理计费记录"></a>1.3 异步处理计费记录</h4><p>系统将API调用和计费处理分离，API调用完成后异步处理计费记录，避免了计费处理对API响应时间的影响。</p><h3 id="2-高效缓存实现"><a href="#2-高效缓存实现" class="headerlink" title="2. 高效缓存实现"></a>2. 高效缓存实现</h3><p>缓存系统是 OpenAPI 的一大亮点，它极大地提升了系统性能和用户体验：</p><h4 id="2-1-内存缓存实现"><a href="#2-1-内存缓存实现" class="headerlink" title="2.1 内存缓存实现"></a>2.1 内存缓存实现</h4><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MemoryCache</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>() &#123;</span><br><span class="line">    <span class="keyword">this</span>.cache = <span class="keyword">new</span> <span class="built_in">Map</span>();</span><br><span class="line">    <span class="keyword">this</span>.timeouts = <span class="keyword">new</span> <span class="built_in">Map</span>();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">set</span>(key, value, ttlSeconds) &#123;</span><br><span class="line">    <span class="keyword">this</span>.cache.set(key, value);</span><br><span class="line">    <span class="keyword">if</span> (ttlSeconds) &#123;</span><br><span class="line">      <span class="comment">// 清除旧的超时</span></span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">this</span>.timeouts.has(key)) &#123;</span><br><span class="line">        clearTimeout(<span class="keyword">this</span>.timeouts.get(key));</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 设置新的超时</span></span><br><span class="line">      <span class="keyword">const</span> timeout = setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">this</span>.cache.delete(key);</span><br><span class="line">        <span class="keyword">this</span>.timeouts.delete(key);</span><br><span class="line">      &#125;, ttlSeconds * <span class="number">1000</span>);</span><br><span class="line">      <span class="keyword">this</span>.timeouts.set(key, timeout);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// ...其他方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>系统实现了高效的内存缓存，使用Map数据结构存储缓存数据，并通过定时器实现缓存过期机制。这种设计比传统的数组遍历检查过期项更高效。</p><h4 id="2-2-智能缓存策略"><a href="#2-2-智能缓存策略" class="headerlink" title="2.2 智能缓存策略"></a>2.2 智能缓存策略</h4><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 判断请求是否可缓存</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isCacheable</span>(<span class="params">method, headers</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 只缓存GET请求，并且请求头没有指定no-cache</span></span><br><span class="line">  <span class="keyword">return</span> method === <span class="string">'GET'</span> &amp;&amp;</span><br><span class="line">          (!headers[<span class="string">'cache-control'</span>] || !headers[<span class="string">'cache-control'</span>].includes(<span class="string">'no-cache'</span>));</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 获取缓存TTL（秒）</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getCacheTTL</span>(<span class="params">resource</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> resource.cacheTTL || <span class="number">300</span>; <span class="comment">// 通过cacheTTL来自定义缓存时间, 默认5分钟</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>系统根据HTTP方法和请求头智能判断请求是否可缓存，并支持通过API资源配置自定义缓存时间。这种灵活的缓存策略能够适应不同API的缓存需求。</p><h4 id="2-3-缓存键生成"><a href="#2-3-缓存键生成" class="headerlink" title="2.3 缓存键生成"></a>2.3 缓存键生成</h4><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 生成缓存键</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">generateCacheKey</span>(<span class="params">ctx, url</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> data = <span class="string">`<span class="subst">$&#123;ctx.method&#125;</span>:<span class="subst">$&#123;url&#125;</span>:<span class="subst">$&#123;<span class="built_in">JSON</span>.stringify(ctx.request.body)&#125;</span>:<span class="subst">$&#123;<span class="built_in">JSON</span>.stringify(ctx.request.querystring)&#125;</span>`</span>;</span><br><span class="line">  <span class="keyword">return</span> crypto.createHash(<span class="string">'md5'</span>).update(data).digest(<span class="string">'hex'</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>缓存键的生成考虑了HTTP方法、URL、请求体和查询参数，确保了缓存的精确匹配。使用MD5哈希算法生成固定长度的缓存键，提高了缓存系统的效率。</p><h3 id="3-安全性设计"><a href="#3-安全性设计" class="headerlink" title="3. 安全性设计"></a>3. 安全性设计</h3><p> OpenAPI 系统在安全性方面做了全面考量：</p><h4 id="3-1-API密钥认证"><a href="#3-1-API密钥认证" class="headerlink" title="3.1 API密钥认证"></a>3.1 API密钥认证</h4><p>系统实现了基于API密钥的认证机制，每个用户都有唯一的API密钥，用于身份验证和访问控制。</p><h4 id="3-2-速率限制"><a href="#3-2-速率限制" class="headerlink" title="3.2 速率限制"></a>3.2 速率限制</h4><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line">exports.rateLimiter = <span class="keyword">async</span> (ctx, next) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> endpoint = ctx.path.replace(<span class="string">'/api/'</span>, <span class="string">''</span>);</span><br><span class="line">  <span class="keyword">const</span> apiKey = ctx.state.apiKey;</span><br><span class="line">  <span class="keyword">if</span> (!apiKey) &#123;</span><br><span class="line">    ctx.status = <span class="number">401</span>;</span><br><span class="line">    ctx.body = &#123; <span class="attr">error</span>: <span class="string">'API key required'</span> &#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> maxRequests = objLimit[endpoint] || DEFAULT_MAX_REQUESTS;</span><br><span class="line">  <span class="keyword">const</span> key = <span class="string">`ratelimit:<span class="subst">$&#123;endpoint&#125;</span>/<span class="subst">$&#123;apiKey&#125;</span>`</span>;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> isAllowed = <span class="keyword">await</span> cache.rateLimit(key, maxRequests, RATE_LIMIT_WINDOW);</span><br><span class="line">    <span class="keyword">const</span> currentCount = cache.get(key) || <span class="number">0</span>;</span><br><span class="line">    ctx.set(<span class="string">'X-RateLimit-Limit'</span>, maxRequests);</span><br><span class="line">    ctx.set(<span class="string">'X-RateLimit-Remaining'</span>, <span class="built_in">Math</span>.max(<span class="number">0</span>, maxRequests - currentCount));</span><br><span class="line">    <span class="keyword">if</span> (!isAllowed) &#123;</span><br><span class="line">      ctx.status = <span class="number">429</span>;</span><br><span class="line">      ctx.body = &#123; <span class="attr">error</span>: <span class="string">`访问频率超限（<span class="subst">$&#123;maxRequests&#125;</span>req/m）...`</span> &#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">return</span> next();</span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    logger.error(<span class="string">'Rate limiter error:'</span>, error);</span><br><span class="line">    <span class="keyword">return</span> next(); <span class="comment">// Proceed even if rate limiting fails</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>系统实现了基于内存缓存的速率限制器，可以针对不同的API端点设置不同的速率限制，有效防止了API滥用和DoS攻击。速率限制器还会自动从数据库加载配置并定期更新，确保限制策略的及时生效。</p><h4 id="3-3-输入验证和错误处理"><a href="#3-3-输入验证和错误处理" class="headerlink" title="3.3 输入验证和错误处理"></a>3.3 输入验证和错误处理</h4><p>系统对所有输入进行严格验证，防止注入攻击和其他安全威胁。同时，系统实现了全面的错误处理机制，确保在出现异常情况时能够优雅地处理并返回适当的错误信息。</p><h3 id="4-灵活的请求处理"><a href="#4-灵活的请求处理" class="headerlink" title="4. 灵活的请求处理"></a>4. 灵活的请求处理</h3><h4 id="4-1-函数式请求模板"><a href="#4-1-函数式请求模板" class="headerlink" title="4.1 函数式请求模板"></a>4.1 函数式请求模板</h4><p>系统最近升级了<em>请求模板</em>功能，支持使用JavaScript函数定义请求转换逻辑：<br><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 检查是否是函数字符串（以 function 开头）</span></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">typeof</span> resource.requestTemplate === <span class="string">'string'</span> &amp;&amp; resource.requestTemplate.trim().startsWith(<span class="string">'function'</span>)) &#123;</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="comment">// 支持匿名函数和命名函数</span></span><br><span class="line">    <span class="keyword">const</span> templateCode = resource.requestTemplate.trim();</span><br><span class="line">    <span class="keyword">let</span> templateFunction = <span class="keyword">new</span> <span class="built_in">Function</span>(<span class="string">'request'</span>, <span class="string">`</span></span><br><span class="line"><span class="string">      try &#123;</span></span><br><span class="line"><span class="string">        return (<span class="subst">$&#123;templateCode&#125;</span>)(request);</span></span><br><span class="line"><span class="string">      &#125; catch (err) &#123;</span></span><br><span class="line"><span class="string">        console.error('Template function execution error:', err);</span></span><br><span class="line"><span class="string">        return &#123;&#125;;</span></span><br><span class="line"><span class="string">      &#125;</span></span><br><span class="line"><span class="string">      `</span>);</span><br><span class="line">    <span class="comment">// 执行函数并获取结果</span></span><br><span class="line">    <span class="keyword">const</span> result = templateFunction(ctx.request);</span><br><span class="line">    <span class="keyword">if</span> (result &amp;&amp; <span class="keyword">typeof</span> result === <span class="string">'object'</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (result.headers) &#123;</span><br><span class="line">        headers = result.headers;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (result.body) &#123;</span><br><span class="line">        body = result.body</span><br><span class="line">        <span class="comment">// 如果是FormData请求但模板返回了body，我们将转换为JSON请求</span></span><br><span class="line">        <span class="keyword">if</span> (isMultipart) &#123;</span><br><span class="line">          headers[<span class="string">'content-type'</span>] = <span class="string">'application/json'</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">catch</span> (error) &#123;</span><br><span class="line">    logger.error(<span class="string">`Error executing request template function: <span class="subst">$&#123;error.message&#125;</span>`</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>这种函数式模板比传统的JSON模板更加灵活，可以实现复杂的请求转换逻辑，如条件判断、数据转换等。前端还配置了Monaco编辑器，提供JavaScript语法高亮，提升了模板编辑体验。</p><h4 id="4-2-流式响应支持"><a href="#4-2-流式响应支持" class="headerlink" title="4.2 流式响应支持"></a>4.2 流式响应支持</h4><p>系统支持流式响应，特别适用于处理大模型响应或需要实时数据的场景：<br><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">handleStreamProxy</span>(<span class="params">ctx, apiResource, upstream, opt</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> stream = <span class="keyword">new</span> PassThrough();</span><br><span class="line">  ctx.body = stream;</span><br><span class="line">  <span class="comment">// 设置 SSE headers</span></span><br><span class="line">  ctx.set(&#123;</span><br><span class="line">    <span class="string">'Content-Type'</span>: <span class="string">'text/event-stream'</span>,</span><br><span class="line">    <span class="string">'Cache-Control'</span>: <span class="string">'no-cache'</span>,</span><br><span class="line">    <span class="string">'Connection'</span>: <span class="string">'keep-alive'</span></span><br><span class="line">  &#125;);</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> headers = &#123;</span><br><span class="line">      ...opt.headers,</span><br><span class="line">      <span class="string">'api-key'</span>: opt.headers[<span class="string">'api-key'</span>] || <span class="string">''</span>,</span><br><span class="line">      <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      <span class="string">'Accept'</span>: <span class="string">'text/event-stream'</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="comment">// 移除不需要的头</span></span><br><span class="line">    <span class="keyword">delete</span> headers.host;</span><br><span class="line">    <span class="keyword">delete</span> headers[<span class="string">'x-api-key'</span>];</span><br><span class="line">    <span class="keyword">delete</span> headers[<span class="string">'content-length'</span>];</span><br><span class="line">    <span class="keyword">const</span> optA = &#123;</span><br><span class="line">      method: ctx.method,</span><br><span class="line">      url: upstream,</span><br><span class="line">      data: &#123;</span><br><span class="line">        ...opt.body,</span><br><span class="line">        stream: <span class="literal">true</span></span><br><span class="line">      &#125;,</span><br><span class="line">      headers,</span><br><span class="line">      responseType: <span class="string">'stream'</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="comment">// 转发请求到上游服务</span></span><br><span class="line">    <span class="keyword">const</span> response = <span class="keyword">await</span> axiosInstance(optA);</span><br><span class="line">    <span class="comment">// 直接转发响应</span></span><br><span class="line">    response.data.pipe(stream);</span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    <span class="built_in">console</span>.error(<span class="string">'Stream proxy error:'</span>, error);</span><br><span class="line">    stream.write(<span class="string">`data: <span class="subst">$&#123;<span class="built_in">JSON</span>.stringify(&#123; error: error.message &#125;</span>)&#125;\n\n`</span>);</span><br><span class="line">    stream.end();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>流式响应处理使系统能够支持现代AI API的流式输出，如OpenAI的流式聊天完成API。</p><h3 id="5-精确的Token计费"><a href="#5-精确的Token计费" class="headerlink" title="5. 精确的Token计费"></a>5. 精确的Token计费</h3><p>系统最近升级了token计费功能，支持更精确的计费方式：</p><ul><li>输入输出分离计费：系统可以分别计算输入和输出token的费用，并设置不同的价格</li><li>智能识别输入token：对于常见的LLM API格式（如包含prompt或messages字段的请求），系统能够智能识别并计算输入token</li><li>灵活的计费模式：系统支持根据API资源的billingMode属性决定使用哪种计费模式</li></ul><p>这种精确的token计费方式特别适合AI API提供商，可以更公平地反映API使用成本。</p><h2 id="产品设计考量"><a href="#产品设计考量" class="headerlink" title="产品设计考量"></a>产品设计考量</h2><h3 id="1-用户体验至上"><a href="#1-用户体验至上" class="headerlink" title="1. 用户体验至上"></a>1. 用户体验至上</h3><p> OpenAPI 系统的设计始终以用户体验为中心：</p><ul><li>简洁的API设计：遵循RESTful原则，API接口简洁明了，支持浏览器调用调试</li><li>详细的使用统计：提供实时使用量统计，帮助用户了解API使用情况</li><li>灵活的计费策略：支持多种计费模式，满足不同用户的需求</li></ul><h3 id="2-可扩展性设计"><a href="#2-可扩展性设计" class="headerlink" title="2. 可扩展性设计"></a>2. 可扩展性设计</h3><p>系统在设计时充分考虑了可扩展性：</p><ul><li>模块化架构：系统分为多个独立模块，如认证、代理、计费等，便于扩展和维护</li><li>插件化设计：关键功能如缓存、速率限制等都设计为可插拔的组件</li><li>配置驱动：大部分功能通过配置驱动，无需修改代码即可调整系统行为</li></ul><h3 id="3-运维友好"><a href="#3-运维友好" class="headerlink" title="3. 运维友好"></a>3. 运维友好</h3><p>系统设计了完善的日志和监控机制，便于运维人员排查问题和优化系统性能。同时，系统支持通过环境变量配置关键参数，便于在不同环境中部署。</p><h2 id="技术实现对比"><a href="#技术实现对比" class="headerlink" title="技术实现对比"></a>技术实现对比</h2><h3 id="缓存实现对比"><a href="#缓存实现对比" class="headerlink" title="缓存实现对比"></a>缓存实现对比</h3><table><thead><tr><th>实现方式</th><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>内存缓存 (🌟当前实现)</td><td>速度快，实现简单</td><td>不支持分布式，重启后缓存丢失</td></tr><tr><td>Redis缓存</td><td>支持分布式，持久化</td><td>需要额外维护Redis服务</td></tr><tr><td>文件缓存</td><td>简单，持久化</td><td>I/O开销大，性能较低</td></tr></tbody></table><p>我们选择内存缓存作为主要实现，同时为分布式部署场景预留了Redis缓存的接口。</p><h3 id="速率限制实现对比"><a href="#速率限制实现对比" class="headerlink" title="速率限制实现对比"></a>速率限制实现对比</h3><table><thead><tr><th>实现方式</th><th>优点</th><th>缺点</th></tr></thead><tbody><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>我们选择内存计数器作为速率限制的实现，在单机部署场景下提供了良好的性能和足够的准确性。</p><h2 id="未来发展方向"><a href="#未来发展方向" class="headerlink" title="未来发展方向"></a>未来发展方向</h2><ul><li>支持多种货币：计划添加多币种支持，满足国际用户需求</li><li>计费预警功能：当用户接近月度限额时发送通知</li><li>自定义计费规则：允许用户定义更复杂的计费规则</li><li>计费报表导出：支持导出详细的计费报表</li><li>集成支付网关：直接在系统中完成充值和支付</li></ul><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p> OpenAPI 系统通过高性能设计、高效缓存实现、全面的安全考量和灵活的请求处理能力，独立开发者提供了一个强大的计费解决方案。系统不仅满足了基本的计费需求，还通过精确的token计费、函数式请求模板等创新功能，提升了用户体验和系统灵活性。</p><p><strong>作为独立开发者，更应追求技术卓越和产品完美</strong>， OpenAPI 系统正是这种追求的体现。我们相信，随着系统的不断发展和完善，它将为更多的API提供者创造价值。</p><p>本文由 OpenAPI 系统开发团队撰写，旨在分享我们在API计费领域的技术实践和产品思考。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;引言&quot;&gt;&lt;a href=&quot;#引言&quot; class=&quot;headerlink&quot; title=&quot;引言&quot;&gt;&lt;/a&gt;引言&lt;/h2&gt;&lt;p&gt;本文从技术和产品角度深入介绍我们开发的 OpenAPI 系统，这是一个基于Koa.js构建的高性能API计费解决方案，它不仅支持多种计费模式，还提供了强大的缓存机制、安全防护和灵活的请求处理能力。&lt;/p&gt;
&lt;h2 id=&quot;系统架构&quot;&gt;&lt;a href=&quot;#系统架构&quot; class=&quot;headerlink&quot; title=&quot;系统架构&quot;&gt;&lt;/a&gt;系统架构&lt;/h2&gt;&lt;p&gt; OpenAPI 系统采用了现代化的技术栈和架构设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;后端框架：基于Koa.js构建，利用其异步特性实现高并发处理&lt;/li&gt;
&lt;li&gt;数据存储：MongoDB用于持久化存储，Redis用于缓存和速率限制&lt;/li&gt;
&lt;li&gt;前端界面：Vue.js构建的管理界面，包含Monaco编辑器支持 &lt;em&gt;请求模板&lt;/em&gt; 编辑&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
      <category term="学习笔记" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
      <category term="建站❤编程" scheme="https://blogs.kainy.cn/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E5%BB%BA%E7%AB%99%E2%9D%A4%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="技术" scheme="https://blogs.kainy.cn/tags/%E6%8A%80%E6%9C%AF/"/>
    
      <category term="网关" scheme="https://blogs.kainy.cn/tags/%E7%BD%91%E5%85%B3/"/>
    
      <category term="项目" scheme="https://blogs.kainy.cn/tags/%E9%A1%B9%E7%9B%AE/"/>
    
  </entry>
  
</feed>
