<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>王帅的博客</title><description>王帅的个人技术博客</description><link>https://blog.wangshuai.app/</link><language>zh_CN</language><item><title>chatgpt使用自建mcp插件和openai的tunnel做开发</title><link>https://blog.wangshuai.app/2026-07-25-chatgpt%E4%BD%BF%E7%94%A8%E7%BD%91%E9%A1%B5%E9%A2%9D%E5%BA%A6%E5%BC%80%E5%8F%91%E6%9C%AC%E5%9C%B0%E9%A1%B9%E7%9B%AE/</link><guid isPermaLink="true">https://blog.wangshuai.app/2026-07-25-chatgpt%E4%BD%BF%E7%94%A8%E7%BD%91%E9%A1%B5%E9%A2%9D%E5%BA%A6%E5%BC%80%E5%8F%91%E6%9C%AC%E5%9C%B0%E9%A1%B9%E7%9B%AE/</guid><pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;最近AI使用频繁;因此开通了日区&lt;code&gt;GPT Plus&lt;/code&gt;;本来之前还研究怎么优化每次&lt;code&gt;Codex&lt;/code&gt;的5小时限额;上周 &lt;code&gt;Tibo&lt;/code&gt;就宣布把5小时限额去掉&lt;/p&gt;
&lt;p&gt;这就导致周额度相形见绌了;前天把额度用完后就在研究其它的方法;&lt;strong&gt;传奇程序员&lt;/strong&gt;不能就这样下线啊;&lt;/p&gt;
&lt;p&gt;正巧看到&lt;code&gt;L&lt;/code&gt;站的一篇文章:&lt;a href=&quot;https://linux.do/t/topic/2259880&quot;&gt;通过 Coding Tools MCP 最大化利用 GPT 订阅额度，解决额度焦虑&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;本文介绍我实践出的简易临时使用&lt;code&gt;GPT Web&lt;/code&gt;开发本地项目的方法; 路径与上文有些不同&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;解决方案和&lt;code&gt;L&lt;/code&gt;站文章介绍的方法类似;都是使用&lt;code&gt;GPT Web&lt;/code&gt;端的插件功能&lt;/p&gt;
&lt;p&gt;一句话总结:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用开发人员模式,自建一个可以访问本地文件的MCP服务,通过GPT官方隧道(&lt;code&gt;tunnel&lt;/code&gt;) 让AI可以直接读写本地指定的文件达到本地开发的目的&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;根据环境选择最终方案&lt;/h4&gt;
&lt;p&gt;如果不想从头判断自己应该走哪套方案,可以直接在下面按实际环境选择。这里的逻辑是: &lt;strong&gt;是否有域名决定能否使用 Cloudflare Tunnel;是否有服务器决定是否增加 OIDC / Pocket ID 认证层&lt;/strong&gt;。选择完成后会自动组合出对应架构、最终步骤和命令;后面的原始教程内容仍然保留,可以继续查看详细说明。&lt;/p&gt;
&lt;p&gt;&amp;lt;div id=&quot;mcp-route-picker&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;script data-pjax src=&quot;/custom_js/mcp-route-picker.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h4&gt;新版方案-纯文件访问&lt;/h4&gt;
&lt;p&gt;在官方tunnel的基础之上我又研究出了用&lt;code&gt;cloudflare tunnel&lt;/code&gt;穿透的方法(PS:我本来也做了公开MCP服务的方法;但没CF的网络加持总是&lt;code&gt;time out&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;此处只说明和下面流程不同的地方:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用支持Oauth认证的&lt;code&gt;MCP proxy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里使用的工具是:&lt;strong&gt;&lt;a href=&quot;https://github.com/sigbit/mcp-auth-proxy&quot;&gt;mcp-auth-proxy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GPT官方隧道(&lt;code&gt;tunnel&lt;/code&gt;) 不仅实现了http访问;还加了自己的API鉴权;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;modelcontextprotocol/server-filesystem&lt;/code&gt;不支持直接Http访问;因此需要加一个&lt;strong&gt;OAuth 2.1/OIDC gateway&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**&lt;a href=&quot;https://github.com/sigbit/mcp-auth-proxy&quot;&gt;mcp-auth-proxy&lt;/a&gt;**不仅是mcp代理,还集成了&lt;code&gt;MCP&lt;/code&gt;所需的认证功能;比如&lt;code&gt;GPTMCP&lt;/code&gt;支持的&lt;code&gt;DCR(动态客户端注册)&lt;/code&gt;;没有这个功能的话就需要同时用tunnel转发&lt;code&gt;MCP Server&lt;/code&gt;以及&lt;code&gt;Oauth&lt;/code&gt;认证服务&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;cf-mcp-auth-proxy&quot;&amp;gt;&amp;lt;/span&amp;gt;
我测试OK的命令是:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  D:\Tools\mcp-auth-proxy.exe `
  -d &quot;D:\Tools\data&quot; `
  --listen 192.168.1.XX:24024 `
  --external-url https://{your-domain} `
  --no-auto-tls  `
  --tls-accept-tos `
  --oidc-configuration-url &quot;https://your-provider.com/.well-known/openid-configuration&quot; `
  --oidc-client-id &quot;your-oidc-client-id&quot; `
  --oidc-client-secret &quot;your-oidc-client-secret&quot; `
  --oidc-allowed-users &quot;user1@example.com,user2@example.com&quot; `
  -- npx.cmd -y @modelcontextprotocol/server-filesystem &quot;D:\Tools&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;无服务器时使用 Password 认证&lt;/h4&gt;
&lt;p&gt;&amp;lt;span id=&quot;cf-password-auth&quot;&amp;gt;&amp;lt;/span&amp;gt;
如果没有可长期运行 &lt;code&gt;Pocket ID&lt;/code&gt; 的服务器,则不需要配置 OIDC;&lt;code&gt;mcp-auth-proxy&lt;/code&gt; 自带 Password 登录认证。&lt;/p&gt;
&lt;p&gt;这里要注意:&lt;strong&gt;ChatGPT 对接的仍然是 OAuth 2.1 / DCR,Password 只是用户在授权页面上的登录方式,不是让 ChatGPT 直接使用密码访问 MCP。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;D:\Tools\mcp-auth-proxy.exe `
-d &quot;D:\Tools\data&quot; `
--listen 192.168.1.XX:24024 `
--external-url https://{your-domain} `
--no-auto-tls `
--password &quot;请替换为强密码&quot; `
-- npx.cmd -y @modelcontextprotocol/server-filesystem &quot;D:\Tools&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果担心明文密码出现在命令行或历史记录中,也可以改用 &lt;code&gt;--password-hash&lt;/code&gt; 配置 bcrypt hash。&lt;/p&gt;
&lt;p&gt;ChatGPT Web 中仍然选择 &lt;code&gt;OAuth&lt;/code&gt; 身份认证,地址填写 &lt;code&gt;https://{your-domain}/mcp&lt;/code&gt;;高级 OAuth 设置保持自动发现即可,不需要填写 Pocket ID/OIDC 的 Client ID 和 Client Secret。&lt;/p&gt;
&lt;p&gt;扫描工具或首次连接时,浏览器会跳转到 &lt;code&gt;mcp-auth-proxy&lt;/code&gt; 的授权页面;输入上面 &lt;code&gt;--password&lt;/code&gt; 设置的密码完成认证后,再回到 ChatGPT 完成连接。&lt;/p&gt;
&lt;p&gt;因此这条路线不要选择“无认证”,也不要把 Password 直接填到 ChatGPT 中。&lt;/p&gt;
&lt;p&gt;这里的“无服务器”只是指没有单独部署 Pocket ID / OIDC 服务;&lt;code&gt;mcp-auth-proxy&lt;/code&gt; 和 &lt;code&gt;cloudflared&lt;/code&gt; 仍然运行在本地 PC,所以本地 PC 关机后这个 MCP 也会离线。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在CF的&lt;a href=&quot;https://dash.cloudflare.com/tunnels&quot;&gt;Tunnels&lt;/a&gt;中配置一个本机路由(到&lt;code&gt;your-domain&lt;/code&gt;)的应用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;span id=&quot;cf-tunnel-config&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/cf_tunnel_application.png&quot; alt=&quot;cf_tunnel_application&quot; /&gt;&lt;/p&gt;
&lt;p&gt;确保直接公网访问会报401&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ChatGpt的插件直接使用&lt;code&gt;OAuth&lt;/code&gt;身份认证&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;地址填&lt;code&gt;your-domain/mcp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;点击高级&lt;code&gt;OAuth&lt;/code&gt;设置的时候会自动识别出认证授权路由&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;chatgpt-oauth-config&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/mcp_oauth.png&quot; alt=&quot;mcp oauth&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建成功后点击连接:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;有服务器 / OIDC&lt;/strong&gt;:会跳转到 &lt;code&gt;Pocket ID&lt;/code&gt;,完成登录后点击页面 &lt;code&gt;Auth&lt;/code&gt; 即可连接成功。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无服务器 / Password&lt;/strong&gt;:会跳转到 &lt;code&gt;mcp-auth-proxy&lt;/code&gt; 的密码认证页面,输入启动命令中 &lt;code&gt;--password&lt;/code&gt; 设置的密码后即可连接成功。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;支持完整开发能力的单MCP服务方案&lt;/h4&gt;
&lt;p&gt;上面的MCP服务&lt;code&gt;modelcontextprotocol/server-filesystem&lt;/code&gt;只能让AI支持访问一个PC的文件夹(可以多目录),一个&lt;code&gt;mcp-auth-proxy.exe&lt;/code&gt;对应一个MCP服务&lt;/p&gt;
&lt;p&gt;除了文件访问,开发时还需要的一大功能是命令执行;我又找到另一个集成专为开发服务的MCP服务:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/wonderwhy-er/DesktopCommanderMCP&quot;&gt;DesktopCommanderMCP&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它的介绍是给&lt;code&gt;Claude&lt;/code&gt;使用,实际也很配&lt;code&gt;ChatGPT Web&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;因此,本地执行命令就变成了:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  D:\Tools\mcp-auth-proxy.exe `
  -d &quot;D:\Tools\data&quot; `
  --listen 192.168.1.XX:24024 `
  --external-url https://{your-domain} `
  --no-auto-tls  `
  --tls-accept-tos `
  --oidc-configuration-url &quot;https://your-provider.com/.well-known/openid-configuration&quot; `
  --oidc-client-id &quot;your-oidc-client-id&quot; `
  --oidc-client-secret &quot;your-oidc-client-secret&quot; `
  --oidc-allowed-users &quot;user1@example.com,user2@example.com&quot; `
  -- npx.cmd -y @wonderwhy-er/desktop-commander@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PS:同理,后面的GPT官方隧道(tunnel),也可以换这个&lt;code&gt;@wonderwhy-er/desktop-commander@latest&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这个启动命令不能设置允许访问的文件;但可以直接在AI中设置;&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;ChatGPT&lt;/code&gt;网页端配置完成后,直接对AI说 &lt;code&gt;修改配置&lt;/code&gt;即可&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;desktop-commander-config&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/gpt_mcp_config.png&quot; alt=&quot;change mcp setting&quot; /&gt;&lt;/p&gt;
&lt;p&gt;MCP测试连通性时,推荐&lt;code&gt;POSTMAN&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;下面是之前使用官方tunnel的保留方案:&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;旧版原生 OpenAI API Tunnels方案&lt;/h4&gt;
&lt;p&gt;经测试,免费用户也可以这样做&lt;/p&gt;
&lt;p&gt;不过免费用户不能使用高级模型;意义不大&lt;/p&gt;
&lt;h3&gt;操作步骤&lt;/h3&gt;
&lt;h4&gt;开启开发人员模式&lt;/h4&gt;
&lt;p&gt;打开&lt;a href=&quot;https://chatgpt.com/&quot;&gt;https://chatgpt.com/&lt;/a&gt;,点击左下角头像:&lt;code&gt;设置&lt;/code&gt;→&lt;code&gt;账户安全与登录&lt;/code&gt;→打开&lt;code&gt;开发人员模式&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;openai-dev-mode&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/chatgpt_dev.png&quot; alt=&quot;chatgpt dev&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;创建GPT隧道(tunnel)&lt;/h4&gt;
&lt;p&gt;打开&lt;code&gt;OpenAI API平台&lt;/code&gt;:设置中的&lt;a href=&quot;https://platform.openai.com/settings/organization/tunnels&quot;&gt;Tunnels - OpenAI API&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;openai-create-tunnel&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/openai_tunnels.png&quot; alt=&quot;OpenAPI tunnels&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建一个&lt;code&gt;tunnel&lt;/code&gt;,复制好它的&lt;code&gt;ID&lt;/code&gt; &lt;code&gt;tunnel_6axxxx&lt;/code&gt;备用;&lt;/p&gt;
&lt;p&gt;点击&lt;code&gt;Download tunnel-client&lt;/code&gt;去&lt;code&gt;Github&lt;/code&gt;上下载最新的客户端备用&lt;/p&gt;
&lt;h4&gt;创建隧道专用APIKey&lt;/h4&gt;
&lt;p&gt;还是&lt;code&gt;OpenAI API平台&lt;/code&gt;:设置中的&lt;a href=&quot;https://platform.openai.com/settings/organization/api-keys&quot;&gt;API keys - OpenAI API&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;创建一个专用的&lt;code&gt;APIKEY&lt;/code&gt;权限勾选&lt;code&gt;Tunnels&lt;/code&gt;的&lt;code&gt;Read&lt;/code&gt; &lt;code&gt;Use&lt;/code&gt;;&lt;code&gt;Project&lt;/code&gt;选&lt;code&gt;Defalt project&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;openai-api-key&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/openai_tunnel_apikey.png&quot; alt=&quot;tunnel api key&quot; /&gt;&lt;/p&gt;
&lt;p&gt;复制生成的&lt;code&gt;sk-proj-IEAXXXX&lt;/code&gt; 这样的&lt;code&gt;APIKey&lt;/code&gt;备用&lt;/p&gt;
&lt;h4&gt;本地连接隧道&lt;/h4&gt;
&lt;p&gt;下载好前面提到的&lt;code&gt;tunnel-client.zip&lt;/code&gt;后解压开;在你期望&lt;code&gt;MCP&lt;/code&gt;访问的目录;按住&lt;code&gt;shift&lt;/code&gt;右键,点击&lt;code&gt;在此处运行powershell&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;由于&lt;code&gt;ChatGPT&lt;/code&gt;不能直连;因此还需要配置&lt;code&gt;socket&lt;/code&gt;代理&lt;/p&gt;
&lt;p&gt;文件路径不知道有什么问题;我发现只能用相对路径,&lt;/p&gt;
&lt;p&gt;填入备用的&lt;code&gt;API Key&lt;/code&gt;和&lt;code&gt;tunnel id&lt;/code&gt;后执行以下命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# OpenAI 控制面走代理
$env:CONTROL_PLANE_HTTP_PROXY = &quot;http://127.0.0.1:7890&quot;

# 原有参数
$env:CONTROL_PLANE_API_KEY = &quot;sk-proj-你的API密钥&quot;
$env:CONTROL_PLANE_TUNNEL_ID = &quot;tunnel_6xxxx&quot;

#直接将当前目录设为mcp可访问
C:\Applications\Tools\tunnel-client.exe run  --mcp.command &apos;cmd.exe /c npx.cmd -y @modelcontextprotocol/server-filesystem &quot;.&quot;&apos;

#或者使用集成的带文件访问及命令执行的desktop-commander,二选一
C:\Applications\Tools\tunnel-client.exe run  --mcp.command &apos;cmd.exe /c npx.cmd -y @wonderwhy-er/desktop-commander@latest&apos;


# http://127.0.0.1:8080/ui#logs
  
# C:\Users\王帅\AppData\Roaming\tunnel-client  

# C:\Applications\Tools\tunnel-client.exe init `
#   --sample sample_mcp_stdio_local `
#   --profile gmail-tunnel `
#   --tunnel-id $([Environment]::GetEnvironmentVariable(&quot;CONTROL_PLANE_TUNNEL_ID&quot;,&quot;User&quot;)) `
#   --mcp.command &apos;cmd.exe /c npx.cmd -y @modelcontextprotocol/server-filesystem &quot;.&quot;&apos;

 # $env:CONTROL_PLANE_HTTP_PROXY=[Environment]::GetEnvironmentVariable(&quot;CONTROL_PLANE_HTTP_PROXY&quot;,&quot;User&quot;); $env:CONTROL_PLANE_API_KEY=[Environment]::GetEnvironmentVariable(&quot;CONTROL_PLANE_API_KEY&quot;,&quot;User&quot;); $env:CONTROL_PLANE_TUNNEL_ID=[Environment]::GetEnvironmentVariable(&quot;CONTROL_PLANE_TUNNEL_ID&quot;,&quot;User&quot;); tunnel-client run --profile gmail-tunnel 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;假如有什么不懂或报错直接问&lt;code&gt;ChatGPT&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;执行成功后打开网页:&lt;a href=&quot;http://127.0.0.1:8080/ui#logs&quot;&gt;http://127.0.0.1:8080&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;正常右上角会显示&lt;code&gt;Health:live&lt;/code&gt;和&lt;code&gt;Ready:ready&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;openai-local-tunnel&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/openai_tunnel_ready.png&quot; alt=&quot;openai tunnel ready&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;新建MCP插件(Plugin)&lt;/h4&gt;
&lt;p&gt;回到&lt;code&gt;GPT Web&lt;/code&gt;打开&lt;a href=&quot;https://chatgpt.com/plugins&quot;&gt;插件页面&lt;/a&gt;;点击右边的+新增插件&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;:要先执行前面的命令,本地启动MCP服务之后再创建&lt;code&gt;Plugin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;隧道&lt;/code&gt;选择刚刚创建的&lt;/p&gt;
&lt;p&gt;&lt;code&gt;身份验证&lt;/code&gt;我直接用的&lt;code&gt;none&lt;/code&gt;(未授权)&lt;/p&gt;
&lt;p&gt;勾选下方的&lt;code&gt;我了解并希望继续&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;span id=&quot;openai-add-plugin&quot;&amp;gt;&amp;lt;/span&amp;gt;
&lt;img src=&quot;/img/chatgpt_add_plugin.png&quot; alt=&quot;chatgpt add plugin&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建成功后点击&lt;code&gt;连接&lt;/code&gt;;&lt;/p&gt;
&lt;p&gt;后续就可以在&lt;code&gt;插件&lt;/code&gt;中看到已安装的&lt;code&gt;个人&lt;/code&gt;插件&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/gpt_person_plugin.png&quot; alt=&quot;person plugin&quot; /&gt;&lt;/p&gt;
&lt;p&gt;也可以在&lt;code&gt;设置&lt;/code&gt;的&lt;code&gt;插件&lt;/code&gt;中查看&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;ChatGPT Web&lt;/code&gt;端的插件中;如果能看到&lt;code&gt;MCP&lt;/code&gt;支持的操作;则表明一切成功;如果看不到可以点击右上角设置→&lt;code&gt;重新连接&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/chatgpt_plugin_mcp_success.png&quot; alt=&quot;chatgpt_plugin_mcp_success&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;测试&lt;/h4&gt;
&lt;p&gt;在&lt;code&gt;ChatGPT web&lt;/code&gt;上新开一个聊天;选择&lt;code&gt;个人&lt;/code&gt;插件让它调用&lt;code&gt;MCP&lt;/code&gt;返回文件列表测试最终结果&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/chatgpt_plugin_test.png&quot; alt=&quot;chatgpt_plugin_test&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;恭喜你,学会了ChatGPT的插件开发!&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;注意事项&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;添加插件报错:&lt;code&gt;创建连接器时出错&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Something went wrong. If this issue persists please contact us through our help center at help.openai.com
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/chatpgt_sometingwrong.png&quot; alt=&quot;gptplugin_something_wrong&quot; /&gt;&lt;/p&gt;
&lt;p&gt;遇到这个错误,就是前面说的;&lt;code&gt;MCP&lt;/code&gt;插件无法通过&lt;code&gt;tunnel&lt;/code&gt;连接到服务器导致的;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方法就是先执行tunnel-client.exe run命令创建好MCP服务再添加插件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过&lt;code&gt;F12&lt;/code&gt;检查:&lt;code&gt;https://chatgpt.com/backend-api/aip/connectors/mcp&lt;/code&gt;的&lt;code&gt;response&lt;/code&gt;返回:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;detail&quot;: {
        &quot;type&quot;: &quot;mcp_error&quot;,
        &quot;developer_message&quot;: &quot;MCP SSE probe returned 404 from openai.org&quot;,
        &quot;mcp_url&quot;: &quot;https://tunnel-service.gateway.unified-0.internal.api.openai.org/v1/mcp/tunnel_6aXXXXX&quot;,
        &quot;kind&quot;: &quot;invalid_response&quot;,
        &quot;upstream_status&quot;: 404,
        &quot;response_content_type&quot;: &quot;application/json&quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即可知道原因&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每次断开&lt;code&gt;tunnel&lt;/code&gt;客户端后假如遇到访问问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在&lt;code&gt;设置&lt;/code&gt;→&lt;code&gt;插件&lt;/code&gt;→选择个人插件→右上角菜单→&lt;code&gt;重新连接&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/chatgpt_plugin_reconnect.png&quot; alt=&quot;chatgpt plugin reconnect&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要是还遇到什么奇怪的问题,可以把GPT的MCP插件删了重新添加&lt;/li&gt;
&lt;li&gt;测试MCP服务可用性方法:使用新版&lt;code&gt;POSTMAN&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;添加一个&lt;code&gt;MCP&lt;/code&gt;服务;输入mcp服务地址(通常以&lt;code&gt;/mcp&lt;/code&gt;结尾);&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/postman_mcp_test.png&quot; alt=&quot;postman_mcp_test&quot; /&gt;&lt;/p&gt;
&lt;p&gt;首次连接时会启动OAuth认证流程,点击按钮弹窗授权;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/postman_mcp_auth.png&quot; alt=&quot;postman_mcp_auth&quot; /&gt;&lt;/p&gt;
&lt;p&gt;连接成功后能在&lt;code&gt;Message&lt;/code&gt;的&lt;code&gt;Tools&lt;/code&gt;中能看到支持的所有操作;点击&lt;code&gt;Run&lt;/code&gt;即可 测试&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://linux.do/t/topic/2259880&quot;&gt;通过 Coding Tools MCP 最大化利用 GPT 订阅额度，解决额度焦虑&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chatgpt.com/&quot;&gt;&lt;code&gt;ChatGPT&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>王者荣耀世界优化着色器报错解决办法</title><link>https://blog.wangshuai.app/2026-07-11-%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80%E4%B8%96%E7%95%8C%E4%BC%98%E5%8C%96%E7%9D%80%E8%89%B2%E5%99%A8%E6%8A%A5%E9%94%99%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/</link><guid isPermaLink="true">https://blog.wangshuai.app/2026-07-11-%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80%E4%B8%96%E7%95%8C%E4%BC%98%E5%8C%96%E7%9D%80%E8%89%B2%E5%99%A8%E6%8A%A5%E9%94%99%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/</guid><pubDate>Sat, 11 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;最近启动《王者荣耀世界》时，在优化着色器的过程中遇到了游戏崩溃。&lt;/p&gt;
&lt;p&gt;报错内容如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Fatal error: [File:Unknown] [Line: 934] 
Rendering thread exception:
Fatal error: [File:Unknown] [Line: 1182] 
ShaderCodeArchive::DecompressShader(): Could not decompress shader (GetShaderCompressionFormat=Oodle). The CPU (13th Gen Intel(R) Core(TM) i7-13700K) may be unstable; for details see http://www.radgametools.com/oodleintel.htm


0x00007ffba9a21c0a KERNELBASE.dll!UnknownFunction []
0x00000001468640f1 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000146866e9c NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000141a11581 NGR-Win64-Shipping.exe!UnknownFunction []
0x000000014682dff2 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000144166640 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000142a4de40 NGR-Win64-Shipping.exe!UnknownFunction []
0x00000001446e23d5 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000141067b8e NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000141065f95 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000141379b11 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000141379cb0 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000141067d6d NGR-Win64-Shipping.exe!UnknownFunction []
0x000000014106a43f NGR-Win64-Shipping.exe!UnknownFunction []
0x000000014106a1b5 NGR-Win64-Shipping.exe!UnknownFunction []
0x0000000142a4841f NGR-Win64-Shipping.exe!UnknownFunction []
0x00000001417e091d NGR-Win64-Shipping.exe!UnknownFunction []
0x00000001417e02b2 NGR-Win64-Shipping.exe!UnknownFunction []
0x00000001417e01ca NGR-Win64-Shipping.exe!UnknownFunction []
0x000000014145c024 NGR-Win64-Shipping.exe!UnknownFunction []
0x000000014145beda NGR-Win64-Shipping.exe!UnknownFunction []
0x00007ffbab75e957 KERNEL32.DLL!UnknownFunction []
0x00007ffbac7ead6c ntdll.dll!UnknownFunction []
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/img/wangzhe-world-shader-crash.png&quot; alt=&quot;王者荣耀世界优化着色器报错&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这问题从6月二十多号的着色器优化出现;等它两周了还没解决;不知道这些人怎么搞的&lt;/p&gt;
&lt;h3&gt;问题原因&lt;/h3&gt;
&lt;p&gt;这个问题主要出现在使用13、14代&lt;code&gt;Intel CPU&lt;/code&gt;中,因为众所周知原因;这两代CPU 缩肛了，报错弹窗中也会提示CPU可能不稳定。理论上可以通过给CPU降频解决。&lt;/p&gt;
&lt;p&gt;我之前玩&lt;code&gt;SC2&lt;/code&gt;时也遇到过13、14代&lt;code&gt;Intel CPU&lt;/code&gt;导致的游戏崩溃，最后通过降频解决&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;&lt;s&gt;解决方法就是在游戏启动器的设置中清理着色器缓存，然后重新启动游戏，让游戏重新生成着色器缓存。&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;这个解决方案不行,多试几次后依旧会报错;最终还是通过降低电压成功进游戏的:&lt;/p&gt;
&lt;p&gt;我是&lt;code&gt;Micro-Star PRO Z690-A WIFI DDR4&lt;/code&gt;主板,在性能中做如下设置:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;关闭&lt;code&gt;Intel SpeedStep&lt;/code&gt;和&lt;code&gt;Intel Speed Shift&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设置&lt;code&gt;p-core ratio&lt;/code&gt; 从&lt;code&gt;+1&lt;/code&gt; 到 &lt;code&gt;-2&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;清理前备份&lt;/h4&gt;
&lt;p&gt;着色器缓存文件位于游戏目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Program Files\KingLauncher\HOKWorld\WindowsNoEditor\NGR\PSOCache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;清理前可以将整个&lt;code&gt;PSOCache&lt;/code&gt;文件夹复制到其它位置备份。如果清理后出现其它问题，可以再将备份文件恢复到原目录。&lt;/p&gt;
&lt;h4&gt;操作步骤&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;打开《王者荣耀世界》启动器，进入&lt;code&gt;设置&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在左侧选择&lt;code&gt;更新修复&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;找到&lt;code&gt;着色器缓存&lt;/code&gt;，点击&lt;code&gt;一键清理&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/wangzhe-world-clear-shader-cache.png&quot; alt=&quot;清理王者荣耀世界着色器缓存&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;清理完成后重新启动游戏，等待游戏再次优化着色器&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;注意事项&lt;/h3&gt;
&lt;p&gt;清理后着色器优化还是有可能失败，但成功率会大大提高;我试了三次就成功了。&lt;/p&gt;
</content:encoded></item><item><title>微信小程序导航站要点解析</title><link>https://blog.wangshuai.app/2026-05-30-%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AF%BC%E8%88%AA%E7%AB%99/</link><guid isPermaLink="true">https://blog.wangshuai.app/2026-05-30-%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AF%BC%E8%88%AA%E7%AB%99/</guid><pubDate>Sat, 30 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;工作有开发微信小程序的内容,而PC微信上的微信浏览器和小程序首页不尽如人意 (打开不方便,首页有广告和其它内容)&lt;/p&gt;
&lt;p&gt;因此结合之前的经验以及最近的发现;写了一个方便的小程序导航页;此为单HTML页面&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/minip_navi.png&quot; alt=&quot;minip_navi&quot; /&gt;&lt;/p&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;Chrome与手机双支持&lt;/li&gt;
&lt;li&gt;自定义跳转参数和页面&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;打开微信浏览器这最后一公里用到了微信的截图识别二维码功能&lt;/p&gt;
&lt;p&gt;代码请看:https://gist.github.com/wangshuai-007/1dcdc5c09ba7d7e2fb3a0e2442800cbd&lt;/p&gt;
&lt;h3&gt;配置说明&lt;/h3&gt;
&lt;p&gt;配置主要为变量&lt;code&gt;miniProgramGroups&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;示例大概是这样的:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  const miniProgramGroups = {   
        &quot;常用&quot;: {
          &quot;wxcff7381e631cf54e&quot;: { name: &quot;微信开发者助手&quot;, icon: &quot;https://developers.weixin.qq.com/community/ngi/personal/suncode/wxcff7381e631cf54e&quot;,prodUrl:&quot;weixin://dl/business/?appid=wxcff7381e631cf54e&amp;amp;path=pages/index/index&quot; , testUrl: &quot;https://open.weixin.qq.com/sns/getexpappinfo?appid=wxcff7381e631cf54e&quot;},   
        },
        &quot;极简&quot;:{
          &quot;wxcff7381e631cf54e&quot;:{
            name:&quot;极简小程序&quot;,
          }
        }      
      };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;支持的参数有:&lt;/p&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示的名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;icon&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;图标,默认用小程序码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;testUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;体验版二维码地址,可以从小程序后台扫码后解析得到&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;prodUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;正式二维码地址,一般不需要;只在需要用参数打开页面时有用;具体参数说明请查看微信文档:&lt;a href=&quot;https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-scheme.html&quot;&gt;获取 URL Scheme&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;要点解析&lt;/h3&gt;
&lt;p&gt;之前写过一篇文章:&lt;a href=&quot;/2026-01-10-open-wechat-miniprogram-by-url/&quot;&gt;通过url打开微信小程序&lt;/a&gt;介绍了 &lt;code&gt;URL Scheme&lt;/code&gt;和&lt;code&gt;PC快捷方式&lt;/code&gt;打开小程序的方法;这里介绍其它的要点&lt;/p&gt;
&lt;h4&gt;打开微信浏览器&lt;/h4&gt;
&lt;p&gt;日常开发使用的chrome;但体验版微信小程序由于有认证必须要在微信浏览器里面才行;所以使用微信浏览器打开指定的链接是最难的部分;&lt;/p&gt;
&lt;p&gt;解决方法是&lt;code&gt;微信截图&lt;/code&gt;;&lt;/p&gt;
&lt;p&gt;聊天记录中的二维码可以直接在微信里面识别 ;微信截图工具也带了这个功能&lt;/p&gt;
&lt;p&gt;只要截图中有二维码,就可以直接使用微信浏览器打开链接或小程序&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/wechat_snip_qrcode.png&quot; alt=&quot;微信截图识别二维码&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;小程序码&lt;/h4&gt;
&lt;p&gt;官方文档中正常打开一个小程序需要有&lt;code&gt;明文URL Scheme&lt;/code&gt;;这个需要在后台给每个小程序单独开通设置;&lt;/p&gt;
&lt;p&gt;还有一个方法就是&lt;code&gt;小程序码&lt;/code&gt;;不过&lt;code&gt;小程序码&lt;/code&gt;是微信私有的算法;网上暂无公开生成方法;但是我找到一个官方的小程序码地址:&lt;code&gt;https://developers.weixin.qq.com/community/ngi/personal/suncode/wxcff7381e631cf54e&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;有了这个地址后,搭配微信截图识别;就可以打开任意小程序了&lt;/p&gt;
&lt;h4&gt;微信开发者助手&lt;/h4&gt;
&lt;p&gt;导航网站一开始我放了&lt;code&gt;微信开发者助手&lt;/code&gt;这个小程序;这个小程序是微信官方开发的;里面可以看到自己管理或体验的所有小程序;还能看到每个人提交的&lt;code&gt;预览版&lt;/code&gt;版本;&lt;/p&gt;
&lt;p&gt;里面可以看到所有的&lt;code&gt;appid&lt;/code&gt;;如果需要知道其它小程序的&lt;code&gt;appid&lt;/code&gt;;在手机小程序的&lt;code&gt;更多资料&lt;/code&gt;中查看&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/wexin_appid.png&quot; alt=&quot;app_id&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.weixin.qq.com/community/develop/doc/000c68ef3d0fa007a37ab5dc656c0c&quot;&gt;小程序助手-微信开放社区&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>PVE安装OPENCLAW的简明教程</title><link>https://blog.wangshuai.app/2026-02-23-pve%E5%AE%89%E8%A3%85openclaw%E5%8F%8A%E4%B8%80%E4%BA%9B%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</link><guid isPermaLink="true">https://blog.wangshuai.app/2026-02-23-pve%E5%AE%89%E8%A3%85openclaw%E5%8F%8A%E4%B8%80%E4%BA%9B%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</guid><pubDate>Mon, 23 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;openclaw&lt;/a&gt;流行的安装方法是&lt;code&gt;Mac Mini&lt;/code&gt;,本文介绍我摸索的&lt;code&gt;PVE&lt;/code&gt;(&lt;code&gt;Proxmox VE&lt;/code&gt;)安装&lt;code&gt;OpenClaw&lt;/code&gt;的实践心得&lt;/p&gt;
&lt;h3&gt;注意事项&lt;/h3&gt;
&lt;h4&gt;安装英文原版&lt;/h4&gt;
&lt;p&gt;虽然&lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;openclaw&lt;/a&gt;现在有不少汉化或者中文的教程,不过由于这个网关是国外弄的我还是建议使用&lt;strong&gt;英文安装&lt;/strong&gt;,不要选中文OS或者中文的版本(我昨天编译安卓的&lt;code&gt;OpenClaw Node apk&lt;/code&gt;就发现没有&lt;code&gt;100%&lt;/code&gt;适配中文)不然就只能&lt;strong&gt;徒增烦恼&lt;/strong&gt;了&lt;/p&gt;
&lt;h4&gt;使用&lt;code&gt;VM&lt;/code&gt;安装&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;openclaw&lt;/a&gt;由于破坏性强,因此需要独立安装,我选用的是独立&lt;code&gt;VM&lt;/code&gt;的&lt;code&gt;ubuntu-24.04.1-live-server-amd64.iso&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;安装&lt;code&gt;ubuntu&lt;/code&gt;没什么好说的,使用默认配置即可;&lt;/p&gt;
&lt;p&gt;安装成功后记下它的IP&lt;code&gt;192.168.xx.xx&lt;/code&gt;;同时在安装时我选择导入了我&lt;code&gt;github&lt;/code&gt;账号的&lt;code&gt;ssh key&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;安装前配置代理&lt;/h4&gt;
&lt;p&gt;安装&lt;code&gt;Open Claw&lt;/code&gt;也可以直接用&lt;a href=&quot;https://docs.openclaw.ai/zh-CN/start/getting-started&quot;&gt;官方文档&lt;/a&gt;;使用命令:&lt;code&gt;curl -fsSL https://openclaw.ai/install.sh | bash&lt;/code&gt;一键安装即可;根据提示选择或输入&lt;/p&gt;
&lt;p&gt;就是安装前应该要先配置代理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export https_proxy=http://192.168.XX.XX:7890;
export http_proxy=http://192.168.XX.XX:7890;
curl google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后用google测一下连通性,出现&lt;code&gt;301 Moved&lt;/code&gt;的&lt;code&gt;HTML&lt;/code&gt;表面代理有效&lt;/p&gt;
&lt;p&gt;上面是临时方法,假如不想要每次都输入;可以修改环境变量,将&lt;code&gt;http_proxy&lt;/code&gt;附加到&lt;code&gt;/etc/enviroment&lt;/code&gt;末尾&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/environment

#enviroment
http_proxy=http://192.168.XX.XX:7890
https_proxy=http://192.168.XX.XX:7890
HTTPS_PROXY=http://192.168.XX.XX:7890
HTTP_PROXY=http://192.168.XX.XX:7890
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;ssh穿透访问&lt;/h4&gt;
&lt;p&gt;安装&lt;code&gt;Open Claw&lt;/code&gt;成功后执行&lt;code&gt;openclaw onboard&lt;/code&gt;命令配置基本的联网方式和模型;默认连接方法是&lt;code&gt;loopback&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;安装成功后执行&lt;code&gt;openclaw&lt;/code&gt;命令查看支持的命令及当前服务信息&lt;/p&gt;
&lt;p&gt;根据提示,在你的电脑上执行&lt;code&gt;ssh&lt;/code&gt;命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh -N -i C:\Users\[user]\.ssh\ssh_key -L 18789:127.0.0.1:18789 [user]@192.168.xx.xx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里会把&lt;code&gt;pve&lt;/code&gt;虚拟机(&lt;code&gt;192.168.xx.xx&lt;/code&gt;)的&lt;code&gt;18789&lt;/code&gt;端口映射到本地;这样你就能在浏览器中使用&lt;code&gt;http://localhost:18789/&lt;/code&gt;打开它的网页了(在配置外网访问之前,每次在本机访问&lt;code&gt;Open Claw&lt;/code&gt;之前都需要创建&lt;code&gt;ssh&lt;/code&gt;隧道映射)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ssh_key&lt;/code&gt;是我&lt;code&gt;github&lt;/code&gt;上的&lt;code&gt;ssh&lt;/code&gt;私钥&lt;/p&gt;
&lt;p&gt;默认的访问方式需要在Gui中配置&lt;code&gt;Gateway Token&lt;/code&gt;;这个在初次配置完后在命令行输出中有显示&lt;/p&gt;
&lt;h4&gt;配置&lt;code&gt;Gateway&lt;/code&gt;的&lt;code&gt;Bind&lt;/code&gt;方式(&lt;strong&gt;外网访问&lt;/strong&gt;)&lt;/h4&gt;
&lt;p&gt;外网访问配置在&lt;code&gt;Config&lt;/code&gt;→&lt;code&gt;Gateway&lt;/code&gt;→&lt;code&gt;Bind&lt;/code&gt;中&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openclaw_gateway_bind.png&quot; alt=&quot;image-20260223014536304&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我把它改为了&lt;code&gt;lan&lt;/code&gt;;&lt;/p&gt;
&lt;p&gt;实际这里假如你的&lt;code&gt;Agents&lt;/code&gt;中&lt;code&gt;model&lt;/code&gt;用的在线模型,可以直接在&lt;code&gt;Chat&lt;/code&gt;中让AI帮你改配置&lt;/p&gt;
&lt;p&gt;这里就体现了它强大的地方;可以自己改自己的设置;&lt;/p&gt;
&lt;p&gt;当然,在改的过程中有好几次都让后台挂了;&lt;/p&gt;
&lt;h5&gt;配置Control Ui&lt;/h5&gt;
&lt;p&gt;除了修改&lt;code&gt;Bind&lt;/code&gt;还需要添加&lt;code&gt;Control Ui&lt;/code&gt;,将&lt;code&gt;https&lt;/code&gt;的域名配置上&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openclaw_gateway_controlui.png&quot; alt=&quot;配置外网访问&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;设置反向代理允许&lt;code&gt;websocket&lt;/code&gt;连接&lt;/h5&gt;
&lt;p&gt;以及,我用的&lt;code&gt;nginx&lt;/code&gt;代理,要允许&lt;code&gt;websocket&lt;/code&gt;连接&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    location / {
        proxy_pass http://192.168.xxx.xx:18789/;

    	#支持websockcet连接
        proxy_http_version 1.1;
    	proxy_set_header Upgrade $http_upgrade;
		proxy_cache_bypass $http_upgrade;
		proxy_connect_timeout 10s;
    	proxy_set_header Connection $http_connection;
     
        # Tinyauth auth request
        auth_request /tinyauth;
        error_page 401 = @tinyauth_login;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;配置网页外部保护(可选)&lt;/h5&gt;
&lt;p&gt;同时,为了保护&lt;code&gt;Open Claw&lt;/code&gt;后台,我使用了&lt;code&gt;Tinyauth&lt;/code&gt;,详情可参考文章:&lt;a href=&quot;https://blog.dejavu.moe/posts/build-passkeys-identity-system-with-pocketid-x-tinyauth/&quot;&gt;自托管部署 Pocket ID 与 Tinyauth 完全指南&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;后台授权同意&lt;/h5&gt;
&lt;p&gt;配置成功后打开后台会提示:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;disconnected (1008): pairing required&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;因此还需要后台授权同意:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#查看当前授权列表
openclaw devices list
#同意设备
openclaw devices approve XXX
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;后台挂了后重启Gui方法&lt;/h4&gt;
&lt;p&gt;假如&lt;code&gt;localhost:18789&lt;/code&gt;访问不到网页,在后台中执行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;openclaw gateway --force
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;命令可以重置网关绑定状态让你可以重新访问&lt;/p&gt;
&lt;h4&gt;重置设置方法&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Open Claw&lt;/code&gt;的配置位于:&lt;code&gt;~/.openclaw/openclaw.json&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在AI自己修改自己的配置过程中,有很多次它都让服务挂了;或者有什么配置不对的地方导致服务出现问题&lt;/p&gt;
&lt;p&gt;此时根据后台提示,可以先尝试命令修复&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;openclaw doctor --fix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是这个网关自带的修复;假如修复后还是有问题&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/.openclaw
ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时你能看到它自动备份了设置,找到最新的一个备份&lt;code&gt;openclaw.json.bak&lt;/code&gt;将当前的设置覆盖后即可恢复&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openclaw_config_back.png&quot; alt=&quot;image-20260223020117835&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;模型切换&lt;/h4&gt;
&lt;p&gt;网关已配置的模型在&lt;code&gt;Agents&lt;/code&gt;→&lt;code&gt;Overview&lt;/code&gt;中&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openclaw_agents.png&quot; alt=&quot;已配置的模型&quot; /&gt;&lt;/p&gt;
&lt;p&gt;当有多个模型需要切换时,在&lt;code&gt;Chat&lt;/code&gt;中输入&lt;code&gt;/model&lt;/code&gt;查看模型相关命令&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openclaw_chat_model.png&quot; alt=&quot;切换模型&quot; /&gt;&lt;/p&gt;
&lt;p&gt;输入&lt;code&gt; /model &amp;lt;provider/model&amp;gt;&lt;/code&gt;切换&lt;/p&gt;
&lt;h4&gt;对接飞书&lt;/h4&gt;
&lt;p&gt;在首次运行的向导中,我添加了飞书的&lt;code&gt;appId&lt;/code&gt;和&lt;code&gt;appSecret&lt;/code&gt;但它无法运行;总会有两个报错&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;15:31:33 [plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load: feishu (/home/shiney/.openclaw/extensions/feishu/index.ts). Set plugins.allow to explicit trusted ids.
15:31:35 [plugins] feishu failed to load from /home/shiney/.openclaw/extensions/feishu/index.ts: Error: Cannot find module &apos;@sinclair/typebox&apos;
Require stack:
- /home/shiney/.openclaw/extensions/feishu/src/bitable.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里有两个问题需要解决&lt;/p&gt;
&lt;h5&gt;安装飞书插件失败&lt;/h5&gt;
&lt;p&gt;安装失败的原因是飞书的&lt;code&gt;package.json&lt;/code&gt;有问题&lt;/p&gt;
&lt;p&gt;通过以下命令重新安装(&lt;code&gt;npm install&lt;/code&gt;)飞书插件即可看到报错&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shiney@openclaw:~$ cd ~/.openclaw/extensions/feishu
shiney@openclaw:~/.openclaw/extensions/feishu$ ls
index.ts  openclaw.plugin.json  package.json  skills  src
shiney@openclaw:~/.openclaw/extensions/feishu$ npm install
npm error code EUNSUPPORTEDPROTOCOL
npm error Unsupported URL Type &quot;workspace:&quot;: workspace:*
npm notice
npm notice New major version of npm available! 10.9.4 -&amp;gt; 11.10.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.10.1
npm notice To update run: npm install -g npm@11.10.1
npm notice
npm error A complete log of this run can be found in: /home/shiney/.npm/_logs/2026-02-24T15_34_28_116Z-debug-0.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改&lt;code&gt;~/.openclaw/extensions/feishu/package.json&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;删除~~&quot;openclaw&quot;: &quot;workspace:*&quot;~~这一行&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openclaw_feishu_packagejson_error.png&quot; alt=&quot;删除异常配置&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后执行以下命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/.openclaw/extensions/feishu
# https://www.cnblogs.com/pautcher/articles/19585433
npm install -g pnpm
pnpm setup

npm install

openclaw plugins install @m1heng-clawd/feishu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时,执行&lt;code&gt;openclaw&lt;/code&gt;会提示这样的警告&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shiney@openclaw:~$ openclaw
15:42:31 [plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load: feishu (/home/shiney/.openclaw/extensions/feishu/index.ts). Set plugins.allow to explicit trusted ids.
15:42:34 [plugins] feishu: loaded without install/load-path provenance; treat as untracked local code and pin trust via plugins.allow or install records (/home/shiney/.openclaw/extensions/feishu/index.ts)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;plugins.allow is empty&lt;/code&gt;意思是扩展没启动,因为我之前安装失败,&lt;code&gt;feishu&lt;/code&gt;初始化向导中断导致配置没写入;按照&lt;a href=&quot;https://docs.openclaw.ai/zh-CN/channels/feishu&quot;&gt;官方文档&lt;/a&gt;重新配置一下就行&lt;/p&gt;
&lt;h5&gt;因为安装失败导致配置异常&lt;/h5&gt;
&lt;p&gt;参照官方的飞书配置文档:&lt;a href=&quot;https://docs.openclaw.ai/zh-CN/channels/feishu&quot;&gt;消息平台:飞书&lt;/a&gt;依次设置即可&lt;/p&gt;
&lt;p&gt;这里有两个注意点:&lt;/p&gt;
&lt;h6&gt;自建应用审核&lt;/h6&gt;
&lt;p&gt;因为我之前发布过飞书自建应用,重新设置时要重新审核;审核的话在手机飞书APP找到&lt;code&gt;开发者小助手&lt;/code&gt;会提示操作方法;&lt;/p&gt;
&lt;p&gt;网页打开&lt;code&gt;飞书管理后台&lt;/code&gt;→&lt;code&gt;工作台&lt;/code&gt;→&lt;code&gt;应用审核&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/feishu_app_approve.png&quot; alt=&quot;飞书自建应用审核&quot; /&gt;&lt;/p&gt;
&lt;h6&gt;自建应用对话&lt;/h6&gt;
&lt;p&gt;审核成功后,手机飞书中会出现你创建的&lt;code&gt;openclaw&lt;/code&gt;机器人;发送任意消息会触发审核操作,复制命令(&lt;code&gt;openclaw pairing approve feishu XXXX&lt;/code&gt;)到后台执行即可&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/feishu_app_msg.jpg&quot; alt=&quot;自建应用对话&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;对接企业微信&lt;/h4&gt;
&lt;p&gt;PC登录企业微信客户端可以看到官方的消息:&lt;a href=&quot;https://open.work.weixin.qq.com/help2/pc/cat?doc_id=21657&quot;&gt;官方插件支持OpenClaw，3步快速接入&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;参照教程安装即可,这里说几个我遇到的问题&lt;/p&gt;
&lt;h6&gt;工作台的智能机器人中没有API机器人菜单&lt;/h6&gt;
&lt;p&gt;因为企业微信不常用,所以没有最新的功能;点击&lt;code&gt;头像&lt;/code&gt;→&lt;code&gt;设置&lt;/code&gt;→&lt;code&gt;关于&lt;/code&gt;→&lt;code&gt;检查更新&lt;/code&gt;;更新最新企业微信客户端,即可看到&lt;code&gt;API模式创建&lt;/code&gt;的菜单&lt;/p&gt;
&lt;h5&gt;参数不合法&lt;/h5&gt;
&lt;p&gt;参数不合法报错是因为没选择&lt;code&gt;可见范围&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openclaw_wecom_%E5%8F%82%E6%95%B0%E4%B8%8D%E5%90%88%E6%B3%95.png&quot; alt=&quot;智能机器人参数不合法&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;添加成功后怎么使用&lt;/h5&gt;
&lt;p&gt;添加成功后在&lt;code&gt;通讯录&lt;/code&gt;→&lt;code&gt;智能机器人&lt;/code&gt;中能看到,可以直接发消息或者把它添加到群聊中&lt;/p&gt;
&lt;p&gt;添加到群聊后可以直接&lt;code&gt;@龙虾&lt;/code&gt;让它回复&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/wecom_bot.png&quot; alt=&quot;企业微信智能机器人&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/openclaw/openclaw/issues/4531&quot;&gt;disconnected (1008): pairing required #4531&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/treasury-manager/p/19601042&quot;&gt;WSL2手工配置Openclaw+minimax接口+飞书插件+踩坑&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/pautcher/articles/19585433&quot;&gt;从源码快速安装 openclaw&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://open.work.weixin.qq.com/help2/pc/cat?doc_id=21657&quot;&gt;官方插件支持OpenClaw，3步快速接入&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>使用sub-store合并多个机场的订阅</title><link>https://blog.wangshuai.app/2026-01-31-clash-verge%E5%90%88%E5%B9%B6%E8%AE%A2%E9%98%85/</link><guid isPermaLink="true">https://blog.wangshuai.app/2026-01-31-clash-verge%E5%90%88%E5%B9%B6%E8%AE%A2%E9%98%85/</guid><pubDate>Sat, 31 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Google AI Studio&lt;/code&gt;是非常好的AI工具,不过它的网络检测也很严格;之前我用的机场一直没问题 ;&lt;/p&gt;
&lt;p&gt;不过最近可能用户太多;导致被它识别到不支持的地区;经查询,它的地区检测域名是&lt;code&gt;alkalimakersuite-pa.clients6.google.com&lt;/code&gt;;&lt;/p&gt;
&lt;p&gt;在我单独给它设置规则后发现所有的节点都无法访问:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rules:
- DOMAIN-SUFFIX,alkalimakersuite-pa.clients6.google.com,AIStudio
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但我用的别的按量计费的机场发现可以访问&lt;code&gt;Google AI Studio&lt;/code&gt;;每次使用切来切去非常不便;而且我还用了&lt;code&gt;TUN&lt;/code&gt;模式,很多应用都会断网&lt;/p&gt;
&lt;p&gt;于是研究几天找到了适合的节点,规则,合并方法&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;我之前用的是&lt;code&gt;Clash for Windows&lt;/code&gt;,它不具备订阅合并功能;现在我测试使用&lt;code&gt;Mihomo&lt;/code&gt;内核的&lt;code&gt;Clash Verge&lt;/code&gt;有人说可行&lt;/p&gt;
&lt;p&gt;官方的issue:&lt;a href=&quot;https://github.com/clash-verge-rev/clash-verge-rev/issues/1092&quot;&gt;[Feature] 能否合并订阅 #1092&lt;/a&gt;里面说了可以自己写配置实现;&lt;/p&gt;
&lt;p&gt;&lt;s&gt;但我实在不懂&lt;code&gt;Clash&lt;/code&gt;的内核;网上也没有一个完整的教程指导如何合并订阅;&lt;/s&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.metacubex.one/example/conf/&quot;&gt;懒人配置&lt;/a&gt;是可行的&lt;/p&gt;
&lt;p&gt;操作方法如下:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;订阅&lt;/code&gt;中新建一个&lt;code&gt;Local&lt;/code&gt;类型的本地配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/545425466-6dc029c8-c825-4a88-9314-8015b5b73b48.png&quot; alt=&quot;Image&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;右键新增的配置点击&lt;code&gt;编辑文件&lt;/code&gt;
把懒人配置的所有内容粘贴进去,需要填写自己的订阅地址&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;##我的示例如下:
proxy-providers:
 p1:
   url: &quot;https://xxxx.com?clash=3&amp;amp;extend=1&quot; ##主要填这个
   type: http
   interval: 86400
   path: ./proxy_provider/p1.yml
   health-check: {enable: true,url: &quot;https://www.gstatic.com/generate_204&quot;,interval: 300}
   override:
     additional-prefix: &quot;[p1]&quot;
### 其它配置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;订阅会自动下载在&lt;code&gt;Clash Verge&lt;/code&gt;目录,默认是&lt;code&gt;%APPDATA%\io.github.clash-verge-rev.clash-verge-rev&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;我加了一个&lt;code&gt;path&lt;/code&gt;配置,这样对应订阅&lt;code&gt;yml&lt;/code&gt;文件就会在&lt;code&gt;%APPDATA%\io.github.clash-verge-rev.clash-verge-rev\proxy_provider&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;保存成功后会拉取一次订阅;假如本地要更新;就要&lt;strong&gt;把本地的文件(p1.yml)删除&lt;/strong&gt;重新拉取&lt;/p&gt;
&lt;p&gt;多个订阅的合并里面用的节点名称正则匹配(&lt;code&gt;filter&lt;/code&gt;);把同一个地区的放到一个&lt;code&gt;proxy-groups&lt;/code&gt;中;&lt;/p&gt;
&lt;p&gt;要修改订阅,简单的方法就是右键订阅配置,使用&lt;code&gt;编辑规则&lt;/code&gt; &lt;code&gt;编辑节点&lt;/code&gt; &lt;code&gt;编辑代理组&lt;/code&gt; 调整&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文主要介绍使用&lt;a href=&quot;https://github.com/sub-store-org/Sub-Store&quot;&gt;&lt;code&gt;Sub-Store&lt;/code&gt;&lt;/a&gt;合并订阅的方法&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sub-Store&lt;/code&gt;只支持节点合并,不过它的&lt;code&gt;文件管理&lt;/code&gt;→&lt;code&gt;Mihomo配置&lt;/code&gt;支持使用js操作组合订阅;进而生成我需要的配置&lt;/p&gt;
&lt;p&gt;基于&lt;code&gt;Sub-Store&lt;/code&gt;还让我的手机也能访问组合订阅;可以说好处多多&lt;/p&gt;
&lt;p&gt;之前我手机用的&lt;code&gt;Clash for Android&lt;/code&gt;,用起来还不错;只是没有方便修改节点或者配置的地方;有了&lt;code&gt;Sub-Store&lt;/code&gt;后也能在&lt;code&gt;Sub-Store&lt;/code&gt;后台修改了;我现在用的安卓客户端是&lt;a href=&quot;https://github.com/chen08209/FlClash&quot;&gt;&lt;code&gt;FIClash&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;处理脚本我使用的是&lt;a href=&quot;https://github.com/powerfullz/override-rules/blob/main/convert.js&quot;&gt;convert.js&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;操作步骤&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;参照教程安装&lt;code&gt;Sub-Store&lt;/code&gt;:&lt;a href=&quot;https://wp.gxnas.com/15067.html&quot;&gt;订阅转换+聚合+排序的高级管理工具Sub-Store搭建和设置教程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我的&lt;code&gt;sub-store&lt;/code&gt;部署在内网,同时使用了&lt;code&gt;Tinyauth&lt;/code&gt;保护,方便外网编辑,详见:&lt;a href=&quot;https://blog.dejavu.moe/posts/build-passkeys-identity-system-with-pocketid-x-tinyauth/&quot;&gt;自托管部署 Pocket ID 与 Tinyauth 完全指南&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;添加&lt;code&gt;Mihomo&lt;/code&gt;配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在添加多个单条订阅并把他们放到一个组合订阅中后,假如你使用&lt;code&gt;Clash&lt;/code&gt;导入订阅;那你本地订阅只有一个&lt;code&gt;Global&lt;/code&gt;的所有订阅组&lt;/p&gt;
&lt;p&gt;之前机场里面的规则,订阅组都不见了;此时需要使用&lt;code&gt;Mihomo&lt;/code&gt;配置功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打开&lt;code&gt;Sub-Store&lt;/code&gt;→&lt;code&gt;文件管理&lt;/code&gt;→&lt;code&gt;添加&lt;/code&gt;→&lt;code&gt;Mihomo配置&lt;/code&gt;→&lt;code&gt;添加一个 脚本操作&lt;/code&gt;→&lt;code&gt;本地内容&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/sub-store_add_mihomo.png&quot; alt=&quot;添加mihomo配置&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/sub-store_add_mihomo_localfile.png&quot; alt=&quot;添加本地内容&quot; /&gt;&lt;/p&gt;
&lt;p&gt;里面的内容可以用&lt;a href=&quot;https://github.com/powerfullz/override-rules/blob/main/convert.js&quot;&gt;convert.js&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个覆写规则会添加地区的节点分组和一些外部的规则组;&lt;/p&gt;
&lt;p&gt;由于我还有一些&lt;code&gt;Clash for Windows&lt;/code&gt;使用的规则,节点以及节点组;因此我改写了它的脚本;&lt;/p&gt;
&lt;p&gt;添加了实现&lt;code&gt;Clash for Windows&lt;/code&gt;中的&lt;code&gt;Parsers&lt;/code&gt;的&lt;code&gt;prepend-rules&lt;/code&gt; &lt;code&gt;append-proxies&lt;/code&gt; &lt;code&gt;append-proxy-groups&lt;/code&gt;功能&lt;/p&gt;
&lt;p&gt;这里先给出我的&lt;code&gt;本地内容&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;我后面又调整了js,将配置改为外部的&lt;code&gt;custom_clash_config&lt;/code&gt;文件:&lt;/p&gt;
&lt;p&gt;先添加额外的&lt;code&gt;json&lt;/code&gt;配置:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sub-Store&lt;/code&gt;→&lt;code&gt;文件管理&lt;/code&gt;→&lt;code&gt;添加&lt;/code&gt; →&lt;code&gt;文件&lt;/code&gt;→输入名称&lt;code&gt;custom_clash_config&lt;/code&gt;→粘贴外置json文件内容&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/substore_add_file.png&quot; alt=&quot;substore_add_file&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/substore_addjson.png&quot; alt=&quot;substore_addjson&quot; /&gt;&lt;/p&gt;
&lt;p&gt;文件内容示例:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;appendProxyGroups&quot;: [
    {
      &quot;name&quot;: &quot;AIStudio&quot;,
      &quot;type&quot;: &quot;select&quot;,
      &quot;icon&quot;: &quot;https://www.gstatic.com/aistudio/ai_studio_favicon_2_128x128.png&quot;,
      &quot;proxies&quot;: [
        &quot;__DEFAULT_SELECTOR__&quot;,
      ]
    }
  ],
  &quot;prependRules&quot;: [
    &quot;DOMAIN-SUFFIX,alkalimakersuite-pa.clients6.google.com,AIStudio&quot;
  ],
  &quot;appendProxies&quot;: [
    {
            &quot;name&quot;: &quot;easyConnect&quot;,
            &quot;server&quot;: &quot;192.168.1.193&quot;,
            &quot;port&quot;: 1080,
            &quot;type&quot;: &quot;socks5&quot;
        }
  ],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;script src=&quot;https://gist.github.com/wangshuai-007/44b3c2089df0f58bb900ebdf69e76ac9.js?theme=dark&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;我实现了&lt;code&gt;appendProxies&lt;/code&gt;  &lt;code&gt;appendProxyGroups&lt;/code&gt;  &lt;code&gt;prependRules&lt;/code&gt;方法对应 &lt;code&gt;Parsers&lt;/code&gt;中的功能&lt;/p&gt;
&lt;p&gt;这里面用的&lt;code&gt;json&lt;/code&gt;对象;和&lt;code&gt;Clash for Windows&lt;/code&gt;中的&lt;code&gt;yml&lt;/code&gt;格式不同;&lt;/p&gt;
&lt;p&gt;因此你可以用在线&lt;code&gt;yaml&lt;/code&gt;转&lt;code&gt;json&lt;/code&gt;的工具转化:&lt;a href=&quot;https://onlineyamltools.com/convert-yaml-to-json&quot;&gt;&lt;strong&gt;YAML to JSON Converte&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;js代码很容易理解,实际就是用js修改生成的对象;有了AI后想要什么逻辑都可以让它帮你生成&lt;/p&gt;
&lt;p&gt;我添加了&lt;code&gt;AIStudio&lt;/code&gt;代理组及对应规则;同时会把所有的&lt;code&gt;vmess&lt;/code&gt;和&lt;code&gt;hysteria2&lt;/code&gt;类型的节点添加到这个组里面,方便访问&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保存文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在确认好覆写js代码后,可以把代码保存到&lt;code&gt;sub-store&lt;/code&gt;路径的&lt;code&gt;data&lt;/code&gt;目录下;然后把脚本操作改为&lt;code&gt;远程链接&lt;/code&gt;路径填&lt;code&gt;/opt/app/data/xxx.js&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/sub-store_add_mihomo_remotefile.png&quot; alt=&quot;remote file&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;补充说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;防止环回设置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为我用了&lt;code&gt;tun&lt;/code&gt;模式 ,且代理了家里的网络;因此使用&lt;code&gt;clash&lt;/code&gt;时不能代理局域网连接防止环回&lt;/p&gt;
&lt;p&gt;需要在&lt;code&gt;设置&lt;/code&gt;→&lt;code&gt;系统设置&lt;/code&gt;→&lt;code&gt;虚拟网卡模式设置&lt;/code&gt;→&lt;code&gt;排除自定义网段&lt;/code&gt;中添加本地网段的排除规则&lt;code&gt;192.168.50.0/24&lt;/code&gt;(请根据你的局域网网段自行填写)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/clash_verge_tun_ignore_net.png&quot; alt=&quot;排除网段&quot; /&gt;&lt;/p&gt;
&lt;p&gt;当然,也可以修改系统代理绕过的网段&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;防止回环统一方法&lt;/p&gt;
&lt;p&gt;第一种方法要每个客户端分别配置,其实可以在&lt;code&gt;proxy group&lt;/code&gt;上做文章
在代理组中添加&lt;code&gt;url-test&lt;/code&gt;类型且配置有&lt;code&gt;DIRECT&lt;/code&gt;方式的代理组&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  type: url-test
  proxies:
  - Home
  - DIRECT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后再在路由器上的指定端口关闭&lt;code&gt;NAT环回&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/openwrt_port_natloop.png&quot; alt=&quot;openwrt的端口回环设置&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这样,在内网时就会默认选择&lt;code&gt;DIRECT&lt;/code&gt;而在外网时就会变成家里的代理&lt;/p&gt;
&lt;p&gt;不用&lt;code&gt;openwrt&lt;/code&gt;的,也可以用nginx的特性根据ip阻断不同的&lt;code&gt;url-test&lt;/code&gt;请求以达到自动切换的目的&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wp.gxnas.com/15067.html&quot;&gt;订阅转换+聚合+排序的高级管理工具Sub-Store搭建和设置教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;https://github.com/powerfullz/override-rules&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>通过url打开微信小程序</title><link>https://blog.wangshuai.app/2026-01-10-open-wechat-miniprogram-by-url/</link><guid isPermaLink="true">https://blog.wangshuai.app/2026-01-10-open-wechat-miniprogram-by-url/</guid><pubDate>Sat, 10 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;最近项目要用到短信跳转小程序的功能;因此特意研究一下相关功能&lt;/p&gt;
&lt;p&gt;顺便集成跳转小程序的功能到导航网站(&lt;a href=&quot;https://dashy.to/&quot;&gt;dashy&lt;/a&gt;)中&lt;/p&gt;
&lt;p&gt;参考微信官方文档:&lt;a href=&quot;https://developers.weixin.qq.com/minigame/dev/wxcloud/guide/staticstorage/msg-miniprogram.html&quot;&gt;短信跳小程序&lt;/a&gt;可以实现需求但这里有两大坑&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它的H5网页我 实测不怎么好用,至少我没研究出来,因此我自己写了简单的跳转代码&lt;/li&gt;
&lt;li&gt;因2025年3.15导致运营商对短信中的链接要求严格,导致使用 &lt;a href=&quot;https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/cloudbase/cloudbase.sendSms.html&quot;&gt;cloudbase.sendsms&lt;/a&gt; 接口几乎都无法发送成功(我测试只有手机开启了网络短信功能的手机号能收到短信;其它全是&lt;code&gt;(MK:100C)运营商关键词拦截&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;截止日前我没找到发短信的方法,因此本文只讨论链接跳转小程序功能&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;在安装了微信的客户端中,微信会在设备上注册:&lt;code&gt;weixin://&lt;/code&gt;的协议,通过这种格式的链接可以快速打开小程序&lt;/p&gt;
&lt;p&gt;协议规范请见官方文档:&lt;a href=&quot;https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-scheme.html&quot;&gt;获取 URL Scheme&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;URL Scheme&lt;/code&gt;有加密和非加密,加密的需要调接口且有时间限制;因此这里讨论的是明文&lt;code&gt;URL Scheme&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;假如你&lt;strong&gt;是小程序的开发者&lt;/strong&gt;,则在允许的情况下在后台设置&lt;code&gt;明文URL Scheme&lt;/code&gt;后可以使用&lt;/p&gt;
&lt;p&gt;&lt;code&gt;weixin://dl/business/?appid=*APPID*&amp;amp;path=*PATH*&amp;amp;query=*QUERY*&amp;amp;env_version=*ENV_VERSION*&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这样的链接访问小程序&lt;/p&gt;
&lt;p&gt;这个链接在手机上正式版体验版都可以跳转;但在PC上&lt;a href=&quot;https://developers.weixin.qq.com/community/develop/doc/000c6c5993cca05a1363609da63c00&quot;&gt;只能跳转正式版&lt;/a&gt;PC跳转体验版的方法可以通过解析小程序体验版的二维码得到,链接是这样的:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://open.weixin.qq.com/sns/getexpappinfo?appid=*APPID*&amp;amp;amp;path=*PATH*#wechat-redirect&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这个链接只能用微信浏览器打开&lt;/p&gt;
&lt;p&gt;小程序需要传参可在&lt;code&gt;path&lt;/code&gt;变量中拼接;比如小程序的启动参数是&lt;code&gt;env=test&lt;/code&gt;时;&lt;code&gt;path&lt;/code&gt;的值就应该是:&lt;code&gt;pages/index/index?env=test&lt;/code&gt;;但这里&lt;code&gt;path&lt;/code&gt;要&lt;code&gt;urlencode&lt;/code&gt;因此就变成&lt;code&gt;pages/index/index%3Fenv=test&lt;/code&gt;读取参数使用API:&lt;a href=&quot;https://developers.weixin.qq.com/miniprogram/dev/api/base/app/life-cycle/wx.getLaunchOptionsSync.html&quot;&gt;&lt;code&gt;getLaunchOptionsSync&lt;/code&gt;&lt;/a&gt;;&lt;/p&gt;
&lt;p&gt;非指定小程序的开发人员可以在PC上跳转到指定小程序的正式版,跳转链接可以使用小程序的&lt;code&gt;添加到电脑桌面&lt;/code&gt;功能&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/wexin_pc_minip_add_shortcut.png&quot; alt=&quot;添加到电脑桌面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;链接大概是这样&lt;code&gt;weixin://launchapplet?app_id=*APPID*&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;其中,&lt;code&gt;app_id&lt;/code&gt;可以在手机小程序的&lt;code&gt;更多资料&lt;/code&gt;中查看&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/wexin_appid.png&quot; alt=&quot;app_id&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里给出我写的&lt;code&gt;H5&lt;/code&gt;跳转小程序的&lt;code&gt;HTML&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;zh-CN&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;title&amp;gt;正在跳转&amp;lt;/title&amp;gt;

  &amp;lt;style&amp;gt;
    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
    }
    body {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      background: #f5f7fa;
      font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;,
                   &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif;
      color: #333;
    }
    .tip {
      font-size: 20px;
      margin-bottom: 20px;
    }
    .btn {
      padding: 10px 20px;
      font-size: 16px;
      margin: 10px;
      border: none;
      border-radius: 6px;
      background: #1677ff;
      color: #fff;
      cursor: pointer;
    }
    .btn:hover {
      background: #0958d9;
    }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

  &amp;lt;div class=&quot;tip&quot;&amp;gt;正在为你打开微信开发助手…&amp;lt;/div&amp;gt;
  &amp;lt;button class=&quot;btn&quot; id=&quot;openBtn&quot;&amp;gt;点击立即跳转&amp;lt;/button&amp;gt;
  &amp;lt;button class=&quot;btn&quot; style=&quot;visibility: hidden;&quot; id=&quot;copyText&quot; onclick=&quot;copyText()&quot;&amp;gt;复制到剪切板&amp;lt;/button&amp;gt;

  &amp;lt;script&amp;gt;
    // 1️⃣ 计算跳转地址（示例：透传当前页面 query）
    const params = new URLSearchParams(window.location.search);


    var queryStr=encodeURIComponent(params.toString())

      var appid=&apos;wxcff7381e631cf54e&apos;;
    var path=&apos;xxx&apos;
    var env_version=&apos;release&apos;
    if(params.has(&apos;appid&apos;)){
        appid=params.get(&apos;appid&apos;)
        params.delete(&quot;appid&quot;)
    }
    if(params.has(&apos;path&apos;)){
        // appid=params.get(&apos;path&apos;)
        params.delete(&quot;path&quot;)
    }
    if(params.has(&apos;env_version&apos;)){
        env_version=params.get(&apos;env_version&apos;)
        params.delete(&quot;env_version&quot;)
    }
    var queryStr=encodeURIComponent(params.toString())

    var ur=`weixin://dl/business/?appid=${appid}&amp;amp;path=${path}&amp;amp;query=${queryStr}&amp;amp;env_version=${env_version}`;

    function getTargetUrl() {

      return ur;
    }
    
    function openTrialShare() {
        // window.location.href = `weixin://dl/business/?appid=wxcff7381e631cf54e&amp;amp;path=xxx&amp;amp;query=${queryStr}&amp;amp;env_version=trial`;
        var ur=`weixin://dl/business/?appid=wxcff7381e631cf54e&amp;amp;path=xxx&amp;amp;query=${queryStr}&amp;amp;env_version=trial`;
        console.log(&apos;href is &apos;,ur)
        window.location.href = ur;
    }
    // 2️⃣ 执行跳转
    function redirect() {
      const url = getTargetUrl();
      window.location.href = url;
    }
    function showCopy() {
      const url = getTargetUrl();
      document.getElementById(&apos;copyText&apos;).style.visibility=&apos;&apos;;
    }
    
    function copyText() {

    navigator.clipboard.writeText(ur)
        .then(() =&amp;gt; {
            alert(&apos;已复制到剪切板&apos;);
        })
        .catch(err =&amp;gt; {
            console.error(err);
            alert(&apos;复制失败&apos;);
        });
    }

    // 3️⃣ 自动跳转（延迟 1 秒，体验更好）
    setTimeout(redirect, 1000);
    setTimeout(showCopy, 3000);

    // 4️⃣ 手动点击兜底
    document.getElementById(&quot;openBtn&quot;).onclick = redirect;
  &amp;lt;/script&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;结语&lt;/h3&gt;
&lt;p&gt;&lt;s&gt;我的初心是替代默认的微信浏览器首页,当前看来还有点差距&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;微信浏览器导航站介绍请查看另一篇博文:&lt;a href=&quot;/2026-05-30-%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AF%BC%E8%88%AA%E7%AB%99/&quot;&gt;如何创建一个微信小程序导航站&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.weixin.qq.com/minigame/dev/wxcloud/guide/staticstorage/jump-miniprogram.html&quot;&gt;静态网站 H5 跳小程序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.weixin.qq.com/minigame/dev/wxcloud/guide/staticstorage/msg-miniprogram.html&quot;&gt;短信跳小程序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/evi0s/WMPFDebugger&quot;&gt;WMPFDebugger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>解决powershell表达式或语句中包含意外的标记问题</title><link>https://blog.wangshuai.app/2025-12-20-powershell-syntax-error/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-12-20-powershell-syntax-error/</guid><pubDate>Sat, 20 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;最近,在编写&lt;code&gt;powershell&lt;/code&gt;脚本时,在&lt;code&gt;vscode&lt;/code&gt;中已经调试好了;但实际执行却总是失败;而且还没任何日志;通过录像弹窗的方法发现是语法格式问题&lt;/p&gt;
&lt;p&gt;&lt;code&gt;表达式或语句中包含意外的标记&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;语句块或类型定义中缺少右“}”&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这个问题是脚本的编码格式导致的&lt;/p&gt;
&lt;p&gt;解决办法就是修改脚本编码&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;解决问题最关键的一步是&lt;strong&gt;认识问题&lt;/strong&gt;;&lt;/p&gt;
&lt;p&gt;那&lt;code&gt;vscode&lt;/code&gt;中执行正常;而运行脚本报错如何才能知道问题在哪?&lt;/p&gt;
&lt;p&gt;答案是:用&lt;code&gt;powershell&lt;/code&gt;识别代码的方法打开代码&lt;/p&gt;
&lt;p&gt;那就是&lt;code&gt;PowerShell ISE&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;用&lt;code&gt;PowerShell ISE&lt;/code&gt;打开你的代码后就有明显的异常&lt;/p&gt;
&lt;p&gt;比如我这里;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/powershell_ise_unicode_error.png&quot; alt=&quot;powershell_ise_unicode_error&quot; /&gt;&lt;/p&gt;
&lt;p&gt;就是中文的内容把字符串的引号给冲掉了;&lt;/p&gt;
&lt;p&gt;因此,也有一个简单的方法;&lt;strong&gt;将代码中所有的中文换成英文&lt;/strong&gt;;这样也不会有问题&lt;/p&gt;
&lt;h3&gt;操作步骤&lt;/h3&gt;
&lt;h4&gt;查看编码&lt;/h4&gt;
&lt;p&gt;使用&lt;code&gt;PowerShell ISE&lt;/code&gt;打开你的脚本文件;&lt;/p&gt;
&lt;p&gt;在下方的控制台中输入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[console]::OutputEncoding
[console]::InputEncoding
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即可看到本机默认编码格式&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/powershell_ise_default_encode.png&quot; alt=&quot;image-20251220005402908&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;修改脚本编码&lt;/h4&gt;
&lt;p&gt;通常可以使用&lt;code&gt;vscode&lt;/code&gt;修改编码,我引用&lt;code&gt;AI&lt;/code&gt;的操作步骤:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;在 VS Code 中打开乱码的脚本。&lt;/li&gt;
&lt;li&gt;查看窗口&lt;strong&gt;右下角&lt;/strong&gt;的状态栏，通常会显示 UTF-8。&lt;/li&gt;
&lt;li&gt;点击 UTF-8，在弹出的菜单中选择 &lt;strong&gt;“通过编码保存 (Save with Encoding)”&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;在列表里找到并选择 &lt;strong&gt;UTF-8 with BOM&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;保存文件。&lt;/li&gt;
&lt;li&gt;再次用 PowerShell ISE 打开，乱码就消失了。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;实测&lt;code&gt;UTF-8 with BOM&lt;/code&gt;和&lt;code&gt;GB2312&lt;/code&gt;都能解决乱码问题&lt;/p&gt;
&lt;h3&gt;结语&lt;/h3&gt;
&lt;p&gt;代码乱码问题相信每个中国开发者都遇到过;终极解决方法就是换英文操作系统&lt;/p&gt;
&lt;p&gt;我新的电脑就是这样干的,省去很多莫名其妙的问题;但也会导致编码格式 或者老的程序显示问题&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.csdn.net/qq_39124701/article/details/142953431&quot;&gt;UTF8编码的PowerShell脚本中文乱码的解决方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zu1k/nali/issues/185&quot;&gt;Powershell 7.4.0 输出乱码&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>TortoiseSVN调用powershell命令及调试详解</title><link>https://blog.wangshuai.app/2025-12-14-TortoiseSVN%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%A7%A6%E5%8F%91Jenkins/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-12-14-TortoiseSVN%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%A7%A6%E5%8F%91Jenkins/</guid><pubDate>Sun, 14 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;一直很喜欢自动化的东西,自己的项目都配置有&lt;code&gt;CI/CD&lt;/code&gt;;但是公司的项目单独用的&lt;code&gt;TortoiseSVN&lt;/code&gt;和&lt;code&gt;Jenkins&lt;/code&gt;,运维也没有配置服务端的&lt;code&gt;Piplile&lt;/code&gt;;因此自己在&lt;code&gt;TortoiseSVN&lt;/code&gt;使用&lt;code&gt;Hook Scripts&lt;/code&gt;的客户端触发方法,本机执行&lt;code&gt;Jenkins&lt;/code&gt;构建,因为&lt;code&gt;Jenkins&lt;/code&gt;直接支持&lt;code&gt;API&lt;/code&gt;创建构建,所以整体流程还算顺利&lt;/p&gt;
&lt;p&gt;脚本实现的功能:&lt;/p&gt;
&lt;p&gt;在每个SVN项目根目录中添加&lt;code&gt;Post-commit&lt;/code&gt;后,根据脚本中的配置,按需在指定路径代码更新后触发指定服务的构建;支持参数设置&lt;/p&gt;
&lt;p&gt;本文将指导:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任意脚本命令调试方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Powershell&lt;/code&gt;调试方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;API调用Jenkins方法&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TortoiseSVN&lt;/code&gt;触发&lt;code&gt;Jenkins&lt;/code&gt;实用脚本&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;h4&gt;API调用&lt;code&gt;Jenkins&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;我的&lt;code&gt;Jenkins&lt;/code&gt;版本为&lt;code&gt;2.190.1&lt;/code&gt; &lt;code&gt;Jenkins&lt;/code&gt;的触发请查看&lt;code&gt;Jenkins&lt;/code&gt; &lt;code&gt;API&lt;/code&gt;;在网页的最下面有显示;地址为:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[Jenkins地址]/api/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;认证方法为&lt;code&gt;Basic&lt;/code&gt;认证,&lt;code&gt;API Token&lt;/code&gt;请在用户设置中创建&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/jenkins_apitoken.png&quot; alt=&quot;jenkins_apitoken &quot; /&gt;&lt;/p&gt;
&lt;p&gt;新建构建在&lt;code&gt;Create Job&lt;/code&gt;中有说明;&lt;/p&gt;
&lt;p&gt;我的CURL命令是这样:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl --location &apos;http://192.168.1.23/job/AAA.Web/buildWithParameters&apos; \
--header &apos;Authorization: Basic XYZZZZXX=&apos; \
--form &apos;REVISION=&quot;HEAD&quot;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AAA.Web&lt;/code&gt;为项目(&lt;code&gt;Job&lt;/code&gt;)名称;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Authorization&lt;/code&gt;为&lt;code&gt;PostMan&lt;/code&gt;使用&lt;code&gt;Basic Auth&lt;/code&gt;自动生成,用户名为账号,密码为&lt;code&gt;APIKey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;form&lt;/code&gt;为我的构建参数&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;code&gt;TortoiseSVN&lt;/code&gt;提交代码后自动执行脚本&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-settings.html#:~:text=Client%20Side%20Hook%20Scripts&quot;&gt;官方文档&lt;/a&gt;中有客户端触发事件的详细说明;我这里只需要代码提交后的事件:&lt;code&gt;Post-commit&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/TortoiseSVN_hookscripts.png&quot; alt=&quot;TortoiseSVN_hookscripts &quot; /&gt;&lt;/p&gt;
&lt;p&gt;其中&lt;code&gt;Work Copy Path&lt;/code&gt;为&lt;code&gt;SVN&lt;/code&gt;本地根路径(每个&lt;code&gt;CheckOut&lt;/code&gt;加一条);执行的命令为&lt;code&gt;powershell  SVN\AAA\autoJenkins.ps1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这个&lt;code&gt;autoJenkins.ps1&lt;/code&gt;文件在后面;保存在&lt;code&gt;SVN&lt;/code&gt;本地路径中;因此意思为使用&lt;code&gt;powershell&lt;/code&gt;调用这个脚本&lt;/p&gt;
&lt;p&gt;这里我先给出我的&lt;code&gt;autoJenkins.ps1&lt;/code&gt;脚本文件:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;#
.SYNOPSIS
    Automated Jenkins Build Trigger for SVN Hooks.

.DESCRIPTION
    This script is designed to be integrated with SVN (Subversion) post-commit hooks. 
    It analyzes the SVN revision, commit messages, and changed paths to automatically 
    trigger specific Jenkins jobs via the Jenkins Remote API.

    Features:
    - Trigger Jenkins jobs based on directory path mapping.
    - Support for Commit Message commands: [ci skip], [build: projectName].
    - Automatic detection of modified files using SVN XML logs.
    - UTF-8 logging for both console and local log files.

.PARAMETER PATH
    The execution path provided by the SVN hook.
.PARAMETER REVISION
    The SVN revision number to analyze.
.PARAMETER RESULTPATH
    The physical path of the committed files in the repository.
.PARAMETER projectName
    (Optional) Force a specific Jenkins job name to build.

.EXAMPLE
    .\autoJenkins.ps1 -REVISION &quot;413&quot; -RESULTPATH &quot;G:\work\SVN\LifeHelper\Program\InterFace\WebService&quot;
#&amp;gt;
# 执行命令
# powershell.exe -command &quot;&amp;amp; {start-process powershell.exe (([system.environment]::GetCommandLineArgs()|ForEach-Object -process { &apos;\&quot;{0}\&quot;&apos; -f $_ })[3..([system.environment]::GetCommandLineArgs().Length-1)])}&quot; &quot;-file&quot; &quot;G:\work\SVN\LifeHelper\autoJenkins.ps1&quot;

# powershell  G:\work\SVN\LifeHelper\autoJenkins.ps1
# PATH DEPTH MESSAGEFILE REVISION ERROR 

param(
    [string]$PATH,      # 命令执行路径
    [string]$DEPTH,  # 对应 arg 1
    [string]$MESSAGEFILE,    # 对应 arg 2
    [string]$REVISION,    # 对应 arg 2
    [string]$SVN_ERROR,    # 对应 arg 2
    [string]$RESULTPATH,   # svn文件提交路径
    [string]$projectName    # 发布的项目名称
)

[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
$OutputEncoding = [System.Text.UTF8Encoding]::new()

Write-Host &quot;$(Get-Date -Format &apos;yyyy-MM-dd HH:mm:ss.fff&apos;) start script&quot;
Add-Content svn-hook.log &quot;$(Get-Date -Format &apos;yyyy-MM-dd HH:mm:ss.fff&apos;) start script&quot;

# Read-Host &quot;Press Enter to exit&quot;

$svnPath = $env:svnPath;
if ([string]::IsNullOrWhiteSpace($svnPath)) {
       $svnPath=&quot;D:\svn\repo&quot;
}


$pathMap = @(
    [PSCustomObject]@{
        Path = &quot;\Program\InterFace\WebService&quot;
        JobName     = &quot;WebService&quot;
    } 
)


# Jenkins 服务器地址
$JENKINS_URL=&quot;http://192.168.1.100:8080&quot;

$username = &quot;007&quot;
# 注意：如果是 Jenkins，这里通常填 API Token，而不是登录密码
$password = &quot;xxx&quot; 

function Log {
    param([string]$Message)
    Write-Host &quot;$(Get-Date -Format &apos;yyyy-MM-dd HH:mm:ss&apos;) $Message&quot;
    Add-Content svn-hook.log &quot;$(Get-Date -Format &apos;yyyy-MM-dd HH:mm:ss&apos;) $Message&quot;
}
Log &quot;PATH: $PATH&quot;
Log &quot;DEPTH: $DEPTH&quot;
Log &quot;MESSAGEFILE: $MESSAGEFILE&quot;
Log &quot;REVISION: $REVISION&quot;
Log &quot;SVN_ERROR: $SVN_ERROR&quot;
Log &quot;RESULTPATH: $RESULTPATH&quot;

$script:listProjectName = @()
# Read-Host &quot;Press Enter to exit&quot;
# 发送 Jenkins 构建请求
function BuildProject {
    param(        
        [string]$projectName,
        [string]$hookPath = &quot;&quot;
    )
    
     # 检查是否存在
    if ($script:listProjectName -contains $ProjectName) {
        Log &quot;ignore project: $ProjectName&quot;
        return
    }

    # 添加到脚本作用域的变量中 (注意 script: 前缀)
    $script:listProjectName += $ProjectName
    # 脚本目录
    # $ScriptDir = $PSScriptRoot
    # $ParentDir = $ScriptDir
    $ParentDir = $hookPath

    $JOB_NAME=$projectName

    # 不设置则取父级名称为项目名称
    if ([string]::IsNullOrWhiteSpace($projectName)) {
        $JOB_NAME=Split-Path $ParentDir -Leaf
    }
    Log &quot; url host is :${JENKINS_URL} &quot;

    $uri = &quot;$($JENKINS_URL.TrimEnd(&apos;/&apos;))/job/$JOB_NAME/buildWithParameters&quot;

    Log &quot;url: $uri&quot;

    $authPair = &quot;$($username):$($password)&quot;
    $encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($authPair))
    $headers = @{
        Authorization = &quot;Basic $encodedCredentials&quot;
    }

    Invoke-WebRequest -UseBasicParsing `
    -Uri $uri `
    -Method Post `
    -Headers $headers `
    -Body @{
        REVISION=&quot;HEAD&quot;
    }
}
function CheckChildUpdate {
    # ---------------------- 配置区域 ----------------------
    param(
        [string]$Revision = &quot;413&quot;,
        [string]$WatchDir = &quot;/&quot;
    )

    # ---------------------- 1. 获取 SVN 日志 ----------------------
    Log &quot;正在查询 SVN 版本: $Revision ...&quot;
    Log &quot;WatchDir is: $WatchDir&quot;

    # 使用 --xml 参数，这样 PowerShell 可以直接转换成对象，不用去截取字符串
    # 这里的 2&amp;gt;&amp;amp;1 是为了捕获可能的错误
    try {
        # 注意：如果是私有仓库，可能需要追加 --username &quot;xxx&quot; --password &quot;xxx&quot;
        [xml]$svnLog = svn log . -r $Revision -v --xml
    }
    catch {
        Log &quot;SVN 命令执行失败，请检查 SVN 命令行工具是否安装，或 URL/权限是否正确。&quot;
        # Read-Host &quot;Press Enter to exit&quot;
        exit 1
    }
    Log &quot;get svn log done.&quot;

    # ---------------------- 2. 提取变更文件列表 ----------------------
    # 容错处理：确保 XML 结构存在
    if ($null -eq $svnLog.log.logentry) {
        Log &quot;未找到版本信息 (可能版本号不存在)&quot;
        exit
    }

    # 获取所有变更路径的节点
    # .InnerText 会获取形如 &quot;/trunk/ProjectA/code.cs&quot; 的字符串
    $changedPaths = $svnLog.log.logentry.paths.path | ForEach-Object { $_.InnerText }

    Log &quot;该版本变更了 $($changedPaths.Count) 个文件。&quot;

    # ---------------------- 3. 匹配逻辑与执行 ----------------------

    # 定义一个标志位
    $isHit = $false

    # 遍历所有变更文件
    foreach ($pathTemp in $changedPaths) {
    
        # Write-Host &quot;变更文件: $path&quot;
        Log &quot;pathTemp  is: $pathTemp&quot;

        $targetPath=Join-Path (Split-Path $Path  -Parent) $pathTemp
        Log &quot;targetpath: $targetPath&quot;

        if ($targetPath -like &quot;$WatchDir*&quot;) {
            Log &quot; fiind target path: $pathTemp&quot;
            $isHit = $true
            break 
        }
    }
    return $isHit
}
function BuildWithCommand {
    # ---------------------- 配置区域 ----------------------
    param(
        [string]$Revision = &quot;413&quot;,
        [string]$WatchDir = &quot;/&quot;
    )

    # ---------------------- 1. 获取 SVN 日志 ----------------------
    Log &quot;for BuildWithCommand search svn version: $Revision ...&quot;
    Log &quot;WatchDir is: $WatchDir&quot;

    # 使用 --xml 参数，这样 PowerShell 可以直接转换成对象，不用去截取字符串
    # 这里的 2&amp;gt;&amp;amp;1 是为了捕获可能的错误
    try {
        # 注意：如果是私有仓库，可能需要追加 --username &quot;xxx&quot; --password &quot;xxx&quot;
        [xml]$svnLog = svn log . -r $Revision -v --xml
    }
    catch {
        Log &quot;SVN 命令执行失败，请检查 SVN 命令行工具是否安装，或 URL/权限是否正确。&quot;
        # Read-Host &quot;Press Enter to exit&quot;
        exit 1
    }
    Log &quot;get svn log done.&quot;

    # ---------------------- 2. 提取变更文件列表 ----------------------
    # 容错处理：确保 XML 结构存在
    if ($null -eq $svnLog.log.logentry) {
        Log &quot;未找到版本信息 (可能版本号不存在)&quot;
        exit
    }

    $commitMsg = $svnLog.log.logentry.msg.ToString()

    Log &quot;Commit Message: $commitMsg&quot;

    # ---------------------- 3. 匹配逻辑与执行 ----------------------

    # 定义一个标志位
    $isHit = $false

    # ----------------------------------------------------
    # 规则 A: 检查是否跳过 CI
    # 使用正则匹配，(?i) 表示不区分大小写
    # ----------------------------------------------------
    if ($commitMsg -match &quot;(?i)\[(ci skip|skip ci|no build)\]&quot;) {
        Log &quot;检测到跳过指令 [ci skip]，停止执行 CI 流程。&quot;
        exit 0 # 正常退出，不报错
    }

    # ----------------------------------------------------
    # 规则 B: 检查是否强制构建特定项目 (针对你的 LifeHelper)
    # ----------------------------------------------------
    if ($commitMsg -match &quot;(?i)\[build:\s*web\]&quot;) {
        Log &quot;检测到 [build: web] 指令，强制触发 Web 构建...&quot;
        # 调用 Web 的构建函数
        # Invoke-JenkinsJob &quot;LifeHelper.Web&quot;
    }

    $pattern = &quot;build\s*:\s*([\w\.-]+)&quot;

    if ($commitMsg -match $pattern) {
        # $matches[0] 是匹配到的完整字符串 (例如 &quot;build: LifeHelper.Web&quot;)
        # $matches[1] 是括号里捕获的内容 (即我们要的 &quot;LifeHelper.Web&quot;)
        
        $serviceName = $matches[1]
        
        Log &quot;match build server: [$serviceName]&quot;
    
        # 这里可以根据提取到的名称去执行逻辑
        if ($serviceName -eq &quot;LifeHelper.Web&quot;) {
            # 触发 Web 构建
        }
        BuildProject $serviceName
        exit 0 # 正常退出，不报错
    }

    return $isHit
}
# ([system.environment]::GetCommandLineArgs()|ForEach-Object -process { &apos;\&quot;{0}\&quot;&apos; -f $_ })
$myArgs = [System.Environment]::GetCommandLineArgs()

$target = $RESULTPATH

for ($i = 0; $i -lt $myArgs.Length; $i++) {
    Log (&quot;arg[{0}] = `&quot;{1}`&quot;&quot; -f $i, $myArgs[$i])
    # if($i -eq 7){
    #     $target=$myArgs[$i];
    # }
}
Log &quot;target is: $target&quot;
$PATH=$myArgs[1]
Log &quot;new PATH: $PATH&quot;

if (![string]::IsNullOrWhiteSpace($projectName)) {
       BuildProject $projectName
}

BuildWithCommand -Revision $REVISION -WatchDir $target

$fullPathMap = [System.Collections.Generic.List[PSCustomObject]]::new()

foreach ($kv in $pathMap) {
    $key=$kv.Path;
     Log &quot;key is $key &quot;
    $fullPath = Join-Path $svnPath $key
    Log &quot;full path ${fullPath}&quot;
    Log &quot;kv is $kv &quot;
    # Log &quot;kvvalue is $(pathMap[$key])&quot;
    $obj = [PSCustomObject]@{
        Path = $fullPath
        JobName     = $kv.JobName
    }
    $fullPathMap.Add($obj);
    # $fullPathMap.Add($fullPath,$(pathMap[$key]))
}


Log &quot;target is: $targetNorm&quot;

# 规范化路径（非常重要）
# $targetNorm = [System.IO.Path]::GetFullPath($target).TrimEnd(&apos;\&apos;)
$targetNorm = $target
Log &quot;targetNorm is: $targetNorm&quot;
# 匹配并取 Value（核心逻辑）
$matchedValue = $null

foreach ($entry in $fullPathMap) {
    $keyNorm = [System.IO.Path]::GetFullPath($entry.Path).TrimEnd(&apos;\&apos;)
    Log &quot;keyNorm is: $keyNorm&quot;
 
    if ($targetNorm.StartsWith($keyNorm, [System.StringComparison]::OrdinalIgnoreCase)) {
        $matchedValue = $entry.JobName
        Log &quot;Matched path: $keyNorm =&amp;gt; value: $matchedValue&quot;
        BuildProject  $matchedValue $keyNorm
    }
    else {
        Log &quot;Not matched path: $keyNorm try find by parent&quot;
        if($keyNorm.StartsWith($targetNorm, [System.StringComparison]::OrdinalIgnoreCase)){
            $isHit = CheckChildUpdate -Revision $REVISION -WatchDir $keyNorm
            if($isHit){
                $matchedValue = $entry.JobName
                Log &quot;Matched by child path: $keyNorm =&amp;gt; value: $matchedValue&quot;
                BuildProject  $matchedValue $keyNorm
            }
        }
    }
}

if ($null -eq $matchedValue) {
    Log &quot;No path matched: $targetNorm&quot;
    # Read-Host &quot;Press Enter to exit&quot;
    return
}

Write-Host &quot;$(Get-Date -Format &apos;yyyy-MM-dd HH:mm:ss.fff&apos;) script end&quot;
Add-Content svn-hook.log &quot;$(Get-Date -Format &apos;yyyy-MM-dd HH:mm:ss.fff&apos;) commit done&quot;
# Read-Host &quot;Press Enter to exit&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;svnPath&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SVN&lt;/code&gt;根目录环境变量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pathMap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SVN&lt;/code&gt;监听目录及其对应的&lt;code&gt;Jenkins&lt;/code&gt;名称字典;此为&lt;code&gt;SVN&lt;/code&gt;目录中的相对路径;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;JENKINS_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jenkins&lt;/code&gt;服务地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username &lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jenkins&lt;/code&gt;服务用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;password&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jenkins&lt;/code&gt;服务API Token&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因为脚本用到了&lt;code&gt;SVN&lt;/code&gt;获取提交记录的方法,因此需要安装&lt;code&gt;SVN CLI&lt;/code&gt;;在安装&lt;code&gt;TortoiseSVN&lt;/code&gt;时需选择&lt;code&gt;command line client tools&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/TortoiseSVN_command_line.png&quot; alt=&quot;TortoiseSVN&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;用法&lt;/h4&gt;
&lt;p&gt;本来是先写这个文章的,结果发现脚本有些问题;经常会报错;于是只能先解决报错;就有了前一篇文章:&lt;a href=&quot;2025-12-20-powershell-syntax-error/&quot;&gt;解决powershell表达式或语句中包含意外的标记问题 &lt;/a&gt;;又经过几次测试使用;改良了脚本;&lt;/p&gt;
&lt;p&gt;当有多个不同目录的文件提交到&lt;code&gt;SVN&lt;/code&gt;时,它的&lt;code&gt;RESULTPATH&lt;/code&gt;会是所有目录的最小父级,因此要能根据&lt;code&gt;SVN&lt;/code&gt;提交的目录来触发对应的&lt;code&gt;Job&lt;/code&gt;还要从&lt;code&gt;REVISION&lt;/code&gt;中遍历所有文件;找到对应的配置匹配的目录触发多个&lt;code&gt;Job&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;此脚本功能:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据配置(&lt;code&gt;$pathMap&lt;/code&gt;)在指定&lt;code&gt;svn&lt;/code&gt;目录&lt;code&gt;commit&lt;/code&gt;后触发对应的&lt;code&gt;Jenkins Job&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用命令直接触发&lt;code&gt;Jenkins Job&lt;/code&gt;,命令:&lt;code&gt;.\autoJenkins.ps1 -projectName &quot;JobName&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;从历史版本号触发对应的&lt;code&gt;Jenkins Job&lt;/code&gt;,命令:&lt;code&gt;.\autoJenkins.ps1 -REVISION &quot;500&quot; -RESULTPATH &quot;G:\work\SVN\LifeHelper\Program\InterFace\WebService&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;SVN&lt;/code&gt; &lt;code&gt;Commit&lt;/code&gt;中编写&lt;code&gt;[build: MySpecialJob]&lt;/code&gt; 直接触发构建&lt;code&gt;MySpecialJob&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Powershell调试方法&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;VS Code&lt;/code&gt;中一般调试方法&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1.安装 &lt;strong&gt;PowerShell 扩展&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;2.打开 &lt;code&gt;.ps1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;3.左侧点红点打断点&lt;/p&gt;
&lt;p&gt;4.&lt;code&gt;F5&lt;/code&gt; 启动调试&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;假如需要参数可以在&lt;code&gt;PowerShell Extension&lt;/code&gt;的控制台中直接输入带参数的命令触发&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/vscode_powershell_extension.png&quot; alt=&quot;vscode_powershell_extension&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;TERMINAL&lt;/code&gt;中直接输入脚本带参数命令&lt;code&gt;powershell.exe -File  &quot;G:\work\SVN\LifeHelper\autoJenkins.ps1&quot; -Revision 537&lt;/code&gt;就可以直接中断调试&lt;/p&gt;
&lt;h3&gt;调试&lt;code&gt;Post-commit&lt;/code&gt;命令的方法&lt;/h3&gt;
&lt;p&gt;如果直接使用&lt;code&gt;powershell  SVN\AAA\autoJenkins.ps1&lt;/code&gt;这样的触发命令;因为命令后台执行;假如有意外的错误完全摸不着头脑&lt;/p&gt;
&lt;p&gt;那有什么可以实时看到控制台输出及结果的方法吗?&lt;/p&gt;
&lt;p&gt;我在这位老哥那里找到了:&lt;a href=&quot;https://www.mikeobrien.net/blog/using-tortoisesvn-client-hook-script-to&quot;&gt;Using a TortoiseSVN Client Hook Script to Run a Visible PowerShell Script&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;将&lt;code&gt;powershell  SVN\AAA\autoJenkins.ps1&lt;/code&gt;命令替换为以下内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;powershell.exe -command &quot;&amp;amp; {start-process powershell.exe (([system.environment]::GetCommandLineArgs()|ForEach-Object -process { &apos;\&quot;{0}\&quot;&apos; -f $_ })[3..([system.environment]::GetCommandLineArgs().Length-1)])}&quot; &quot;-file&quot; &quot;G:\work\SVN\LifeHelper\autoJenkins.ps1&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它可以将启动参数传递给一个新的有前台界面的&lt;code&gt;powershell&lt;/code&gt;进程;这样就可以直观看到命令结果了&lt;/p&gt;
&lt;p&gt;假如命令太快弹窗一下就消失,可以在代码中添加&lt;code&gt;Read-Host &quot;Press Enter to exit&quot;&lt;/code&gt;这样的暂停代码;这样只有在回车确认之后才回继续执行&lt;/p&gt;
&lt;p&gt;如果还有一些异常情况;可以本地开启录屏;在录像中逐帧分析报错&lt;/p&gt;
&lt;h3&gt;结语&lt;/h3&gt;
&lt;p&gt;实测&lt;code&gt;Post-commit&lt;/code&gt;触发器只在&lt;code&gt;svn&lt;/code&gt;的命令执行时才有效;比如文件管理器集成的&lt;code&gt;TortoiseSVN&lt;/code&gt; &lt;code&gt;GUI&lt;/code&gt;操作,&lt;code&gt;SVN Commit&lt;/code&gt;命令以及&lt;code&gt;visual studio&lt;/code&gt;的&lt;code&gt;VisualSVN&lt;/code&gt;插件操作;&lt;/p&gt;
&lt;p&gt;第三方集成的&lt;code&gt;svn&lt;/code&gt;客户端无法触发;比如&lt;code&gt;IDEA&lt;/code&gt;的&lt;code&gt;SVN&lt;/code&gt; &lt;code&gt;VCS&lt;/code&gt;代码工具无法触发&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mikeobrien.net/blog/using-tortoisesvn-client-hook-script-to&quot;&gt;Using a TortoiseSVN Client Hook Script to Run a Visible PowerShell Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-settings.html&quot;&gt;TortoiseSVN:Client Side Hook Scripts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>微信小程序cli工具miniprogram-ci报错处理</title><link>https://blog.wangshuai.app/2025-12-07-miniprogram-ci_browserslist_error/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-12-07-miniprogram-ci_browserslist_error/</guid><pubDate>Sun, 07 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;最近在&lt;code&gt;Jenkins&lt;/code&gt;上的小程序发布报错:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;child process stderr: Browserslist: browsers &lt;strong&gt;data&lt;/strong&gt; (caniuse-lite) &lt;strong&gt;is&lt;/strong&gt; 14 months old. Please run:
npx update-browserslist-db@latest
Why you should &lt;strong&gt;do&lt;/strong&gt; it regularly: https://github.com/browserslist/update-db#readme&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里记录一下解决方案&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;出现问题时的&lt;code&gt;miniprogram-ci&lt;/code&gt;版本是&lt;code&gt;2.0.10&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;直接按照提示执行&lt;code&gt;npx update-browserslist-db@latest&lt;/code&gt;会发现并不能解决问题&lt;/p&gt;
&lt;p&gt;根据提示,是知道因为包过期了导致编译失败;因此更新&lt;code&gt;miniprogram-ci&lt;/code&gt;版本就行了&lt;/p&gt;
&lt;h4&gt;操作步骤&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;首先直接尝试更新到最新版&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;执行命令&lt;code&gt;npm install -g miniprogram-ci@latest&lt;/code&gt;安装好后尝试发布,现在是不会报这个错了;但是因为小程序很大,会报超2M的的问题:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[error] 20003 Error: {&quot;errCode&quot;:-1,&quot;errMsg&quot;:&quot;inner upload fail with errcode: 80200, errmsg: main package source size 2576KB exceed max limit 2048KB&quot;}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;尝试直接使用开发者工具会发现主包只有1.6M,可以直接上传;而且同样的代码;在升级&lt;code&gt;cli&lt;/code&gt;前是不会有这个问题的;因此需要换一个&lt;code&gt;ci&lt;/code&gt;版本&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;找到其它主要&lt;code&gt;miniprogram-ci&lt;/code&gt;版本多次尝试&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在npm官网:&lt;a href=&quot;https://www.npmjs.com/package/miniprogram-ci?activeTab=versions&quot;&gt;miniprogram-ci&lt;/a&gt;上可以看到所有版本;依次尝试最新的&lt;code&gt;2.1.29&lt;/code&gt; &lt;code&gt;2.1.28&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;2.1.18&lt;/code&gt;都有同样的问题;再往后看到了&lt;code&gt;1.9.17&lt;/code&gt;;经测试这个版本可以同时解决前面的两个报错;因此解决方法就是执行这个命令:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;npm install -g miniprogram-ci@1.9.17&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>暴雪游戏崩溃报错解决办法</title><link>https://blog.wangshuai.app/2025-11-16-sc2%E6%88%98%E7%BD%91%E6%9A%B4%E9%9B%AA%E6%B8%B8%E6%88%8F%E5%87%BA%E7%8E%B0%E4%B8%80%E4%B8%AA%E6%84%8F%E5%A4%96%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-11-16-sc2%E6%88%98%E7%BD%91%E6%9A%B4%E9%9B%AA%E6%B8%B8%E6%88%8F%E5%87%BA%E7%8E%B0%E4%B8%80%E4%B8%AA%E6%84%8F%E5%A4%96%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/</guid><pubDate>Sun, 16 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;前一段时间玩SC2的时候经常会崩溃报错:程序运行中出现意外错误&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/sc2_crash.jpg&quot; alt=&quot;sc2_crash&quot; /&gt;&lt;/p&gt;
&lt;p&gt;表现行为就是能开游戏,但是玩2~10分钟就会游戏崩溃;如此往复好几次后我终于找到解决方法&lt;/p&gt;
&lt;p&gt;本解决方案是暴雪游戏崩溃的终极解决方法,任意暴雪游戏出现这个弹窗都可据此找到解决方法&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;我遇到的问题是&lt;code&gt;INT_DIVIDE_BY_ZERO&lt;/code&gt;;通过这个关键字你可以找到很多相关的内容;&lt;/p&gt;
&lt;p&gt;根本原因就是13,14代&lt;code&gt;Intel CPU&lt;/code&gt;缺陷导致程序异常,基本的处理方法就是给CPU降频&lt;/p&gt;
&lt;p&gt;这里的报错只是弹窗提示程序出现意外错误,实际的异常在日志文件中记录;&lt;/p&gt;
&lt;p&gt;因此终极解决办法就是:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从本地磁盘中找到异常报错明细&lt;/li&gt;
&lt;li&gt;根据报错明细网上搜索前辈的解决方法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后面我也会给出我这里的处理方法(CPU降频方法)&lt;/p&gt;
&lt;h4&gt;操作步骤&lt;/h4&gt;
&lt;h5&gt;找到崩溃报错明细&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;打开崩溃游戏的日志&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SC2&lt;/code&gt;的崩溃日志在&lt;code&gt;%USERPROFILE%\Documents\StarCraft II\GameLogs&lt;/code&gt;中,其它游戏请在对应目录中查找(假如你不知道你的游戏名字,打开战网游戏设置,安装路径的最后一层就是游戏名字);&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/sc2_gamepath.png&quot; alt=&quot;game path&quot; /&gt;&lt;/p&gt;
&lt;p&gt;找到最近一次&lt;code&gt;Crash&lt;/code&gt;日志(文件夹形如&lt;code&gt;2025-11-17 12.17.32 XXX B11111 Crash&lt;/code&gt;);打开&lt;code&gt;XXXXCrash.txt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/SC2_crash_txt.png&quot; alt=&quot;SC2&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;找到报错明细&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Crash.txt&lt;/code&gt;中有很多内容,最关键的就是&lt;code&gt;BlizzardError.Summary&lt;/code&gt;,可以看到我这里的报错内容是:&lt;code&gt;INT_DIVIDE_BY_ZERO : DBG-OPTIONS&amp;lt;FunctionsOnly SingleLine&amp;gt;&lt;/code&gt;;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/sc2_crash_blizzarderror.png&quot; alt=&quot;BlizzardError&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在google中搜索&lt;code&gt;sc2 INT_DIVIDE_BY_ZERO&lt;/code&gt;第一个就是解决方法&lt;/p&gt;
&lt;h5&gt;INT_DIVIDE_BY_ZERO处理方法&lt;/h5&gt;
&lt;p&gt;我的主板是&lt;code&gt;Micro-Star PRO Z690-A WIFI DDR4&lt;/code&gt;从网上搜索微星主板CPU降频方法很容易就知道怎么做&lt;/p&gt;
&lt;p&gt;我做的调整是:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;关闭&lt;code&gt;Intel SpeedStep&lt;/code&gt;和&lt;code&gt;Intel Speed Shift&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设置&lt;code&gt;p-core ratio&lt;/code&gt; 从&lt;code&gt;+1&lt;/code&gt; 到 &lt;code&gt;-2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里我设置了几次,每次&lt;code&gt;-1&lt;/code&gt;然后测试游戏,最终发现&lt;code&gt;-2&lt;/code&gt;不会报错;你可以多次测试找到你最佳设置&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;结语&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sc2&lt;/code&gt;作为一个&lt;code&gt;Dead Game&lt;/code&gt;崩溃肯定不是游戏内的原因&lt;/p&gt;
&lt;p&gt;而这次问题其实之前早已预见;魔兽世界一早就遇到同样的问题;有很多人反馈给了暴雪;因此当时进游戏就会弹窗提示:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;《魔兽世界》检测到你的电脑正在使用英特尔第13或14代处理器，且未安装合适的更新...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最终这个问题还是到了我CPU上&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;只要你的问题合理,报错清晰;那就很容易从关键字中找到解决方案&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因为大多数问题,都不会是你第一个遇到;网上找找,就很容易有解决方法;这才是任何问题的&lt;strong&gt;终极解决方法&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/wow/comments/1dspd3t/game_crash_int_divide_by_zero_solution/&quot;&gt;Game Crash INT_DIVIDE_BY_ZERO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>使用ssh连接h3c堡垒机服务器</title><link>https://blog.wangshuai.app/2025-08-01-ssh-h3c-server/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-08-01-ssh-h3c-server/</guid><pubDate>Fri, 01 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;公司正式环境使用了&lt;code&gt;H3C&lt;/code&gt;的堡垒机,因此在查看正式数据时需使用对应的堡垒机客户端&lt;code&gt;Tgent&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;之前公司还使用过&lt;code&gt;Vone&lt;/code&gt;客户端连接到堡垒机;&lt;/p&gt;
&lt;p&gt;这些堡垒机以我的经验来看都使用的是&lt;code&gt;ssh tunnel&lt;/code&gt;技术&lt;/p&gt;
&lt;p&gt;这一点可以在我使用&lt;code&gt;ssh -J&lt;/code&gt;命令的报错得到印证&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;channel 0: open failed: administratively prohibited: Generic error while opening channel: 0
stdio forwarding failed
kex_exchange_identification: Connection closed by remote host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;堡垒机(B)登录需要三组IP和用户名密码&lt;/p&gt;
&lt;p&gt;S: 堡垒机外网入口 零信任 &lt;code&gt;Tgent&lt;/code&gt; IP,即为&lt;code&gt;VPN&lt;/code&gt; 服务地址假设 &lt;code&gt;200.0.0.0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;S1:堡垒机登录IP ,即实际管理内网资源的服务网站,IP假设为:&lt;code&gt;10.0.0.0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;B:需要访问的正式服务器内网地址,假设为:&lt;code&gt;192.168.10.0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;客户端C连接目标服务器B的数据流转图大概如下:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;graph LR
 		C-- &quot;Tgent连接&quot; ---&amp;gt;S;
		S-- &quot;Tgent连接&quot; ---&amp;gt;C;
		S-- &quot;内网访问&quot; ---&amp;gt;S1;
	    S1-- &quot;内网访问&quot; --&amp;gt;S;
	    S1--&quot;SSH Tunnel&quot; --&amp;gt;B;
	    B--&quot;SSH Tunnel&quot; ---&amp;gt;S1;  
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;C到S的&lt;code&gt;Tgent&lt;/code&gt;连接的用户密码登录是必输的&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/tgent_login.png&quot; alt=&quot;tgent_login&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在进入内网后S到B的连接可直接通过命令简化,本文主要介绍一般登录及简化步骤&lt;/p&gt;
&lt;h4&gt;操作步骤&lt;/h4&gt;
&lt;h5&gt;所需工具&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VPN&lt;/code&gt;客户端&lt;code&gt;Tgent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;数据审计工具&lt;code&gt;AccessClient&lt;/code&gt;此工具在帮助页面下载&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SSH&lt;/code&gt;客户端&lt;code&gt;xshell&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;正常GUI登录过程&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;打开&lt;code&gt;Tgent&lt;/code&gt;,输入控制器地址&lt;code&gt;200.0.0.0&lt;/code&gt;,然后输入用户名密码登录&lt;/li&gt;
&lt;li&gt;登录后即可在&lt;code&gt;门户&lt;/code&gt;中查看到账号的堡垒机,点击后进入&lt;code&gt;H3C&lt;/code&gt;运维审计系统&lt;code&gt;10.0.0.0&lt;/code&gt;,同样输入用户名密码登录&lt;/li&gt;
&lt;li&gt;登录后点击访问资产,此处浏览器会提示安装&lt;code&gt;AccessClient&lt;/code&gt;客户端&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/h3c_install_accessclient.png&quot; alt=&quot;install_access_client&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安装完成后点击资产右侧的访问,选择方式开启&lt;code&gt;ssh&lt;/code&gt;客户端&lt;/p&gt;
&lt;p&gt;根据服务端设置可能需要使用不同的客户端,开启成功后输入对应的密码即可正常使用&lt;/p&gt;
&lt;p&gt;PS:异常情况请查看最后的常见问题&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Xshell一键登录步骤&lt;/h5&gt;
&lt;p&gt;通过查看&lt;code&gt;AccessClient&lt;/code&gt;打开的&lt;code&gt;SSH&lt;/code&gt;客户端的启动命令&lt;code&gt;&quot;C:\Program Files\VanDyke Software\SecureCRT\securecrt.exe&quot; /T /N root@xxx-aaa /ssh2 10.0.0.0 /P 122 /L account_10.0.0.0 /PASSWORD OTP:OtmBXhl3chsq&lt;/code&gt;,即可了解其作用原理;经分析尝试后得出以下简化登录方法&lt;/p&gt;
&lt;p&gt;从页面点击启动的&lt;code&gt;AccessClient&lt;/code&gt;会启动服务端设定的&lt;code&gt;SSH&lt;/code&gt;客户端,假如本地没有安装则无法连接服务器&lt;/p&gt;
&lt;p&gt;实际使用时,只要支持&lt;code&gt;SSH2&lt;/code&gt;协议即可连接&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;SSH&lt;/code&gt;客户端连接堡垒机服务&lt;code&gt;S1&lt;/code&gt;,目标&lt;code&gt;10.0.0.0&lt;/code&gt;端口根据&lt;code&gt;AccessClient&lt;/code&gt;启动的&lt;code&gt;SSH&lt;/code&gt;客户端命令确定,我这里为122,启动命令可在任务管理器中确定;用户名密码为&lt;code&gt;S1&lt;/code&gt;的用户名密码&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/ssh_secuercrt_cmd.png&quot; alt=&quot;ssh_secuercrt_cmd&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;登录堡垒机的&lt;code&gt;SSH&lt;/code&gt;成功后可查看到当前用户可管理的资产,使用数字切换服务和登录名&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里显示乱码,但不影响使用&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/ssh_h3c_resource.png&quot; alt=&quot;ssh_h3c_resource&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输入完成再输入目标服务器&lt;code&gt;B&lt;/code&gt;的用户名密码即可登录成功&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这是交互式切换登录,实际使用可以用&lt;code&gt;xshell&lt;/code&gt;的&lt;code&gt;Login Scripts&lt;/code&gt;帮助一键登录&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/xshell_login_scripts.png&quot; alt=&quot;login scripts&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Login Scripts&lt;/code&gt;是&lt;code&gt;SSH&lt;/code&gt;连接建立好后立即执行的脚本,我这里输入的是&lt;code&gt;5&lt;/code&gt;,&lt;code&gt;3&lt;/code&gt;和登录密码&lt;/p&gt;
&lt;p&gt;这样即可自动选择资产,选择登录用户以及自动登录;假如部分操作反应慢,可以添加&lt;code&gt;Expect&lt;/code&gt;文本,比如期望&lt;code&gt;Last Login&lt;/code&gt;文本出现后(登录成功后),再输入其它命令,比如登录数据库&lt;/p&gt;
&lt;h3&gt;常见问题&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在访问资产页面点击&lt;code&gt;访问&lt;/code&gt;无任何反应&lt;/p&gt;
&lt;p&gt;需要安装帮助页面的&lt;code&gt;AccessClient&lt;/code&gt;,然后重启浏览器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点击&lt;code&gt;访问&lt;/code&gt;后弹出了一个文件选择的框&lt;/p&gt;
&lt;p&gt;此现象表面本地没有对应的客户端,可以根据选择的客户端名字,网上下载对应程序安装后重试&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;弹出的的文件选择错误导致无法启动&lt;code&gt;SSH&lt;/code&gt;客户端&lt;/p&gt;
&lt;p&gt;弹出的文件路径选择后&lt;code&gt;AccessClient&lt;/code&gt;会将路径保存到注册表中,需要修改注册表才能正常运行;注册表路径在日志文件中有记录;&lt;code&gt;AccessClient&lt;/code&gt;日志文件位置为:&lt;code&gt;C:\Users\[用户名]\AppData\Local\Temp\AccessClient.log&lt;/code&gt;;打开后会看到这样的日志:&lt;code&gt; find path, key: Software\Microsoft\Windows\CurrentVersion\App Paths\securecrt.exe&lt;/code&gt;;因此在注册表的&lt;code&gt;Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\securecrt.exe&lt;/code&gt;中添加正确的路径即可&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2025-05-06-%E6%B7%B1%E4%BF%A1%E6%9C%8D%20%E6%9C%AC%E5%9C%B0%20%E9%80%9A%E8%BF%87%20Easy%20Connect%E5%8F%8A%20ssh%E8%BF%9E%E6%8E%A5%E6%9C%8D%E5%8A%A1%E5%99%A8/&quot;&gt;深信服 本地 通过 Easy Connect及 ssh连接服务器&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>使用sidecar container dump 正在运行的容器</title><link>https://blog.wangshuai.app/2025-05-21-csharp_dump_in_docker/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-05-21-csharp_dump_in_docker/</guid><pubDate>Wed, 21 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/zh-cn/dotnet/core/diagnostics/debug-memory-leak&quot;&gt;&lt;code&gt;memory dump&lt;/code&gt;&lt;/a&gt;是分析线上程序内存占用非常好的工具&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;windows&lt;/code&gt;上可以直接任务管理器右键生成&lt;code&gt;dump&lt;/code&gt;,假如需要根据条件比如CPU 内存占用到多少生成&lt;code&gt;dump&lt;/code&gt;可以使用&lt;a href=&quot;https://learn.microsoft.com/zh-cn/sysinternals/downloads/procdump&quot;&gt;&lt;code&gt;procdump&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;额外的,还可以使用&lt;a href=&quot;https://www.jetbrains.com/help/dotmemory/Importing_Process_Dumps.html&quot;&gt;&lt;code&gt;dotmemory.exe&lt;/code&gt;&lt;/a&gt;创建&lt;code&gt;dump&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;而&lt;code&gt;linux&lt;/code&gt;呢?&lt;/p&gt;
&lt;p&gt;可以使用&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dump&quot;&gt;&lt;code&gt;dotnet-dump&lt;/code&gt;&lt;/a&gt; 或 &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-gcdump&quot;&gt;&lt;code&gt;dotnet-gcdump&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;经我测试,&lt;code&gt;dotnet-gcdump&lt;/code&gt;安装后可直接执行命令无问题,但在&lt;code&gt;dump&lt;/code&gt;中未发现更多数据,于是尝试使用&lt;code&gt;dotnet-dump&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;但是我在正式服务器上安装一堆东西执行命令后却报错:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet-dump fails with &quot;Writing dump failed (HRESULT: 0x80004005)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;GPT&lt;/code&gt;告诉我这是因为&lt;code&gt;docker run&lt;/code&gt;时未添加特权参数&lt;code&gt;--cap-add=SYS_PTRACE --security-opt seccomp=unconfined&lt;/code&gt;导致的&lt;/p&gt;
&lt;p&gt;但问题是,我只需要为这个线上容器(&lt;code&gt;Container&lt;/code&gt;)创建&lt;code&gt;dump&lt;/code&gt;而不是要重新起一个容器&lt;/p&gt;
&lt;p&gt;本文介绍解决方法&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;微软的官方文档里面有提到这种方法:&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/diagnostics/diagnostics-in-containers&quot;&gt;Collect diagnostics in Linux containers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;即为&lt;code&gt;sidecar container&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;就是另起一个带有特权参数的容器,通过命名空间共享(&lt;a href=&quot;https://docs.docker.com/reference/cli/docker/container/run/#pid&quot;&gt;share a process namespace&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;在特权容器中创建&lt;code&gt;dump&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里给出我的命令&lt;/p&gt;
&lt;p&gt;以下命令皆由AI生成&lt;/p&gt;
&lt;h4&gt;操作步骤&lt;/h4&gt;
&lt;h5&gt;正常使用&lt;code&gt;dotnet-dump&lt;/code&gt;的命令&lt;/h5&gt;
&lt;p&gt;这里先给出正常情况下,特权参数启用&lt;code&gt;testServer&lt;/code&gt;时的命令以做参考&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;###docker run --name test007 --security-opt seccomp=unconfined --rm --cap-add=SYS_PTRACE testServer
###docker run --name test007 -v tmp-shared-volume:/tmp --security-opt seccomp=unconfined --rm --cap-add=SYS_PTRACE testServer

docker exec -it test007 bash
###add proxy
export https_proxy=http://127.0.0.1:7890
export http_proxy=http://127.0.0.1:7890


###install sdk
apt-get update
apt-get install -y wget apt-transport-https software-properties-common

wget https://packages.microsoft.com/config/debian/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
dpkg -i packages-microsoft-prod.deb

apt-get update
apt-get install -y dotnet-sdk-5.0


####install dump tool
dotnet tool install --global dotnet-dump --version 5.0.251802
dotnet tool install --global dotnet-gcdump --version 5.0.251802


export PATH=&quot;$PATH:$HOME/.dotnet/tools&quot;

###should get error: dotnet-dump fails with &quot;Writing dump failed (HRESULT: 0x80004005)&quot; if not   --security-opt seccomp=unconfined --rm --cap-add=SYS_PTRACE
dotnet-dump collect -p 1 -o /tmp/webservice.dmp --type Full

exit
docker cp test007:/tmp/webservice.dmp .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里因为我的服务用的&lt;code&gt;.NET 5.0&lt;/code&gt;因此选用&lt;code&gt;5.0&lt;/code&gt;的版本,假如不知道对应安装的&lt;code&gt;dotnet-dump&lt;/code&gt;版本可查看&lt;a href=&quot;https://www.nuget.org/packages/dotnet-dump#versions-body-tab&quot;&gt;&lt;code&gt;dotnet-dump versions&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PS:测试时可以使用&lt;code&gt;docker commit test007 test007-2&lt;/code&gt;命令临时将安装的内容保存,方便调试&lt;/p&gt;
&lt;h5&gt;sidecar container &lt;code&gt;dotnet-dump&lt;/code&gt;生成dump&lt;/h5&gt;
&lt;p&gt;正常&lt;code&gt;sidecar&lt;/code&gt;应该是这样的命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --rm -it --name t07 --pid=container:test007       --cap-add SYS_PTRACE    -v /tmp/dumps:/dumps_out     test007-2    bash -c &quot;dotnet-dump collect -p 1 -o /dumps_out/myapp.dmp --type Full&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里使用安装了&lt;code&gt;dotnet-dump&lt;/code&gt;的临时&lt;code&gt;image&lt;/code&gt;:&lt;code&gt;test007-2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;生成的&lt;code&gt;dump&lt;/code&gt;文件为&lt;code&gt;Host&lt;/code&gt;的&lt;code&gt;/tmp/dumps/myapp.dmp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;但实际执行会发现报错:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Process 1 not running compatible .NET runtime.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;微软的官方文档里有提到这个报错:&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/diagnostics/diagnostics-in-containers#use-net-cli-tools-in-a-sidecar-container-or-from-the-host&quot;&gt;Use .NET CLI tools in a sidecar container or from the host&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;它的方案是共享&lt;code&gt;/tmp&lt;/code&gt; 路径,这里我没明白什么意思,但是我找到另一种支持的方法&lt;/p&gt;
&lt;h5&gt;sidecar container &lt;code&gt;createdump&lt;/code&gt;生成dump&lt;/h5&gt;
&lt;p&gt;在&lt;code&gt;Microsoft.NETCore.App&lt;/code&gt;中已经自带了&lt;code&gt;createdump&lt;/code&gt;程序,可以直接生成&lt;code&gt;dump&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这个文件位于容器的&lt;code&gt;/usr/share/dotnet/shared/Microsoft.NETCore.App&lt;/code&gt;目录中,根据你安装的&lt;code&gt;runtime&lt;/code&gt;版本有所不同,因此首先我找到本地自带的&lt;code&gt;createdump&lt;/code&gt;版本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run  --rm -it --name t07   mcr.microsoft.com/dotnet/aspnet:5.0    bash -c &quot;ls /usr/share/dotnet/shared/Microsoft.NETCore.App/&quot;
####output 5.0.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;直接使用&lt;code&gt;createdump&lt;/code&gt;创建&lt;code&gt;dump&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --rm -it --name t07 --pid=container:test007       --cap-add SYS_PTRACE    -v /tmp/dumps:/dumps_out         mcr.microsoft.com/dotnet/aspnet:5.0         bash -c &quot;/usr/share/dotnet/shared/Microsoft.NETCore.App/5.0.5/createdump --full     --name /dumps_out/myapp.dmp    1&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成的&lt;code&gt;dump&lt;/code&gt;文件为&lt;code&gt;Host&lt;/code&gt;的&lt;code&gt;/tmp/dumps/myapp.dmp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;1为&lt;code&gt;test007&lt;/code&gt;中&lt;code&gt;dotnet&lt;/code&gt;服务的&lt;code&gt;pid&lt;/code&gt;,可以通过命令查询&lt;/p&gt;
&lt;p&gt;&lt;code&gt;5.0.5&lt;/code&gt;为本机&lt;code&gt;mcr.microsoft.com/dotnet/aspnet:5.0&lt;/code&gt;的&lt;code&gt;createdump&lt;/code&gt;版本&lt;/p&gt;
&lt;p&gt;同时,使用&lt;code&gt;aspnet:5.0&lt;/code&gt;的镜像还避免了正式服务多实例数据异常的风险,可以说是一劳多得,一箭双雕&lt;/p&gt;
&lt;h5&gt;传输&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;dump&lt;/code&gt;文件一般很大,所以需要压缩传输&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tar -czvf dump.tar.gz /tmp/dumps/myapp.dmp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;假如压缩后还是很大,且正式服务器带宽不大,可以看我之前的文章:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/2023-06-16-%E9%98%BF%E9%87%8C%E4%BA%91ECS%E4%B8%8B%E8%BD%BD%E5%8A%A0%E9%80%9F/&quot;&gt;使用docker加速阿里云ECS下载&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aistudio.google.com/&quot;&gt;Google AI Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/diagnostics/diagnostics-in-containers&quot;&gt;Collect diagnostics in Linux containers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>connect server by Easy connect</title><link>https://blog.wangshuai.app/2025-05-06-%E6%B7%B1%E4%BF%A1%E6%9C%8D%20%E6%9C%AC%E5%9C%B0%20%E9%80%9A%E8%BF%87%20Easy%20Connect%E5%8F%8A%20ssh%E8%BF%9E%E6%8E%A5%E6%9C%8D%E5%8A%A1%E5%99%A8/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-05-06-%E6%B7%B1%E4%BF%A1%E6%9C%8D%20%E6%9C%AC%E5%9C%B0%20%E9%80%9A%E8%BF%87%20Easy%20Connect%E5%8F%8A%20ssh%E8%BF%9E%E6%8E%A5%E6%9C%8D%E5%8A%A1%E5%99%A8/</guid><pubDate>Tue, 06 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;公司正式的服务器使用了深信服,本文介绍深信服服务器的连接方法&lt;/p&gt;
&lt;p&gt;连接正式服务器需要的&lt;code&gt;vpn&lt;/code&gt;软件为&lt;a href=&quot;https://support.sangfor.com.cn/productSoftware/list?product_id=20&amp;amp;category_id=56&quot;&gt;&lt;strong&gt;EasyConnect&lt;/strong&gt;&lt;/a&gt;,这个软件第一坑的地方就是官方下载需要登录深信服社区;我直接拒绝&lt;/p&gt;
&lt;p&gt;后面我找到腾讯的下载地址:&lt;a href=&quot;https://pc.qq.com/detail/8/detail_26728.html&quot;&gt;&lt;strong&gt;EasyConnect下载:腾讯软件下载&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;第二个不便的地方是开启&lt;code&gt;VPN&lt;/code&gt;后本机所有的外网都没了,在找&lt;strong&gt;EasyConnect&lt;/strong&gt;的时候,我意外发现了这个开源项目:&lt;strong&gt;&lt;a href=&quot;https://github.com/docker-easyconnect/docker-easyconnect&quot;&gt;docker-easyconnect&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本文主要使用此项目&lt;/p&gt;
&lt;p&gt;默认的从客户端(A)连接到服务器(B)的方法是直接连接&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/easyconnect_a-b.png&quot; alt=&quot;easy connect a b&quot; /&gt;&lt;/p&gt;
&lt;p&gt;开启&lt;strong&gt;EasyConnect&lt;/strong&gt;后AB组成了一个局域网,导致A也没有网络了&lt;/p&gt;
&lt;p&gt;而**&lt;a href=&quot;https://github.com/docker-easyconnect/docker-easyconnect&quot;&gt;docker-easyconnect&lt;/a&gt;**的作用是添加一个A1和服务器B通讯,而本机A只用和A1通讯,进而可以自由访问外网&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/easyconnect_aa1b.png&quot; alt=&quot;easy connect a-a1-b&quot; /&gt;&lt;/p&gt;
&lt;p&gt;参照网上的攻略:&lt;a href=&quot;https://zhuanlan.zhihu.com/p/389894063&quot;&gt;用docker封印EasyConnect并连接远程桌面和数据库 - Jortana的文章 - 知乎&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;可以在本机的docker实现这样的功能,攻略中的A1就是本机docker环境,也可以是wsl&lt;/p&gt;
&lt;p&gt;但是我的PC没有docker,于是将A1独立出来,放到另外的测试服务器上&lt;/p&gt;
&lt;p&gt;实际上A1的作用就是堡垒机,本文也是创建一个堡垒机.&lt;/p&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;code&gt;ssh&lt;/code&gt;连接正式服务器&lt;/li&gt;
&lt;li&gt;可以直接连接到正式服务器上的任意本地服务比如数据库,因此就有直接debug正式服务的能力&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;h4&gt;首先,参照官方方法安装安装&lt;a href=&quot;https://github.com/docker-easyconnect/docker-easyconnect&quot;&gt;docker-easyconnect&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;这里给出我的命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#192.168.1.101 为测试服务器Ip 即为A1
docker run --rm --name easyconnect --device /dev/net/tun --cap-add NET_ADMIN -ti -p 192.168.1.101:1080:1080 -p 127.0.0.1:8888:8888 -e EC_VER=7.6.7 -e CLI_OPTS=&apos;-d https://11.22.33.44:123 -u ssss -p xxxx&apos; hagb/docker-easyconnect:cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是&lt;code&gt;cli&lt;/code&gt;的连接方法&lt;/p&gt;
&lt;p&gt;需要注意的是,知乎教程中用的是&lt;code&gt;docker desktop&lt;/code&gt;,因此&lt;code&gt;socket&lt;/code&gt;服务IP填的&lt;code&gt;127.0.0.1&lt;/code&gt;,而我这里需要从外部访问测试服务器&lt;code&gt;A1&lt;/code&gt;,因此&lt;code&gt;1080&lt;/code&gt;端口的IP需调整为运行docker服务的地址,即&lt;code&gt;192.168.1.101&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;假如一切正常,能看到&lt;code&gt;user &quot;ssss&quot; login successfully!&lt;/code&gt;登录成功的提示&lt;/p&gt;
&lt;hr /&gt;
&lt;h5&gt;vnc登录&lt;/h5&gt;
&lt;p&gt;假如&lt;code&gt;cli&lt;/code&gt;登录报错,可以使用&lt;code&gt;vnc&lt;/code&gt;远程登录 官方文档有参数详细说明&lt;/p&gt;
&lt;p&gt;我就遇到&lt;code&gt;cli&lt;/code&gt;登录报错的问题:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/local/bin/start.sh: line 152: tigervncpasswd: command not found
WARNING: logging deactivated (can&apos;t log to stdout when daemonized)
/usr/local/bin/start.sh: line 158: tigervncserver: command not found
/usr/local/bin/start.sh: line 170: xclip: command not found
auto login is disabled
login failed!
svpn stop!
Terminated
auto login is disabled
login failed!
svpn stop!
Terminated
auto login is disabled
login failed!
svpn stop!
Terminated
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经后续测试,这里原因为密码过期,后台强制换密码导致无法登录&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/easy_connect_change_password.png&quot; alt=&quot;easy_connect_change_password&quot; /&gt;&lt;/p&gt;
&lt;p&gt;因此,使用&lt;code&gt;VNC&lt;/code&gt;方法登录换过密码后就能用&lt;code&gt;cli&lt;/code&gt;登录了&lt;/p&gt;
&lt;p&gt;这里给出我的&lt;code&gt;vnc&lt;/code&gt;命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --rm --device /dev/net/tun --cap-add NET_ADMIN -ti -e PASSWORD=password -e DISABLE_PKG_VERSION_XML=1 -e URLWIN=1 -v $HOME/.ecdata:/root -p 192.168.1.101:5901:5901 -p 192.168.1.101:1080:1080 -p 127.0.0.1:8888:8888 hagb/docker-easyconnect:7.6.7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中&lt;code&gt;password&lt;/code&gt;是&lt;code&gt;vnc&lt;/code&gt;登录密码&lt;/p&gt;
&lt;p&gt;arm64 和 mips64el 架构需要加入 &lt;code&gt;-e DISABLE_PKG_VERSION_XML=1&lt;/code&gt; 参数&lt;/p&gt;
&lt;p&gt;根据我这里的参数,使用&lt;code&gt;vnc&lt;/code&gt;连接&lt;code&gt;192.168.1.101:5901&lt;/code&gt;即可&lt;/p&gt;
&lt;h4&gt;配置&lt;code&gt;Clash&lt;/code&gt;服务&lt;/h4&gt;
&lt;p&gt;还是可以参照知乎教程中&lt;code&gt;Clash&lt;/code&gt;的配置方法,将IP改为&lt;code&gt;192.168.1.101&lt;/code&gt;即可&lt;/p&gt;
&lt;p&gt;我这里因为用到了订阅,因此使用&lt;a href=&quot;https://docs.gtk.pw/contents/parser.html&quot;&gt;&lt;code&gt;Parsers&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parsers:
      prepend-rules:
        - IP-CIDR,192.168.0.11/32,深信服
      append-proxies:
        - {name: easyConnect, server: 192.168.1.101, port: 1080, type: socks5}
      append-proxy-groups:
        - name: 深信服
          type: select
          proxies:
            - easyConnect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中的&lt;code&gt;prepend-rules&lt;/code&gt;我设置了固定的IP&lt;code&gt;192.168.0.11&lt;/code&gt;,此为服务器IP地址;因为本地网段和服务器的网段会有冲突,因此手写了规则,如果网段不同则不需要&lt;/p&gt;
&lt;p&gt;配置好后&lt;code&gt;Update&lt;/code&gt;订阅即可看到&lt;code&gt;Proxies&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/clash_easyconnect.png&quot; alt=&quot;easy connect clash proxy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;点击&lt;code&gt;Check&lt;/code&gt;会发现&lt;code&gt;Timeout&lt;/code&gt;,实际不影响&lt;/p&gt;
&lt;p&gt;假如&lt;code&gt;Clash&lt;/code&gt;的配置遇到问题可以看前文&lt;a href=&quot;/2023-01-14-%E4%BD%BF%E7%94%A8clash%E4%BB%A3%E7%90%86SSR%E7%9A%84%E5%86%85%E7%BD%91%E8%AF%B7%E6%B1%82/&quot;&gt;使用clash代理SSR的内网请求&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;配置&lt;code&gt;Xshell&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;ssh&lt;/code&gt;的连接及正式服务器的服务连接使用&lt;code&gt;xshell&lt;/code&gt;的功能&lt;/p&gt;
&lt;h5&gt;ssh连接服务器&lt;/h5&gt;
&lt;p&gt;假如&lt;code&gt;xshell&lt;/code&gt;直连正式的服务器没问题可以跳过;我这里因为网段冲突及服务器本身是通过&lt;code&gt;Clash&lt;/code&gt;连接的,因此需要额外配置&lt;/p&gt;
&lt;p&gt;打开配置好的&lt;code&gt;xshell&lt;/code&gt;的&lt;code&gt;Session&lt;/code&gt;配置,右键&lt;code&gt;Properties(属性)&lt;/code&gt;→&lt;code&gt;Proxy(代理)&lt;/code&gt;→&lt;code&gt;Browse(浏览)&lt;/code&gt;新增一个&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/xshell_add_proxy.png&quot; alt=&quot;add proxy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Type(类型)&lt;/code&gt;选&lt;code&gt;Sockes5&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Host&lt;/code&gt;为&lt;a href=&quot;https://github.com/docker-easyconnect/docker-easyconnect&quot;&gt;docker-easyconnect&lt;/a&gt;服务(A1)的地址&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ssh&lt;/code&gt;连接成功后可以在&lt;code&gt;SSH Channel List(隧道窗格)&lt;/code&gt;中看到连接状态&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/xshell_ssh_channel_list.png&quot; alt=&quot;ssh channel list&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SSH Channel List&lt;/code&gt;可以通过在底部快速命令处右键打开&lt;/p&gt;
&lt;h5&gt;使用ssh tunnel创建 Outgoing转移规则&lt;/h5&gt;
&lt;p&gt;转移规则介绍可查看:&lt;a href=&quot;https://www.xshellcn.com/zhishi/local-zhuanyi.html&quot;&gt;Xshell本地转移规则讲解&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;此设置的目的是将服务器的端口映射到本地,比如将服务器B上面&lt;code&gt;5432&lt;/code&gt;端口的&lt;code&gt;pgsql&lt;/code&gt;服务映射到本地&lt;code&gt;5234&lt;/code&gt;,这样可以直接用&lt;code&gt;DataGrip&lt;/code&gt;等数据库工具设置&lt;code&gt;localhost:5234&lt;/code&gt;直连正式数据库&lt;/p&gt;
&lt;p&gt;将上面的创建的&lt;code&gt;SSH&lt;/code&gt; &lt;code&gt;Session&lt;/code&gt;复制并打开&lt;code&gt;Properties(属性)&lt;/code&gt;→&lt;code&gt;SSH&lt;/code&gt;→&lt;code&gt;Tunneling(隧道)&lt;/code&gt;新增一个&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/xshell_ssh_tunnel_pgsql.png&quot; alt=&quot;xshell ssh tunnel&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Type(类型)&lt;/code&gt;选择&lt;code&gt;Local(Outgoing)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Sourse Host(源主机)&lt;/code&gt;填&lt;code&gt;localhost&lt;/code&gt; 端口 &lt;code&gt;5234&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Destination Host(目标主机)&lt;/code&gt;填正式上需要访问的服务IP和端口&lt;/p&gt;
&lt;p&gt;创建完开启&lt;code&gt;Session&lt;/code&gt;连上服务器后可以看到&lt;code&gt;Forwarding Rules(转移规则)&lt;/code&gt;的状态为&lt;code&gt;Open&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/xshell_ssh_tunnel_forwarding_rules.png&quot; alt=&quot;xshell forwarding rules&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SSH Channel List&lt;/code&gt;可以通过在底部快速命令处右键打开&lt;/p&gt;
&lt;h5&gt;vnc登录&lt;/h5&gt;
&lt;p&gt;要代理&lt;code&gt;VNC&lt;/code&gt;连接,只需参照&lt;code&gt;ssh&lt;/code&gt;规则重新创建一个&lt;code&gt;192.168.1.101:5901&lt;/code&gt;的转发规则即可&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/xshell_vnc_tunnel.png&quot; alt=&quot;xshell vnc forwarding&quot; /&gt;&lt;/p&gt;
&lt;p&gt;此规则会将&lt;code&gt;easyconnect&lt;/code&gt;服务器(&lt;code&gt;192.168.1.101&lt;/code&gt;)上的&lt;code&gt;5901&lt;/code&gt;端口映射到本地&lt;code&gt;5901&lt;/code&gt;端口&lt;/p&gt;
&lt;p&gt;此时使用&lt;code&gt;vnc&lt;/code&gt;客户端连接&lt;code&gt;localhost:5901&lt;/code&gt;密码&lt;code&gt;password&lt;/code&gt;即可&lt;/p&gt;
&lt;p&gt;非&lt;code&gt;127.0.0.1&lt;/code&gt;连接正式环境毕竟还是比较危险,所以我只在每次使用的时候开启&lt;a href=&quot;https://github.com/docker-easyconnect/docker-easyconnect&quot;&gt;docker-easyconnect&lt;/a&gt;服务,使用完毕立即停止&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/docker-easyconnect/docker-easyconnect&quot;&gt;docker-easyconnect&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/389894063&quot;&gt;用docker封印EasyConnect并连接远程桌面和数据库 - Jortana的文章 - 知乎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.aliyun.com/article/1035160&quot;&gt;ssh端口转发(跳板机)详解&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.xshellcn.com/zhishi/local-zhuanyi.html&quot;&gt;Xshell本地转移规则讲解&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://johnliu55.tw/ssh-tunnel.html&quot;&gt;SSH Tunneling (Port Forwarding) 详解&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>homeassistant自定义微信消息通知</title><link>https://blog.wangshuai.app/2025-01-02-homeassistant%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BE%AE%E4%BF%A1%E6%B6%88%E6%81%AF%E9%80%9A%E7%9F%A5/</link><guid isPermaLink="true">https://blog.wangshuai.app/2025-01-02-homeassistant%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BE%AE%E4%BF%A1%E6%B6%88%E6%81%AF%E9%80%9A%E7%9F%A5/</guid><pubDate>Thu, 02 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;随着小米开源了它的&lt;code&gt;Home Assistant&lt;/code&gt;仓库:&lt;a href=&quot;https://github.com/XiaoMi/ha_xiaomi_home&quot;&gt;ha_xiaomi_home&lt;/a&gt; 最近有了捣鼓HA的想法&lt;/p&gt;
&lt;p&gt;安装完成后(安装方法可见:&lt;a href=&quot;/2025-01-08-homeassistant%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%8AHACS%E7%9A%84%E5%AE%89%E8%A3%85/&quot;&gt;homeassistant初始化及HACS的安装&lt;/a&gt;)首先想到的是给自己的手机发送一个通知.&lt;/p&gt;
&lt;p&gt;搜索后发现这个插件:&lt;a href=&quot;https://github.com/nesror/ha-wework_notify&quot;&gt;ha-wework_notify&lt;/a&gt;,但是企业微信现在发送通知需要可信固定IP,于是想到折衷的企业微信机器人的办法:&lt;a href=&quot;https://developer.work.weixin.qq.com/document/path/91770&quot;&gt;企业微信群机器人配置说明&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;而HA原生支持&lt;a href=&quot;https://www.home-assistant.io/integrations/notify.rest/&quot;&gt;rest&lt;/a&gt;请求,但是官方没有给出足够的&lt;code&gt;sample&lt;/code&gt;,这里给出我捣鼓两天总结的&lt;code&gt;POST&lt;/code&gt;带参数的请求方法&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;直接给出&lt;code&gt;POST&lt;/code&gt;请求&lt;code&gt;configuration.yaml&lt;/code&gt;配置:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;notify:
  - platform: rest
    name: wepush
    resource: &quot;https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx&quot;
    method: POST_JSON
    data:
      msgtype: &quot;text&quot;
      text:
        content: &quot;{{message}}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改完成后重启HA服务(首次添加时需完整重启服务器而非&lt;code&gt;yaml&lt;/code&gt;配置),在&lt;a href=&quot;http://homeassistant.local:8123/developer-tools/action&quot;&gt;&lt;code&gt;开发者工具→动作&lt;/code&gt;&lt;/a&gt;中选中&lt;code&gt;通知: Send a notification with wepush&lt;/code&gt;输入&lt;code&gt;message&lt;/code&gt;即可测试&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/ha_test_notify.png&quot; alt=&quot;test notify&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里给出我的 图示说明&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/ha_rest_desc.png&quot; alt=&quot;rest description&quot; /&gt;&lt;/p&gt;
&lt;p&gt;意思是HA会自动将&lt;code&gt;data&lt;/code&gt;数据传递给下一个&lt;code&gt;action&lt;/code&gt;,且这个对象会在&lt;code&gt;method: POST_JSON&lt;/code&gt;时自动转为json ,通过模板&lt;code&gt;{{varname}}&lt;/code&gt;可以取到上一个&lt;code&gt;action&lt;/code&gt;传过来的参数&lt;/p&gt;
</content:encoded></item><item><title>使用docker加速阿里云ECS下载</title><link>https://blog.wangshuai.app/2023-06-16-%E9%98%BF%E9%87%8C%E4%BA%91ECS%E4%B8%8B%E8%BD%BD%E5%8A%A0%E9%80%9F/</link><guid isPermaLink="true">https://blog.wangshuai.app/2023-06-16-%E9%98%BF%E9%87%8C%E4%BA%91ECS%E4%B8%8B%E8%BD%BD%E5%8A%A0%E9%80%9F/</guid><pubDate>Fri, 16 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;公司正式服务器在阿里云上,为节省成本;公司购买的是1M小水管.运行服务跑跑网站的时候倒也够用;一旦遇到从服务器下载大文件的需求时就捉急了.&lt;/p&gt;
&lt;p&gt;最近服务器上内存占用异常,为分析内存占用原因;需要将dump文件下载下载本地分析.一个dump有6G大,就算压缩后也有500M;&lt;/p&gt;
&lt;p&gt;粗算一下也要1H,实际服务器有其它网络请求的情况下我花3小时才下载下来.&lt;/p&gt;
&lt;p&gt;那有什么下载加速的方法吗?&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;网络传输受限公网带宽,除了加钱没什么直接方案;不过阿里云内网里面没有网络限制,只要我们找到一种可以内网上传+外网下载不限速的服务就可以了,要是还免费就更佳.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件传输最优方案应该是阿里云盘,毕竟是阿里的云盘;可惜我不知道阿里云盘的内网地址,此方案PASS.&lt;/li&gt;
&lt;li&gt;还有一种可靠方案,就是对象存储OSS(&lt;a href=&quot;https://help.aliyun.com/document_detail/39584.html&quot;&gt;ECS实例通过OSS内网地址访问OSS资源&lt;/a&gt;);临时上传下载要不了多少钱,不过我没有开通此服务,因此此方案优先级较低&lt;/li&gt;
&lt;li&gt;阿里云还提供有免费的镜像仓库服务,同时它提供内网地址;只要你在内网有linux服务器;通过服务器&lt;code&gt;docker build push&lt;/code&gt;本地&lt;code&gt;docker pull&lt;/code&gt;就可以间接将文件传回本地&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;操作步骤&lt;/h4&gt;
&lt;p&gt;首先在阿里云中开通&lt;a href=&quot;https://cr.console.aliyun.com/cn-hangzhou/instance/dashboard&quot;&gt;容器镜像服务&lt;/a&gt;,创建命名空间和镜像仓库;在&lt;a href=&quot;https://cr.console.aliyun.com/cn-hangzhou/instance/credentials&quot;&gt;访问凭证&lt;/a&gt;中设置固定密码用于账号登录;在基本信息中可查看操作指南;据此可以编写上传下载的命令.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;阿里云内网linux服务器用于文件上传.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里我写出我用的命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#先cd到空目录并将文件拷贝到这里
#info.log是要上传的文件
echo -e &apos;FROM hello-world\n COPY info.log /info.log \n CMD [&quot;hello&quot;] &apos; &amp;gt; Dockerfile

docker build -t upload .

#根据你的操作指南选择合适的内网镜像仓库地址
docker login --username=xxxx@yy.com registry-vpc.cn-hangzhou.aliyuncs.com

#zzzz是命名空间,download是我创建的用于文件传输的仓库名称
docker tag upload registry-vpc.cn-hangzhou.aliyuncs.com/zzzz/download
docker push registry-vpc.cn-hangzhou.aliyuncs.com/zzzz/download
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;本地使用&lt;code&gt;docker cp&lt;/code&gt;命令将文件拷到本地,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里贴出我用的powershell命令(windows)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#docker login xxxxx

#linux
id=$(docker create registry.cn-hangzhou.aliyuncs.com/zzzz/download)

docker cp $id:dump.tar.gz - &amp;gt; dump.tar.gz
docker rm -v $id

#windows
$container= &apos;registry.cn-hangzhou.aliyuncs.com/zzzz/download&apos;
docker pull $container
$id=$(docker create $container)
$fileName= &apos;info.log&apos;

$cp_arguments = @(&quot;cp&quot;,                                               `
                  &quot;$($id):$($fileName)&quot;,  `
                  &quot;D:\Work\docker\${fileName}&quot;)
docker $cp_arguments
docker rm -v $id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用docker传输确实略显麻烦,不过临时用用肯定比等三个小时强;毕竟服务器不是每天都需要dump.&lt;/p&gt;
&lt;p&gt;同理,腾讯云或者其它的只要提供免费docker服务的一般都可以用此方法.&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/62053469/docker-cp-parameter-expansion-in-powershell&quot;&gt;Docker cp parameter expansion in powershell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>浙里办真机调试方法,解决跳转地址不在白名单中问题</title><link>https://blog.wangshuai.app/2023-01-22-%E6%B5%99%E9%87%8C%E5%8A%9E%E7%9C%9F%E6%9C%BA%E8%B0%83%E8%AF%95%E6%96%B9%E6%B3%95/</link><guid isPermaLink="true">https://blog.wangshuai.app/2023-01-22-%E6%B5%99%E9%87%8C%E5%8A%9E%E7%9C%9F%E6%9C%BA%E8%B0%83%E8%AF%95%E6%96%B9%E6%B3%95/</guid><pubDate>Sun, 22 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;最近做的浙里办H5应用里面遇到一个文件上传的问题,这是一个偶发性问题;因此需要大量上传测试&lt;/p&gt;
&lt;p&gt;而浙里办的开发工具&lt;code&gt;ZWEurope&lt;/code&gt;在绑定安卓设备时选不了文件,要想测试bug就需要发布后真机测试&lt;/p&gt;
&lt;p&gt;要是能有一个本地真机调试的方法,不就完美了吗?&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;从&lt;code&gt;ZWEurope&lt;/code&gt;里面就能知道浙里办为我们提供了基本的认证方法 ,除此之外和普通的H5应用并无区别&lt;/p&gt;
&lt;p&gt;通过扫描发布二维码,我们可以直接在浙里办APP上查看不同的发布内容;而直接打开二维码链接可以看到它就是普通的H5网站;因此我大胆尝试,用手机APP直接扫描本地&lt;code&gt;npm run serve&lt;/code&gt;网址二维码(在chrome中可以直接点击网址后面的分享箭头选择&lt;code&gt;创建二维码&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;APP提示&lt;code&gt;网页无法打开&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这也正常,因为手机并不能访问PC的localhost的网站&lt;/p&gt;
&lt;p&gt;重新扫描192.158.1.xx:8080(局域网访问网址)的网址,会发现浙里办无响应;这里使用&lt;code&gt;ZWEurope&lt;/code&gt;重试可以知道是因为&lt;code&gt;localhost:8080&lt;/code&gt;无法访问导致的;修改&lt;code&gt;redirectUrl=http://localhost:8080&lt;/code&gt;为&lt;code&gt;redirectUrl=http://192.168.1.xx:8080&lt;/code&gt;重试&lt;/p&gt;
&lt;p&gt;结果APP提示&lt;code&gt;跳转地址不在白名单中!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这就比较难办了,因为这个白名单是不归我们管的;后台并没有配置方法&lt;/p&gt;
&lt;p&gt;除非可以有代理手机localhost的方法&lt;/p&gt;
&lt;p&gt;通过前文&lt;a href=&quot;../2023-01-20-%E8%BF%9C%E7%A8%8B%E6%97%A0%E7%BA%BF%E8%B0%83%E8%AF%95%E5%AE%89%E5%8D%93%E6%89%8B%E6%9C%BA(mi9)%E7%9A%84chrome%E6%B5%8F%E8%A7%88%E5%99%A8&quot;&gt;远程无线调试安卓手机(mi9)的chrome浏览器&lt;/a&gt;可知&lt;code&gt;google&lt;/code&gt;为我们提供了强大的手机--PC联调机制;&lt;/p&gt;
&lt;p&gt;其实它还有一个功能,就是端口转发(&lt;code&gt;Port forwarding&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/chrome_inspect_devices_forwarding.png&quot; alt=&quot;port forwarding&quot; /&gt;&lt;/p&gt;
&lt;p&gt;开启此功能后即可在手机上通过&lt;code&gt;loclahost:8080&lt;/code&gt;访问PC的&lt;code&gt;localhost:8080&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;所以真机调试浙里办的方法就是:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;npm run&lt;/code&gt;之后 确保可以通过&lt;code&gt;ZWEurope&lt;/code&gt;本地访问待调试应用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;手机开启&lt;code&gt;USB调试&lt;/code&gt;(&lt;code&gt;无线调试&lt;/code&gt;)并与PC连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;配置手机到PC的端口转发(二选一)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用&lt;code&gt;adb&lt;/code&gt;命令直接转发(推荐)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;adb reverse tcp:8080 tcp:8080&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用chrome的&lt;code&gt;Port forwarding&lt;/code&gt;转发&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;chrome://inspect/#devices&lt;/code&gt;中开启&lt;code&gt;Port forwarding&lt;/code&gt;并配置待调试应用端口转发&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PC打开&lt;code&gt;npm run&lt;/code&gt;的服务(如:&lt;code&gt;localhost:8080&lt;/code&gt;),选择&lt;code&gt;分享&lt;/code&gt;→&lt;code&gt;创建二维码&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打开浙里办APP扫描二维码&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样操作后并不能如&lt;code&gt;ZWEurope&lt;/code&gt;一样在手机上触发代码中的断点;因为浙里办APP并未启用调试功能;只能通过&lt;code&gt;log&lt;/code&gt;确认问题;唯一的好处是可以即时查看代码效果,避免发布再测试的流程&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[&lt;a href=&quot;https://stackoverflow.com/questions/4779963/how-can-i-access-my-localhost-from-my-android-device&quot;&gt;How can I access my localhost from my Android device?&lt;/a&gt;](https://stackoverflow.com/a/46795769/7960551)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>远程无线调试安卓手机(mi9)的chrome浏览器</title><link>https://blog.wangshuai.app/2023-01-20-%E8%BF%9C%E7%A8%8B%E6%97%A0%E7%BA%BF%E8%B0%83%E8%AF%95%E5%AE%89%E5%8D%93%E6%89%8B%E6%9C%BA(mi9)%E7%9A%84chrome%E6%B5%8F%E8%A7%88%E5%99%A8/</link><guid isPermaLink="true">https://blog.wangshuai.app/2023-01-20-%E8%BF%9C%E7%A8%8B%E6%97%A0%E7%BA%BF%E8%B0%83%E8%AF%95%E5%AE%89%E5%8D%93%E6%89%8B%E6%9C%BA(mi9)%E7%9A%84chrome%E6%B5%8F%E8%A7%88%E5%99%A8/</guid><pubDate>Fri, 20 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;最近使用&lt;a href=&quot;http://zh.uniapp.dcloud.io/&quot;&gt;uni-app&lt;/a&gt;创建了一个H5项目;里面使用了自带的video播放&lt;code&gt;m3u8&lt;/code&gt;格式的直播视频;由于播放器的限制PC上没有对应解码器,因此只能在手机上看到视频播放效果;这就给debug调试带来了很大的不便.&lt;/p&gt;
&lt;p&gt;既然电脑上可以debug调试,手机同为chrome浏览器难道没有对应的调试方法吗?&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;答案当然是肯定的,chrome为我们提供了远程调试方法(&lt;a href=&quot;https://developer.chrome.com/docs/devtools/remote-debugging/&quot;&gt;Remote debug Android devices&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;我在公司没有USB数据线,因此决定采用无线调试的方法,若你可以有线连接PC则可以跳过这部分&lt;/p&gt;
&lt;h4&gt;无线调试&lt;/h4&gt;
&lt;p&gt;我手机的系统是&lt;code&gt;MIUI 12.5.6&lt;/code&gt; 是&lt;code&gt;Android 11&lt;/code&gt;的版本&lt;/p&gt;
&lt;p&gt;无线调试的方法就是首先使用&lt;code&gt;adb&lt;/code&gt;工具和手机建立连接,然后再调试&lt;/p&gt;
&lt;p&gt;因为我不做安卓开发,没有&lt;a href=&quot;https://developer.android.com/studio?hl=zh-cn&quot;&gt;Android Studio&lt;/a&gt;,因此需要下载&lt;code&gt;adb&lt;/code&gt;命令行工具:&lt;a href=&quot;https://developer.android.com/studio/releases/platform-tools?hl=zh-cn&quot;&gt;SDK 平台工具版本说明&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;下载解压后将解压目录添加到环境变量中;&lt;/p&gt;
&lt;p&gt;手机打开&lt;code&gt;设置&lt;/code&gt;→&lt;code&gt;更多设置&lt;/code&gt;→&lt;code&gt;开发者选项&lt;/code&gt;→&lt;code&gt;无线调试&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;手机在&lt;code&gt;无线调试&lt;/code&gt;中点击&lt;code&gt;使用配对码配对设备&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/android_wifi_paire.png&quot; alt=&quot;adb pair&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PC根据手机的IP 端口 和配对码 输入命令配对&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;命令为&lt;code&gt;adb pair 192.168.1.12:42213&lt;/code&gt;根据提示输入配对码&lt;code&gt;633060&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PC输入手机的IP地址和端口与之建立连接&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;命令为&lt;code&gt;adb connect 192.168.1.12:39715&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PC输入&lt;code&gt;adb devices&lt;/code&gt;查看设备连接状态&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/android_adb_command.png&quot; alt=&quot;adb command&quot; /&gt;&lt;/p&gt;
&lt;p&gt;连接成功后手机将会显示:&lt;code&gt;已连接到无线调试&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;USB调试&lt;/h4&gt;
&lt;p&gt;有线连接手机后打开&lt;code&gt;设置&lt;/code&gt;→&lt;code&gt;更多设置&lt;/code&gt;→&lt;code&gt;开发者选项&lt;/code&gt;→&lt;code&gt;USB调试&lt;/code&gt;即可&lt;/p&gt;
&lt;h4&gt;远程调试&lt;/h4&gt;
&lt;p&gt;手机&lt;code&gt;Chrome&lt;/code&gt;打开任意网页&lt;/p&gt;
&lt;p&gt;PC在Chrome中打开&lt;code&gt;chrome://inspect/#devices&lt;/code&gt;将可以看到手机中打开的网页&lt;/p&gt;
&lt;p&gt;点击&lt;code&gt;Inspect&lt;/code&gt;即可看到手机端的开发者工具;若开发者工具白屏,则可点击&lt;code&gt;inspect fallback&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/chrome_inspect_devices.png&quot; alt=&quot;inspect devices&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/devtools/remote-debugging/&quot;&gt;Remote debug Android devices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://remysharp.com/2016/12/17/chrome-remote-debugging-over-wifi&quot;&gt;Chrome remote debugging over wifi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Ey4y147Bu/&quot;&gt;MIUI如何无线调试安卓应用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>使用clash代理SSR的内网请求</title><link>https://blog.wangshuai.app/2023-01-14-%E4%BD%BF%E7%94%A8clash%E4%BB%A3%E7%90%86SSR%E7%9A%84%E5%86%85%E7%BD%91%E8%AF%B7%E6%B1%82/</link><guid isPermaLink="true">https://blog.wangshuai.app/2023-01-14-%E4%BD%BF%E7%94%A8clash%E4%BB%A3%E7%90%86SSR%E7%9A%84%E5%86%85%E7%BD%91%E8%AF%B7%E6%B1%82/</guid><pubDate>Sat, 14 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://zh.m.wikipedia.org/zh-hans/Shadowsocks#ShadowsocksR&quot;&gt;SSR&lt;/a&gt;是非常好网络代理协议,通过它我们可以用服务端的网络访问特定资源，我们一般都用它来科学上网；也就是上公网&lt;/p&gt;
&lt;p&gt;但它其实也能访问服务端内网,只是需要做一些设置.&lt;/p&gt;
&lt;h3&gt;解决方案&lt;/h3&gt;
&lt;p&gt;这里我以&lt;code&gt;Clash for Windows&lt;/code&gt;为例介绍连接方法&lt;/p&gt;
&lt;p&gt;SSR服务端可以使用&lt;a href=&quot;https://github.com/winterssy/SSR-Docker&quot;&gt;SSR-Docker&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在安装好服务后本地先使用SSR(ShadowsocksR)连接测试以确定配置无误&lt;/p&gt;
&lt;p&gt;连接成功后可在&lt;code&gt;docker logs&lt;/code&gt;中看到连接请求&lt;/p&gt;
&lt;p&gt;Clash支持SSR的连接方式,只是不能直接导入SSR的节点;&lt;/p&gt;
&lt;p&gt;这里可以使用配置转换工具,如:&lt;a href=&quot;https://acl4ssr-sub.github.io/&quot;&gt;ACL4SSR 在线订阅转换&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;复制配置好的SSR链接(&lt;code&gt;ssr://&lt;/code&gt;)到订阅链接中,点击&lt;code&gt;生成订阅链接&lt;/code&gt;,然后把这个链接导入到&lt;code&gt;Clash&lt;/code&gt;中&lt;/p&gt;
&lt;p&gt;这时候尝试输入服务端内网的一个服务地址,发现无法访问;查看Clash生成的日志(点击Clash左下角的&lt;code&gt;Connected&lt;/code&gt;可以打开日志目录)&lt;/p&gt;
&lt;p&gt;会发现没有触发代理,这是因为默认Clash会忽略本地地址的请求&lt;/p&gt;
&lt;p&gt;因此需要调整几处配置&lt;/p&gt;
&lt;p&gt;订阅导入成功后可以在本地看到yml文件(或者也可以直接在&lt;code&gt;Profiles&lt;/code&gt;中&lt;code&gt;yml&lt;/code&gt;中右键&lt;code&gt;Edit&lt;/code&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1.在&lt;code&gt;rules&lt;/code&gt;中添加需要代理的网段或者IP地址&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;IP-CIDR,192.168.1.1/32,🔰 节点选择&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/clash_local_rules.png&quot; alt=&quot;image-20230115221349239&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;然后在&lt;code&gt;Settings&lt;/code&gt;→&lt;code&gt;System Proxy&lt;/code&gt;→&lt;code&gt;Bypass Domain/IpNet&lt;/code&gt;中移除&lt;code&gt;192.168.*&lt;/code&gt;的配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(或者改成本地的Ip段,因此这里就要求本地的网段和服务的网段不同;这样可以方便配置)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/clash_local_bypass.png&quot; alt=&quot;clash&quot; /&gt;&lt;/p&gt;
&lt;p&gt;调整后就可以访问了.&lt;/p&gt;
&lt;h3&gt;扩展&lt;/h3&gt;
&lt;p&gt;这样配置后切换到对应的&lt;code&gt;Proxy&lt;/code&gt;后当然可以访问服务器的内网,但假如本身有Google的需求每次访问内网的时候还要切换代理;这里可以使用&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Parsers&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在你的&lt;code&gt;Proxy&lt;/code&gt;中右键&lt;code&gt;Parsers&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后输入对应的配置项&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;parsers: # array
  - url: https://xxx.com #Google代理订阅地址 不知道的话可以从配置的Settings中查看
    yaml:
      prepend-rules:
        - IP-CIDR,192.168.1.0/24,🔰 节点选择
        - DOMAIN-SUFFIX,xxx.cn,🔰 节点选择
      append-proxies:
        - {...}#添加的代理配置
      append-proxy-groups:
        - name: 🔰 节点选择
          type: select
          proxies:
            - XX
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后再右键&lt;code&gt;yml&lt;/code&gt;配置选择&lt;code&gt;Update&lt;/code&gt;更新完后可以在&lt;code&gt;yml&lt;/code&gt;配置的&lt;code&gt;Rules&lt;/code&gt;中看到自动修改的配置&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.cfw.lbyczf.com/contents/parser.html&quot;&gt;Clash 配置文件预处理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>任天堂各区最新实时会员价格 任天堂会员最新价格 任天堂会员实时价格</title><link>https://blog.wangshuai.app/2022-09-21-%E4%BB%BB%E5%A4%A9%E5%A0%82%E5%90%84%E5%8C%BA%E6%9C%80%E6%96%B0%E5%AE%9E%E6%97%B6%E4%BC%9A%E5%91%98%E4%BB%B7%E6%A0%BC/</link><guid isPermaLink="true">https://blog.wangshuai.app/2022-09-21-%E4%BB%BB%E5%A4%A9%E5%A0%82%E5%90%84%E5%8C%BA%E6%9C%80%E6%96%B0%E5%AE%9E%E6%97%B6%E4%BC%9A%E5%91%98%E4%BB%B7%E6%A0%BC/</guid><pubDate>Wed, 21 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;最近打算开通任天堂在线会员，但是找了一圈互联网却并没有那么一个汇总各区价格的地方；于是花两个月时间做了这样一个任天堂会员价格表。&lt;/p&gt;
&lt;p&gt;已知任天堂会员可以全区通用，所以找到一个最便宜的区开通在线会员是一个省钱的方法。&lt;/p&gt;
&lt;p&gt;下面汇总了已知的常用区的会员价格，原价和汇率每日更新。&lt;/p&gt;
&lt;h3&gt;实时价格(点击后可查看原价)&lt;a href=&quot;https://nsonlineprice.wangshuai.app/&quot;&gt;点击查看&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;640&quot; height=&quot;450&quot; src=&quot;https://nsonlineprice.wangshuai.app/#/home&quot; border=&quot;0&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; &lt;strong&gt;idm_id&lt;/strong&gt;=&quot;2465793&quot; style=&quot;
width: 100%;frameborder=&quot;no&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>无需VPS,使用重新打tag的方式 拉取、转存mcr.microsoft.com的镜像</title><link>https://blog.wangshuai.app/2020-01-17-%E6%97%A0%E9%9C%80VPS%EF%BC%8C%E4%BD%BF%E7%94%A8%E9%87%8D%E6%96%B0%E6%89%93tag%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E6%8B%89%E5%8F%96%E3%80%81%E8%BD%AC%E5%AD%98mcr.microsoft.com%E7%9A%84%E9%95%9C%E5%83%8F/</link><guid isPermaLink="true">https://blog.wangshuai.app/2020-01-17-%E6%97%A0%E9%9C%80VPS%EF%BC%8C%E4%BD%BF%E7%94%A8%E9%87%8D%E6%96%B0%E6%89%93tag%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E6%8B%89%E5%8F%96%E3%80%81%E8%BD%AC%E5%AD%98mcr.microsoft.com%E7%9A%84%E9%95%9C%E5%83%8F/</guid><pubDate>Fri, 17 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;hr /&gt;
&lt;p&gt;根据此文档:&lt;a href=&quot;https://github.com/microsoft/containerregistry/blob/main/docs/mcr-endpoints-guidance.md&quot;&gt;docs/mcr-endpoints-guidance.md&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Performance Impact on Azure CDN Endpoint in Azure China Starting November 27, 2025&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;现在可以使用&lt;code&gt;mcr.azure.cn&lt;/code&gt;这个域名在国内拉取镜像&lt;/p&gt;
&lt;p&gt;比如:&lt;code&gt;docker pull mcr.azure.cn/dotnet/aspnet&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;因此本文现在仅做参考;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;引言&lt;/h2&gt;
&lt;p&gt;用&lt;code&gt;docker&lt;/code&gt;的都知道镜像加速，通过配置阿里云、腾讯云的镜像源确实可以大幅提升&lt;code&gt;docker pull&lt;/code&gt;的效果，但对于某些不常用或新版的镜像却收效甚微。&lt;/p&gt;
&lt;p&gt;比如最近想要部署私有ExceptionLess服务，它的dockerfile使用了&lt;code&gt;mcr.microsoft.com/dotnet/core/sdk:2.2.401&lt;/code&gt;和&lt;code&gt;mcr.microsoft.com/dotnet/core/aspnet:2.2&lt;/code&gt;，这两个镜像拉取非常慢，只能使用手动&lt;code&gt;tag&lt;/code&gt;的方式来解决。&lt;/p&gt;
&lt;p&gt;另外，本人在腾讯云中创建了&lt;code&gt;dotnet-core&lt;/code&gt;命名空间，源自&lt;code&gt;mcr.microsoft.com&lt;/code&gt;可直接使用&lt;code&gt;ccr.ccs.tencentyun.com/dotnet-core/runtime&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/tencenyun_aspnet_core_repository.png&quot; alt=&quot;image-20200415142923048&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;解决办法&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;2020-04-15更新&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原标题为：&lt;em&gt;使用travis-ci的Trigger build功能一键转存&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;但是本人多次实测，&lt;code&gt;travis-ci&lt;/code&gt;的&lt;code&gt;Build&lt;/code&gt;带宽限制严重，如果你要Retag &lt;code&gt;Runtime&lt;/code&gt;还好，设置&lt;code&gt;travis_wait 30&lt;/code&gt;基本也能用；但是如果是SDK，基本都会超时&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Still running (50 of 300): sudo docker push ccr.ccs.tencentyun.com/dotnet-core/sdk:5.0
The job exceeded the maximum time limit for jobs, and has been terminated.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此改用&lt;code&gt;Azure Devops&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;2020-3-9&lt;/strong&gt;更新:&lt;/p&gt;
&lt;h3&gt;&lt;s&gt;使用Azure官方镜像mirror&lt;/s&gt;&lt;/h3&gt;
&lt;p&gt;&lt;s&gt;根据此issue:&lt;a href=&quot;https://github.com/Azure/container-service-for-azure-china/issues/52&quot;&gt;dockerhub.azk8s.cn how to get the multiple path image&lt;/a&gt;，可使用&lt;code&gt;mcr.azk8s.cn&lt;/code&gt;仓库替换&lt;code&gt;mcr.microsoft.com&lt;/code&gt;，即，将&lt;code&gt;mcr.microsoft.com/dotnet/core/aspnet:2.2&lt;/code&gt;替换为&lt;code&gt;mcr.azk8s.cn/dotnet/core/aspnet:2.2&lt;/code&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;此方案只能在Azure中使用。。。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;手动Tag&lt;/h3&gt;
&lt;p&gt;如果你有一台国外的VPS，那很简单；只需执行&lt;code&gt;docker pull&lt;/code&gt;、&lt;code&gt;docker login&lt;/code&gt;、&lt;code&gt;docker tag&lt;/code&gt;、&lt;code&gt;docker push&lt;/code&gt;就OK了。无奈我的VPS到期了，只能另寻它法，google之后从这篇文章找到灵感：&lt;a href=&quot;https://www.zhoujiangang.com/p/fetch-google-image-use-tag/&quot;&gt;使用重新打 tag 的方式，拉取 k8s.gcr.io 的镜像&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;使用Azure Devops&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;首先，去腾讯云中创建保存&lt;code&gt;image&lt;/code&gt;的仓库
&lt;img src=&quot;/img/qcloud_images_list.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;参考&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&amp;amp;tabs=yaml#create-a-service-connection&quot;&gt;create-a-service-connection&lt;/a&gt;，在project→project settings →Service connections →New ervice connection中新建一个名为&lt;code&gt;tencentyun&lt;/code&gt;的&lt;code&gt;Docker Registry&lt;/code&gt;，其中&lt;code&gt;Docker Registry&lt;/code&gt;地址为：https://ccr.ccs.tencentyun.com/v2/，用户名和密码请查看腾讯云的镜像使用指引&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/AzureDevops_createTencentyun_DockerRegistry.png&quot; alt=&quot;image-20200415111820887&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在你项目里面的&lt;code&gt;Piplines&lt;/code&gt;中新建一个连接到Github仓库的yml，创建模板随便选&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/AzureDevops_CreatePipline_yml.png&quot; alt=&quot;image-20200415135902763&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最后把Review中的yml文件替换成如下：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;trigger:
- master

pool:
  vmImage: &apos;ubuntu-latest&apos;

variables:
  tag: &apos;aspnet:5.0&apos;

steps:
- task: Docker@2
  inputs:
    containerRegistry: &apos;tencentyun&apos;
    command: &apos;login&apos;
- task: PowerShell@2
  inputs:
    targetType: &apos;inline&apos;
    script: |
      $env:version=&quot;$(tag)&quot;
      
      docker pull mcr.microsoft.com/dotnet/core/$env:version
      
      docker tag mcr.microsoft.com/dotnet/core/$env:version ccr.ccs.tencentyun.com/dotnet-core/$env:version
      docker push ccr.ccs.tencentyun.com/dotnet-core/$env:version
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;然后点击&lt;code&gt;Save and run&lt;/code&gt;(或者也可以在自己的仓库中创建一个上述的&lt;code&gt;azure-pipelines.yml&lt;/code&gt;文件,在Azure Devops中连接好后提交)就可以了&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;s&gt;使用travis-ci自动Tag&lt;/s&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;travis-ci&lt;/code&gt;的&lt;code&gt;Build&lt;/code&gt;带宽限制严重，已改用Azure Devops，以下步骤仅作参考&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;使用第三方的CI、CD服务&lt;code&gt;push&lt;/code&gt;镜像到国内私有仓库中解决&lt;code&gt;docker pull&lt;/code&gt;过慢的问题，本例的CI-CD使用的是&lt;a href=&quot;https://travis-ci.com/&quot;&gt;travis-ci&lt;/a&gt;，由于自己使用了腾讯云的容器服务，因此私有库使用了腾讯云提供的免费镜像仓库。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先，去腾讯云中创建保存&lt;code&gt;image&lt;/code&gt;的仓库
&lt;img src=&quot;/img/qcloud_images_list.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/li&gt;
&lt;li&gt;其次，访问&lt;a href=&quot;https://travis-ci.com/&quot;&gt;travis-ci&lt;/a&gt;，并授权其对自己git库的访问权限(&lt;strong&gt;随便什么仓库都行，因为我们并不需要使用里面的代码&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;参照腾讯云提供的镜像使用指引，编写&lt;code&gt;.travis.yml&lt;/code&gt;脚本文件
&lt;img src=&quot;/img/qcloud_images_guid.png&quot; alt=&quot;image.png&quot; /&gt;
我的脚本文件如下：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;language: bash
env:
  - version=sdk:2.2
services:
  - docker
sudo: required
branches:
  only:
    - master
script:
  - echo &quot;$DOCKER_PASSWORD&quot; | docker login -u &quot;$DOCKER_USERNAME&quot; --password-stdin ccr.ccs.tencentyun.com
  - docker pull mcr.microsoft.com/dotnet/core/$version

after_success:
  - sudo docker tag mcr.microsoft.com/dotnet/core/$version ccr.ccs.tencentyun.com/dotnet-core/$version
  - sudo docker push ccr.ccs.tencentyun.com/dotnet-core/$version
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;a href=&quot;https://travis-ci.com/&quot;&gt;travis-ci&lt;/a&gt;的首页上，任意选择一个仓库，然后在&lt;code&gt;More Options&lt;/code&gt;→&lt;code&gt;Settings&lt;/code&gt;里面添加docker登陆的用户名密码环境变量&lt;code&gt;DOCKER_USERNAME&lt;/code&gt;和&lt;code&gt;DOCKER_PASSWORD&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/img/travis-ci_setEnv.png&quot; alt=&quot;image-20200410113527361&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;More Options&lt;/code&gt;→&lt;code&gt;Trigger build&lt;/code&gt;的&lt;code&gt;CUSTOM CONFIG&lt;/code&gt;中粘贴写好的&lt;code&gt;.travis.yml&lt;/code&gt;脚本并点击&lt;code&gt;Trigger custom build&lt;/code&gt;
&lt;img src=&quot;/img/travis-ci_Trigger_Custom_Build.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;稍等几分钟即可在&lt;code&gt;job log&lt;/code&gt;中看到脚本的执行结果&lt;/s&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里并不会立即出结果，图示是因为images已经存在于&lt;code&gt;ccr.ccs.tencentyun.com&lt;/code&gt;中了，所以给人以速度很快的假象&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/img/travis-ci_wait_job_result.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;参考链接&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/containers/push-image?view=azure-devops&quot;&gt;push-image&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/build-stages/share-docker-image/&quot;&gt;share-docker-image&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/docker/&quot;&gt;docker&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item></channel></rss>