<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>LiaoKe的博客</title><description>记录生活,分享技术</description><link>https://blog.liao-ke.com/</link><templateTheme>Firefly</templateTheme><templateThemeVersion>6.16.4</templateThemeVersion><templateThemeUrl>https://github.com/CuteLeaf/Firefly</templateThemeUrl><lastBuildDate>2026年8月26日 20:25:11</lastBuildDate><item><title>随笔杂谈 | Waline用户列表加载失败 </title><link>https://blog.liao-ke.com/posts/waline-bugfix/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/waline-bugfix/</guid><description>记录一次 Waline 评论系统用户列表接口返回 500 的排查与修复过程，问题最终定位在 avatar 服务的字段名不匹配。</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;前几天登录博客的评论系统waline，发现用户列表加载不出来，打开网络调试器发现请求接口返回500，一直是以为我数据库出错了，连续换了几个类型的数据库（MongoDB,SQLite,PostgreSQL），后来又尝试换了部署平台从Vercel换到了Netlify，所有情况都试遍了，仍然加载不出用户列表。
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1304&quot; height=&quot;403&quot; src=&quot;/_astro/1.eFbZDqKQ_rfKfX.webp&quot; /&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;排查&lt;a href=&quot;#排查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;尝试了众多方法无果之后，我在想是不是waline server端的代码本身出了问题，于是就去翻看了一下他们官方的&lt;a href=&quot;https://github.com/walinejs/waline/blob/main/packages/server/src/controller/user.js&quot; target=&quot;_blank&quot;&gt;源代码&lt;/a&gt;，打开 &lt;code&gt;packages/server/src/controller/user.js&lt;/code&gt;，定位到用户列表接口 &lt;code&gt;getAction&lt;/code&gt; 里生成头像的这一行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;avatar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;think&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;service&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;avatar&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;再看 &lt;code&gt;avatar&lt;/code&gt; 服务内部的模板：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;%-&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;elif&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;qqMailExp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mail&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-%&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;span&gt;mail&lt;/span&gt;&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;@qq.com&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;)}}&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;%-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-%&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;https&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;//seccdn.libravatar.org/avatar/{{mail | trim | lower | md5}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;%-&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;endif&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-%&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;模板取的是 &lt;code&gt;mail&lt;/code&gt; 字段，但 &lt;code&gt;user&lt;/code&gt; 表里邮箱字段叫 &lt;code&gt;email&lt;/code&gt;，不叫 &lt;code&gt;mail&lt;/code&gt;。直接把 &lt;code&gt;user&lt;/code&gt; 对象传进去，模板里 &lt;code&gt;mail&lt;/code&gt; 是 &lt;code&gt;undefined&lt;/code&gt;，执行 &lt;code&gt;mail|replace(...)&lt;/code&gt; 时报错：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;TypeError: Cannot read properties of undefined (reading &apos;replace&apos;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;跟控制台报错完全对上。跟数据库类型、部署平台没有任何关系。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;定位根因&lt;a href=&quot;#定位根因&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;全局搜了一下项目里所有调用 &lt;code&gt;avatar&lt;/code&gt; 服务的地方，发现 &lt;code&gt;token.js&lt;/code&gt;（登录）和 &lt;code&gt;base.js&lt;/code&gt;（评论列表）在处理同一张 &lt;code&gt;user&lt;/code&gt; 表时，都做了字段映射：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;think&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;service&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;avatar&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;mail&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;email&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;nick&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;display_name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;link&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;只有 &lt;code&gt;user.js&lt;/code&gt; 这一处漏了映射，直接传了原始对象。是官方代码里孤立的一处遗漏。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;修复&lt;a href=&quot;#修复&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;把 &lt;code&gt;user.js&lt;/code&gt; 改成和另外两处一致的写法：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;avatar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;think&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;service&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;avatar&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;mail&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;email&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;nick&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;display_name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;link&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;重新部署waline服务，用户列表恢复正常。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;小结&lt;a href=&quot;#小结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;最后改完之后也是把修复补丁重新&lt;a href=&quot;https://github.com/walinejs/waline/pull/3816&quot; target=&quot;_blank&quot;&gt;pr&lt;/a&gt;回上游了。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>开发日记 | AutoGlm：用 Chaquopy 把 AI 控制手机的 Python 项目搬进安卓 APP</title><link>https://blog.liao-ke.com/posts/autoglm-dev-diary/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/autoglm-dev-diary/</guid><description>记录将 Open-AutoGLM 这套基于 ADB 的手机自动化控制系统，通过 Chaquopy 嵌入式 Python 和自制 libadb.so 移植进安卓原生 APP 的开发过程与踩坑经历。</description><pubDate>Thu, 30 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;几个月前，偶然间发现了一个项目&lt;a href=&quot;https://github.com/iamr0s/Ruto-GLM&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;Ruto&lt;/strong&gt;&lt;/a&gt;，简单来说就是可以用自然语言让AI操控手机进行一些操作，比如说点外卖，给谁发消息之类的。于是乎我突发奇想，想着能不能做一个类似的项目,但是让我从零手搓一套ai控制系统显然是有一点难度的。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;开发历程&lt;a href=&quot;#开发历程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;然后我又看到了一个项目&lt;a href=&quot;https://github.com/zai-org/Open-AutoGLM&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;Open-AutoGLM&lt;/strong&gt;&lt;/a&gt;,这个项目是在电脑上基于Python，通过有线或者无线ADB连接手机，然后让AI操作手机，是一个现成的操作控制系统，但是我要如何把这套系统移植到安卓手APP上来呢？&lt;/p&gt;&lt;section&gt;&lt;h3&gt;用 Chaquopy 把 Python 塞进安卓&lt;a href=&quot;#用-chaquopy-把-python-塞进安卓&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;这个项目是基于Python的，于是我便利用了&lt;a href=&quot;https://chaquo.com/chaquopy&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;chaquopy&lt;/strong&gt;&lt;/a&gt;这个嵌入式Python运行器(因为安卓上没有runtime这个概念,不像windows一样可以装Python运行环境，安卓应用只能使用嵌入式python来运行python代码,且&lt;a href=&quot;https://chaquo.com/chaquopy&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;chaquopy&lt;/strong&gt;&lt;/a&gt;他的Python依赖库不全，而且有些版本有点落后,出现了项目的语法兼容性问题。为了让&lt;a href=&quot;https://chaquo.com/chaquopy&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;chaquopy&lt;/strong&gt;&lt;/a&gt;兼容&lt;a href=&quot;https://github.com/zai-org/Open-AutoGLM&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;Open-AutoGLM&lt;/strong&gt;&lt;/a&gt;,当时调试依赖版本，就费了好长的时间)。在 &lt;code&gt;build.gradle.kts&lt;/code&gt; 里接入：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;plugins&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt;(libs.plugins.android.application)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt;(libs.plugins.kotlin.compose)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;com.chaquo.python&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这样原项目 &lt;code&gt;phone_agent&lt;/code&gt; 这一整套 Python 包（&lt;code&gt;agent.py&lt;/code&gt;、&lt;code&gt;adb/&lt;/code&gt;、&lt;code&gt;actions/&lt;/code&gt;、&lt;code&gt;config/&lt;/code&gt; 等）就可以原封不动地放进 &lt;code&gt;app/src/main/python/&lt;/code&gt; 目录，跟着 APK 一起打包，运行时由 Kotlin 侧直接调用：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; py &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Python.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;getInstance&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; module &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; py.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;getModule&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;main&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; module.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;callAttr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;main&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;--adb-path&quot;&lt;/span&gt;&lt;span&gt;, adbPath,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;--base-url&quot;&lt;/span&gt;&lt;span&gt;, baseUrl,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;--model&quot;&lt;/span&gt;&lt;span&gt;, model,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;--apikey&quot;&lt;/span&gt;&lt;span&gt;, apiKey,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;--device-type&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;adb&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;adb 二进制变成 libadb.so&lt;a href=&quot;#adb-二进制变成-libadbso&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;原项目里面用的是adb命令连接手机，于是我费了九牛二虎之力，终于在github上找到了能在安卓上成功运行起来的adb二进制文件,但是由于在新的安卓开发标准中不允许直接把现成的二进制文件打包进APK里了,必须要把adb命名为adb.so。为了让它落地到真实文件系统而不是留在压缩包里，还得在 &lt;code&gt;build.gradle.kts&lt;/code&gt; 里强制用 legacy 打包方式：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;android&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;packaging&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;jniLibs&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;// 强制将 .so 文件提取到磁盘上，而不是留在 APK 中&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;// 这样 context.applicationInfo.nativeLibraryDir 目录下才会有真实文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;useLegacyPackaging &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;defaultConfig&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;ndk&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;abiFilters &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;listOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;arm64-v8a&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;让 Python 侧的 adb 调用重定向到 libadb.so&lt;a href=&quot;#让-python-侧的-adb-调用重定向到-libadbso&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;但是原项目又是直接调用终端环境中的adb,最后没办法，只能修改源代码，又增加了对adb执行命令的hook，让它自动重定向到我设置目录下的adb.so。&lt;/p&gt;&lt;p&gt;&lt;code&gt;phone_agent/adb/connection.py&lt;/code&gt;（以及 &lt;code&gt;screenshot.py&lt;/code&gt;、&lt;code&gt;input.py&lt;/code&gt;、&lt;code&gt;device.py&lt;/code&gt;）里的每一处 adb 调用，默认都是直接执行名为 &lt;code&gt;adb&lt;/code&gt; 的命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ADBConnection&lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;adb_path&lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;str&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;None&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;None&lt;/span&gt;&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&lt;span&gt;.adb_path &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; adb_path &lt;/span&gt;&lt;/span&gt;&lt;span&gt;or&lt;/span&gt;&lt;span&gt;&lt;span&gt; os.&lt;/span&gt;&lt;span&gt;getenv&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;PHONE_AGENT_ADB_PATH&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;adb&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;address&lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;/span&gt;&lt;span&gt;) -&amp;gt; tuple[&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;str&lt;/span&gt;&lt;span&gt;]:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; subprocess.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.adb_path, &lt;/span&gt;&lt;span&gt;&quot;connect&quot;&lt;/span&gt;&lt;span&gt;, address],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;capture_output&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;timeout,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;好在原作者已经预留了 &lt;code&gt;PHONE_AGENT_ADB_PATH&lt;/code&gt; 这个环境变量作为覆盖入口，所以我不需要大动干戈改 Python 逻辑，只要在 Kotlin 侧启动 Python 之前，把这个环境变量／命令行参数指向我 APK 私有目录下解压出来的 &lt;code&gt;libadb.so&lt;/code&gt; 即可：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;runPython&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;context: &lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;baseUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;model: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;apiKey: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;task: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;onLog: (&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;) -&amp;gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;onFinish: () &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; Unit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;thread&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; wakeLock &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; pm.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;newWakeLock&lt;/span&gt;&lt;span&gt;(PowerManager.PARTIAL_WAKE_LOCK, &lt;/span&gt;&lt;span&gt;&quot;Python:Run&quot;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;acquire&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;60&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;1000L&lt;/span&gt;&lt;span&gt;) }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; adbPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;File&lt;/span&gt;&lt;span&gt;(context.applicationInfo.nativeLibraryDir, &lt;/span&gt;&lt;span&gt;&quot;libadb.so&quot;&lt;/span&gt;&lt;span&gt;).absolutePath&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; py &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Python.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;getInstance&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; module &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; py.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;getModule&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;main&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; module.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;callAttr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&quot;main&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;&quot;--adb-path&quot;&lt;/span&gt;&lt;span&gt;, adbPath,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;onLog&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;任务结束：&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;$result&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (e: &lt;/span&gt;&lt;span&gt;Exception&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;onLog&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;运行错误：&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;e.message&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;finally&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (wakeLock.isHeld) wakeLock.&lt;/span&gt;&lt;span&gt;release&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;onFinish&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;而 &lt;code&gt;main.py&lt;/code&gt; 里接收到这个参数后，会写回同一个环境变量，&lt;code&gt;connection.py&lt;/code&gt;、&lt;code&gt;screenshot.py&lt;/code&gt;、&lt;code&gt;input.py&lt;/code&gt;、&lt;code&gt;device.py&lt;/code&gt; 里所有 &lt;code&gt;os.getenv(&quot;PHONE_AGENT_ADB_PATH&quot;, &quot;adb&quot;)&lt;/code&gt; 的调用就都会统一指向 &lt;code&gt;libadb.so&lt;/code&gt;，而不是系统里根本不存在的 &lt;code&gt;adb&lt;/code&gt; 命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;os.environ[&lt;/span&gt;&lt;span&gt;&quot;PHONE_AGENT_ADB_PATH&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; args.adb_path &lt;/span&gt;&lt;/span&gt;&lt;span&gt;or&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;adb&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;另外我还单独封装了一个 &lt;code&gt;Adb.kt&lt;/code&gt; 工具对象，用来处理无线连接、配对这类交互场景（比如输入配对码），逻辑上和 Python 侧是平行的两条调用链：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Adb&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ctx: &lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;args: &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&amp;gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;input: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;? &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;onLine: ((&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;) -&amp;gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;&lt;span&gt;)? &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; adbPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;File&lt;/span&gt;&lt;span&gt;(ctx.applicationInfo.nativeLibraryDir, &lt;/span&gt;&lt;span&gt;&quot;libadb.so&quot;&lt;/span&gt;&lt;span&gt;).absolutePath&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt;&lt;span&gt; process &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProcessBuilder&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;listOf&lt;/span&gt;&lt;span&gt;&lt;span&gt;(adbPath) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; args)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;redirectErrorStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;connect&lt;/span&gt;&lt;span&gt;(ctx: &lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span&gt;, addr: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, onLine: ((&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;) -&amp;gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;&lt;span&gt;)? &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt;(ctx, &lt;/span&gt;&lt;span&gt;listOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;connect&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;, addr), onLine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; onLine)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pair&lt;/span&gt;&lt;span&gt;(ctx: &lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span&gt;, addr: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, code: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, onLine: ((&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;) -&amp;gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;&lt;span&gt;)? &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt;(ctx, &lt;/span&gt;&lt;span&gt;listOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;pair&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;, addr), input &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; code, onLine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; onLine)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这样一来，“电脑上跑的 Python + 命令行 adb”这套控制系统，就被完整地搬进了一个安卓 APP 里：Chaquopy 用于跑 Python 逻辑，&lt;code&gt;libadb.so&lt;/code&gt; 冒充原生库绕过打包限制，&lt;code&gt;PHONE_AGENT_ADB_PATH&lt;/code&gt; 这个环境变量作为两边的”接口”，把 Python 里所有原本指向系统 &lt;code&gt;adb&lt;/code&gt; 命令的调用，重定向到了 APK 自己私有目录下的这个二进制文件上。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;后记&lt;a href=&quot;#后记&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这种项目本质上是把安卓系统上的操作截图让ai理解，然后&lt;strong&gt;返回相应的指令模拟人为的触屏操作&lt;/strong&gt;，这种方法过于低效，而且容易让ai陷入死循环，无法执行正确的决策。不过最新的安卓应用开发标准，已经支持应用对外暴露函数接口和方法让ai智能体直接调用，不需要模拟人为的触屏。相信不久的将来马上会出现更为高效的Ai控制手机的方案。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;项目地址&lt;a href=&quot;#项目地址&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/iliaoke/AutoGlm/tree/main&quot; target=&quot;_blank&quot;&gt;https://github.com/iliaoke/AutoGlm/tree/main&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>学习笔记 | 简单设计一个OAuth认证回调服务器</title><link>https://blog.liao-ke.com/posts/github-oauth-callback-worker/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/github-oauth-callback-worker/</guid><description>使用 Cloudflare Worker 实现一个无状态的 GitHub OAuth 回调服务器，完成 code 换取 access_token，并通过自定义 App Scheme 返回移动端，分析这种方案的实现原理、优缺点及适用场景。</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;暑假待在家里没得事做，想做一个移动端的博客写作客户端,由于我的博客内容是储存在github上的,所以在开发的过程中，我需要学习一下github OAuth认证流程。简单的了解了一下 github的OAuth认证流程大致是当用户认证成功之后，会下发一个code给认证地址,然后通过code和客户端id以及客户端密钥向github发起请求,便可以得到用户的access token。我一开始以为这个code到access token的流程必须要一个服务器才可以完成，但是突然想到这种流程化的事情，不需要保存状态的,像cloudflare worker这样的serverless平台,应该也可以办到,于是用cloudflare worker简单的做了一个认证回调服务器。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;代码&lt;a href=&quot;#代码&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;先解析 URL 上的参数:&lt;code&gt;code&lt;/code&gt;、&lt;code&gt;state&lt;/code&gt;,还有可能出现的 &lt;code&gt;error&lt;/code&gt;。这里有个容易漏掉的点——用户在授权页点”取消”的时候,GitHub 不会给 &lt;code&gt;code&lt;/code&gt;,而是直接带 &lt;code&gt;error=access_denied&lt;/code&gt; 跳回来,所以必须先判断 &lt;code&gt;errorParam&lt;/code&gt;,不然后面拿着空 &lt;code&gt;code&lt;/code&gt; 去请求 GitHub,只会得到一个莫名其妙的报错。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;errorParam&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;errorParam&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;errorDescription&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;拿到正常的 &lt;code&gt;code&lt;/code&gt; 之后,就是 POST 请求打到 &lt;code&gt;https://github.com/login/oauth/access_token&lt;/code&gt;,body 里带上 &lt;code&gt;client_id&lt;/code&gt;、&lt;code&gt;client_secret&lt;/code&gt;、&lt;code&gt;code&lt;/code&gt;、&lt;code&gt;redirect_uri&lt;/code&gt;,这一步是服务端对服务端换 token,&lt;code&gt;client_secret&lt;/code&gt; 只能放在这里,绝对不能出现在 App 里,不然反编译一下就全露了。这里踩了个小坑&amp;lt;请求头一定要加&amp;gt; &lt;code&gt;Accept: application/json&lt;/code&gt;,不加的话 GitHub 默认返回的是 &lt;code&gt;key=value&amp;amp;key2=value2&lt;/code&gt; 这种查询字符串格式,还得自己手动解析,挺麻烦的。&lt;/p&gt;&lt;p&gt;换完之后,不管是换 token 失败、GitHub 返回业务错误（比如 &lt;code&gt;bad_verification_code&lt;/code&gt;，也就是 code 过期或者已经被用过了）、还是成功拿到了 &lt;code&gt;access_token&lt;/code&gt;,最后都统一走 &lt;code&gt;redirectToApp&lt;/code&gt; 这一个函数 302 回 App:&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;params&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;APP_SCHEME&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Object&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;params&lt;/span&gt;&lt;span&gt;)) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;searchParams&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;redirect&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;302&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这样设计的好处是,App 那边只需要检查跳转回来的 URL 上有没有 &lt;code&gt;access_token&lt;/code&gt;,就能判断整个流程走没走通,完全不用关心中间到底是哪个环节出的问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;后记&lt;a href=&quot;#后记&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;弄完之后，才发现其实连服务器都不需要,浏览器是支持输入应用app scheme的,在浏览器通过这个跳转到应用内部，让应用接收code，然后在应用内部实现code转access token的过程。不过这样的话，就得把客户端id和客户端密钥写进应用内部，如果被人反编译出来，就会有密钥泄露的风险。而且如果是设计更复杂的应用，涉及到第三方账号的绑定，数据库的查询读写，这些操作都应该放到云端认证回调服务器上去执行，而不应该放在本地客户端里面。把认证回调服务器写成本地APP scheme这种方案只能临时用于没有服务器的情况，不能放在正式的生产环境。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;index.js&lt;a href=&quot;#indexjs&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* GitHub OAuth 回调 Worker（简化版，仅用于拿到 access_token）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 流程：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 1. App 用系统浏览器打开 GitHub 授权页&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*    https://github.com/login/oauth/authorize?client_id=...&amp;amp;redirect_uri=&amp;lt;本Worker的/callback地址&amp;gt;&amp;amp;scope=repo&amp;amp;state=xxx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 2. 用户同意后，GitHub 302 重定向到本 Worker 的 /callback，带上 code、state&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 3. 本 Worker 用 code 向 GitHub 换取 access_token（服务端对服务端，带 client_secret）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 4. 本 Worker 302 重定向到 App 的自定义 scheme，把 access_token 直接带回去&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*    myapp://oauth/callback?access_token=xxx&amp;amp;state=xxx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 5. App 拦截该 scheme，取出 access_token，存到本地安全存储，之后用它直接调 GitHub API&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 需要在 wrangler 中配置以下变量：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* - GITHUB_CLIENT_ID      GitHub OAuth App 的 Client ID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* - GITHUB_CLIENT_SECRET  GitHub OAuth App 的 Client Secret（用 secret 存储）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* - APP_SCHEME            App 自定义 scheme，例如 &quot;myapp://oauth/callback&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[REQUEST] &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pathname&lt;/span&gt;&lt;span&gt;}${&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;search&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;pathname&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;/callback&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;GET&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;handleCallback&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[REQUEST] 未匹配任何路由，返回默认响应`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;GitHub OAuth callback worker is running.&quot;&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;handleCallback&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;37&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;38&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;code&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;searchParams&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;code&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;39&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;searchParams&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;state&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;40&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;errorParam&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;searchParams&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;error&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;41&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;errorDescription&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;searchParams&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;error_description&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;42&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;43&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;44&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;`[CALLBACK] 收到回调参数: code=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;code&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;code&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;45&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;`state=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, error=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;errorParam&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;46&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;`error_description=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;errorDescription&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;47&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;48&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;49&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;// 用户在 GitHub 授权页点击了&quot;取消&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;50&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;errorParam&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;51&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[CALLBACK] 用户拒绝授权或GitHub返回错误: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;errorParam&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; - &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;errorDescription&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;52&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;53&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;errorParam&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;54&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;errorDescription&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;55&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;56&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;57&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;58&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;59&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;&lt;span&gt;code&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;60&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[CALLBACK] 缺少code参数，终止处理`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;61&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;缺少 code 参数&quot;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;400&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;62&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;63&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;64&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;65&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;66&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;`[TOKEN] 开始向GitHub换取access_token, client_id=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GITHUB_CLIENT_ID&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;, `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;67&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;`redirect_uri=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;origin&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/callback`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;68&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;69&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;70&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenRes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;https://github.com/login/oauth/access_token&quot;&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;71&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;POST&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;72&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;73&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;74&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;Accept&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;75&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;User-Agent&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;cloudflare-worker-github-oauth&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;76&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;77&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;78&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;client_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GITHUB_CLIENT_ID&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;79&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;client_secret&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GITHUB_CLIENT_SECRET&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;80&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;code&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;81&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;redirect_uri&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;origin&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/callback`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;82&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;83&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;84&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;85&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[TOKEN] GitHub token接口HTTP状态码: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenRes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;86&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;87&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;&lt;span&gt;tokenRes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;88&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;bodyText&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenRes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;89&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[TOKEN] 请求失败，响应体: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;bodyText&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;90&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;91&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;token_exchange_failed&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;92&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`GitHub token endpoint returned &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenRes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;93&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;94&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;95&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;96&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;97&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenRes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;98&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;99&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 注意：access_token 只打印前几位，避免完整token出现在日志里&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;100&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;101&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;`[TOKEN] GitHub返回内容: `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;102&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;`access_token=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;access_token&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;access_token&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;103&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;`scope=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;scope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;104&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;`token_type=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;token_type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;105&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;`error=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;, `&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;106&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;`error_description=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;107&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;108&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;109&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;110&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;// 常见：bad_verification_code（code过期/已用过）、incorrect_client_credentials（client_id或secret错）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;111&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[TOKEN] GitHub返回业务错误: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;112&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;113&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;114&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;115&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;116&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;117&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;118&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;119&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;access_token&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;120&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[TOKEN] 异常：GitHub未返回error，但也没有access_token`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;121&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;122&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;no_access_token&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;123&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;GitHub未返回access_token&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;124&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;125&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;126&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;127&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;128&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[TOKEN] 换取成功，即将302重定向回App`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;129&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;130&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 直接把 GitHub 的 access_token 带回 App&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;131&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 注意：GitHub 传统 OAuth App 签发的 token 默认长期有效，没有 refresh_token&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;132&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;133&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;access_token&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;access_token&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;134&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;scope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tokenData&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;scope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;135&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;136&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;137&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;138&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[ERROR] 处理过程中抛出异常: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stack&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stack&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;139&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;140&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;internal_error&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;141&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;error_description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;142&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;143&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;144&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;145&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;146&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;147&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;148&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* 把结果通过 302 重定向带回 App 自定义 scheme&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;149&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* env.APP_SCHEME 形如：&quot;myapp://oauth/callback&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;150&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;151&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;redirectToApp&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;params&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;152&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;APP_SCHEME&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;153&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Object&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;params&lt;/span&gt;&lt;span&gt;)) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;154&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;155&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;searchParams&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;156&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;157&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;158&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;159&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;// access_token 是敏感信息，日志里只打印前几位，避免完整token写入日志&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;160&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;loggedUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;161&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;/access_token=(&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;^&lt;/span&gt;&lt;span&gt;&amp;amp;]&lt;/span&gt;&lt;span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;)/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;162&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`access_token=&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;...`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;163&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;164&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`[REDIRECT] 302重定向回App: &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;loggedUrl&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;165&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;166&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;redirect&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;302&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;167&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;wrangler.toml&lt;a href=&quot;#wranglertoml&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;&apos;oauth-woker&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;&quot;index.js&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;compatibility_date&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;&quot;2026-07-24&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 非敏感变量可以直接写在这里&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;vars&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;APP_SCHEME&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;&quot;xxx://xx/xx&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 以下敏感信息不要写在 toml 里，改用 wrangler secret 命令设置：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;#&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;#   wrangler secret put GITHUB_CLIENT_ID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;#   wrangler secret put GITHUB_CLIENT_SECRET&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;#&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 设置后 Cloudflare 会加密存储，不会出现在代码仓库或部署日志中&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;observability&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;enabled&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;# 总开关必须是 true，下面的子配置才会生效&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;observability&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;logs&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;enabled&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;head_sampling_rate&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;invocation_logs&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;observability&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;traces&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;enabled&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;# 你现在确实不需要traces，关掉没问题&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content:encoded></item><item><title>学习笔记 | 头歌破解考试的防复制粘贴</title><link>https://blog.liao-ke.com/posts/educoder-anti-copy-paste-bypass/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/educoder-anti-copy-paste-bypass/</guid><description>从作业到考试，头歌（EduCoder）的防复制粘贴限制分别实现在配置层和事件层，记录一次逆向分析与油猴脚本破解过程。</description><pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate><content:encoded>本文已加密保护，请访问网站查看。</content:encoded></item><item><title>学习笔记 | 一次网页端逆向到 OpenAI 接口封装的完整过程</title><link>https://blog.liao-ke.com/posts/orchids-openai-proxy/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/orchids-openai-proxy/</guid><description>基于 Orchids 网页端会话链路做协议分析，复用既有鉴权与 SSE 数据流，封装出兼容 OpenAI API 的本地中转服务，并支持流式输出、思考模式与文件上传。</description><pubDate>Tue, 21 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;最近看到 &lt;a href=&quot;https://www.orchids.app&quot; target=&quot;_blank&quot;&gt;Orchids&lt;/a&gt; 给了免费的 Claude 和 GPT 额度，但它只提供网页端，没有开放后端 API。&lt;br /&gt;
我就做了一个小实验：不去改它服务端，只复用网页端已有调用链路，把能力封装成一个 &lt;strong&gt;OpenAI API 兼容网关&lt;/strong&gt;，方便接入各类客户端和工具链。&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;210&quot; height=&quot;327&quot; src=&quot;/_astro/1.BKWxusSM_1aaSNI.webp&quot; /&gt;
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;293&quot; height=&quot;109&quot; src=&quot;/_astro/2.BCHg8sUG_1jK7Iv.webp&quot; /&gt;&lt;/p&gt;&lt;p&gt;这个方案可以跑通，支持流式、思考模式和文件上传，但并不适合做高并发号池，额度和速率都受原平台会话机制限制。本文主要是技术复盘与工程总结。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;一、协议适配&lt;a href=&quot;#一协议适配&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这次的目标很明确：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;复用网页端已有会话与鉴权流程&lt;/li&gt;
&lt;li&gt;把上游 SSE 数据流转换成标准 OpenAI 返回结构&lt;/li&gt;
&lt;li&gt;对外暴露常见 OpenAI 接口，做到低改造接入&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;最终本地服务提供了这些路由：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /health&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/models&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /v1/chat/completions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /v1/responses&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /v1/files&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/files&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/files/{file_id}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/files/{file_id}/content&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /v1/files/{file_id}/url&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /v1/files/{file_id}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;二、链路分析：从网页请求里抽象最小参数集&lt;a href=&quot;#二链路分析从网页请求里抽象最小参数集&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在网页端实际请求里，可以定位到这几个关键参数：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;clerk_active_context&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;projectId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;userId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__client&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;其中：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;projectId&lt;/code&gt; 来自对话创建后的项目上下文&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clerk_active_context&lt;/code&gt; 与 &lt;code&gt;__client&lt;/code&gt; 用于会话鉴权&lt;/li&gt;
&lt;li&gt;&lt;code&gt;userId&lt;/code&gt; 用于拼接上游请求体&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这四个参数就是整个中转服务的最小可用配置。程序启动时交互输入，避免硬编码到源码里。&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1035&quot; height=&quot;496&quot; src=&quot;/_astro/3.BPPPOOQw_Z1hUB2b.webp&quot; /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;三、程序架构&lt;a href=&quot;#三程序架构&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1) 配置与服务启动&lt;a href=&quot;#1-配置与服务启动&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;服务启动后读取配置并初始化两个 HTTP Client：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;jwtClient&lt;/code&gt;：用于向 Clerk 换取 JWT&lt;/li&gt;
&lt;li&gt;&lt;code&gt;upstreamClient&lt;/code&gt;：用于请求 Orchids 的 &lt;code&gt;stream-run&lt;/code&gt; SSE 接口&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;同时挂载 OpenAI 风格路由，作为统一入口。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2) 鉴权流程&lt;a href=&quot;#2-鉴权流程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;核心流程是：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;调用 Clerk token 接口（带 &lt;code&gt;__client&lt;/code&gt; Cookie）&lt;/li&gt;
&lt;li&gt;获取临时 JWT&lt;/li&gt;
&lt;li&gt;用 JWT 访问上游推理 SSE&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;也就是说，本地网关没有伪造新鉴权体系，而是复用了网页端已有会话链路。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3) 上游请求与容错&lt;a href=&quot;#3-上游请求与容错&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;上游请求采用以下策略：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Authorization: Bearer &amp;lt;jwt&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Accept: text/event-stream&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;网络可重试错误自动重试一次&lt;/li&gt;
&lt;li&gt;失败时返回清晰错误（包含状态码与上游响应）&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这块是工程稳定性的关键，不然很容易因为临时网络抖动导致误判不可用。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;四、协议转换：把 Orchids SSE 映射成 OpenAI 语义&lt;a href=&quot;#四协议转换把-orchids-sse-映射成-openai-语义&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;上游事件流里主要有三类信息：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;文本增量（&lt;code&gt;text_delta&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;思考增量（&lt;code&gt;thinking_delta&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;最终结果与 usage&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;程序分两套解析逻辑：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;parseOrchidsSSEForFinalResult&lt;/code&gt;：非流式聚合&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parseOrchidsSSEStream&lt;/code&gt;：流式逐段回传&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;再映射为：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Chat Completions：&lt;code&gt;chat.completion&lt;/code&gt; / &lt;code&gt;chat.completion.chunk&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Responses API：&lt;code&gt;response.output_text.delta&lt;/code&gt; / &lt;code&gt;response.completed&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;并且 reasoning 开关打开时，会把 thinking 内容透传到对应字段，保证“思考模式”可用。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;五、文件能力：兼容 OpenAI Files 接口&lt;a href=&quot;#五文件能力兼容-openai-files-接口&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;除了聊天接口，程序还实现了文件链路：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;POST /v1/files&lt;/code&gt; 接收 multipart 文件上传&lt;/li&gt;
&lt;li&gt;本地落盘并生成 &lt;code&gt;file-xxxx&lt;/code&gt; 形式的 file_id&lt;/li&gt;
&lt;li&gt;在消息输入中提取 &lt;code&gt;input_file&lt;/code&gt; 的 &lt;code&gt;file_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;映射为上游可访问的 &lt;code&gt;attachmentUrls&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;这意味着可以兼容部分依赖 Files API 的客户端工作流，而不只是纯文本对话。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;六、支持模型&lt;a href=&quot;#六支持模型&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;当前版本内置模型列表如下：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;claude-sonnet-4-6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gpt-5.4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gpt-5.3-codex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;claude-opus-4.6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;claude-opus-4.5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gpt-5.2-codex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gpt-5.2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gemini-3-flash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gemini-3-pro&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gemini-3.1-pro&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;可通过 &lt;code&gt;GET /v1/models&lt;/code&gt; 查询。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;七、实际体验与边界&lt;a href=&quot;#七实际体验与边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这个方案的优点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;对接现有 OpenAI 生态方便&lt;/li&gt;
&lt;li&gt;协议统一后可被多数工具直接消费&lt;/li&gt;
&lt;li&gt;流式和 reasoning 都可跑通&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;但边界也很明显：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;依赖网页会话参数，稳定性受平台变更影响&lt;/li&gt;
&lt;li&gt;额度和速度都不适合当号池&lt;/li&gt;
&lt;li&gt;上游接口一旦改字段，网关要同步维护&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;所以它更适合作为逆向与协议适配实践，而不是生产级高可用方案。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;其实本质上是：&lt;br /&gt;
&lt;strong&gt;把“网页端调用流程”重构成“标准 API 服务”。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;从工程角度看，真正有价值的是：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;能否抽象出最小参数集&lt;/li&gt;
&lt;li&gt;能否稳定解析 SSE 并保持语义一致&lt;/li&gt;
&lt;li&gt;能否用统一接口服务不同客户端&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;如果只是临时脚本，那是一次调用；&lt;br /&gt;
完成了协议映射、错误模型和流式对齐，才算一个可复用的接口封装方案。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;程序下载链接：&lt;br /&gt;
&lt;a href=&quot;https://www.123865.com/s/vxarVv-o7yHH&quot; target=&quot;_blank&quot;&gt;https://www.123865.com/s/vxarVv-o7yHH&lt;/a&gt;&lt;/p&gt;&lt;p&gt;仅用于学习逆向、协议理解和网关设计；&lt;br /&gt;
如果想直接拿来做业务化池子，建议降低预期。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>开发日记 | Page-agent项目改进</title><link>https://blog.liao-ke.com/posts/pageagent/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/pageagent/</guid><pubDate>Sun, 14 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;有一次在&lt;a href=&quot;https://linux.do&quot; target=&quot;_blank&quot;&gt;linux.do&lt;/a&gt;上逛的时候,发现了一个有趣的项目(&lt;a href=&quot;https://alibaba.github.io/page-agent/docs/introduction/quick-start&quot; target=&quot;_blank&quot;&gt;page-agent&lt;/a&gt;),可以用自然语言让ai控制网页，不像传统的自动化网页方案，需要利用Python使用有头或者无头浏览器之类的。这个项目直接是作为js脚本，直接可以嵌入或hook在浏览器中,不需要依赖Python或者其他的东西,更简单易用，好上手。
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2556&quot; height=&quot;1342&quot; src=&quot;/_astro/1.Bhw3m5iz_1vj0Q8.webp&quot; /&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;思考&lt;a href=&quot;#思考&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;不过很可惜，原项目是完全基于网页dom文本化的操作方案，网页上的图片信息并不会输出在给ai的文本信息里面，也就是说无法识别网页图片，并且在在网页的文字识别上也加了很多限制，有时候有一些网站的有效信息无法被正常识别。于是乎我想研究一下，看一下能不能在原项目的基础上，让它支持识别图片，并且可以识别更多的网页文字。在经过几天的努力，也是终于把这两个问题给搞定了。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;改进方法&lt;a href=&quot;#改进方法&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;一、让 AI 识别图片：将图片链接注入 DOM 树&lt;a href=&quot;#一让-ai-识别图片将图片链接注入-dom-树&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;原项目在生成 DOM 树字符串时，默认的属性白名单 &lt;code&gt;r&lt;/code&gt; 中 &lt;strong&gt;不包含 &lt;code&gt;src&lt;/code&gt;&lt;/strong&gt;，因此 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 标签的链接不会传递给 AI。此外，图片元素通常不被标记为“可交互”，导致其属性在 &lt;code&gt;F()&lt;/code&gt; 函数中根本不会被提取。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;修改步骤&lt;/strong&gt;：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;将 &lt;code&gt;src&lt;/code&gt; 加入属性白名单&lt;/strong&gt;&lt;br /&gt;
在 &lt;code&gt;flatTreeToString&lt;/code&gt; 函数的开头，&lt;code&gt;r&lt;/code&gt; 数组中添加 &lt;code&gt;&apos;src&apos;&lt;/code&gt;，这样 &lt;code&gt;src&lt;/code&gt; 属性就会在 &lt;code&gt;matchAttributes&lt;/code&gt; 中被匹配并输出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;在 &lt;code&gt;dom_tree_default&lt;/code&gt; 的 &lt;code&gt;F()&lt;/code&gt; 函数中手动提取 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 的属性&lt;/strong&gt;&lt;br /&gt;
原代码只有满足 &lt;code&gt;k(e)&lt;/code&gt;（交互元素）或 &lt;code&gt;iframe&lt;/code&gt;/&lt;code&gt;body&lt;/code&gt; 的元素才会提取属性。我们在 &lt;code&gt;F()&lt;/code&gt; 中增加一个分支：当 &lt;code&gt;e.tagName.toLowerCase() === &apos;img&apos;&lt;/code&gt; 时，手动将其所有属性复制到 &lt;code&gt;r.attributes&lt;/code&gt; 对象中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;在 &lt;code&gt;flatTreeToString&lt;/code&gt; 中为 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 特殊输出&lt;/strong&gt;&lt;br /&gt;
在 &lt;code&gt;u()&lt;/code&gt; 函数中，当遇到 &lt;code&gt;e.tagName === &apos;img&apos;&lt;/code&gt; 时，直接输出 &lt;code&gt;&amp;lt;img src=&quot;...&quot; alt=&quot;...&quot; /&amp;gt;&lt;/code&gt; 格式，并附带 &lt;code&gt;[图片链接: ...]&lt;/code&gt; 标记，便于 AI 识别。为了避免输出 &lt;code&gt;data:image&lt;/code&gt; 等内嵌图片，用正则过滤掉 Base64 链接。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;效果&lt;/strong&gt;：&lt;br /&gt;
AI 收到的 &lt;code&gt;&amp;lt;browser_state&amp;gt;&lt;/code&gt; 中会出现如 &lt;code&gt;[图片链接: https://example.com/photo.jpg]&lt;/code&gt; 的信息，AI 知道这是一张图片，可以调用后续的工具来识别。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;二、突破文字识别限制：移除文本节点的可见性过滤&lt;a href=&quot;#二突破文字识别限制移除文本节点的可见性过滤&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;原项目对文本节点的输出设有多重限制：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;l(e)&lt;/code&gt; 检查：若文本位于可交互元素内部则跳过。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isTopElement&lt;/code&gt; 检查：只有父元素是“顶层元素”（未被遮挡、不在视口外）时才输出。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isVisible&lt;/code&gt; 检查：父元素必须可见（&lt;code&gt;offsetWidth/Height &amp;gt; 0&lt;/code&gt; 且 CSS 未隐藏）。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这些限制导致许多嵌套较深或位置特殊的文本（如 Monaco 编辑器内的代码、被 &lt;code&gt;overflow: hidden&lt;/code&gt; 包裹的内容）无法被 AI 读取。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;修改步骤&lt;/strong&gt;：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;移除 &lt;code&gt;l(e)&lt;/code&gt; 检查&lt;/strong&gt;：在 &lt;code&gt;flatTreeToString&lt;/code&gt; 中删除 &lt;code&gt;if (l(e)) return;&lt;/code&gt; 这一行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;移除 &lt;code&gt;isTopElement&lt;/code&gt; 检查&lt;/strong&gt;：将文本输出的条件从 &lt;code&gt;e.parent.isTopElement&lt;/code&gt; 改为直接忽略，只保留 &lt;code&gt;e.parent.isVisible&lt;/code&gt;（或完全去掉，保留所有可见文本）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;放宽 &lt;code&gt;x(e)&lt;/code&gt; 函数&lt;/strong&gt;：在 &lt;code&gt;dom_tree_default&lt;/code&gt; 中，将 &lt;code&gt;x(e)&lt;/code&gt; 改为始终返回 &lt;code&gt;true&lt;/code&gt;，让所有文本节点都被视为可见，不会被丢弃。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可选：移除 &lt;code&gt;C(e)&lt;/code&gt; 中的尺寸检查&lt;/strong&gt;：如果希望进一步解除限制，可将 &lt;code&gt;C(e)&lt;/code&gt; 中的 &lt;code&gt;offsetWidth &amp;gt; 0 &amp;amp;&amp;amp; offsetHeight &amp;gt; 0&lt;/code&gt; 条件改为始终 &lt;code&gt;true&lt;/code&gt;，但这会导致大量不可见元素被纳入，建议谨慎。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;效果&lt;/strong&gt;：&lt;br /&gt;
现在几乎所有可见的文本节点都会被输出，包括代码编辑器内部的代码、被遮挡的说明文字、侧边栏小字等。AI 的上下文信息量显著增加，但同时 token 消耗也会上升，可根据实际场景调整。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;三、让 AI 自主调用图片识别工具&lt;a href=&quot;#三让-ai-自主调用图片识别工具&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;仅让 AI “看到”图片链接还不够，还需要让它能够&lt;strong&gt;理解图片内容&lt;/strong&gt;。我们增加一个自定义工具 &lt;code&gt;recognize_image&lt;/code&gt;，AI 可以调用它来识别指定 URL 的图片，并将结果写回图片的 &lt;code&gt;alt&lt;/code&gt; 属性。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;工具定义&lt;/strong&gt;（使用 Zod 进行参数校验）：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;recognize_image&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;识别指定 URL 的图片内容，将识别结果写入该图片的 alt 属性，并返回描述文本。&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;inputSchema&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;z&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;imageUrl&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;z&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;signal&lt;/span&gt;&lt;span&gt; }) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;imageUrl&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 优先尝试直接使用 URL，失败则转换为 Base64&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 调用视觉 API（如 Qwen-VL、GPT-4V 等）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;...&apos;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// 从 API 响应中提取描述&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// 查找页面中对应的 img 元素，写入 alt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;document&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`img[src=&quot;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;imageUrl&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;]`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;alt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`图片识别完成，描述为：“&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;”`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;于是乎，在经过了以上这些操作，成功让原项目支持了图片识别以及解除了一些网页文字识别的限制。以下是我改进版的仓库地址
&lt;a href=&quot;https://github.com/iliaoke/page-agent&quot; target=&quot;_blank&quot;&gt;https://github.com/iliaoke/page-agent&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>随笔杂谈 | 我的第一个开源 PR：适配 APatch 的 gbl_root_canoe 兼容性修复</title><link>https://blog.liao-ke.com/posts/first-open-source-pr/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/first-open-source-pr/</guid><description>记录在一加15T上折腾ESP分区漏洞Root方案时，发现模块在APatch上WebUI初始化失败的问题，通过阅读源码定位原因并提交修复，完成了自己的第一个开源项目Pull Request。</description><pubDate>Sun, 24 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在我初中接触Github并逐渐了解之后，我一直也想为开源社区做份贡献，也想给项目提交Pr。不过受限于自己的技术力还不够，也没有足够的时间与精力，以及合适的项目与机会。不过这个想法一直扎根在我的心头。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;机会&lt;a href=&quot;#机会&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在上了大学之后，我换了新手机一加15T，芯片骁龙8 Elite5。而在这一代手机刚好引入了esp分区，而且由于高通的疏忽，没有验证esp分区，导致部分版本的系统可以执行任意efi底层代码，于是便有了这个&lt;a href=&quot;https://github.com/superturtlee/gbl_root_canoe&quot; target=&quot;_blank&quot;&gt;项目&lt;/a&gt;。简单来说，这个项目可以在手机启动前无论手机有没有解锁bl，都返回bl已经上锁的信息，来通过手机的keystore效验。于是我尝试了这个项目的magisk模块，但是在&lt;a href=&quot;https://blog.liao-ke.com/p/android-root/&quot;&gt;APatch&lt;/a&gt;上发现模块的WebUI无法初始化成功。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;解决&lt;a href=&quot;#解决&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;于是乎，我翻了一下&lt;a href=&quot;https://blog.liao-ke.com/p/android-root/&quot;&gt;APatch&lt;/a&gt;和这个&lt;a href=&quot;https://github.com/superturtlee/gbl_root_canoe/blob/main/targets/magisk_module/module/webroot/app.js&quot; target=&quot;_blank&quot;&gt;项目&lt;/a&gt;的源代码，我发现了问题的原因，这个项目模块在初始化的时候会调用KSU里面内置的一些函数方法，但是&lt;a href=&quot;https://blog.liao-ke.com/p/android-root/&quot;&gt;APatch&lt;/a&gt;并没有内置这个方法函数，所以会导致在&lt;a href=&quot;https://blog.liao-ke.com/p/android-root/&quot;&gt;APatch&lt;/a&gt;上面，这个模块会初始化失败，于是乎，我改了一下&lt;a href=&quot;https://github.com/superturtlee/gbl_root_canoe/blob/main/targets/magisk_module/module/webroot/app.js&quot; target=&quot;_blank&quot;&gt;项目&lt;/a&gt;的源代码，当检测到没有这个方法函数的时候，将会采取手动历遍，并且返回相对应的数据结构的方法来兼容&lt;a href=&quot;https://blog.liao-ke.com/p/android-root/&quot;&gt;APatch&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;灵机一动&lt;a href=&quot;#灵机一动&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;当我完成了以上事宜之后，突然想到，我做的这些不正好可以提交一个Pr来改进项目吗？于是乎抱着坎坷的心情，我提交了我第1个&lt;a href=&quot;https://github.com/superturtlee/gbl_root_canoe/pull/44#event-25855613583&quot; target=&quot;_blank&quot;&gt;Pr&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;结果&lt;a href=&quot;#结果&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在怀着坎坷的心情等了几天之后，原作者受理并成功通过了我的PR请求，这次经历无疑是圆了我初中时一直有的一个愿望。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>学习笔记 | 最简单的绕过校园网多设备热点检测方案</title><link>https://blog.liao-ke.com/posts/bypass-campus-wifi/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/bypass-campus-wifi/</guid><description>通过 tun 虚拟网卡与网络共享手动指定热点上级网卡，绕过校园网热点设备数检测</description><pubDate>Mon, 09 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;弄到了一个白嫖的校园网账号,但是触发设备连接上限了(电脑只要开热点，wifi就无法访问互联网),我手机电脑无法同时连接,于是便有了接下来这篇教程&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;原因解析&lt;a href=&quot;#原因解析&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;当电脑连接WIFI的时候,网络适配器中的wlan网卡便是已连接的状态&lt;/li&gt;
&lt;li&gt;此时我们打开热点,在网络适配器中会自动创建一个新的本地连接的网卡&lt;/li&gt;
&lt;li&gt;在默认情况下,热点的网卡会自动寻找可以访问互联网的网卡，作为上级网卡.&lt;/li&gt;
&lt;li&gt;但是由于校园网有检测,当热点网卡的流量转发到wlan时,校园网就会检测到有多个设备，从而断开访问
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2536&quot; height=&quot;1021&quot; src=&quot;/_astro/1.Bu9y58EQ_1o6Lew.webp&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;解决方法&lt;a href=&quot;#解决方法&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;通过手动设置热点网卡的上级网卡到其他的网卡,然后其他网卡的流量(经过这个网卡，对流量进行处理)再流入wlan,这样便不会被校园网检测.&lt;/li&gt;
&lt;li&gt;于是我们便要用到clash/singbox这样的代理工具的tun模式创造另外一个网卡(其实也可以用wintun驱动手动创建,不过得手动配置一些东西，比较麻烦)
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2524&quot; height=&quot;1522&quot; src=&quot;/_astro/4.B6jJdMyP_1gjzNJ.webp&quot; /&gt;&lt;/li&gt;
&lt;li&gt;不一定需要添加clash的代理配置文件,只要打开tun模式即可.&lt;/li&gt;
&lt;li&gt;此时网络适配器中将会多出一张其他的网络设备
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2536&quot; height=&quot;1279&quot; src=&quot;/_astro/2.C1_-sxVc_1umMY0.webp&quot; /&gt;&lt;/li&gt;
&lt;li&gt;此时右击该网卡属性点击共享，然后设置共享的网络为本地连接(相当手动指定热点的上级网络),便可以实现绕过校园网检测
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2548&quot; height=&quot;1455&quot; src=&quot;/_astro/3.CJUm1Ihm_1pM0Pr.webp&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;</content:encoded></item><item><title>学习笔记 | openwrt25.10设置vlan实现单线复用</title><link>https://blog.liao-ke.com/posts/openwrt-vlan/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/openwrt-vlan/</guid><description>通过在光猫、主路由与房间子路由三端统一配置vlanid，实现桥接模式下的单线复用，让光猫其他网口/房间网口也能正常获取主路由DHCP下发的IP，并给出openwrt25.10的配置步骤与注意事项。</description><pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;原理解析&lt;a href=&quot;#原理解析&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;(特别注意&amp;lt;有一些路由器的系统是不支持设置vlanid的&amp;gt;,所以建议所有路由器都为openwrt软路由，方便操作.)&lt;/p&gt;&lt;p&gt;在传统方案中,当光猫设置&lt;strong&gt;桥接模式&lt;/strong&gt;,软路由负责拨号,此时光猫的其他网口在正常情况下是无法工作的,因为光猫此时只做光电转换，不做路由ip下发.&lt;/p&gt;&lt;p&gt;此时我们便需要用到一项技术实现光猫在桥接模式下光猫的其他网口也能正常工作.这便是&lt;strong&gt;vlanid&lt;/strong&gt;.vlanid并不只有&lt;strong&gt;单线复用&lt;/strong&gt;这一个功能,它也可以用来划分局域网,从本质上来讲，它的作用就是给流量打上标记.&lt;/p&gt;&lt;p&gt;当光猫桥接主路由拨号时,其他房间网口的流量是流向光猫的网口,在流量没有打&lt;strong&gt;vlanid&lt;/strong&gt;标识的情况下，光猫也不知道要把这些流量弄到哪里去,所以光猫其他网口便无法正常通讯.&lt;/p&gt;&lt;p&gt;所以这个时候我们便用&lt;strong&gt;vlanid&lt;/strong&gt;来实现&lt;strong&gt;单线复用&lt;/strong&gt;(&lt;strong&gt;即一条网线，负责实现两个功能,也就是说我们主路由与光猫连接的那根网线既负责主路由的拨号，又负责主路由dhcp服务器下发ip到光猫的其他网口&lt;/strong&gt;),我们在其他网口的房间里的路由器里面设置&lt;strong&gt;vlanid&lt;/strong&gt;,然后在光猫的管理员后台里也设置的&lt;strong&gt;vlanid&lt;/strong&gt;,最后在主路由里面设置一样的&lt;strong&gt;vlanid&lt;/strong&gt;.就这样在三台设备中都设置了&lt;strong&gt;vlanid&lt;/strong&gt;,设备就知道这些流量该如何传输.&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;具体操作&lt;a href=&quot;#具体操作&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在房间的子路由中把&lt;strong&gt;wan接口删除&lt;/strong&gt;,只留lan口,然后在设备中添加连接网线的网口的vlan设备,然后把这个设备添加到&lt;strong&gt;br-lan&lt;/strong&gt;的网桥设备集合之中
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2383&quot; height=&quot;991&quot; src=&quot;/_astro/1.J30e56H1_Z105urz.webp&quot; /&gt;
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2281&quot; height=&quot;1236&quot; src=&quot;/_astro/2.YPhIfmZg_ZviXXm.webp&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在光猫的管理员后台(&lt;strong&gt;不同的型号的光猫进入管理员后台的方法不同，有一些甚至进不去管理员后台，这里就不细讲了&lt;/strong&gt;),把对应连接方式的lan口绑定全部取消,然后设置对应网口的&lt;strong&gt;vlanid和vlan绑定&lt;/strong&gt;
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1228&quot; height=&quot;985&quot; src=&quot;/_astro/3.CFXcMmDn_24uRKX.webp&quot; /&gt;
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1219&quot; height=&quot;998&quot; src=&quot;/_astro/4.DXqJFPL7_ZcLKtd.webp&quot; /&gt;
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;1180&quot; src=&quot;/_astro/5.DrBrQrGh_22cd5M.webp&quot; /&gt;
以上这张图中，网络连接二是用于主路由和光猫拨号的，而网络连接五则是用于设置vlanid来实现单线复用的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在主路由进行和子路由中一样的操作,只是这一次不用把wan口删除了,把wan口对应的连接端口设置&lt;strong&gt;vlanid&lt;/strong&gt;,然后也一并添加到&lt;strong&gt;br-lan&lt;/strong&gt;中即可完成配置
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2553&quot; height=&quot;1320&quot; src=&quot;/_astro/6.2Nt2Jjm6_Z1X1Eon.webp&quot; /&gt;
&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;2553&quot; height=&quot;1351&quot; src=&quot;/_astro/7.BvTVToMy_Z1dovC6.webp&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;完成了以上三个步骤,就可以实现光猫在&lt;strong&gt;桥接模式&lt;/strong&gt;下，房间的子路由仍然可以接收到主路由下发的ip了&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>方案分析 | 2026年软路由系统分析和推荐</title><link>https://blog.liao-ke.com/posts/routeros-choose/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/routeros-choose/</guid><description>2026年软路由系统分析和推荐，涵盖openwrt系、ikuai、RouterOS的对比与分支选择建议。</description><pubDate>Wed, 18 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;2026年软路由系统分析和推荐&lt;a href=&quot;#2026年软路由系统分析和推荐&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;截止到目前为止,还在持续维护更新的软路由系统有&lt;code&gt;openwrt&lt;/code&gt;系,&lt;code&gt;ikuai&lt;/code&gt;,&lt;code&gt;RouterOS&lt;/code&gt;.&lt;/p&gt;&lt;section&gt;&lt;h3&gt;三大系统简述&lt;a href=&quot;#三大系统简述&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ikuai系统&lt;/strong&gt;不开源,可玩性和软件生态上比openwrt和RouterOS差,但是稳定,适用于对稳定性和兼容性要求比较高的工作环境，比如说企业.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routeros系统&lt;/strong&gt;是开源的,基于linux,但是软件生态和可玩性也不如openwrt,Linux内核版本也较低,主打的也是偏稳定向的.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;openwrt系统&lt;/strong&gt;是开源的,相当于阉割魔改版之后的linux（linux可以干的,openwrt通过补全环境和其他方法，基本都可以干,如docker,php,python等）,且积极更新Linux内核和对应s组件依赖,社区力量和软件包是远远大于另外两个软路由系统的,由于openwrt系统非常轻量，所以适配的硬件特别广.而另外两个软路由系统对硬件的要求多相对较高,而openwrt各种嵌入式设备也可以刷入,很多厂商的硬路由openwrt也会适配.所以对于个人玩家来说,强烈推荐openwrt系.&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;openwrt系分支&lt;a href=&quot;#openwrt系分支&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;而openwrt系又主要分&lt;code&gt;openwrt官方系统&lt;/code&gt;,&lt;code&gt;immortalwrt&lt;/code&gt;,&lt;code&gt;kwrt&lt;/code&gt;,&lt;code&gt;lead&lt;/code&gt;,&lt;code&gt;x-wrt&lt;/code&gt;,&lt;code&gt;istoreos&lt;/code&gt;&lt;/p&gt;&lt;section&gt;&lt;h4&gt;openwrt官方系统:&lt;a href=&quot;#openwrt官方系统&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;是所有其他分支的源头，更新速度最快,但是软件包源服务器是在国外，国内用户无法直接更新里面的软件包,而且官方服务器里面的软件包数量很少.&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;immortalwrt:&lt;a href=&quot;#immortalwrt&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;基于openwrt源代码轻量改动,可以看成openwrt中国特供版,而且极大的丰富了软件包数量,有很多github上面的第三方的软件包，以及把软件包服务器改成了在国内,还有一些其他的优化以及添加了更多的硬件支持,但是每当openwrt新的版本出来,immortalwrt需要过一小段时间才能适配完&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;kwrt:&lt;a href=&quot;#kwrt&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;基于openwrt,可以看成在openwrt源代码的基础上，自己写了一套代码流程来自定义一些东西,有自己自建的软件仓库,里面软件的数量是openwrt系里面最多的,构建系统镜像的时候还可以提前自定义后台IP地址，宽带账号之类的东西,但是魔改的比较多，特别容易出bug（比如我的r2s固件直接开不了机）,而且这个系统作者的名声在圈内不太好,合并上游系统速度还算及时(immortal需要一点时间)&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;lede:&lt;a href=&quot;#lede&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;准确来说是lean的lede,最原始的lede是openwrt里面分出来，后面又重新与openwrt合并,而github上面的lede是lean(作者)基于最后的lede源代码的个人维护版本,也就是说基于的openwrt主线版本已经十分老旧了,这个系统的优点是有一些闭源驱动，性能非常强大,但由于已经和新版的openwrt代码相差很大，所以很多软件包已经不兼容了.&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;x-wrt:&lt;a href=&quot;#x-wrt&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;基于openwrt的主线分支(不是release分支),所以代码更新速度很快,有自己的软件仓库，国内用户可以直连,相对于官方的系统，已经内置集成的一些功能&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;istoreos:&lt;a href=&quot;#istoreos&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;基于openwrt以前的分支,一般不会基于最新的主线分支，一般会隔一两个大版本,有自己的软件源，国内用户可直接连,主要就是ui和功能改动,openwrt官方系统或其他分支系统也可以安装istoreos的软件包来实现成istoreos的ui和功能.主打的是将路由器和nas结合，里面内置了很多跟nas有关的功能。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;结论&lt;a href=&quot;#结论&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;综上所述目前软路由系统，我个人推荐openwrt系,openwrt系里面结合更新速度和软件包数量以及稳定性,lede基于的主线版本太老,istoreos更新上游的速度较慢,kwrt魔改openwrt有点多(不是基于源代码魔改),稳定性较差.x-wrt特色不是很强,所以我个人综合起来更推荐immortalwrt&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>方案分析 | 我对几种LLM扩展工具的区别与使用心得</title><link>https://blog.liao-ke.com/posts/llm-tool-calls/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/llm-tool-calls/</guid><description>从“LLM 只能决策不能执行”出发，对 Tool Calls、MCP、Skills 三种扩展方式的调用链路、桥接成本与上下文风险做对比，并给出适用场景与个人取舍。</description><pubDate>Mon, 02 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;关于LLM的几种工具扩展方法的区别和见解&lt;a href=&quot;#关于llm的几种工具扩展方法的区别和见解&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;LLM本身只能当做&lt;strong&gt;聊天对话机器&lt;/strong&gt;,他只可以接收对话，然后返回回答,本身是&lt;strong&gt;不能干任何额外的事情&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;我们使用ai的一些扩展功能，比如联网搜索和其他的工具本质上是让&lt;strong&gt;AI返回指定参数&lt;/strong&gt;,&lt;strong&gt;交由外部工具去完成&lt;/strong&gt;,然后在拿&lt;strong&gt;外部工具执行到的信息作为上下文&lt;/strong&gt;,再返回给AI,&lt;strong&gt;llm只是决策者而并非执行者&lt;/strong&gt;,&lt;strong&gt;工具真正的逻辑执行部分和判断部分需要人为的完成&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;而市面上主流的LLM主要有以下几种方法扩展工具&lt;/p&gt;&lt;section&gt;&lt;h3&gt;1.Tool Calls(很少使用)&lt;a href=&quot;#1tool-calls很少使用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;这个是一些大语言模型本身自带的功能,可以让用户&lt;strong&gt;自定义一段工具介绍&lt;/strong&gt;，然后让LLM在适当的时候&lt;strong&gt;返回工具调用的结构体&lt;/strong&gt;,然后由用户&lt;strong&gt;解析结构体执行程序&lt;/strong&gt;之后，再返回获取到的结果来完善上下文&lt;/p&gt;&lt;p&gt;&lt;strong&gt;缺点:&lt;/strong&gt;
LLM和工具的衔接部分&lt;strong&gt;需要自己人为书写&lt;/strong&gt;,比如需要&lt;strong&gt;判断LLM有没有返回工具调用信息&lt;/strong&gt;,如果返回了，要根据返回的信息进行选择调用,&lt;strong&gt;写的工具越复杂&lt;/strong&gt;，衔接部分需要花费的时间就越大,并且不同的模型的Tool Calls返回的信息可能还有所不同，&lt;strong&gt;不同模型的Tool Calls标准不一样，同一个工具需要对不同的模型单独做适配&lt;/strong&gt;,所以并不流行(不过算是最早的给llm扩展工具的方法)&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2.Mcp(流行)&lt;a href=&quot;#2mcp流行&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;这是一套&lt;strong&gt;严格的标准&lt;/strong&gt;,不会像Tool Calls一样可能因为模型的问题，返回的结构体有所差异,有&lt;strong&gt;mcp客户端&lt;/strong&gt;,还有&lt;strong&gt;mcp服务器&lt;/strong&gt;,工具的连接方式有&lt;strong&gt;远程&lt;/strong&gt;，也有&lt;strong&gt;本地调用&lt;/strong&gt;,是一套很完善的规则.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;缺点:&lt;/strong&gt;
因为&lt;strong&gt;调用流程过于严谨和繁琐&lt;/strong&gt;,所以很容易引起&lt;strong&gt;llm上下文直接爆炸&lt;/strong&gt;,让llm抓不到重点,对话越到后面效果越差。&lt;strong&gt;部署和开发也相对麻烦&lt;/strong&gt;,因为有服务端，客户端，还有一些七七八八.而Tool Calls,可以直接在一个片段代码里面完成开发.&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3.Skills(流行)&lt;a href=&quot;#3skills流行&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;这个是最近claude推出,我对他的理解是&lt;strong&gt;最高级别的prompt&lt;/strong&gt;,这个严格来说&lt;strong&gt;并不是一个标准,而是共识&lt;/strong&gt;,更偏向于一个技术理念,&lt;strong&gt;需要IDE自己去实现这个理念（&lt;a href=&quot;https://github.com/anthropics/skills&quot; target=&quot;_blank&quot;&gt;Claude开源了他们官方skills的实现&lt;/a&gt;）&lt;/strong&gt;,不像mcp和Tool Calls是有一定的标准的,要严格按照官方的标准来。&lt;/p&gt;&lt;p&gt;Skills某种程度上来说和Tool Calls有点类似,但是&lt;strong&gt;他不需要写LLM和工具之间的桥接代码&lt;/strong&gt;,并且还可以完成一些prompt才可以做的事，比如说&lt;strong&gt;自定义一下语气和注意事项&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Tool Calls每写一个工具，我需要自己再写程序去判断LLM返回的工具调用信息，然后再去执行运算(并且还可能因为不同的模型返回的信息有差异而导致兼容性问题),&lt;strong&gt;而放到Skills&lt;/strong&gt;,我只需要&lt;strong&gt;自定义一段话&lt;/strong&gt;,&lt;strong&gt;不需要写具体的代码&lt;/strong&gt;(工具本身是要写代码的，只是&lt;strong&gt;调用不需要写代码&lt;/strong&gt;),比如在特定的时候执行某个文件目录下面的某个代码片段传入某些参数,相当于把&lt;strong&gt;桥接部分交由了程序本身&lt;/strong&gt;(如Vscode和windsurf)去执行,所以说需要程序去适配Skills,&lt;strong&gt;它是共识和理念，而不是一套标准&lt;/strong&gt;.(不过当流行起来的时候，共识理念最终也会成为大家默认的标准)&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;总结&amp;lt;以上三种给llm扩展工具的方式&amp;gt;,我个人对未来最看好的是&lt;strong&gt;Skills&lt;/strong&gt;,我认为把这套逻辑和共识再进行优化加强是完全可以比过Tool Calls和mcp。Tool Calls桥接部分比较麻烦,&lt;strong&gt;一切运转都要依靠代码&lt;/strong&gt;,还有&lt;strong&gt;兼容性问题&lt;/strong&gt;;mcp&lt;strong&gt;开发部署繁琐,且容易引起上下文爆炸&lt;/strong&gt;,LLM运行缓慢.Skills&lt;strong&gt;恰好能解决这两者的缺点&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>学习笔记 | Hugo自动修正文章最后修改时间的最佳方案</title><link>https://blog.liao-ke.com/posts/hugo-add-lastmod-to-posts/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/hugo-add-lastmod-to-posts/</guid><description>面向 Serverless/CI 自动部署场景，分析 Hugo 获取 lastmod 的几种方式（:filemodtime/:git/lastmod/date）的坑点，并给出“用 Git 提交时间回写文件时间戳 + :filemodtime”的稳定方案与脚本思路。</description><pubDate>Sun, 25 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h1&gt;Hugo 全自动修正文章修改时间的最佳实践（Serverless 场景）&lt;a href=&quot;#hugo-全自动修正文章修改时间的最佳实践serverless-场景&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;在使用 Hugo 构建静态博客时，&lt;strong&gt;文章的修改时间（Last Modified Time）&lt;/strong&gt; 是一个非常重要但又容易踩坑的问题，尤其是在 &lt;strong&gt;Serverless / CI 自动部署&lt;/strong&gt; 场景下。&lt;/p&gt;&lt;p&gt;Hugo 官方目前提供了多种用于确定文章修改时间的方式：&lt;/p&gt;&lt;section&gt;&lt;h2&gt;Hugo 支持的修改时间来源&lt;a href=&quot;#hugo-支持的修改时间来源&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;:filemodtime&lt;/code&gt;&lt;/strong&gt;&lt;br /&gt;
使用文件本身的最后修改时间作为文章的修改时间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;lastmod&lt;/code&gt;&lt;/strong&gt;&lt;br /&gt;
需要在文章 Front Matter 中手动维护 &lt;code&gt;lastmod&lt;/code&gt; 字段。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;:git&lt;/code&gt;&lt;/strong&gt;&lt;br /&gt;
使用 Git 中该文件的&lt;strong&gt;最后一次提交时间&lt;/strong&gt;作为修改时间（依赖 &lt;code&gt;gitinfo&lt;/code&gt;）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;date&lt;/code&gt;&lt;/strong&gt;&lt;br /&gt;
使用文章的发布时间作为修改时间。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;各方案的自动化可行性分析&lt;a href=&quot;#各方案的自动化可行性分析&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在上述方案中：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;✅ &lt;strong&gt;可自动化&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:filemodtime&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:git&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;❌ &lt;strong&gt;不适合全自动&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lastmod&lt;/code&gt;（需要人工维护）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;date&lt;/code&gt;（语义不符）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt; 在 Serverless 场景下的问题&lt;a href=&quot;#-在-serverless-场景下的问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;使用 Hugo 的一个重要原因，正是为了 &lt;strong&gt;方便地将网站部署到 Serverless 平台&lt;/strong&gt;（如 Cloudflare Pages、Vercel、Netlify 等）。&lt;/p&gt;&lt;p&gt;然而在 Serverless / CI 场景中：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;每次部署都会重新 &lt;code&gt;git clone&lt;/code&gt; 仓库&lt;/li&gt;
&lt;li&gt;所有文件的 &lt;strong&gt;文件系统修改时间&lt;/strong&gt; 都会变成「拉取时间」&lt;/li&gt;
&lt;li&gt;这会导致：
&lt;ul&gt;
&lt;li&gt;所有文章的修改时间被错误地更新为“本次部署时间”&lt;/li&gt;
&lt;li&gt;完全失去文章真实修改时间的意义&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;因此，&lt;strong&gt;&lt;code&gt;:filemodtime&lt;/code&gt; 在默认情况下并不适合 Serverless 场景&lt;/strong&gt;。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt; 方案的现实问题&lt;a href=&quot;#-方案的现实问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;理论上，&lt;code&gt;:git&lt;/code&gt; 是最理想的方案：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;修改时间与 Git 提交严格一致&lt;/li&gt;
&lt;li&gt;完全自动化&lt;/li&gt;
&lt;li&gt;不依赖文件系统时间戳&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;但在实际使用中：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;即使开启了 &lt;code&gt;enableGitInfo = true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;某些情况下 &lt;code&gt;:git&lt;/code&gt; &lt;strong&gt;无法正确生效&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;在 CI / Serverless 环境中尤为明显&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;不确定这是环境限制、Git shallow clone、还是 Hugo 本身的 Bug，但结果是：&lt;strong&gt;该方案在实践中不够稳定&lt;/strong&gt;。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;最终解决方案：修改文件时间戳为Git 提交时间 + &lt;a href=&quot;#最终解决方案修改文件时间戳为git-提交时间--&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;综合以上问题，我最终总结出了一套&lt;strong&gt;最适合 Serverless 管理的全自动方案&lt;/strong&gt;：&lt;/p&gt;&lt;section&gt;&lt;h3&gt;核心思路&lt;a href=&quot;#核心思路&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;在 Hugo 构建之前，将文件的修改时间戳“伪装”为 Git 最后提交时间。&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;具体流程如下：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Hugo 中使用 &lt;code&gt;:filemodtime&lt;/code&gt; 作为文章修改时间来源&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[frontmatter]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;lastmod = [&apos;:fileModTime&apos;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;将脚本放在文件夹根目录&lt;/li&gt;
&lt;li&gt;将自动执行脚本的命令和正式部署命令合二为一(&lt;strong&gt;这里需要注意的是一般的serverless平台拉取项目只是浅层克隆不会把文件的最后提交信息给拉取过来，所以我们要在最前面要执行完整的拉取命令。&lt;/strong&gt;)&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;git fetch --unshallow &amp;amp;&amp;amp; chmod +x 1.sh &amp;amp;&amp;amp; ./1.sh &amp;amp;&amp;amp; hugo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Serverless平台设置环境变量TZ为Asia/Shanghai(不然的话，一般Serverless平台默认应该是美国的时间,会影响构建出来的网站的文章的最后修改日期的准确性)&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;这样就可以做到：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;✅ 修改时间与 Git 提交时间一致&lt;/li&gt;
&lt;li&gt;✅ 完全自动化&lt;/li&gt;
&lt;li&gt;✅ 与 Serverless / CI 环境完美兼容&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;自动同步 Git 提交时间到文件修改时间的脚本&lt;a href=&quot;#自动同步-git-提交时间到文件修改时间的脚本&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;下面的脚本用于：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;将当前目录下所有文件的最后修改时间，统一修改为对应的 Git 最后提交时间&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;git-set-filetime.sh&lt;/span&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# （此处放置你的脚本内容）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;#!/bin/bash&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 功能：将 git 仓库中所有被追踪文件的修改时间改为最后一次提交时间&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 确保当前目录是 git 仓库&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;.git&quot;&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Error: 当前目录不是 git 仓库根目录&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;fi&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 获取所有被追踪文件（包含特殊字符/空格/中文）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ls-files&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-z&lt;/span&gt;&lt;span&gt; | &lt;/span&gt;&lt;span&gt;while&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IFS&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-r&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# 获取最后一次提交的 Unix 时间戳&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;timestamp&lt;/span&gt;&lt;span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-1&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--format=&lt;/span&gt;&lt;span&gt;&quot;%ct&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$file&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$timestamp&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# 使用 touch 修改文件修改时间&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# -d &quot;@$timestamp&quot; 表示从 Unix 时间戳设置时间&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;touch&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;@&lt;/span&gt;&lt;span&gt;$timestamp&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$file&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Updated: &lt;/span&gt;&lt;span&gt;$file&lt;/span&gt;&lt;span&gt; -&amp;gt; $(&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &quot;@&lt;/span&gt;&lt;span&gt;$timestamp&lt;/span&gt;&lt;span&gt;&quot; &apos;+%Y-%m-%d %H:%M:%S&apos;)&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Skipped (not tracked): &lt;/span&gt;&lt;span&gt;$file&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;fi&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;done&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;All tracked files&apos; modification times updated.&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>随笔杂谈 | 谈谈我对AI的一些理解</title><link>https://blog.liao-ke.com/posts/ai-understanding/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/ai-understanding/</guid><description>结合个人使用大模型的经历，聊聊我对AI的理解：AI是提升效率的工具而非核心，关键在于掌握AI而不是依赖AI。</description><pubDate>Tue, 09 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;前言:&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;用ai也用了这么久了,今天想谈一下自己对AI的理解.从chatgpt刚问世开始,我就在开始使用大模型.也算是最早使用大模型的那批人.随着大模型的发展愈演愈烈,也衍生出了很多分支比如&lt;strong&gt;AI IDE&lt;/strong&gt;,应用内集成AI聊天助手,大模型识别图像等等.&lt;/p&gt;&lt;p&gt;而随着AI能干的事越来越多,有些人产生了&lt;strong&gt;自我怀疑&lt;/strong&gt;(我能做的事AI都能做,那还需要我干什么),而另外一部分人则产生了&lt;strong&gt;依赖&lt;/strong&gt;(你看ai都是这么说的了(盲目相信AI)).&lt;/p&gt;&lt;p&gt;而我也用大模型用了这么久了,今天便在这里谈一下我自己的认知&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;我的认知&lt;a href=&quot;#我的认知&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我始终认为&lt;strong&gt;Ai始终是作为一个工具,用来提升工作效率,而非核心&lt;/strong&gt;.大模型本身的特点就注定了有一些工作是无法代替人类.比如&lt;strong&gt;项目的一些宏观设计和管理&lt;/strong&gt;,一些最新的技术的使用和获取.它是一个超大知识的集合体,它的作用是降低我在知道该怎么做的情况下，让我避免去查代码文档，一步一步慢慢实现功能所带来的时间成本.而不是想做什么，跟AI说一句话，让他帮我实现就行了,我们要做的是工程师，是设计师，而不是让AI作为核心，我们负责提要求。不然就相当于我们是甲方，AI是乙方。&lt;strong&gt;我们应该当的是boss，是甲方,AI当我们底下的员工，来负责完成我设计的东西（乙方需求）。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;所以在我看来,使用AI无非就两个档次&lt;a href=&quot;#所以在我看来使用ai无非就两个档次&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;初级者&amp;lt;什么都不懂&amp;gt;,只知道自己想要什么,反正让AI完成就行了。(这在学习的初期确实可以很快带来成就感,但始终无法避免一个问题,&lt;strong&gt;你不懂的始终不懂，懂的是AI而不是你&lt;/strong&gt;,你并没有任何的核心竞争力)&lt;/li&gt;
&lt;li&gt;真正掌握AI的人&amp;lt;自己设置架构&amp;gt;，自己设置语法要求,自己设置UI层级和UI设计风格,规定使用的技术栈,让AI按照自己的规定去完成对应的工作。&lt;strong&gt;AI是提升效率的工具，而不是自己的大脑&lt;/strong&gt;,真正应该怎么做，应该是自己知道，而不是AI知道。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;所以在这个时代,有人害怕ai,有人依赖AI,那我的答案是掌握AI.&lt;a href=&quot;#所以在这个时代有人害怕ai有人依赖ai那我的答案是掌握ai&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/section&gt;</content:encoded></item><item><title>方案分析 | Android Root 的演进与抉择</title><link>https://blog.liao-ke.com/posts/Android-root/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/Android-root/</guid><description>从技术路线与时间线梳理 Android Root 的演进：用户态/内核态/漏洞 Root 的差异与适用条件，并对 KingRoot、SuperSU、Magisk、KernelSU、APatch 等方案做原理拆解与优缺点对比，给出选择建议。</description><pubDate>Tue, 09 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;Android Root 发展历程和方案分析&lt;a href=&quot;#android-root-发展历程和方案分析&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Android Root 顾名思义即给安卓系统获取根权限，让用户拥有系统级权限，极大提升系统可玩性。&lt;br /&gt;
一般来说，Root 需要先解锁 bootloader（BL），解锁的目的，是让用户有权限刷写各个分区，从而能：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;更换系统（system / vendor / product 等）&lt;/li&gt;
&lt;li&gt;更换内核（boot ）&lt;/li&gt;
&lt;li&gt;注入 Root / 模块方案&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;注意：解锁 BL ≠ 必然 Root&lt;/strong&gt;，也可以只刷机不 Root。&lt;br /&gt;
主流 Root 方案按时间大致可以排成这样：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;KingRoot → SuperSU → Magisk → SKRoot（小众） → KernelSU → APatch&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;hr /&gt;&lt;section&gt;&lt;h3&gt;一、Root 实现思路：按技术路线分类&lt;a href=&quot;#一root-实现思路按技术路线分类&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;用户态 Root（User-space Root）&lt;a href=&quot;#用户态-rootuser-space-root&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;不直接修改内核代码&lt;/li&gt;
&lt;li&gt;修改 &lt;strong&gt;boot.img → ramdisk → init 脚本&lt;/strong&gt;，在早期启动阶段插入自己的用户态 root 程序&lt;/li&gt;
&lt;li&gt;通过 &lt;strong&gt;用户态守护进程&lt;/strong&gt; 管理权限（例如 &lt;code&gt;magiskd&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;一般依赖一个 &lt;strong&gt;管理 App&lt;/strong&gt; 配合使用（授权弹窗、模块管理等）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代表方案：Magisk&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优点&lt;/strong&gt;：对内核无强依赖，兼容面最广&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点&lt;/strong&gt;：本质不在内核，某些内核安全策略/厂商定制下会有局限&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;内核态 Root（Kernel-space Root）&lt;a href=&quot;#内核态-rootkernel-space-root&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;直接在内核中 &lt;strong&gt;Hook 权限相关函数 / LSM / syscall&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;在内核层修改 &lt;code&gt;cred&lt;/code&gt;、&lt;code&gt;capabilities&lt;/code&gt; 等结构，获得最高权限&lt;/li&gt;
&lt;li&gt;部分方案需要内核源码（早期 KernelSU），部分不需要（APatch、SKRoot）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代表方案：KernelSU、APatch、SKRoot&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优点&lt;/strong&gt;：权限层级最高，可做更“隐蔽”和细粒度的控制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点&lt;/strong&gt;：与内核版本/厂商定制强相关，适配成本较高&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;漏洞 Root（Exploit-based Root）&lt;a href=&quot;#漏洞-rootexploit-based-root&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;利用系统或内核漏洞临时/半永久获取 Root&lt;/li&gt;
&lt;li&gt;通常依赖特定 Android / 内核版本，系统一更新就失效&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代表方案：KingRoot 等一键 Root 工具&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优点&lt;/strong&gt;：用户体验简单，历史上对锁 BL 的机器也有机会&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点&lt;/strong&gt;：完全吃漏洞红利，维护性差，安全风险高&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;二、按时间线看典型方案&lt;a href=&quot;#二按时间线看典型方案&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;KingRoot：漏洞驱动的早期 Root&lt;a href=&quot;#kingroot漏洞驱动的早期-root&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;主要活跃在 &lt;strong&gt;Android 4.4 ~ 6.0&lt;/strong&gt; 时代&lt;/li&gt;
&lt;li&gt;通过 &lt;strong&gt;内核 / 系统漏洞&lt;/strong&gt;（如提权漏洞）获得 Root&lt;/li&gt;
&lt;li&gt;多为 &lt;strong&gt;临时或半永久 Root&lt;/strong&gt;，重启或 OTA 后经常失效&lt;/li&gt;
&lt;li&gt;随着漏洞不断被修复，这类方案很快被淘汰&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;定位&lt;/strong&gt;：&lt;br /&gt;
完全基于漏洞的时代产物，如今更多是历史意义。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;SuperSU：system 分区注入 su 的经典方案&lt;a href=&quot;#supersusystem-分区注入-su-的经典方案&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;思路：直接修改 &lt;code&gt;system.img&lt;/code&gt;，在 &lt;code&gt;/system/bin&lt;/code&gt; 或 &lt;code&gt;/system/xbin&lt;/code&gt; 注入 &lt;code&gt;su&lt;/code&gt; 二进制&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;su&lt;/code&gt; 的 setuid 机制实现提权&lt;/li&gt;
&lt;li&gt;典型适用 &lt;strong&gt;Android 4.x ~ 6.x&lt;/strong&gt;，system 还比较“好改”的时代&lt;/li&gt;
&lt;li&gt;随着：
&lt;ul&gt;
&lt;li&gt;system 分区逐渐只读 / 受更严格完整性保护&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Magisk 引入 systemless Root&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;SuperSU 很快失去优势。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;定位&lt;/strong&gt;：&lt;br /&gt;
传统“改 system.img 注入 su”的代表&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://github.com/topjohnwu/Magisk&quot; target=&quot;_blank&quot;&gt;Magisk&lt;/a&gt;：用户态 systemless Root 的时代&lt;a href=&quot;#magisk用户态-systemless-root-的时代&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Magisk 把 Root 方式拉到了一个新高度。&lt;/p&gt;&lt;section&gt;&lt;h5&gt;核心实现&lt;a href=&quot;#核心实现&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;修改 &lt;strong&gt;boot.img → ramdisk → init&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;用 &lt;code&gt;magiskinit&lt;/code&gt; 接管早期启动，作为“第一个用户态进程”&lt;/li&gt;
&lt;li&gt;启动 root 守护进程 &lt;code&gt;magiskd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/system/bin/su&lt;/code&gt; 在 Magisk 中 &lt;strong&gt;只是前端/中转&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;解析参数 → 连接 &lt;code&gt;magiskd&lt;/code&gt; → 由 &lt;code&gt;magiskd&lt;/code&gt; 以 root fork/exec 真正的命令&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提权的决策和执行&lt;/strong&gt;在 &lt;code&gt;magiskd&lt;/code&gt; 中完成，而不是在 &lt;code&gt;su&lt;/code&gt; 本身&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;不在 system 分区直接写入文件，做到 &lt;strong&gt;systemless&lt;/strong&gt;&lt;br /&gt;
（实际上是用挂载/覆盖的方式“虚拟出”修改过的系统视图）&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h5&gt;关键特点&lt;a href=&quot;#关键特点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;首创 magic mount 模块系统&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;在不实际修改系统文件的情况下，实现对 &lt;code&gt;/system&lt;/code&gt;、&lt;code&gt;/vendor&lt;/code&gt; 等目录的文件覆盖&lt;/li&gt;
&lt;li&gt;极大提升“玩机模块生态”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强兼容性&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;只要能改 boot.img中的init脚本，大多数内核版本都能使用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;依赖管理 App&lt;/strong&gt;（Magisk App）：
&lt;ul&gt;
&lt;li&gt;管理模块、处理 su 授权弹窗、升级/卸载&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h5&gt;局限&lt;a href=&quot;#局限&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;纯用户态方案，需要搭配app&lt;/li&gt;
&lt;li&gt;模块生态与内核态模块（如 APatch 的 KPM ）相比，在&lt;strong&gt;内核能力利用上&lt;/strong&gt;略逊一筹&lt;/li&gt;
&lt;li&gt;不支持kernelsu后来的模块webui功能,需要额外安装app解决&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://github.com/abcz316/SKRoot-linuxKernelRoot&quot; target=&quot;_blank&quot;&gt;SKRoot&lt;/a&gt;：早期“内核 Root + su 环境注入”的探索者&lt;a href=&quot;#skroot早期内核-root--su-环境注入的探索者&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;时间上早于目前主流内核 Root（KernelSU / APatch）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无需内核源码&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;离线分析目标内核镜像（ELF/镜像格式）&lt;/li&gt;
&lt;li&gt;找到如 &lt;code&gt;do_execve&lt;/code&gt; 等关键函数与 &lt;code&gt;task_struct/cred/seccomp&lt;/code&gt; 的偏移&lt;/li&gt;
&lt;li&gt;插入自定义 shellcode 实现内核级提权&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;号称“&lt;strong&gt;隐藏性很强&lt;/strong&gt;”：
&lt;ul&gt;
&lt;li&gt;没有模块系统&lt;/li&gt;
&lt;li&gt;常见用法是：针对&lt;strong&gt;单个或少数进程&lt;/strong&gt;注入 su 环境&lt;/li&gt;
&lt;li&gt;通过 PATH / so 寄生等方式，让特定 APP 获得 su，而不是全局暴露&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;适配范围：&lt;strong&gt;大致 3.10 ~ 6.6 内核&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;不依赖内核源码，适配范围相对广&lt;/li&gt;
&lt;li&gt;su 环境可以“定向注入”，对其他进程很隐蔽&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;没有完整的模块系统，操作较繁琐&lt;/li&gt;
&lt;li&gt;生态小众，文档和社区支持相对较弱&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://github.com/tiann/KernelSU&quot; target=&quot;_blank&quot;&gt;KernelSU&lt;/a&gt;：主流内核态 Root + overlayfs 模块&lt;a href=&quot;#kernelsu主流内核态-root--overlayfs-模块&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;section&gt;&lt;h5&gt;基本定位&lt;a href=&quot;#基本定位&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;代表性的 &lt;strong&gt;内核态 Root&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;在内核中安装 hook（LSM / cred 修改等）&lt;/li&gt;
&lt;li&gt;在执行 &lt;code&gt;/system/bin/su&lt;/code&gt; 时，内核直接修改进程 cred 实现提权&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/system/bin/su&lt;/code&gt; 在 KernelSU 中是真正的 &lt;strong&gt;提权入口&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;它触发内核 hook&lt;/li&gt;
&lt;li&gt;提权是在内核里完成的，而不是转发给某个守护进程（区别于 Magisk）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h5&gt;技术路径演进&lt;a href=&quot;#技术路径演进&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;早期：通过 &lt;strong&gt;谷歌GKI 内核（已被官方淘汰） / 内核源码集成（已被官方淘汰）&lt;/strong&gt; 集成 KernelSU&lt;/li&gt;
&lt;li&gt;现在主流：&lt;strong&gt;LKM（ko 模块）方式&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;把修改封装成内核模块加载进 GKI 内核&lt;/li&gt;
&lt;li&gt;同一大版本Gki内核编译出来的ko模块具有一定通用性,所以安装体验上不需要内核源代码&lt;/li&gt;
&lt;li&gt;但 &lt;strong&gt;ko 的编译仍依赖内核的源码&lt;/strong&gt;，只是这部分由项目方/维护者完成&lt;/li&gt;
&lt;li&gt;对用户体验来说“不需要自己改源码”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h5&gt;模块系统：元模块（支持overlyfs/magic mount或者自定义挂载方式）&lt;a href=&quot;#模块系统元模块支持overlyfsmagic-mount或者自定义挂载方式&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;默认使用 &lt;strong&gt;overlayfs&lt;/strong&gt; 实现模块系统(首创)：
&lt;ul&gt;
&lt;li&gt;支持对 &lt;code&gt;/system&lt;/code&gt; 等只读分区做“上层覆盖”(模块安装后通常需要 &lt;strong&gt;重启才能生效对/system的修改&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;对比 Magisk 的 magic mount：
&lt;ul&gt;
&lt;li&gt;overlayfs 是内核特性，语义更标准&lt;/li&gt;
&lt;li&gt;但实时性稍差，多数变更需要重启&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h5&gt;特点与限制&lt;a href=&quot;#特点与限制&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;内核态 su：安全模型清晰，可做细粒度 App profile（按 UID/GID 控制权限大小）&lt;/li&gt;
&lt;li&gt;官方overlayfs 模块系统：结构正规，可与 GKI 思路统一&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;限制&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对低版本 / 非 GKI 内核兼容性差&lt;/li&gt;
&lt;li&gt;一些魔改了内核且不开源的gki设备对谷歌官方gki内核支持差,刷了可能开不了机&lt;/li&gt;
&lt;li&gt;官方更推荐搭配 &lt;strong&gt;5.10以上的 GKI 内核搭配ko模块使用&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://github.com/bmax121/APatch&quot; target=&quot;_blank&quot;&gt;APatch&lt;/a&gt;：无需源码的 kpimg 内核 Root + KPM 模块&lt;a href=&quot;#apatch无需源码的-kpimg-内核-root--kpm-模块&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;在内核 Root 方案中，APatch 的技术路线是目前&lt;strong&gt;最“工程化 + 通用”的一类&lt;/strong&gt;。&lt;/p&gt;&lt;section&gt;&lt;h5&gt;核心实现方式&lt;a href=&quot;#核心实现方式&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;仍然是 &lt;strong&gt;内核态 Root&lt;/strong&gt;，但：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不需要内核源码&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;使用 KernelPatch 工具链解析并 patch 目标内核镜像&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;通过在内核镜像中注入 &lt;strong&gt;&lt;code&gt;kpimg&lt;/code&gt;&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;修改内核启动入口 / early init 流程&lt;/li&gt;
&lt;li&gt;把自定义 hook 注入到内核的启动过程&lt;/li&gt;
&lt;li&gt;重启后，&lt;code&gt;kpimg&lt;/code&gt; 会在早期阶段接管部分逻辑，实现：
&lt;ul&gt;
&lt;li&gt;Root 提权&lt;/li&gt;
&lt;li&gt;内核 hook（supercall / inline hook）&lt;/li&gt;
&lt;li&gt;启动用户态守护/事件（&lt;a&gt;apd&lt;/a&gt; 等）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h5&gt;兼容性&lt;a href=&quot;#兼容性&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;内核版本范围广：&lt;strong&gt;3.18 ~ 6.12&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;不依赖 GKI，不要求厂商公开内核源码&lt;/li&gt;
&lt;li&gt;对各家定制内核更友好（因为是直接对内核二进制镜像做符号分析与 patch）&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h5&gt;特点&lt;a href=&quot;#特点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h5&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;KPM 内核模块&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在已经被 kpimg 接管的内核里，动态加载 KPM 模块&lt;/li&gt;
&lt;li&gt;支持对内核函数进行 hook，部分 hook 即时生效&lt;/li&gt;
&lt;li&gt;无&lt;code&gt;/system/bin/su&lt;/code&gt;文件，通过监听拦截&lt;code&gt;/system/bin/su&lt;/code&gt;或&lt;code&gt;su&lt;/code&gt;指令来实现提权&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;模块系统 + Lua 脚本&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户态 &lt;a&gt;apd&lt;/a&gt; 管理模块目录、事件（post-fs-data / boot-completed 等）&lt;/li&gt;
&lt;li&gt;最新版本中可以用 &lt;strong&gt;Lua&lt;/strong&gt; 替代传统 shell 脚本，增强复杂逻辑可维护性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;不依赖内核源码的工程化链路&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用 &lt;a&gt;tools/kallsym.c&lt;/a&gt;、&lt;a&gt;tools/patch.c&lt;/a&gt; 等做符号解析、patch&lt;/li&gt;
&lt;li&gt;用 &lt;a&gt;kernel/patch/android/user_init.sh&lt;/a&gt; 等把 apd 接到系统启动阶段&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持kernelsu的元模块挂载方案(2026.1.12补)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;三、综合对比与结论&lt;a href=&quot;#三综合对比与结论&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;技术路线对比（简表）&lt;a href=&quot;#技术路线对比简表&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&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;是否需Kernel源码&lt;/th&gt;&lt;th&gt;是否依赖 App&lt;/th&gt;&lt;th&gt;su 角色&lt;/th&gt;&lt;th&gt;模块系统&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;KingRoot&lt;/td&gt;&lt;td&gt;漏洞 Root&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;需要&lt;/td&gt;&lt;td&gt;各家自定义&lt;/td&gt;&lt;td&gt;无 / 简单补丁&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SuperSU&lt;/td&gt;&lt;td&gt;system 注入 su&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;可选&lt;/td&gt;&lt;td&gt;传统 setuid su&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Magisk&lt;/td&gt;&lt;td&gt;用户态 Root&lt;/td&gt;&lt;td&gt;否（但改boot.img中的ramdisk）&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;强依赖&lt;/td&gt;&lt;td&gt;&lt;code&gt;/system/bin/su&lt;/code&gt;中转到 &lt;code&gt;magiskd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;magic mount&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SKRoot&lt;/td&gt;&lt;td&gt;内核 Root&lt;/td&gt;&lt;td&gt;是（patch 镜像）&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;有工具/库&lt;/td&gt;&lt;td&gt;隐藏 su + 进程定向注入&lt;/td&gt;&lt;td&gt;无完整模块系统&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;KernelSU&lt;/td&gt;&lt;td&gt;内核 Root&lt;/td&gt;&lt;td&gt;是（源码/GKI/LKM）&lt;/td&gt;&lt;td&gt;技术层面上需要&lt;/td&gt;&lt;td&gt;App 非必须&lt;/td&gt;&lt;td&gt;&lt;code&gt;/system/bin/su&lt;/code&gt; 触发内核提权&lt;/td&gt;&lt;td&gt;元模块&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;APatch&lt;/td&gt;&lt;td&gt;内核 Root&lt;/td&gt;&lt;td&gt;是（kpimg patch）&lt;/td&gt;&lt;td&gt;否&lt;/td&gt;&lt;td&gt;App 非必须&lt;/td&gt;&lt;td&gt;内核 hook su/execve 等&lt;/td&gt;&lt;td&gt;APM/KPM + Lua&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;目前最主流的三款root方案分析&lt;a href=&quot;#目前最主流的三款root方案分析&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Magisk&lt;/strong&gt;：&lt;br /&gt;
适合追求 &lt;strong&gt;广泛兼容 + 成熟模块生态&lt;/strong&gt; 的用户，一般设备能解锁 boot.img 就能用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;KernelSU&lt;/strong&gt;：&lt;br /&gt;
适合有 &lt;strong&gt;GKI 内核&lt;/strong&gt;，且希望在内核层面细控 Root 权限（App profile）的人，&lt;br /&gt;
更偏“官方化”的内核模块方案，但对旧机型支持有限
可以自定义挂载&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;APatch&lt;/strong&gt;：&lt;br /&gt;
从技术理念上最“硬核”，不依赖源码、支持广泛内核版本，&lt;br /&gt;
内核模块 hook + Lua 模块系统，对研究者 / 高级玩家非常友好。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>方案分析 | 如何选择最适合你的 AI IDE 与扩展插件</title><link>https://blog.liao-ke.com/posts/ai-ide/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/ai-ide/</guid><description>从使用场景与评价指标出发，梳理 CLI/IDE 两类 AI 编程工具，并对比国内外主流 AI IDE 的特点、限制与适用人群，给出个人的选型建议与推荐。</description><pubDate>Mon, 08 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;AI IDE 工具推荐&lt;a href=&quot;#ai-ide-工具推荐&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;为什么使用 AI IDE？&lt;a href=&quot;#为什么使用-ai-ide&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;传统 AI 聊天无法：
&lt;ul&gt;
&lt;li&gt;实时读取本地文件&lt;/li&gt;
&lt;li&gt;兼顾项目的宏观框架管理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;偏商业化的 AI IDE：
&lt;ul&gt;
&lt;li&gt;一般不允许自定义第三方服务商接口&lt;/li&gt;
&lt;li&gt;强制使用平台模型收取订阅费&lt;/li&gt;
&lt;li&gt;实时读取本地文件&lt;/li&gt;
&lt;li&gt;适配开发的执行流程与逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;因此，为了高效开发和项目管理，需要使用 AI IDE。&lt;/p&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;AI IDE 的能力评价指标&lt;a href=&quot;#ai-ide-的能力评价指标&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;硬实力：自带模型能力&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;软实力：上下文补全与逻辑能力&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;通过插件、执行策略、隐藏的上下文prompt 等实现&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;ul&gt;
&lt;li&gt;两者缺一不可&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;AI 编程工具分类&lt;a href=&quot;#ai-编程工具分类&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;1. CLI 命令行AI开发工具&lt;a href=&quot;#1-cli-命令行ai开发工具&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;开发效率比 IDE 差
&lt;ul&gt;
&lt;li&gt;文件引用需手动输入&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;不适合宏观项目管理&lt;/li&gt;
&lt;li&gt;适合单一功能的改进&lt;/li&gt;
&lt;li&gt;代表工具：
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://openai.com/blog/openai-codex&quot; target=&quot;_blank&quot;&gt;OpenAI Codex★★★&lt;/a&gt;(也有vscode 插件版本,但开发效率不如集成式ai ide,仍然是片段式更改)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://claude.com/product/claude-code&quot; target=&quot;_blank&quot;&gt;Claude Code★★★&lt;/a&gt;(也有vscode 插件版本,但开发效率不如集成式ai ide,仍然是片段式更改)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sst/opencode&quot; target=&quot;_blank&quot;&gt;OpenCode（开源）&lt;/a&gt;（可自定义服务商接口，但上下文能力较弱）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;2. IDE AI 开发工具&lt;a href=&quot;#2-ide-ai-开发工具&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;直接从文件管理器拖入文件即可&lt;/li&gt;
&lt;li&gt;支持项目级宏观管理&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;国内 AI IDE&lt;a href=&quot;#国内-ai-ide&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.trae.ai/&quot; target=&quot;_blank&quot;&gt;Trae&lt;/a&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;特有 Solo 模式（和普通模式感觉主要是 UI 差别，在功能上感觉差的不是很大，可能隐藏 prompt 有所优化）&lt;/li&gt;
&lt;li&gt;可使用规定的国内其他服务商接口&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://qoder.ai/&quot; target=&quot;_blank&quot;&gt;Qoder&lt;/a&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;无特色&lt;/li&gt;
&lt;li&gt;上下文消耗快&lt;/li&gt;
&lt;li&gt;无法使用国外模型或其他接口&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://lingma.aliyun.com/&quot; target=&quot;_blank&quot;&gt;通义灵码&lt;/a&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;无特色&lt;/li&gt;
&lt;li&gt;无法使用国外模型或其他接口&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;section&gt;&lt;h4&gt;国内 IDE 的共性&lt;a href=&quot;#国内-ide-的共性&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;喜欢构建工作区文件全量索引，每次提问前先查索引文件，消耗大量上下文 token，有时查找的文件过多反而忽略关键问题&lt;/li&gt;
&lt;li&gt;国内模型编码能力较弱，且不允许使用国外更强的模型&lt;/li&gt;
&lt;li&gt;方便支付订阅, 界面中文支持较好&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;国外 AI IDE&lt;a href=&quot;#国外-ai-ide&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/features/copilot&quot; target=&quot;_blank&quot;&gt;GitHub Copilot★★&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VSCode 插件形式&lt;/li&gt;
&lt;li&gt;适合片段式的文件&lt;/li&gt;
&lt;li&gt;上下文补全能力较弱&lt;/li&gt;
&lt;li&gt;无法全面定制化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/cline/cline&quot; target=&quot;_blank&quot;&gt;Cline★★&lt;/a&gt;（开源）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可自定义任意服务商&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;VSCode 插件形式&lt;/li&gt;
&lt;li&gt;适合片段式的文件&lt;/li&gt;
&lt;li&gt;上下文补全能力较弱&lt;/li&gt;
&lt;li&gt;无法全面定制化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/Kilo-Org/kilocode&quot; target=&quot;_blank&quot;&gt;Kilo&lt;/a&gt;（开源）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可使用规定的第三方服务商api&lt;/li&gt;
&lt;li&gt;VSCode 插件形式&lt;/li&gt;
&lt;li&gt;适合片段式的文件&lt;/li&gt;
&lt;li&gt;上下文补全能力较弱&lt;/li&gt;
&lt;li&gt;无法全面定制化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.cursor.so/&quot; target=&quot;_blank&quot;&gt;Cursor★★★&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于 VSCode 深度定制&lt;/li&gt;
&lt;li&gt;自研模型 Composer 1 (专为编程训练, 功能强大)&lt;/li&gt;
&lt;li&gt;可使用规定的其他服务商 API&lt;/li&gt;
&lt;li&gt;agent可以直接连接github远程储存库(特色功能)&lt;/li&gt;
&lt;li&gt;预设 Prompt 优秀输出质量高，但免费额度少，订阅贵&lt;/li&gt;
&lt;li&gt;亮眼功能：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;浏览器设计模式&lt;/strong&gt;：可以直接在ide里面打开网页，并且选择元素，方便设计网页&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;debug&lt;/strong&gt;：可以根据log寻找隐藏bug&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://kiro.dev&quot; target=&quot;_blank&quot;&gt;kiro&lt;/a&gt;&lt;/strong&gt;
电脑安装闪退，我用不了(哭)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://windsurf.ai/&quot; target=&quot;_blank&quot;&gt;Windsurf★★★&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于 VSCode 深度定制&lt;/li&gt;
&lt;li&gt;自研模型 SWE-1.5 (专为编程训练, 功能强大)&lt;/li&gt;
&lt;li&gt;亮眼功能：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memories&lt;/strong&gt;：可以根据对话和习惯生成对应的记忆（ai自动生成记忆，以在对话之间保持上下文连贯性）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DeepWiki&lt;/strong&gt;：独家功能,定位项目中关键函数或变量，了解用途和在项目其他地方引用 (方便学习他人的开源项目)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CodeMap&lt;/strong&gt;：独家功能,用于分析现有项目代码结构,可以根据输入的问题生成项目代码实现的流程图,点击流程图可以定位对应代码实现的部分（对于解剖他人项目的功能实现很有用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器设计模式&lt;/strong&gt;：可以直接在ide里面打开网页，并且选择元素，方便设计网页&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对话消息互通&lt;/strong&gt;：独家功能,不同对话之间可以选择互通消息，如两个不同的项目,具有一定的关联性，我们就可以通过这个功能实现两个项目在对话层面上的互通，而不需要ai去研究另外一个项目的代码，防止添加过多的内容，导致上下文混乱&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;免费额度高，价格便宜&lt;/li&gt;
&lt;li&gt;支持规定的其他服务商 API&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://zed.dev&quot; target=&quot;_blank&quot;&gt;Zen Editor&lt;/a&gt;（开源）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可使用任意服务商接口&lt;/li&gt;
&lt;li&gt;自带免费额度高&lt;/li&gt;
&lt;li&gt;上下文补全能力较弱&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;hr /&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;总结推荐&lt;a href=&quot;#总结推荐&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;综合价格、模型能力和上下文补全能力，我个人首推 &lt;strong&gt;&lt;a href=&quot;https://windsurf.ai/&quot; target=&quot;_blank&quot;&gt;Windsurf&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;DeepWiki、CodeMap 和消息互通是其最大亮点，让其上下文补全能力非常强大&lt;/li&gt;
&lt;li&gt;其他 AI IDE 在 UI 功能上同质化严重，差别主要在 AI 模型、执行逻辑和预设 Prompt&lt;/li&gt;
&lt;li&gt;如果不考虑开发效率，单论编码能力,openai的codex和claude code这种命令行式开发可能是最强的一批,其次就是cursor和windsurf&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>学习笔记 | GKI 内核不完全编译实战</title><link>https://blog.liao-ke.com/posts/android-gki-kernel-compile/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/android-gki-kernel-compile/</guid><description>以 GKI 5.10+ 为例，记录 Android 内核“不完全编译”的完整流程：环境依赖、编译链选择、编译命令到 AnyKernel3 打包刷入，并附常见坑与排查思路。</description><pubDate>Fri, 05 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;Android内核编译&lt;a href=&quot;#android内核编译&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;以编译5.10以上的内核为例,所需资源:&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;一台配置较好的电脑&lt;/li&gt;
&lt;li&gt;linux系统&lt;/li&gt;
&lt;li&gt;内核源代码&lt;/li&gt;
&lt;li&gt;编译链工具&lt;/li&gt;
&lt;/ol&gt;&lt;section&gt;&lt;h3&gt;linux系统&lt;a href=&quot;#linux系统&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;各大Linux系统(Ubuntu系/arch系/fedora系/Wsl2)都可以，网上教程多以Ubuntu lts版本为例(&lt;strong&gt;便于找依赖和教程&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;内核源代码&lt;a href=&quot;#内核源代码&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;从github上搜索自己机型的内核源代码&lt;br /&gt;
如&lt;code&gt;https://github.com/Evolution-X-Devices/kernel_xiaomi_sm8450&lt;/code&gt;(&lt;strong&gt;项目名一般采用   kernel_厂家名_芯片组代号   的形式,5.10之后都是gki内核,所以内核名称基本是以芯片组命名如sm8450,有些项目也可能是按机型代号命名，而不是芯片组&lt;/strong&gt;)&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;编译链工具&lt;a href=&quot;#编译链工具&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;5.10以上的内核一般采用纯clang/llvm进行编译(低版本内核也可尝试，但有可能能成功编译但会开不了机)&lt;/p&gt;&lt;section&gt;&lt;h4&gt;Clang/llvm&lt;a href=&quot;#clangllvm&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;Clang 一般情况下采用的是&lt;a href=&quot;https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+/refs/heads/main&quot; target=&quot;_blank&quot;&gt;google&lt;/a&gt;的正式分支,也可以采用&lt;a href=&quot;https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+/refs/heads/mirror-goog-main-prebuilts&quot; target=&quot;_blank&quot;&gt;测试分支&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;编译过程&lt;a href=&quot;#编译过程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;更新环境依赖&lt;a href=&quot;#更新环境依赖&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;以Ubuntu24.04为例,执行以下命令安装依赖&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;apt-get&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;git-core&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;gnupg&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;flex&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;bison&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build-essential&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;zip&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;zlib1g-dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;gcc-multilib&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;g++-multilib&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;libc6-dev-i386&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;libncurses5&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib32ncurses5-dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x11proto-core-dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;libx11-dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib32z1-dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;libgl1-mesa-dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;libxml2-utils&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;xsltproc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tar&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;xz-utils&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cpio&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;findutils&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;克隆内核源代码和编译链工具&lt;a href=&quot;#克隆内核源代码和编译链工具&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;内核:&lt;code&gt;git clone https://github.com/Evolution-X-Devices/kernel_xiaomi_sm8450.git --depth=1&lt;/code&gt;&lt;br /&gt;
编译链工具:&lt;code&gt;git clone https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86.git --depth=1&lt;/code&gt;&lt;br /&gt;
&lt;strong&gt;depth=1&lt;/strong&gt;只拉取文件，不拉取历史提交，可以极大减少下载时间&lt;br /&gt;
如果想拉取其他的测试分支，也可以在后面加&lt;code&gt;-b 测试分支名字&lt;/code&gt;&lt;br /&gt;
如拉取测试版的编译链则添加&lt;code&gt;-b mirror-goog-main-prebuilts&lt;/code&gt;&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;设置环境变量&lt;a href=&quot;#设置环境变量&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;注:&lt;code&gt;以下操作需要在同一个终端环境下执行，因为添加的变量是临时变量&lt;/code&gt;&lt;br /&gt;
此时在你的工作目录下面应该会有两个文件夹，一是&lt;code&gt;内核文件夹&lt;/code&gt;，二是&lt;code&gt;编译链工具文件夹&lt;/code&gt;&lt;br /&gt;
打开终端,执行&lt;code&gt;cd 编译链工具文件夹路径&lt;/code&gt;,当前目录下应该会有若干个&lt;code&gt;clang-rxxxx&lt;/code&gt;子文件夹，选择后缀数字最大的最新版本即可,将它下面的/bin添加到环境变量中&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PATH&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$PATH&lt;/span&gt;&lt;span&gt;:/../../编译链工具文件夹/clang-rxxxx/bin&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;然后再&lt;code&gt;cd 内核源代码文件夹&lt;/code&gt;&lt;br /&gt;
设置编译环境变量&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ARCH&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;arm64&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SUBARCH&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;arm64&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CC&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;clang&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LLVM&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LLVM_IAS&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HOSTCC&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;clang&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LD&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;ld&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lld&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CLANG_TRIPLE&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;aarch64-linux-gnu-&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果电脑的内存不太够，可以额外设置&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LTO&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;thin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;执行编译命令&lt;a href=&quot;#执行编译命令&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;make&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ARCH=&quot;arm64&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;gki_defconfig&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;make&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-j$(&lt;/span&gt;&lt;span&gt;nproc&lt;/span&gt;&lt;span&gt; --all)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;第一行命令是加载配置文件gki_defconfig,他所在的目录是&lt;code&gt;/内核源代码/arch/arm64/configs/gki_defconfig&lt;/code&gt;（可以自行修改里面的配置项）&lt;br /&gt;
编译出来的内核二进制文件会在&lt;code&gt;/内核源代码/arch/arm64/boot/Image&lt;/code&gt;&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;打包内核&lt;a href=&quot;#打包内核&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;由于没有编译kernel-devicetree,也没ramdisk,所以无法和内核二进制文件打包成boot.img刷入手机分区(也可以用magiskboot把手机原本的boot.img进行解包，把其中的内核二进制文件替换之后,再打包就行了)&lt;br /&gt;
这个时候就需要&lt;a href=&quot;https://github.com/osm0sis/AnyKernel3&quot; target=&quot;_blank&quot;&gt;AnyKernel3&lt;/a&gt;对内核二进制文件进行打包&lt;br /&gt;
详细教程参考&lt;br /&gt;
&lt;a href=&quot;https://github.com/tiann/KernelSU/discussions/952&quot; target=&quot;_blank&quot;&gt;https://github.com/tiann/KernelSU/discussions/952&lt;/a&gt;&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;刷入内核&lt;a href=&quot;#刷入内核&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;可以在twrp或一些用于刷写内核的app中刷入打包后的AnyKernel3.zip&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;注意&lt;a href=&quot;#注意&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;不同型号内核以及不同版本的编译器，可能对依赖和代码语法要求也有所不同，需要自行解决。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>方案分析 | 代理工具的选择</title><link>https://blog.liao-ke.com/posts/proxy-tools/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/proxy-tools/</guid><description>从“代理核心 + GUI 前端”的视角，介绍并对比 Clash/Mihomo、Sing-Box、V2Ray、Xray、dae 等主流核心的特点与取舍，同时按系统整理常见客户端选择，便于快速完成选型。</description><pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;主流代理核心简介（代理核心 + 前端 UI）&lt;a href=&quot;#主流代理核心简介代理核心--前端-ui&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;所有代理工具本质上都是 &lt;strong&gt;代理核心 + 前端图形界面（UI）&lt;/strong&gt; 组成。&lt;br /&gt;
前端 UI 可以千变万化，但真正承担流量处理的 &lt;strong&gt;代理核心只有少数几种&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;以下是目前主流、最常见的核心介绍。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/Dreamacro/clash&quot; target=&quot;_blank&quot;&gt;Clash&lt;/a&gt;(更新停滞)&lt;a href=&quot;#clash更新停滞&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Clash 是一个最初由 Go 编写的多协议代理核心（原项目已删除）。&lt;br /&gt;
使用广泛，生态庞大。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;使用统一的 YAML 配置，无需因平台不同而修改&lt;/li&gt;
&lt;li&gt;GUI 客户端数量最多、生态最大&lt;/li&gt;
&lt;li&gt;跨平台兼容性极强&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;原项目已停止维护&lt;/li&gt;
&lt;li&gt;新协议支持较慢（如 Reality、Hysteria2 等）&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/MetaCubeX/mihomo&quot; target=&quot;_blank&quot;&gt;Mihomo（Clash Meta）&lt;/a&gt;★★★&lt;a href=&quot;#mihomoclash-meta&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;MetaCubeX 社区维护的 Clash 增强版，也是目前最主流的 Clash 继承者。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;完全兼容 Clash 配置&lt;/li&gt;
&lt;li&gt;支持现代协议（Reality、Hysteria2、TUIC 等）&lt;/li&gt;
&lt;li&gt;活跃维护，性能更高&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/SagerNet/sing-box&quot; target=&quot;_blank&quot;&gt;Sing-Box（sb）&lt;/a&gt;★★&lt;a href=&quot;#sing-boxsb&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;由 SagerNet 开发的现代化代理核心，目前增长最快、架构最先进。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;极度轻量，理论性能高&lt;/li&gt;
&lt;li&gt;高度可定制的网络与路由配置&lt;/li&gt;
&lt;li&gt;支持大量现代协议&lt;/li&gt;
&lt;li&gt;跨平台优秀&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;配置难度高，对新手不友好&lt;/li&gt;
&lt;li&gt;GUI 生态较少&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/v2fly/v2ray-core&quot; target=&quot;_blank&quot;&gt;V2Ray&lt;/a&gt;(更新缓慢)&lt;a href=&quot;#v2ray更新缓慢&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;由 v2fly 社区维护的原始 V2Ray 核心。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;配置灵活&lt;/li&gt;
&lt;li&gt;结构成熟&lt;/li&gt;
&lt;li&gt;较为轻量&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;开发速度慢&lt;/li&gt;
&lt;li&gt;新协议支持不佳&lt;/li&gt;
&lt;li&gt;配置复杂&lt;/li&gt;
&lt;li&gt;GUI 生态弱&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/XTLS/Xray-core&quot; target=&quot;_blank&quot;&gt;Xray&lt;/a&gt;&lt;a href=&quot;#xray&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/v2fly/v2ray-core&quot; target=&quot;_blank&quot;&gt;V2Ray&lt;/a&gt; 的增强版核心，由 XTLS 项目维护。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;完全兼容 V2Ray 配置&lt;/li&gt;
&lt;li&gt;支持 Reality&lt;/li&gt;
&lt;li&gt;支持 XTLS，性能大幅提升&lt;/li&gt;
&lt;li&gt;性能明显高于官方 V2Ray&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;配置复杂&lt;/li&gt;
&lt;li&gt;GUI 生态较弱&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;&lt;a href=&quot;https://github.com/daeuniverse/dae&quot; target=&quot;_blank&quot;&gt;dae&lt;/a&gt;&lt;a href=&quot;#dae&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;基于 eBPF 的 Linux / 路由器高性能代理引擎，更像“下一代分流框架”。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;特点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;基于 eBPF，性能极高&lt;/li&gt;
&lt;li&gt;几乎不占 CPU&lt;/li&gt;
&lt;li&gt;延迟极低&lt;/li&gt;
&lt;li&gt;路由分流能力极强&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;仅支持 Linux / OpenWRT&lt;/li&gt;
&lt;li&gt;配置复杂&lt;/li&gt;
&lt;li&gt;GUI少&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;各操作系统主流GUI代理客户端(整体按照知名度排序)&lt;a href=&quot;#各操作系统主流gui代理客户端整体按照知名度排序&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;Windows&lt;a href=&quot;#windows&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/2dust/v2rayN&quot; target=&quot;_blank&quot;&gt;v2rayN★★&lt;/a&gt; — 支持 Xray / sing-box / clash/others 内核,支持Windows/Linux/macOS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Clash-Verge-rev/clash-verge-rev&quot; target=&quot;_blank&quot;&gt;Clash Verge Rev★★&lt;/a&gt; — 内置 Mihomo内核,支持 Linux/macOS/Windows&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mihomo-party-org/clash-party&quot; target=&quot;_blank&quot;&gt;Mihomo Party★★★&lt;/a&gt;(推荐)  - 支持linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/karing&quot; target=&quot;_blank&quot;&gt;Karing&lt;/a&gt; — 基于 sing-box 内核,支持Android/ios/linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xishang0128/sparkle&quot; target=&quot;_blank&quot;&gt;Sparkle★★&lt;/a&gt; — 基于 Mihomo 内核，支持 Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/clashmi&quot; target=&quot;_blank&quot;&gt;Clash Mi&lt;/a&gt; —支持android/ios/Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chen08209/FlClash&quot; target=&quot;_blank&quot;&gt;FlClash&lt;/a&gt; — 基于 Mihomo 内核,支持Android/linux/windows、macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GUI-for-Cores/GUI.for.Clash&quot; target=&quot;_blank&quot;&gt;GUI.for.Clash&lt;/a&gt; — Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/snakem982/Pandora-Box&quot; target=&quot;_blank&quot;&gt;Pandora-Box&lt;/a&gt; — 基于 Mihomo 内核,支持linux/windows/macos&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;macOS&lt;a href=&quot;#macos&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nssurge.com&quot; target=&quot;_blank&quot;&gt;Surge★★★&lt;/a&gt; — 付费高级客户端,支持ios/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/us/app/quantumult-x/id1443988620&quot; target=&quot;_blank&quot;&gt;Quantumult X★★★&lt;/a&gt; — 付费,支持ios/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/us/app/loon/id1373567447&quot; target=&quot;_blank&quot;&gt;Loon&lt;/a&gt; —  付费,支持ios/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/2dust/v2rayN&quot; target=&quot;_blank&quot;&gt;v2rayN&lt;/a&gt; — 支持 Xray / sing-box / clash/others 内核,支持Windows/Linux/macOS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Clash-Verge-rev/clash-verge-rev&quot; target=&quot;_blank&quot;&gt;Clash Verge Rev&lt;/a&gt; — 内置 Mihomo 内核,支持 Linux/macOS/Windows&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mihomo-party-org/clash-party&quot; target=&quot;_blank&quot;&gt;Mihomo Party&lt;/a&gt;  - 支持linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/karing&quot; target=&quot;_blank&quot;&gt;Karing&lt;/a&gt; — 基于 sing-box 内核,支持Android/ios/linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xishang0128/sparkle&quot; target=&quot;_blank&quot;&gt;Sparkle&lt;/a&gt; — 基于 Mihomo 内核，支持 Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chen08209/FlClash&quot; target=&quot;_blank&quot;&gt;FlClash&lt;/a&gt; — 基于 Mihomo 内核,支持Android/linux/windows、macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/clashmi&quot; target=&quot;_blank&quot;&gt;Clash Mi&lt;/a&gt; —支持android/ios/Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GUI-for-Cores/GUI.for.Clash&quot; target=&quot;_blank&quot;&gt;GUI.for.Clash&lt;/a&gt; — Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stash.ws&quot; target=&quot;_blank&quot;&gt;Stash★★&lt;/a&gt; — 基于 sing-box（付费）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/snakem982/Pandora-Box&quot; target=&quot;_blank&quot;&gt;Pandora-Box&lt;/a&gt; — 基于 Mihomo 内核,支持linux/windows/macos&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;Linux&lt;a href=&quot;#linux&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/2dust/v2rayN&quot; target=&quot;_blank&quot;&gt;v2rayN★★&lt;/a&gt; — 支持 Xray / sing-box / clash/others 内核,支持Windows/Linux/macOS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Clash-Verge-rev/clash-verge-rev&quot; target=&quot;_blank&quot;&gt;Clash Verge Rev★★&lt;/a&gt; — 内置 Mihomo 内核,支持 Linux/macOS/Windows&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mihomo-party-org/clash-party&quot; target=&quot;_blank&quot;&gt;Mihomo Party★★★&lt;/a&gt;  - 支持linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/karing&quot; target=&quot;_blank&quot;&gt;Karing&lt;/a&gt; — 基于 sing-box 内核,支持Android/ios/linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xishang0128/sparkle&quot; target=&quot;_blank&quot;&gt;Sparkle&lt;/a&gt; — 基于 Mihomo 内核，支持 Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chen08209/FlClash&quot; target=&quot;_blank&quot;&gt;FlClash&lt;/a&gt; — 基于 Mihomo 内核,支持Android/linux/windows、macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/clashmi&quot; target=&quot;_blank&quot;&gt;Clash Mi&lt;/a&gt; —支持android/ios/Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GUI-for-Cores/GUI.for.Clash&quot; target=&quot;_blank&quot;&gt;GUI.for.Clash&lt;/a&gt;  — 支持 Linux/macOS/Windows&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/snakem982/Pandora-Box&quot; target=&quot;_blank&quot;&gt;Pandora-Box&lt;/a&gt; — 基于 Mihomo 内核,支持linux/windows/macos&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;Android&lt;a href=&quot;#android&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MetaCubeX/ClashMetaForAndroid&quot; target=&quot;_blank&quot;&gt;Clash Meta for Android★★★&lt;/a&gt;(推荐)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/karing&quot; target=&quot;_blank&quot;&gt;Karing&lt;/a&gt; — 基于 sing-box 内核,支持Android/ios/linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/clashmi&quot; target=&quot;_blank&quot;&gt;Clash Mi&lt;/a&gt; —支持android/ios/Windows / macOS / Linux&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chen08209/FlClash&quot; target=&quot;_blank&quot;&gt;FlClash★★&lt;/a&gt; — 基于 Mihomo 内核,支持Android/linux/windows、macos&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;iOS&lt;a href=&quot;#ios&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nssurge.com&quot; target=&quot;_blank&quot;&gt;Surge★★★&lt;/a&gt; — 付费高级客户端,支持ios/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/us/app/shadowrocket/id932747118&quot; target=&quot;_blank&quot;&gt;Shadowrocket★★★&lt;/a&gt; — 付费,支持多协议&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/us/app/quantumult-x/id1443988620&quot; target=&quot;_blank&quot;&gt;Quantumult X★★★&lt;/a&gt; — 付费,支持ios/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/us/app/loon/id1373567447&quot; target=&quot;_blank&quot;&gt;Loon&lt;/a&gt; —  付费,支持ios/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/karing&quot; target=&quot;_blank&quot;&gt;Karing&lt;/a&gt; — 基于 sing-box 内核,支持Android/ios/linux/windows/macos&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/KaringX/clashmi&quot; target=&quot;_blank&quot;&gt;Clash Mi&lt;/a&gt; —支持android/ios/Windows / macOS / Linux&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;HarmonyOS NEXT&lt;a href=&quot;#harmonyos-next&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xiaobaigroup/ClashBox&quot; target=&quot;_blank&quot;&gt;ClashBox&lt;/a&gt; — 独苗这一块&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;路由器（OpenWRT / Linux）&lt;a href=&quot;#路由器openwrt--linux&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vernesong/OpenClash&quot; target=&quot;_blank&quot;&gt;OpenClash★★&lt;/a&gt; - OpenWRT 上主流的 Clash 客户端&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nikkinikki-org/OpenWrt-nikki&quot; target=&quot;_blank&quot;&gt;OpenWrt-nikki★★★&lt;/a&gt;(推荐) —  基于clash核心&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/daeuniverse/daed&quot; target=&quot;_blank&quot;&gt;daed&lt;/a&gt; — 基于dae内核&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xiaorouji/openwrt-passwall&quot; target=&quot;_blank&quot;&gt;Passwall2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Thaolga/openwrt-nekobox&quot; target=&quot;_blank&quot;&gt;openwrt-nekobox&lt;/a&gt; — 基于 Sing-box核心&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;小白无脑选择clash系客户端，有其他要求可自定义选择。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>学习笔记 | Steam 假入库那些事</title><link>https://blog.liao-ke.com/posts/steam-fake-inventory/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/steam-fake-inventory/</guid><description>从 Steam 授权与清单文件机制出发，拆解“假入库”的实现思路（清单/密钥获取、Steamworks API 劫持等），对常见做法的局限与风险做说明，并给出辨别与处理建议。</description><pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;Steam假入库到底是什么？&lt;a href=&quot;#steam假入库到底是什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;淘宝上有很多低价的steam游戏cdk,但购买之后实际是运行脚本入库(有自己steam账号信息泄露的风险),可以在本地游玩.（&lt;strong&gt;换台设备重新登录账号，假入库游戏将会被清空。&lt;/strong&gt;）&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实际上账号并没有拥有游戏,别人是看不到你的账号拥有该游戏的&lt;/strong&gt;&lt;/p&gt;&lt;section&gt;&lt;h3&gt;假入库原理分析:&lt;a href=&quot;#假入库原理分析&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Steam购买游戏相当于购买游戏的游玩资格，购买完成后，将会下载游戏的清单文件(相当于下载列表),然后steam会用游戏的depot key(正版购买用户自动下发)对清单文件进行解密下载,下载完成后，打开游戏会调用steamwork api进行验证当前运行的steam账号是否拥有该游戏,认证通过后即可正常游玩。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我们可以在其中做些手脚,便可以实现假入库。&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;游戏清单文件是可以公开找到的，但是需要正版账号的depot key解密才可以解密下载(&lt;strong&gt;游戏每一个版本的清单文件对应着一个depot key,所以想要玩到最新的游戏内容，密钥文件也需要及时更新&lt;/strong&gt;)。假入库的商家可能会根据爬虫或者其他技术手段(如通过木马病毒从其他steam玩家账号中提取depot key)，可以搞到最新的游戏depot key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过解密清单将游戏完整下下来后,通过steamtool/GreenLuma hook注入自己的.dll文件,对steam原有的steamwork api进行劫持,便可以实现让游戏认为账号已经获取了该游戏的游玩权限。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;于是乎通过以上手段，便实现了一套完整的steam游戏假入库&lt;/p&gt;&lt;p&gt;&lt;strong&gt;在steam游戏破解游玩方面,主要有两种破解方法&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;一是对steam客户端进行crak&lt;a href=&quot;#一是对steam客户端进行crak&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;让steam认为你拥有该游戏的游玩权限,再搭配实时获取别人最新的depot key,便可实现几乎与正版购买一致的游戏体验(云存档,成就系统等等)&lt;/p&gt;&lt;section&gt;&lt;h4&gt;弊端:&lt;a href=&quot;#弊端&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;无法使用联机功能&lt;/li&gt;
&lt;li&gt;别人看不到你库中的游戏(无伤大雅,除非你想要通过玩游戏来证明自己的老资历,在某盒软件舆论战中占上风)&lt;/li&gt;
&lt;li&gt;系统重装后，steam假入库游戏入库数据会消失(要玩的时候重新入一下库就行了，问题不大)&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;典型代表:&lt;a href=&quot;#典型代表&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.steamtools.net&quot; target=&quot;_blank&quot;&gt;steamtool&lt;/a&gt; (闭源，国人大佬开发,功能强大)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cs.rin.ru/forum/viewtopic.php?t=103709&quot; target=&quot;_blank&quot;&gt;GreenLuma&lt;/a&gt;(原版纯命令行,操作较难,闭源,外国论坛发布)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/clinlx/CN_GreenLumaGUI&quot; target=&quot;_blank&quot;&gt;GreenLuma_CN&lt;/a&gt;(原版加上前端，方便操作)&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;二是对游戏文件本身进行修改&lt;a href=&quot;#二是对游戏文件本身进行修改&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;对游戏文件夹本身进行修改,内置一个模仿steam api行为的第三方轻量steam client,实现steam游戏脱离steam官方客户端运行,方便游戏在互联网上传播&lt;/p&gt;&lt;section&gt;&lt;h4&gt;弊端:&lt;a href=&quot;#弊端-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;不方便游戏新版本的更新和获取&lt;/li&gt;
&lt;li&gt;无法使用steam官方客户端的一些功能&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;典型代表:&lt;a href=&quot;#典型代表-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Detanup01/gbe_fork&quot; target=&quot;_blank&quot;&gt;gbe_fork&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/SteamAutoCracks/Steam-auto-crack&quot; target=&quot;_blank&quot;&gt;steam-auto-crak&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;其他:&lt;a href=&quot;#其他&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;steamlan/gbe 通过模仿steam lan api,可以实现游戏在线/离线模式下局域网联机,而不需要走steam官方服务器&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/atom0s/Steamless&quot; target=&quot;_blank&quot;&gt;steamless&lt;/a&gt; 移除steam端的d加密(不会绕过游戏游玩验证,并且非steam的d加密无法破解，比如说黑猴,需要使用别人的d加密密钥才可以认证游玩)&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;总结:&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Steam假入库商家通常通过劫持steam根目录的hid.dll文件进行自定义操作,hook核心一般采用steamtool,加上不知道哪里搞来的清单depot key源,由于是黑箱代码,无法准确判断是否含有其他的木马病毒,来获取自己steam的一些信息,对账号造成隐性风险,所以不建议使用淘宝上的 steam假入库。&lt;/p&gt;&lt;section&gt;&lt;h4&gt;辨别方法:&lt;a href=&quot;#辨别方法&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;由于steam假入库这件事已经有一定的知名度了,有些商家也学聪明了，把正版的激活流程放在介绍页，然后下面配一行小字，如果正版激活不行(100%是不成功的)，再采用其他方法(他们自己的脚本).&lt;/p&gt;&lt;p&gt;主要由以下两个方法判断:&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;cdk价格过低的，100%都是假入库&lt;/li&gt;
&lt;li&gt;直接询问客服是否可以在手机上通过steam客户端cdk激活（假入库的脚本程序无法在手机上运行）&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;解除假入库&lt;a href=&quot;#解除假入库&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;使用&lt;a href=&quot;https://cloud.ksmlc.cn/home?path=cloudreve%3A%2F%2FPDSB%40share&quot; target=&quot;_blank&quot;&gt;steam解锁文件管理器&lt;/a&gt;删除假入库的游戏&lt;/li&gt;
&lt;li&gt;然后删除steam根目录的hid.dll(steam更新64位后,hid.dll劫持的方案已经失效了,换别的方案了)&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;最后严肃声明，本文章仅供技术探讨，支持正版从我做起&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>方案分析 | 博客框架的选择</title><link>https://blog.liao-ke.com/posts/blog-framework-choose/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/blog-framework-choose/</guid><description>从静态博客与动态博客的架构差异出发，对资源占用、部署方式、运维成本与可扩展性做对比，并给出 WordPress/Typecho/Halo 与 Hexo/Hugo/Jekyll/Astro 等常见框架的选择建议。</description><pubDate>Tue, 02 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;博客框架我们应该如何选择？&lt;a href=&quot;#博客框架我们应该如何选择&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;博客大体上可以分为&lt;strong&gt;静态博客&lt;/strong&gt;和&lt;strong&gt;动态博客&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;动态博客采用的是&lt;strong&gt;前端+后端&lt;/strong&gt;的模式,而静态博客就是&lt;strong&gt;纯前端静态文件&lt;/strong&gt;（方便托管）&lt;/p&gt;&lt;section&gt;&lt;h3&gt;动态博客的优缺点:&lt;a href=&quot;#动态博客的优缺点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;优点:&lt;a href=&quot;#优点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;适合大型博客或者论坛&lt;/li&gt;
&lt;li&gt;自带后台管理评论&lt;/li&gt;
&lt;li&gt;功能集成很多，适合小白，基本不需要额外去弄什么&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;缺点:&lt;a href=&quot;#缺点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;资源占用大&lt;/li&gt;
&lt;li&gt;必须依赖服务器运行，不可使用静态host主机/serverless服务提供商(cloudflare/vercle/github pages)&lt;/li&gt;
&lt;li&gt;网站加载速度相对较慢&lt;/li&gt;
&lt;li&gt;有一定的运维成本(服务器/防火墙等费用)&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;静态博客的优缺点:&lt;a href=&quot;#静态博客的优缺点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;优点:&lt;a href=&quot;#优点-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;加载速度相对较快&lt;/li&gt;
&lt;li&gt;资源占用少。&lt;/li&gt;
&lt;li&gt;可以将网站交给serverless服务商托管（白嫖党狂喜，不需要专门的服务器）&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;缺点:&lt;a href=&quot;#缺点-1&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;要有一定的web技术功底，会手动改配置文件、布局,写文章模板&lt;/li&gt;
&lt;li&gt;框架集成的功能较少，如评论功能，音频播放器，需要自行对接第三方接口（不过很多静态博客主题里面已经把功能模板写好了，只需要更换接口地址就行）&lt;/li&gt;
&lt;li&gt;缺乏统一的后台管理功能&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;动态博客框架&lt;a href=&quot;#动态博客框架&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://wordpress.org/&quot; target=&quot;_blank&quot;&gt;WordPress★★★&lt;/a&gt;&lt;a href=&quot;#wordpress&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;世界知名动态博客框架，主题资源插件丰富，教程多。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://typecho.org/&quot; target=&quot;_blank&quot;&gt;Typecho&lt;/a&gt;&lt;a href=&quot;#typecho&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;轻量级动态博客框架，主打一个快速部署，快速上线&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://halo.run/&quot; target=&quot;_blank&quot;&gt;Halo★★&lt;/a&gt;&lt;a href=&quot;#halo&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;界面很漂亮，资源插件相对来说比较丰富，社区正在逐步发展，安装部署方法较为麻烦，比较吃服务器性能&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;静态博客框架&lt;a href=&quot;#静态博客框架&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://hexo.io/&quot; target=&quot;_blank&quot;&gt;Hexo★★★&lt;/a&gt;&lt;a href=&quot;#hexo&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;node.js开发,教程很多，社区插件主题资源丰富，缺点是当文章数量&amp;gt;1k时，构建速度会显著减缓&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://gohugo.io/&quot; target=&quot;_blank&quot;&gt;Hugo★★★&lt;/a&gt;&lt;a href=&quot;#hugo&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;go语言开发,使用go template模板，学习门槛相对其他的来说高点。运行build效率很高,支持热加载,更改不需要刷新网页页面即可生效。教程资源丰富,社区插件资源也很多，稍逊hexo,最大的优势是当文章数量很多时，构建静态网站的速度可以快其他框架几倍.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://jekyllrb.com/&quot; target=&quot;_blank&quot;&gt;Jekyll★★&lt;/a&gt;&lt;a href=&quot;#jekyll&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;资源插件相对较少,界面简洁直观,但有github官方支持,可以直接将存入仓库的md文件转换成网页&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://vitepress.dev/&quot; target=&quot;_blank&quot;&gt;VitePress&lt;/a&gt;&lt;a href=&quot;#vitepress&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;资源插件丰富，可扩性强,常用于构建文档，不用于博客&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;&lt;a href=&quot;https://astro.build/&quot; target=&quot;_blank&quot;&gt;Astro★★&lt;/a&gt;&lt;a href=&quot;#astro&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;新一代静态框架,0 javascript的技术理念让网站首页加载起来非常快,采用服务端渲染的技术理念&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;可局部初始化组件为spa,增强网站运行效率,可搭配其他前端框架组件使用，但主题资源相对较少。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;总结&lt;a href=&quot;#总结&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;对于零基础的小白，想搭建博客，首先推荐动态博客框架，首选wordpress,有一定技术基础，搭建自己个人的轻量博客推荐静态框架,首选hexo/hugo,想要更快的构建速度和热加载，选择hugo.如果想尝试更先进的技术理念和更快的首页加载速度，可以尝试astro&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;杂谈&lt;a href=&quot;#杂谈&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;本站采用hugo构建,github仓库储存,cloudflare远程克隆部署,评论功能对接waline。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>开发日记 | 用cloudflare worker实现telegram bot</title><link>https://blog.liao-ke.com/posts/cloudflare-worker-telegram-bot/</link><guid isPermaLink="true">https://blog.liao-ke.com/posts/cloudflare-worker-telegram-bot/</guid><description>使用Cloudflare Worker和KV数据库实现带有记忆功能的Telegram聊天机器人，无需服务器即可部署AI对话功能</description><pubDate>Mon, 20 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这段时间闲着没事，想做一个 Telegram Bot 来玩玩。了解了一下，可实施的开发方案还挺多的，Java/Python 等等都有相对应的库。但是奈何&lt;strong&gt;我没有服务器&lt;/strong&gt;，无法进行传统的前后端开发。&lt;/p&gt;
&lt;p&gt;于是乎，我想到了另一种开发思路：利用 &lt;strong&gt;Cloudflare 提供的 Serverless 无状态 JavaScript Worker&lt;/strong&gt; 以及 &lt;strong&gt;Telegram Bot 官方支持的 Webhook 功能&lt;/strong&gt;来实现无服务器聊天机器人。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;实现原理&lt;a href=&quot;#实现原理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我们在聊天机器人的界面发送命令：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/chat 聊天内容&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;通过设置 Webhook 地址指向 Worker，Worker 中写好处理指令的代码，截取 &lt;code&gt;/开始&lt;/code&gt; 后面的文字，然后转发给 &lt;strong&gt;Cloudflare 官方提供的免费的大语言模型后端&lt;/strong&gt;，然后再处理返回的信息，最后再通过 &lt;strong&gt;Telegram Bot API&lt;/strong&gt; 再返回消息到客户端。&lt;/p&gt;&lt;p&gt;这样便实现了&lt;strong&gt;无服务器的聊天 AI Bot&lt;/strong&gt;，但是这有个缺点：用户的每一次聊天都是单独的一次请求，bot没有上下文记忆,因为 Worker 本身是个&lt;strong&gt;无状态的js执行器&lt;/strong&gt;，所以这个 Bot 其实相当于是一个&lt;strong&gt;图形化的终端命令请求器&lt;/strong&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;但是 &lt;strong&gt;Cloudflare 有提供免费的额外的 KV 数据库&lt;/strong&gt;，于是我们再改动一下代码：&lt;a href=&quot;#但是-cloudflare-有提供免费的额外的-kv-数据库于是我们再改动一下代码&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;用户发来的文字不直接请求大语言模型后端&lt;/li&gt;
&lt;li&gt;而是先&lt;strong&gt;存入 KV 数据库&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;最后将 KV 数据库里的数据一起再发给大语言模型后端&lt;/li&gt;
&lt;li&gt;处理返回的信息&lt;/li&gt;
&lt;li&gt;返回 Telegram 客户端&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;于是Worker通过外挂KV数据库，最终便实现了&lt;strong&gt;带有记忆的无服务器聊天 AI 机器人&lt;/strong&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;实现源代码&lt;a href=&quot;#实现源代码&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TELEGRAM_BOT_TOKEN&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CF_API_TOKEN&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;`https://api.cloudflare.com/client/v4/accounts/1f5b3d5417456835c8191a2ec42f449e/ai/run/&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;Authorization&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`Bearer &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;CF_API_TOKEN&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;POST&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sendTelegramMessage&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;chat_id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`https://api.telegram.org/bot&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;TELEGRAM_BOT_TOKEN&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/sendMessage`&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;POST&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;headers&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;22&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;chat_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;23&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;24&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;parse_mode&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;MarkdownV2&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;25&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;26&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;27&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;发送 Telegram 消息失败:&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;29&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;30&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;31&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;32&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;33&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;34&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;method&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;POST&quot;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;ok&quot;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;35&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;36&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;37&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;38&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Telegram Update:&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;39&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;40&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;41&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;ok&quot;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;42&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;43&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;44&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;^&lt;/span&gt;&lt;span&gt;&lt;span&gt;\/&lt;/span&gt;&lt;span&gt;chat(?:@&lt;/span&gt;&lt;/span&gt;&lt;span&gt;\w&lt;/span&gt;&lt;span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;(?:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;\s&lt;/span&gt;&lt;span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;\s\S&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;45&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;arg&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;trim&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;46&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;47&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;完整消息文本:&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;48&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;命令参数:&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;arg&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;49&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;50&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;arg&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;51&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sendTelegramMessage&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;请在 /chat 后输入要生成的内容，例如：/chat 写一个小故事&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;52&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;53&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;54&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;bot&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;55&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;parse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;56&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;role&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;user&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;arg&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;57&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;bot&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;put&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;58&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;59&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;aiResponse&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;@cf/openai/gpt-oss-120b&quot;&lt;/span&gt;&lt;span&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;60&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;instructions&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;你是liaoke的私人中文AI助手，简洁地回答用户的问题。&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;61&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;reasoning&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;&quot;effort&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;medium&quot;&lt;/span&gt;&lt;span&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;62&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;63&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;64&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;65&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;AI 原始响应:&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;aiResponse&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;66&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;67&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;68&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reasonText&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;aiResponse&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;output&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;69&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;reasoning&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;70&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;71&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;72&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\n\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;AI 无法生成内容&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;73&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;74&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;outputText&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;aiResponse&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;output&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;75&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;76&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;77&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;78&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\n\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;AI 无法生成内容&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;79&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;80&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;81&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;escapeMD&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;82&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;83&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;84&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\\\&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;85&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/`/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;`&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;86&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/_/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;_&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;87&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\*&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;*&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;88&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\[&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;[&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;89&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\]&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;]&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;90&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/~/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;~&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;91&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&amp;gt;/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;&amp;gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;92&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/#/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;#&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;93&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\+&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;+&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;94&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/-/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;-&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;95&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/=/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;=&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;96&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\|&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;|&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;97&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\{&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;{&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;98&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;}&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;99&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\.&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;.&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;100&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;replace&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/!/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;!&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;101&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;102&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;103&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;104&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;messageMD&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;105&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;🧠 推理过程：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;106&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;\`\`\`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;107&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;escapeMD&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;reasonText&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;108&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;\`\`\`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;109&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;110&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;💬 最终回答：&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;111&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;escapeMD&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;outputText&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;112&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;113&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;114&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;115&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sendTelegramMessage&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;messageMD&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;116&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;role&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;assistant&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;outputText&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;117&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;bot&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;put&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;118&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;AI 输出发送给用户:&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;messageMD&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;119&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;120&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;121&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;ok&quot;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;122&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;123&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;解析 JSON 或处理失败:&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;124&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Response&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;error&quot;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;400&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;125&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;126&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;127&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content:encoded></item></channel></rss>