<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Hao_Tian的折腾日志</title>
  
  <subtitle>Hao_Tian的博客(｡･∀･)ﾉﾞ嗨</subtitle>
  <link href="https://haotian22.top/atom.xml" rel="self"/>
  
  <link href="https://haotian22.top/"/>
  <updated>2026-01-17T07:55:47.563Z</updated>
  <id>https://haotian22.top/</id>
  
  <author>
    <name>Hao_Tian</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>使用Tileserver-GL+MapLiberGL+OSM创建自己的地图</title>
    <link href="https://haotian22.top/bddb0203.html"/>
    <id>https://haotian22.top/bddb0203.html</id>
    <published>2026-01-16T03:11:55.000Z</published>
    <updated>2026-01-17T07:55:47.563Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>近期，突发奇想，因为学校的地图并不太直观，要么细节数据不全，要么操作很难，需要点击多级才可以进入查看<br>因此，决定自己动手创建一份地图，方便日常使用</p><p>最后在询问了 AI 之后，决定使用 Tileserver-GL（后端底图）+ MapLiberGL（前端显示+POI叠加层）+ OSM（数据源） 来创建自己的地图</p><h2 id="部署-Tileserver-GL"><a href="#部署-Tileserver-GL" class="headerlink" title="部署 Tileserver-GL"></a>部署 Tileserver-GL</h2><h3 id="安装-Tileserver-GL"><a href="#安装-Tileserver-GL" class="headerlink" title="安装 Tileserver-GL"></a>安装 Tileserver-GL</h3><p>根据<a href="https://openmaptiles.org/docs/host/tileserver-gl/">官方的教程</a>, 使用 docker 来安装 Tileserver-GL 是最为便捷的</p><p>但是，官方并没有说明后期需要导入数据的时候应该如何操作，我在这里也踩了很多坑</p><p>最后，我根据自己的情况，写了一个 <code>docker-compose.yml</code>文件，内容如下，可以参考一下：</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">tileserver:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">maptiler/tileserver-gl</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;8080:8080&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;/home/u0_a244/TileServer-GL/data:/data&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;/home/u0_a244/TileServer-GL/styles:/styles&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;/home/u0_a244/TileServer-GL/config.json:/config.json&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;/home/u0_a244/TileServer-GL/fonts:/fonts&quot;</span></span><br><span class="line">    <span class="attr">command:</span> [<span class="string">&quot;--config&quot;</span>, <span class="string">&quot;/config.json&quot;</span>]</span><br></pre></td></tr></table></figure><p>其中，ports 部分是将容器的 8080 端口映射到宿主机的 8080 端口<br>volumes 部分是将宿主机的相关目录挂载到容器中</p><p>在我的环境中，&#x2F;home&#x2F;u0_a244&#x2F;TileServer-GL&#x2F; 是我用来存放 Tileserver-GL 相关文件的目录，数据如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">~/TileServer-GL$ tree -L 2</span><br><span class="line">.</span><br><span class="line">├── config.json</span><br><span class="line">├── data</span><br><span class="line">│   └── guangdong.mbtiles</span><br><span class="line">├── docker-compose.yml</span><br><span class="line">├── fonts</span><br><span class="line">│   └── MiSans Semibold</span><br><span class="line">└── styles</span><br><span class="line">    └── osm_liberty.json</span><br></pre></td></tr></table></figure><p>请根据自己的实际情况，修改 <code>docker-compose.yml</code> 中的路径</p><p>至于这些文件是怎么来的，后面会讲到</p><h2 id="修改配置文件"><a href="#修改配置文件" class="headerlink" title="修改配置文件"></a>修改配置文件</h2><p>在前面的 <code>docker-compose.yml</code> 文件中，我挂载了一个 <code>config.json</code> 文件，这个文件就是用来配置 Tileserver-GL 的配置</p><p>相关的文档可以在<a href="https://tileserver.readthedocs.io/en/latest/config.html">官网</a>找到</p><p>我这里使用的配置文件为：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;options&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;paths&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;styles&quot;</span><span class="punctuation">:</span> <span class="string">&quot;styles&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;fonts&quot;</span><span class="punctuation">:</span> <span class="string">&quot;fonts&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;mbtiles&quot;</span><span class="punctuation">:</span> <span class="string">&quot;data&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;domains&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="string">&quot;my-domain:8080&quot;</span></span><br><span class="line">    <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;formatOptions&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;jpeg&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;quality&quot;</span><span class="punctuation">:</span> <span class="number">80</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;webp&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;quality&quot;</span><span class="punctuation">:</span> <span class="number">90</span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;maxScaleFactor&quot;</span><span class="punctuation">:</span> <span class="number">3</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;maxSize&quot;</span><span class="punctuation">:</span> <span class="number">2048</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;pbfAlias&quot;</span><span class="punctuation">:</span> <span class="string">&quot;pbf&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;serveAllFonts&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;serveAllStyles&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;serveStaticMaps&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;allowRemoteMarkerIcons&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;allowInlineMarkerImages&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;staticAttributionText&quot;</span><span class="punctuation">:</span> <span class="string">&quot;© OpenMapTiles  © OpenStreetMaps&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;tileMargin&quot;</span><span class="punctuation">:</span> <span class="number">0</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;styles&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;osm-liberty&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;style&quot;</span><span class="punctuation">:</span> <span class="string">&quot;osm_liberty.json&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;serve_rendered&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;remote&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;style&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://demotiles.maplibre.org/style.json&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;data&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;openmaptiles&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;mbtiles&quot;</span><span class="punctuation">:</span> <span class="string">&quot;guangdong.mbtiles&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>这里重点需要修改的是 <code>domains</code>部分，将 <code>my-domain:8080</code> 修改为你自己的域名或者 IP 地址加端口号，否则无法正常请求，另外根据文档所述，还能在访问的时候达到负载均衡的效果（挂载到服务器用的时候绝对不能写成 localhost）</p><p>此外，<code>mbtiles</code> 部分需要修改为你自己的 mbtiles 文件名（因为我在文件上方已经说明了 <code>mbtiles</code> 是在 <code>data</code> 目录下的，所以就不用再写 <code>data/</code> 了）</p><p><code>styles</code> 部分是用来配置样式文件的，也需要改成自己的样式文件名，后面会讲到如何获取和修改样式文件</p><h2 id="获取-mbtiles-数据"><a href="#获取-mbtiles-数据" class="headerlink" title="获取 mbtiles 数据"></a>获取 mbtiles 数据</h2><p>Tileserver-GL 需要 mbtiles 格式的数据才能运行，获取 mbtiles 数据有很多种方式，这里介绍两种比较常用的方式</p><h3 id="方式一：BBBike-下载"><a href="#方式一：BBBike-下载" class="headerlink" title="方式一：BBBike 下载"></a>方式一：BBBike 下载</h3><p>BBBike 是一个提供地图数据下载的网站，支持多种格式的地图数据下载，包括 mbtiles 格式</p><ol><li>访问 <a href="https://extract.bbbike.org/">BBBike 官网</a></li><li>在地图上选择你需要的区域，可以通过搜索城市名称来快速定位</li><li>选择输出格式为 mbtiles</li><li>提交下载请求，填入邮箱，等待 10 分钟左右处理完成后下载 mbtiles 文件</li></ol><p>这个方式的优点是简单快捷，适合下载小范围的地图数据</p><p>但是因为地图的生成方式不是自己控制的，后续在数据处理和渲染的时候会遇到不少问题</p><p>这部分我会在渲染样式的时候讲到</p><h3 id="方式二：使用-MapTiler-下载"><a href="#方式二：使用-MapTiler-下载" class="headerlink" title="方式二：使用 MapTiler 下载"></a>方式二：使用 MapTiler 下载</h3><p>MapTiler 官方提供了数据下载，可以直接访问 <a href="https://www.maptiler.com/on-prem-datasets/dataset/osm/#0.22/0/0">MapTiler 数据下载页面</a>，选择区域下载即可</p><p>但是它的免费数据下载有一些限制：</p><ul><li>OpenStreetMap Vectors (2020)</li><li>Satellite Low-Res (2016)</li><li>Non-commercial</li></ul><p>反正我是觉得 2020 年的数据有点旧了，而且所以就没有选这个</p><h3 id="方式三：使用-OSM-数据-tilemaker-自己生成-mbtiles"><a href="#方式三：使用-OSM-数据-tilemaker-自己生成-mbtiles" class="headerlink" title="方式三：使用 OSM 数据 + tilemaker 自己生成 mbtiles"></a>方式三：使用 OSM 数据 + tilemaker 自己生成 mbtiles</h3><ol><li>下载 OSM 数据，可以从 <a href="https://download.geofabrik.de/">Geofabrik</a> 下载所需区域的 PBF 文件</li><li>安装 tilemaker，可以参考 <a href="https://github.com/systemed/tilemaker">tilemaker 的 GitHub 页面</a></li></ol><p>其实，如果并不在意程序的最新版本的话，可以直接在GitHub的 Releases 页面下载编译好的二进制文件但是需要注意的是，Windows 下的 v3.0.0 版本是有问题的，Windows用户 建议下载 v2.4.0 版本<br>另外，还需要下载配置文件 <code>config-openmaptiles.json</code> 和处理脚本 <code>process-openmaptiles.lua</code>，可以从该仓库的 <code>resources</code> 目录中获取</p><ol start="3"><li>使用 tilemaker 将 PBF 文件转换为 mbtiles 文件，实例命令如下：</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tilemaker --input <span class="string">&quot;guangdong-260113.osm.pbf&quot;</span>  --output <span class="string">&quot;guangdong.mbtiles&quot;</span> --config .\config-openmaptiles.json --process .\process-openmaptiles.lua</span><br></pre></td></tr></table></figure><p>其中，<code>--input</code> 指定输入的 PBF 文件，<code>--output</code> 指定输出的 mbtiles 文件，<code>--config</code> 和 <code>--process</code> 分别指定配置文件和处理脚本，需要自己替换成实际的文件路径</p><p>如果想裁切数据，可以使用 <code>--bbox</code> 参数，格式为 <code>minLon,minLat,maxLon,maxLat</code>，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tilemaker.exe --input <span class="string">&quot;guangdong-260113.osm.pbf&quot;</span> --bbox 113,22.34,114,22.50 --output <span class="string">&quot;guangdong.mbtiles&quot;</span> --config .\config-openmaptiles.json --process .\process-openmaptiles.lua</span><br></pre></td></tr></table></figure><p>还有值得注意的是，<code>process-openmaptiles.lua</code> 文件开头的几个带 <code>language</code> 的变量需要根据自己后面的 <code>style.json</code> 文件来决定，否则可能会导致某些标签无法显示，我后面会再次提到</p><p>然后打完这个命令之后，等待一段时间（我生成一个学校的大小用时大概为 30s, 使用 i7-12700H CPU，占用 5.5GB 内存），就可以得到一个 mbtiles 文件了</p><p>最后记得将它移动到 Tileserver-GL 的 data 目录下</p><p>但是这个方法也有一定的缺点（相对于 Maptiler 提供的文件来说），因为它经过一次转换，例如 building:part 之类的细节就会被去掉，没法准确的渲染出来 3D 效果</p><center><img src="https://s41.ax1x.com/2026/01/17/pZsWKE9.png" style="width:60%;" alt="tilemaker 生成的数据结果预览"/></center><p>另外，这个图也解释了为什么无法直接从平台 Geojson 变成 Tileserver-GL 样式渲染需要的格式：它是分为右侧那几大类来分类渲染，普通 Geojson 是没分类的，会导致无法识别类型而对应不上样式</p><p>至于有没有方法可以从普通的在 Overpass 上获得的 Geojson 转化为这个分类的格式，再用 osmium-tool 之类的转为 mbtiles呢？或许是有机会的，但是我似乎没有找到，如果有找到的话可以在评论区提一下</p><h3 id="方法四：使用-OpenMapTiles-构建完整数据集"><a href="#方法四：使用-OpenMapTiles-构建完整数据集" class="headerlink" title="方法四：使用 OpenMapTiles 构建完整数据集"></a>方法四：使用 OpenMapTiles 构建完整数据集</h3><p>这个是官方推荐的方法，使用 OpenMapTiles 工具链来生成完整的地图数据集，但是部署的文件相当复杂，会变得非常慢</p><p>可以参考官方 <a href="https://github.com/openmaptiles/openmaptiles">GitHub 仓库</a>的 README 文档来进行操作</p><p>如果需要裁切之前的整个 PBF 为特定区域的数据，可以使用 <a href="https://wiki.openstreetmap.org/wiki/Osmconvert">OSMconvert</a> 来操作，链接里面直接下载二进制文件就行了，然后使用以下命令来裁切数据，经纬度可以使用 <a href="https://boundingbox.klokantech.com/">Bounding Box Tool</a> 来获取</p><p>（这是我在 Windows 下的命令，其他系统请自行参照文档更改）</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.\osmconvert64-0.8.8p.exe .\guangdong-260113.osm.pbf -b=<span class="string">&quot;113.4,22.3,114.5,22.6&quot;</span> -o=<span class="string">&quot;guangdong.osm.pbf&quot;</span></span><br></pre></td></tr></table></figure><p>然后将下载好的 pbf 放进 OpenMapTiles 的 <code>data</code> 目录下，根据文档走一次，就可以生成一个完整的 mbtiles 文件了</p><p>以下内容截取自 GitHub 仓库的 README 文档，有些我标了 optional 的没有需要就可以跳过：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">make clean                  <span class="comment"># clean / remove existing build files</span></span><br><span class="line">make                        <span class="comment"># generate build files</span></span><br><span class="line">make start-db               <span class="comment"># start up the database container.</span></span><br><span class="line">make import-data            <span class="comment"># Import external data from OpenStreetMapData, Natural Earth and OpenStreetMap Lake Labels.</span></span><br><span class="line">make download area=albania  <span class="comment"># download albania .osm.pbf file -- can be skipped if a .osm.pbf file already existing (optional)</span></span><br><span class="line">make import-osm             <span class="comment"># import data into postgres</span></span><br><span class="line">make import-wikidata        <span class="comment"># import Wikidata (optional)</span></span><br><span class="line">make import-sql             <span class="comment"># create / import sql functions </span></span><br><span class="line">make generate-bbox-file     <span class="comment"># compute data bbox -- not needed for the whole planet or for downloaded area by `make download`</span></span><br><span class="line">make generate-tiles-pg      <span class="comment"># generate tiles</span></span><br></pre></td></tr></table></figure><p>实测以我老笔记本 i7-2677M + SSD 的配置，生成一个学校的范围就部署了将近 5 个小时（因为主力机没装 Linux，没法跑 make）<br>主要卡在 SSD 的 I&#x2F;O 写入瓶颈上，因为总共会生成多个 Docker Container，产生大量的写入<br>建议使用高速的 M.2 NVMe SSD 来进行操作</p><p>第二次跑似乎就快点了，0.05 的经度和 0.03 的纬度范围大概跑了 20 分钟，跑出来的文件大小在 500KB 左右</p><p>然后我又试了下我 Azure 的 1 年免费 VPS（2C1G + 64G Premium SSD，开了 2G 的 Swap），跑了就大概 5 分钟，读写平均上到了 70MB&#x2F;s，可以根据自己的硬件情况来预估时间</p><p>另外服务器上部署要注意的是，HDD 的服务器几乎完全不能部署，性能都不太行，跑几分钟还不够我笔记本上跑几秒</p><center><img src="https://s41.ax1x.com/2026/01/17/pZsWEcT.png" style="width:60%;" alt="OpenMapTiles 的数据结果预览"/></center><h2 id="获取-Tileserver-GL-渲染样式文件"><a href="#获取-Tileserver-GL-渲染样式文件" class="headerlink" title="获取 Tileserver-GL 渲染样式文件"></a>获取 Tileserver-GL 渲染样式文件</h2><p>虽然默认直接启动，它是会自动加载自带的样式文件的，但是因为调整配置不方便，而且并不是很好看，我就选择了使用其他的 style 文件</p><p>我是在 <a href="https://maplibre.org/maputnik/">Maputnik</a> 上的左上角找到了一个叫做 OSM Liberty 的样式文件，预览后觉得还可以，就点击左上角的 Save 按钮下载</p><p>但是，由于各个文件的渲染逻辑不同，为了不渲染出现问题，需要对样式文件进行一些修改</p><h3 id="修改名称读取"><a href="#修改名称读取" class="headerlink" title="修改名称读取"></a>修改名称读取</h3><p>打开下载下来的 <code>osm-liberty.json</code> 文件，<code>ctrl+f</code>找到 <code>name</code> 部分，将某些的 <code>name:latin</code> 进行修改</p><p>具体是怎么改，还是要看回去上一节中 <code>process-openmaptiles.lua</code> 文件中 <code>language</code> 变量的设置</p><p>比如我在上面的 lua 设置的是：</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- Preferred language can be (for example) &quot;en&quot; for English, &quot;de&quot; for German, or nil to use OSM&#x27;s name tag:</span></span><br><span class="line">preferred_language = <span class="literal">nil</span></span><br><span class="line"><span class="comment">-- This is written into the following vector tile attribute (usually &quot;name:latin&quot;)</span></span><br><span class="line">preferred_language_attribute = <span class="string">&quot;name&quot;</span></span><br><span class="line"><span class="comment">-- If OSM&#x27;s name tag differs, then write it into this attribute (usually &quot;name_int&quot;):</span></span><br><span class="line">default_language_attribute = <span class="string">&quot;name_int&quot;</span></span><br><span class="line"><span class="comment">-- Also write these languages if they differ - for example, &#123; &quot;de&quot;, &quot;fr&quot; &#125;</span></span><br><span class="line">additional_languages = &#123;<span class="string">&quot;zh&quot;</span>,<span class="string">&quot;en&quot;</span>&#125;</span><br></pre></td></tr></table></figure><p>这个设置就决定在前面生成 mbtiles 的时候，将 OpenStreetMap 中的 <code>name</code> 标签写入 <code>name</code> 属性中，<code>name:zh</code> 标签写入 <code>name:zh</code> 属性中，<code>name:en</code> 标签写入 <code>name:en</code> 属性中 （理论上是，但是不知道为什么我生成的文件中并没有 <code>name:zh</code> 标签）</p><p>我这样改是为了避免歧义，反正默认操作会在生成 mbtiles 的时候把中文写入 <code>name:latin</code>标签，听起来逻辑怪怪的</p><p>所以，我就应该把全部 <code>name:latin</code> 改成 <code>name</code>，因为生成的文件根本就没有 <code>name:latin</code> 标签</p><p>另外，如果不是用 maputnik 转换生成文件的话（即不是用上面的方法3），具体应该写什么可以先跳过这部分，先启动一次 Tileserver-GL，在网页下方的 Data 选项卡的 Inspect 按钮，点进去随机看几个 POI，看文件里面究竟写了什么字段</p><p>示例：</p><center><img src="https://s41.ax1x.com/2026/01/17/pZsRf1K.png" style="width:30%;" alt="使用方法 4 OpenMapTiles 构建的数据"/></center><p>如上图，我写的就是下面这样，来同时支持中文和英文的显示</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;text-field&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">          <span class="string">&quot;case&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="punctuation">[</span></span><br><span class="line">            <span class="string">&quot;all&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="punctuation">[</span><span class="string">&quot;has&quot;</span><span class="punctuation">,</span> <span class="string">&quot;name:latin&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">            <span class="punctuation">[</span><span class="string">&quot;!=&quot;</span><span class="punctuation">,</span> <span class="punctuation">[</span><span class="string">&quot;get&quot;</span><span class="punctuation">,</span> <span class="string">&quot;name&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="punctuation">[</span><span class="string">&quot;get&quot;</span><span class="punctuation">,</span> <span class="string">&quot;name:latin&quot;</span><span class="punctuation">]</span><span class="punctuation">]</span></span><br><span class="line">          <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">          <span class="punctuation">[</span></span><br><span class="line">            <span class="string">&quot;format&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="punctuation">[</span><span class="string">&quot;get&quot;</span><span class="punctuation">,</span> <span class="string">&quot;name&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span><span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="string">&quot;\n&quot;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span><span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="punctuation">[</span><span class="string">&quot;get&quot;</span><span class="punctuation">,</span> <span class="string">&quot;name:latin&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;font-scale&quot;</span><span class="punctuation">:</span> <span class="number">0.8</span> <span class="punctuation">&#125;</span></span><br><span class="line">          <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">          <span class="punctuation">[</span><span class="string">&quot;get&quot;</span><span class="punctuation">,</span> <span class="string">&quot;name&quot;</span><span class="punctuation">]</span></span><br><span class="line">        <span class="punctuation">]</span><span class="punctuation">,</span></span><br></pre></td></tr></table></figure><h3 id="修改地图路径"><a href="#修改地图路径" class="headerlink" title="修改地图路径"></a>修改地图路径</h3><p>在样式文件中，通常都会直接指定地图 tiles 的路径，但是这个也可以通过引用 config.json 文件中的数据源来读取</p><p>比如我就写成了</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;sources&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;openmaptiles&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;vector&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mbtiles://&#123;openmaptiles&#125;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;attribution&quot;</span><span class="punctuation">:</span> <span class="string">&quot;© OpenStreetMap contributors&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>这样就可以直接引用 <code>config.json</code> 文件中 <code>data</code> 部分的 <code>openmaptiles</code> 数据源了</p><p>如果你的 <code>config.json</code> 文件中 <code>data</code> 部分的名称不是 <code>openmaptiles</code> 的话，需要相应地修改这里的名称</p><h3 id="修改字体"><a href="#修改字体" class="headerlink" title="修改字体"></a>修改字体</h3><p>默认字体是无法显示中文的，所以需要修改字体</p><p>首先是下载字体，我这里使用的是 MiSans ，先获取到字体的 ttf 或者 otf 文件</p><p>然后，需要用特殊的工具将字体转换为 PBF 格式</p><p>可以使用 <a href="https://maplibre.org/font-maker/">font-maker</a> 这个网站来转换</p><p>也可以使用 <a href="https://github.com/openmaptiles/fonts">fonts</a> 这个工具来转换</p><p>效果应该都差不多的</p><p>转换完成后，将生成的存有 pbf 文件夹整个放到 Tileserver-GL 的 fonts 目录下</p><p>最后，修改样式文件中的字体引用，找到以下位置修改：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;glyphs&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&#123;fontstack&#125;/&#123;range&#125;.pbf&quot;</span><span class="punctuation">,</span></span><br></pre></td></tr></table></figure><p>此外，还需要搜索整个文件，找到带有 <code>text-font</code> 的地方，将字体名称修改为你刚才转换的字体文件夹的名称</p><p>例如我写的是 <code>&quot;text-font&quot;: [&quot;MiSans Semibold&quot;],</code></p><h2 id="启动-Tileserver-GL"><a href="#启动-Tileserver-GL" class="headerlink" title="启动 Tileserver-GL"></a>启动 Tileserver-GL</h2><p>完成以上步骤后，就可以启动 Tileserver-GL 了<br>在 Tileserver-GL 目录下，运行以下命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><p>然后，打开浏览器，访问 <code>http://your-domain:8080</code> （将 <code>your-domain</code> 替换为你的域名或者 IP 地址），就可以看到自己的地图了</p><center><img src="https://s41.ax1x.com/2026/01/17/pZsWQ41.jpg" style="width:60%;" alt="Tileserver-GL + Openmaptiles + OSM Liberty 最终渲染效果"/></center><h2 id="创建前端-html-页面"><a href="#创建前端-html-页面" class="headerlink" title="创建前端 html 页面"></a>创建前端 html 页面</h2><p>最后，如果想要创建一个前端的 html 页面来展示地图，可以参考以下代码：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>My Map<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">href</span>=<span class="string">&quot;https://unpkg.com/maplibre-gl@2.1.9/dist/maplibre-gl.css&quot;</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css">        <span class="selector-tag">body</span> &#123; <span class="attribute">margin</span>: <span class="number">0</span>; <span class="attribute">padding</span>: <span class="number">0</span>; &#125;</span></span><br><span class="line"><span class="language-css">        <span class="selector-id">#map</span> &#123; <span class="attribute">position</span>: absolute; <span class="attribute">top</span>: <span class="number">0</span>; <span class="attribute">bottom</span>: <span class="number">0</span>; <span class="attribute">width</span>: <span class="number">100%</span>; &#125;</span></span><br><span class="line"><span class="language-css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;map&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/maplibre-gl@2.1.9/dist/maplibre-gl.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> map = <span class="keyword">new</span> maplibregl.<span class="title class_">Map</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">container</span>: <span class="string">&#x27;map&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">style</span>: <span class="string">&#x27;http://your-domain:8080/styles/osm-liberty/style.json&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">center</span>: [<span class="number">113.5</span>, <span class="number">22.4</span>],</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">zoom</span>: <span class="number">12</span></span></span><br><span class="line"><span class="language-javascript">        &#125;);</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span>   </span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>这里的 <code>style</code> 地址需要修改为你自己的 Tileserver-GL 的样式地址，建议使用 https 来避免跨域问题</p><p>后面再在上方加 POI 标记、自定义画线什么的，参照 <a href="https://maplibre.org/maplibre-gl-js-docs/">MapLibre GL JS 官方文档</a> 就可以了，或者问 AI 也行，实测错误率不高</p><p>反正我后面使用的 Overpass API 来获取 POI 数据，然后使用 MapLibre GL JS 的 Marker 功能来渲染这些数据，效果还不错</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>以上就是使用 Tileserver-GL + MapLiberGL + OSM 创建自己的地图的详细教程<br>希望对大家有所帮助，如果有任何问题，欢迎在评论区留言讨论！</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://tileserver.readthedocs.io/">Tileserver-GL 官方文档</a></li><li><a href="https://maplibre.org/maplibre-gl-js/docs">MapLibre GL JS 官方文档</a></li><li><a href="https://docs.mapbox.com/style-spec/reference/expressions/">Expressions | Mapbox Style Spec | Mapbox Docs | Mapbox</a></li><li><a href="https://openmaptiles.org/docs/">OpenMapTiles 官方文档</a></li><li><a href="https://github.com/openmaptiles/openmaptiles">OpenMapTiles GitHub</a></li><li><a href="https://blog.sparktour.me/posts/2021/08/03/self-host-openstreetmap-tiles-server/">自建OpenStreetmap地图瓦片服务 | Sparktour’s Blog</a></li><li><a href="https://github.com/mapbox/tippecanoe/">Tippecanoe GitHub</a> (用来 GeoJSON 生成 mbtiles 的，但是因为 layer 样式对不上用不了)</li><li><a href="https://juejin.cn/post/7371423076661231656">简单地图应用-开源地图OpenStreetMap仿Mapbox样式部署本地矢量瓦片（上）一、引言近期在实验性质的做自己 - 掘金</a></li><li><a href="https://openmaptiles.org/docs/generate/create-custom-extract/">Create custom map extract - OpenMapTiles</a></li><li><a href="https://wiki.openstreetmap.org/wiki/Osmconvert">Osmconvert - OpenStreetMap Wiki</a> (OSMconvert 用来裁切 PBF 数据)</li><li><a href="https://gis.stackexchange.com/questions/185927/how-to-clip-a-osm-pbf-file-to-a-shapefile-in-r">openstreetmap - How to clip a .osm.pbf file to a shapefile in R - Geographic Information Systems Stack Exchange</a></li><li><a href="https://extract.bbbike.org/">BBBike extracts OpenStreetMap (OSM,Garmin,Shapefile etc.)</a></li><li><a href="https://maplibre.org/maputnik/">Maputnik</a> (在线样式编辑器)</li><li><a href="https://maplibre.org/font-maker/">font-maker</a> (在线字体转换工具)</li></ul>]]></content>
    
    
    <summary type="html">使用Tileserver-GL+MapLiberGL+OSM创建自己的地图的详细教程，包括部署Tileserver-GL、获取mbtiles数据、配置样式文件以及使用MapLibre GL JS进行地图渲染。</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>迁移LeanCloud到TiDB</title>
    <link href="https://haotian22.top/5d6475bb.html"/>
    <id>https://haotian22.top/5d6475bb.html</id>
    <published>2026-01-12T16:06:38.000Z</published>
    <updated>2026-01-26T00:07:30.747Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>今天，突然受到了一封邮件，内容是 LeanCloud 宣布将于 2027 年 1 月关闭其数据库服务。<br>我点进去看了一下，发现是真的。<br><a href="https://console.leancloud.app/docs/sdk/announcements/sunset-announcement">LeanCloud 关闭数据库服务通知</a><br>毕竟，我博客上评论区、统计阅读量之类的数据都放在了 LeanCloud 上，所以这件事对我来说还是挺重要的。</p><p>然后，我就上了 <a href="https://waline.js.org/en/guide/database.html">Waline</a> 的官网，发现 Waline 支持 TiDB 作为后端数据库，而且看起来免费额度还挺大，教程也是第一个推荐这个，于是就选了它</p><h2 id="创建-TiDB-数据库"><a href="#创建-TiDB-数据库" class="headerlink" title="创建 TiDB 数据库"></a>创建 TiDB 数据库</h2><p>第一步，当然是跟着<a href="https://waline.js.org/en/guide/deploy/tidb.html#create-database">官方教程</a>走，创建数据库。不过，因为官方的文档实在是太旧了，UI界面什么的完全不一样，因此我还花了不少时间摸索了一下。总之，和官方的教程差异如下：</p><ul><li><code>Chat2Query</code>变成了 <code>SQL Editor</code></li><li>链接数据库的时候选择 <code>General</code>选项就好了，里面的几个信息分别填入 Vercel 的 <code>TIDB_HOST</code>、<code>TIDB_USER</code>、<code>TIDB_PASSWORD</code>、<code>TIDB_DB</code>环境变量</li></ul><h2 id="导出-LeanCloud-数据"><a href="#导出-LeanCloud-数据" class="headerlink" title="导出 LeanCloud 数据"></a>导出 LeanCloud 数据</h2><p>接下来，就是导出 LeanCloud 的数据了。<br>LeanCloud 提供了数据导出的功能，根据停运公告的教程，我过了 20 分钟左右就收到了包含我数据库所有内容的邮件</p><p>不过导出的数据是 JSONL 格式的，而 TiDB 需要的是 CSV (150MB 以下) 格式的，因此还需要进行一些转换。</p><p>我最终让 Copilot 帮我写了一个 Python 脚本来完成这个任务，代码如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> csv</span><br><span class="line"></span><br><span class="line">input_file = <span class="string">&quot;input.jsonl&quot;</span></span><br><span class="line">output_file = <span class="string">&quot;output.csv&quot;</span></span><br><span class="line"></span><br><span class="line">rows = []</span><br><span class="line"></span><br><span class="line"><span class="comment"># 读取 JSONL</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(input_file, <span class="string">&quot;r&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    <span class="keyword">for</span> line <span class="keyword">in</span> f:</span><br><span class="line">        <span class="keyword">if</span> line.strip():</span><br><span class="line">            rows.append(json.loads(line))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 自动收集所有字段作为表头</span></span><br><span class="line">headers = <span class="built_in">set</span>()</span><br><span class="line"><span class="keyword">for</span> r <span class="keyword">in</span> rows:</span><br><span class="line">    headers.update(r.keys())</span><br><span class="line">headers = <span class="built_in">list</span>(headers)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 写入 CSV</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(output_file, <span class="string">&quot;w&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>, newline=<span class="string">&quot;&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    writer = csv.DictWriter(f, fieldnames=headers)</span><br><span class="line">    writer.writeheader()</span><br><span class="line">    writer.writerows(rows)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Done!&quot;</span>)</span><br></pre></td></tr></table></figure><p>看起来还是挺不错的</p><h2 id="导入旧数据到-TiDB"><a href="#导入旧数据到-TiDB" class="headerlink" title="导入旧数据到 TiDB"></a>导入旧数据到 TiDB</h2><p>因为原有的 Leancloud 转换出来的 CSV 字段和 TiDB 的表结构并不完全匹配，所以还需要对 CSV 进行一些手动的修改，主要是删除一些多余的字段，和调整字段顺序。<br>我于是又让他帮我写了下面这个脚本：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> csv</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">from</span> datetime <span class="keyword">import</span> datetime</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">parse_parse_date</span>(<span class="params">value</span>):</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> value:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        obj = json.loads(value.replace(<span class="string">&quot;&#x27;&quot;</span>, <span class="string">&#x27;&quot;&#x27;</span>))</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">isinstance</span>(obj, <span class="built_in">dict</span>) <span class="keyword">and</span> obj.get(<span class="string">&quot;__type&quot;</span>) == <span class="string">&quot;Date&quot;</span>:</span><br><span class="line">            iso = obj.get(<span class="string">&quot;iso&quot;</span>)</span><br><span class="line">            dt = datetime.fromisoformat(iso.replace(<span class="string">&quot;Z&quot;</span>, <span class="string">&quot;+00:00&quot;</span>))</span><br><span class="line">            <span class="keyword">return</span> dt.strftime(<span class="string">&quot;%Y-%m-%d %H:%M:%S&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">return</span> value <span class="keyword">or</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">to_int_or_null</span>(<span class="params">value</span>):</span><br><span class="line">    <span class="keyword">if</span> value <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="number">0</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line">    value = <span class="built_in">str</span>(value).strip()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Checking value: &#x27;<span class="subst">&#123;value&#125;</span>&#x27;&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> value.isdigit():</span><br><span class="line">        <span class="built_in">print</span>(<span class="number">1</span>)</span><br><span class="line">        <span class="keyword">return</span> value</span><br><span class="line">    <span class="keyword">return</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">to_str_or_null</span>(<span class="params">value</span>):</span><br><span class="line">    <span class="keyword">if</span> value <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">r&quot;&quot;</span></span><br><span class="line">    v = <span class="built_in">str</span>(value).strip()</span><br><span class="line">    <span class="keyword">return</span> v <span class="keyword">if</span> v <span class="keyword">else</span> <span class="string">r&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">nullify</span>(<span class="params">value</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;把空字符串、None、空白都变成 \\N&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">if</span> value <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line">    v = <span class="built_in">str</span>(value).strip()</span><br><span class="line">    <span class="keyword">return</span> v <span class="keyword">if</span> v <span class="keyword">else</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">input_file = <span class="string">&quot;output.csv&quot;</span></span><br><span class="line">output_file = <span class="string">&quot;db_ready.csv&quot;</span></span><br><span class="line"></span><br><span class="line">target_fields = [</span><br><span class="line">    <span class="string">&quot;id&quot;</span>, <span class="string">&quot;user_id&quot;</span>, <span class="string">&quot;comment&quot;</span>, <span class="string">&quot;insertedAt&quot;</span>, <span class="string">&quot;ip&quot;</span>, <span class="string">&quot;link&quot;</span>, <span class="string">&quot;mail&quot;</span>, <span class="string">&quot;nick&quot;</span>,</span><br><span class="line">    <span class="string">&quot;pid&quot;</span>, <span class="string">&quot;rid&quot;</span>, <span class="string">&quot;sticky&quot;</span>, <span class="string">&quot;status&quot;</span>, <span class="string">&quot;like&quot;</span>, <span class="string">&quot;ua&quot;</span>, <span class="string">&quot;url&quot;</span>, <span class="string">&quot;createdAt&quot;</span>, <span class="string">&quot;updatedAt&quot;</span></span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 读取所有行</span></span><br><span class="line">rows = []</span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(input_file, <span class="string">&quot;r&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    reader = csv.DictReader(f)</span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> reader:</span><br><span class="line">        rows.append(row)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 建立 objectId → new_id 映射</span></span><br><span class="line">objectId_to_newId = &#123;row[<span class="string">&quot;objectId&quot;</span>]: i <span class="keyword">for</span> i, row <span class="keyword">in</span> <span class="built_in">enumerate</span>(rows)&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 生成新 CSV 数据</span></span><br><span class="line">output_rows = []</span><br><span class="line"><span class="keyword">for</span> row <span class="keyword">in</span> rows:</span><br><span class="line">    new_row = &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 新 id</span></span><br><span class="line">    new_row[<span class="string">&quot;id&quot;</span>] = objectId_to_newId[row[<span class="string">&quot;objectId&quot;</span>]]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># user_id</span></span><br><span class="line">    new_row[<span class="string">&quot;user_id&quot;</span>] = to_int_or_null(row.get(<span class="string">&quot;user_id&quot;</span>, <span class="string">&quot;&quot;</span>))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 普通字段</span></span><br><span class="line">    <span class="keyword">for</span> field <span class="keyword">in</span> [<span class="string">&quot;comment&quot;</span>, <span class="string">&quot;link&quot;</span>, <span class="string">&quot;mail&quot;</span>, <span class="string">&quot;nick&quot;</span>, <span class="string">&quot;sticky&quot;</span>, <span class="string">&quot;like&quot;</span>, <span class="string">&quot;ua&quot;</span>, <span class="string">&quot;url&quot;</span>]:</span><br><span class="line">        new_row[field] = nullify(row.get(field, <span class="string">&quot;&quot;</span>))</span><br><span class="line">  </span><br><span class="line">    <span class="comment"># status and ip use empty string as default (not \N)</span></span><br><span class="line">    new_row[<span class="string">&quot;status&quot;</span>] = to_str_or_null(row.get(<span class="string">&quot;status&quot;</span>, <span class="string">&quot;&quot;</span>))</span><br><span class="line">    new_row[<span class="string">&quot;ip&quot;</span>] = to_str_or_null(row.get(<span class="string">&quot;ip&quot;</span>, <span class="string">&quot;&quot;</span>))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 时间字段</span></span><br><span class="line">    new_row[<span class="string">&quot;insertedAt&quot;</span>] = parse_parse_date(row.get(<span class="string">&quot;insertedAt&quot;</span>, <span class="string">&quot;&quot;</span>))</span><br><span class="line">    new_row[<span class="string">&quot;createdAt&quot;</span>]  = parse_parse_date(row.get(<span class="string">&quot;createdAt&quot;</span>, <span class="string">&quot;&quot;</span>))</span><br><span class="line">    new_row[<span class="string">&quot;updatedAt&quot;</span>]  = parse_parse_date(row.get(<span class="string">&quot;updatedAt&quot;</span>, <span class="string">&quot;&quot;</span>))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># pid 映射</span></span><br><span class="line">    old_pid = row.get(<span class="string">&quot;pid&quot;</span>, <span class="string">&quot;&quot;</span>)</span><br><span class="line">    new_row[<span class="string">&quot;pid&quot;</span>] = objectId_to_newId.get(old_pid, <span class="string">r&quot;\N&quot;</span>) <span class="keyword">if</span> old_pid <span class="keyword">else</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># rid 映射</span></span><br><span class="line">    old_rid = row.get(<span class="string">&quot;rid&quot;</span>, <span class="string">&quot;&quot;</span>)</span><br><span class="line">    new_row[<span class="string">&quot;rid&quot;</span>] = objectId_to_newId.get(old_rid, <span class="string">r&quot;\N&quot;</span>) <span class="keyword">if</span> old_rid <span class="keyword">else</span> <span class="string">r&quot;\N&quot;</span></span><br><span class="line"></span><br><span class="line">    output_rows.append(new_row)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 写入 CSV</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(output_file, <span class="string">&quot;w&quot;</span>, encoding=<span class="string">&quot;utf-8&quot;</span>, newline=<span class="string">&quot;&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    writer = csv.DictWriter(f, fieldnames=target_fields)</span><br><span class="line">    writer.writeheader()</span><br><span class="line">    writer.writerows(output_rows)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;完成：所有空值已转换为 \\N，适用于 TiDB Lightning 导入。&quot;</span>)</span><br></pre></td></tr></table></figure><p>这段代码可以自动将已有的 ObjectId 转换为 TiDB 需要的递增 id ，自动将 <code>pid</code>和 <code>rid</code>等需要互相对应的值迁移到新的 id 结构里，将空值填上 <code>\N</code>或者空字符串。</p><p>不过，因为<strong>用户数据</strong>并不在这个 Comment 数据表里面，需要对应回去的话需要<strong>手动</strong>查查 User 的数据表迁移后的各个用户对应 id 再手动替换一下（但是一般来说都没几个人会专门注册才来评论，反正我这里就我一个，因此我就只需要简单的 Ctrl+H 替换自己的 id 就行了）。</p><p>在迁移过程中，我踩过最大的坑应该就是空值的问题了<br>前期，我一直以为直接在 CSV 里留空就行，结果导入 TiDB 的时候各种报错，后来才发现 TiDB Lightning 要求空值必须是 <code>\N</code>才行，于是我加上了 <code>nullify</code>函数来处理这些空值。</p><p>不过，总算是顺利完成了数据的迁移工作。<br>最后，用起来感觉的话，似乎 TiDB 的网络链接会比 LeanCloud 要慢一点？查表的时候要等待好一会才能出来，加载博客评论的时间似乎也比 LeanCloud 要长一些。</p>]]></content>
    
    
    <summary type="html">本文记录了我将博客评论系统从LeanCloud迁移到TiDB的全过程，包括创建TiDB数据库、导出LeanCloud数据、转换数据格式以及导入TiDB的步骤和遇到的问题。</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>Google Pay与其他NFC付款App的共存与切换</title>
    <link href="https://haotian22.top/4b516b74.html"/>
    <id>https://haotian22.top/4b516b74.html</id>
    <published>2025-09-06T15:29:15.894Z</published>
    <updated>2025-09-06T15:29:16.232Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>来到香港生活后，因为开了 Android 八达通，平时经常需要用到Google Wallet来支付食堂和交通费，但是，由于银联给的89.9的汇率实在是有点香（相对比市场价91.7），因此又挺希望用手机自带的钱包Pay来银联NFC&#x2F;二维码付款的。</p><img src="https://s2.loli.net/2025/09/06/lTebpz6wcAIQJrZ.jpg" style="width:30%;" alt="银联手机Pay的超绝优惠汇率"/><p>然而，由于 Android 的限制，手机的默认付款 App 只能设置为一个默认的，此外再无更多的选项，造成了多个付款 App 之间会有冲突。</p><p>需要频繁切换的情况下，每次都需要打开设置，经过几次点击找到更换默认NFC付款的选项，确实有点麻烦了，尤其是在排队给钱的时候，一通操作下来少说也得5秒，会显得非常尴尬</p><p>于是，正当我烦恼的时候，打开手机钱包时候的“设置为默认NFC”的选项引起了我的注意，我就开始在想，有没有第三方的 App 能够把这个过程做到自动化，点一下按钮就能自动从两个或者更多保存过的 NFC 付款应用之间来切换，甚至能做到根据位置或使用习惯等自动切换呢？</p><p>然而，在 Google&#x2F;小红书&#x2F;Bilibili 等搜了一轮之后，结果却——基本没有Orz</p><p>但是，我又想到了 Android 有可以直接调用 Activtity 来快速打开页面的特性，于是向着这个方向找了找，果然还是找到了一点思路</p><p>最终，我现在的解决方案是：</p><p>利用<a href="https://github.com/sdex/ActivityManager">ActivityManager</a>，在里面找到<code>设置/Settings</code>（指的是系统设置的App）</p><p>再搜索<code>payment</code>，会发现一个叫<code>Settings$PaymentSettingsActivity Contactless payments</code>的选项</p><p>点击旁边的三个点，选择<code>Create Shortut</code>的选项，就会在桌面出来一个切换NFC付款程序的入口了</p><p>以后点击一下那个图标，就会出现如下图所示的这个选择框来切换</p><img src="https://s2.loli.net/2025/09/06/rF5678ExcNfbzdL.jpg" style="width:30%;" alt="NFC付款App选择框"/><p>虽然这并不是一个特别好的方式，但是至少，切换起来还是比进入设置里面一步步找要方便不少了</p><p>还有的教程会建议用Tasker，我看了看，其实也相差不大，但是那个可以自动化得更加彻底，例如设定在某个时间&#x2F;地点自动弹出选择NFC付款程序的框（指上面图里那个框，然而依然不能自动设置默认付款程序，还是得要手动点那么一下），所以也就没研究下去了</p><p>如果有更好的方式，欢迎在评论区提出</p><p><strong>后续研究</strong></p><p>后面我又用了几天，似乎发现NFC付款程序并不完全冲突，至少Type-F的八达通和Type-A的工商银行云闪付是可以共存的。</p><p>在一次测试中，我把默认付款应用设为八达通，保持八达通和工商银行的后台开启（通知栏显示Active的通知），然后贴了下八达通付款机是能直接给的</p><p>之后我还会继续测试更多的情况</p>]]></content>
    
    
    <summary type="html">在海外使用手机时遇到的Google Pay与其他NFC付款App冲突与切换问题，并尝试通过Android Activity特性来快速切换NFC默认付款程序来解决的过程</summary>
    
    
    
    
    <category term="生活" scheme="https://haotian22.top/tags/%E7%94%9F%E6%B4%BB/"/>
    
  </entry>
  
  <entry>
    <title>期末，搬宿舍时候的复杂情感</title>
    <link href="https://haotian22.top/ec3c92ec.html"/>
    <id>https://haotian22.top/ec3c92ec.html</id>
    <published>2025-06-18T17:06:00.301Z</published>
    <updated>2025-06-18T17:22:46.431Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>今天，大概是我今年在中国境内大学上课，或许也是我今年在这个城市的最后一天了。</p><p>收拾行李的时候，各种复杂的情感涌向脑海中，让我预期中收拾东西的时间变得漫长。不是因为东西太多，而是因为情绪太重。每一次弯腰、每一次翻找，仿佛不是在收拾物品，而是在和一段时光告别。当我终于拖着行李离开时，那种说不清的情感——不舍、焦虑、回忆的冲撞感，像潮水一样漫上来，压得人想哭。</p><img src="https://s21.ax1x.com/2025/06/19/pVVAFoV.md.jpg" alt="pVVAFoV.md.jpg" border="0" style="zoom:70%;"><p>我这种感觉的起因，很大程度上源于即将前往境外交换的决定。尽管因为嫌麻烦，或是对未来新室友的不确定性感到焦虑，我最终还是决定保留宿舍，并留下了一些个人物品。但这，反而也加剧了我的纠结：哪些该带走，哪些可以留？因为一旦离开，至少半年内我都不会回来。我今天的每一个判断错误，都将要留给未来半年后的我来承担。</p><p>于是，这次的“收拾”不再是一个简单的动作，而像是生活的一道分水岭：它把过去的我——在大学的生活、习惯、情绪一刀切开，连通了一个我无法完全想象的未来旅程。在这种旧时期已终结、新阶段尚未开启的过渡时刻，我感到一种强烈的“存在的空隙”：我还没从过去完全抽身，却也尚未真正踏入未来。这种悬在半空的状态，让我格外不安。</p><p>我还记得去年秋天返校时打开宿舍门的那一瞬间：霉菌爬满桌面，黑色的斑点布满墙壁和天花板，甚至桌角还有虫子爬动。曾经崭新的床边缘也锈迹斑斑，那些鞋子、衣物、抽屉里残留的潮气，无声地侵蚀着我对宿舍的信任。即使这次我吸取了教训，放了除湿剂，也还是担心这点准备根本撑不过两个假期。我很怕，回来之后看到的，是自己用心维系的小小生活空间，被霉和潮气吞没。无论那些物品是便宜的，还是我格外珍视的，都可能要被“重置”——我必须亲手清理、舍弃，哪怕它们陪我走过了一个时段的人生。</p><p>我这种焦虑，其实和我性格中的“对自己没信心”紧密相关。我常常在做事时反复思考：我有没有遗漏什么？这决定对吗？有些东西，当下觉得不重要，但真的找不到的时候，会无比烦躁。就因为这种性格，我会反复在手上拿着一个物品，思前想后，迟迟无法决定要不要带走。</p><p>还有一种莫名的感受，是在浏览宿舍物品时被记忆撞了一下的那种感觉——那些从活动中拿来的纪念品，也许在别人眼里不值一提，但我知道它们承载着一个个鲜活的瞬间。丢弃它们，就像在主动擦掉一些回忆。我甚至会担心，等我以后想起那段日子时，会变得模糊，甚至一无所获。</p><p>而最让我情绪复杂的，也许是我终于意识到——我真的住在这个空间里生活了好几个月。我用它、整理它、逐渐习惯它，把它变成我的一个“小基地”。即使它并不完美，即使它只是临时住所，但我确实在这里，经历了生活。而现在，我要亲手拆掉这个“基地”，和这段生活正式告别。那种割舍的感觉，比我想象得还要真切。</p><img src="https://s21.ax1x.com/2025/06/19/pVVAid0.md.jpg" alt="pVVAid0.md.jpg" border="0" style="zoom:80%;"><p>就这样，带着各种复杂的心情，我拖着箱子，离开了宿舍……</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    
    <category term="随笔" scheme="https://haotian22.top/tags/%E9%9A%8F%E7%AC%94/"/>
    
    <category term="生活" scheme="https://haotian22.top/tags/%E7%94%9F%E6%B4%BB/"/>
    
  </entry>
  
  <entry>
    <title>英语/外语Windows中的中文显示问题</title>
    <link href="https://haotian22.top/e0733a8a.html"/>
    <id>https://haotian22.top/e0733a8a.html</id>
    <published>2025-02-28T00:33:57.572Z</published>
    <updated>2025-04-08T02:29:44.959Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>许多想要出国留学以及热爱学习语言的人，都喜欢将自己手头上的电子设备操作系统语言设置为想学习的语言（e.g. 英语&#x2F;日语…….），但是由于Windows Font Fallback的特性，非中文语言的系统在显示中文的时候字体就会变得有些怪怪的，看着不像是平时看到的微软雅黑字体</p><p>这篇文字会详细说明非中文Windows系统下中文字体的显示问题以及如何解决（但是有些其实并不能解决）</p><h2 id="前言：更改系统语言"><a href="#前言：更改系统语言" class="headerlink" title="前言：更改系统语言"></a>前言：更改系统语言</h2><p>在讲问题之前，首先要明确要更改Windows系统语言需要哪些操作</p><p>首先，Windows专业版是需要的，现今不少电脑都只是出场安装了<strong>Windows中文单语言家庭版</strong>，是无法更改系统语言的，需要更改的话可以自行搜索“家庭版Windows升级到专业版”等教程，一般来说网上随便找个激活码再运行一个激活脚本就完成了</p><p>然后，就是更改语言的三个部分，或者说是三个等级</p><ol><li>系统设置 - 时间与语言 - 语言与地区 - Windows显示语言（Settings - Time &amp; Language - Language &amp; Region - Windows display language）</li></ol><p>这里影响了大部分Windows界面和软件的语言</p><p>如果在这里没有找到想要的语言，可以先点击下方的“添加语言”按钮添加</p><p><img src="https://s21.ax1x.com/2025/02/28/pE8Yzaq.png" alt="pE8Yzaq.png"></p><ol start="2"><li>系统设置 - 时间与语言 - 语言与地区 - 管理语言设置</li></ol><p>这里主要是影响少部分传统框架的应用，如安装器的语言等</p><p><img src="https://s21.ax1x.com/2025/03/03/pEG7y1P.md.png" alt="pEG7y1P.md.png"></p><ol start="3"><li>系统设置 - 时间与语言 - 语言与地区 - 国家和地区</li></ol><p>这里影响一些应用内的资料，如Microsoft Store的应用资料，如应用内的个性化推送等</p><h2 id="在英语-外语Windows系统下中文的问题"><a href="#在英语-外语Windows系统下中文的问题" class="headerlink" title="在英语&#x2F;外语Windows系统下中文的问题"></a>在英语&#x2F;外语Windows系统下中文的问题</h2><h3 id="Windows资源管理器问题"><a href="#Windows资源管理器问题" class="headerlink" title="Windows资源管理器问题"></a>Windows资源管理器问题</h3><p>在更改语言后，绝大部分人发现到的第一个问题都会是Windows资源管理器（Windows Explorer）文件名的字体变细和大小不一</p><p>这个问题还算好解决，只需要修改注册表中各字体的Fallback顺序即可，使用这款<a href="https://github.com/zBuffer/fix-fontlink">Fix-FontLink软件</a>就可以一件更改注册表了</p><p><img src="https://s21.ax1x.com/2025/03/03/pEGbAMV.png" alt="pEGbAMV.png"></p><h3 id="Edge问题"><a href="#Edge问题" class="headerlink" title="Edge问题"></a>Edge问题</h3><p>另一个问题就是一些地方出现的日文字体问题，如在Microsoft Edge&#x2F;Chrome浏览器的标题中，这些字体通常可以由“关复门置”这四个简体字的渲染可以看出来</p><p>不过，这其实是浏览器自己的语言系统问题，和Windows关系并不是非常大</p><p><img src="https://s21.ax1x.com/2025/03/03/pEGofKS.png" alt="pEGofKS.png"></p><p>目前来说，虽然社区中有不少人提问过，但是还是找不到什么好的方法</p><h3 id="其他问题-实用工具"><a href="#其他问题-实用工具" class="headerlink" title="其他问题&#x2F;实用工具"></a>其他问题&#x2F;实用工具</h3><p>部分程序有可能也会遇到语言乱码等问题（以日本Galgame等为主），可以尝试使用以下工具临时调整应用内的语言来解决</p><p><a href="https://github.com/xupefei/Locale-Emulator">Language Emulator</a></p>]]></content>
    
    
    <summary type="html">英语/外语Windows中的中文显示问题及部分解决方法</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>UIC Anyconnect的校园VPN研究</title>
    <link href="https://haotian22.top/546c6c89.html"/>
    <id>https://haotian22.top/546c6c89.html</id>
    <published>2024-05-22T17:01:07.000Z</published>
    <updated>2024-05-22T23:53:33.836Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>本文包含了关于 UIC VPN 与 Clash 协同使用，基本逻辑，和虚拟内网(Zerotier)&#x2F;局域网协同使用的研究</p><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>UIC 校园 VPN 是一个基于 Cisco Anyconnect 的 VPN ，可以在校外网络环境访问校园网资源<br>我这里使用的学校推荐的那个版本 <a href="https://itsc.uic.edu.cn/UIC%20Campus%20VPN%20Service%20Guideline.pdf">ITSC校园VPN使用指引</a></p><p>Clash 是一个基于 Go 语言的代理软件，可以实现代理转发，支持多种代理协议<br>我这里使用的是 <a href="https://github.com/LibNyanpasu/clash-nyanpasu">Clash Nyanpasu</a> 的 GUI + <a href="https://github.com/MetaCubeX/mihomo">Mihomo</a> 1.18.3 的内核<br>（但是其实用什么版本的关系并不大）</p><p>Zerotier 是一个虚拟内网软件，可以实现全球范围内的虚拟内网连接</p><p>另外，我使用的是 Windows 11 23H2 版本，用 MacOS 和 Linux 的同学需要根据这个逻辑自行调整</p><p>我研究这个的起因非常简单：我开了 UIC 校园 VPN ，但是同时又开了 Clash ，导致了<code>uic.edu.cn</code>的域名解析出现了问题，我无法访问 iSpace 交作业</p><h2 id="与Clash协同使用"><a href="#与Clash协同使用" class="headerlink" title="与Clash协同使用"></a>与Clash协同使用</h2><p>我使用的Clash，是只开了系统代理(使用 TUN 模式的话可能会有点区别)</p><p>根据7层网络模型，系统代理位于应用层（第七层），虚拟网卡工作在数据链路层（第二层）和物理层（第一层）之间，所以逻辑上流量是会先经过 Clash 再经过 VPN 的</p><p>Clash 的配置文件中，可以配置一个 <code>dns</code> 字段，用于指定 DNS 服务器</p><p>主要问题就出现在这里：Clash 的 DNS 服务器因为层级较高会被优先使用，使得<code>uic.edu.cn</code>的域名解析到了 <code>61.143.62.100</code></p><p>这个地址，是 UIC 官网在一般网络环境下访问的地址，这没有任何问题</p><p>但是，当我开了 UIC 校园 VPN 的时候，这个 IP 就会被防火墙拦截(可能是因为避免用了VPN还是使用外部地址，访问不到学术资源的”Bug”)，导致了无法访问 UIC 官网及 iSpace</p><p>那么就诞生了<strong>方法1</strong>：在 Clash 的配置文件中，将 UIC 的 <code>dns</code> 匹配改成跟随系统即可（但是还是有缺陷，看下文）</p><p>例如我写的是：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">dns:</span></span><br><span class="line">  <span class="string">...</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">nameserver-policy:</span></span><br><span class="line">  <span class="attr">&quot;*.uic.edu.cn&quot;:</span> [<span class="string">system</span>,<span class="string">dhcp://system</span>]</span><br><span class="line"></span><br><span class="line">  <span class="string">...</span></span><br></pre></td></tr></table></figure><p>需要注意的是，Clash-Go&#x2F;Clash-Premium&#x2F;Stash 的内核对 DNS 的配置写法有些不同，可能不支持一个地址对应多个 DNS 服务器，有需要的可以尝试以下写法</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">dns:</span></span><br><span class="line">  <span class="string">...</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">nameserver-policy:</span></span><br><span class="line">  <span class="attr">&quot;*.uic.edu.cn&quot;:</span> <span class="string">system</span></span><br><span class="line">  <span class="string">...</span></span><br></pre></td></tr></table></figure><p>这样，Clash 就会优先使用 UIC 校园 VPN 的 DNS 服务器 (172.16.240.10)，解析出内网的 IP 地址，通过校园 VPN 访问 UIC 官网及 iSpace</p><p>然而，虽然看起来这个方案能行，但是还是有<strong>致命的缺点</strong>：DNS 缓存<br>在关闭校园 VPN 后的数分钟内，校园网连接时期的缓存依然存在，导致了一段时间内都不能访问同一个域名</p><p>为此，还有两种逻辑上可行的备用方法</p><p><strong>方法2</strong>：使用 Zero Omega 浏览器插件预先分流</p><ol><li>在Chrome商店安装插件，打开设置</li><li>从左侧进入 proxy –&gt; Bypass list，填入<code>*uic.edu.cn</code> ，再在上面的 Proxy servers 填上 Clash 本地设置的端口</li><li>点击左侧的 Apply changes</li><li>浏览器右上角的插件栏，找到这个插件，使它长期处于 proxy 模式即可</li></ol><p>这个方案，直接让浏览器预先分流，而不会受到 Clash 相关 DNS 设置的影响<br>不过缺点同样也很明显，这个方法只作用于浏览器。其他程序没法正常获取校内资源（如语言大模型(LLM)的本地客户端中，给它链接来读论文的场景就行不通了）<br>另外，对于那些经常开关 Clash 的人来说，每次关闭后都需要在浏览器右上角切换代理模式，会有点烦</p><p><strong>方法3</strong>：让 Clash 的层级比校园 VPN 的层级高（如同样用TUN）</p><p>这个方案我还没试过，但是显然会很混乱</p><p>另为了避免学术网站地址被 Clash 代理走到外国服务器，无法获取校内 IP 才能访问的资源，可以在配置文件中加入以下规则</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">rules:</span></span><br><span class="line"> <span class="string">...</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 学术论文（需要机构内网）</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,uic.edu.cn,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,acm.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,airitilibrary.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,journals.aps.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,artstor.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,gale.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,brillonline.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,corpus.byu.edu,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,zju.edu.cn,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,cambridge.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,chant.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ckcest.cn,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,cityu.edu.hk,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,cnki.net,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,corpus.byu.edu,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,csmar.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,diaolong.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,buddhism-dict.net,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,doaj.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,duxiu.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,eadl.asia,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ebscohost.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,emerald.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,myendnoteweb.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,bl.uk,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,euromonitor.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ebscohost.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,gale.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,nssd.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,global-sci.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ieee.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,imf.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,clarivate.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,jstor.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,lexisnexis.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ams.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,uic.edu.hk,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ebscohost.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,mintel.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,nlc.cn,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,nature.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,oecd-ilibrary.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,osapublishing.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,oxfordartonline.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,oxfordbibliographies.com,DIRECT</span> </span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,oxfordmusiconline.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ebscohost.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,muse.jhu.edu,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,proquest.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ebscohost.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,resset.cn,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,sagepub.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,sciencedirect.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,scival.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,scopus.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,siam.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,springer.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,tandfonline.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,tlg.uci.edu,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,warc.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,webofknowledge.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,westlaw.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,wiley.com,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,worldbank.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,zbmath.org,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,ckcest.cn,DIRECT</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">DOMAIN-SUFFIX,cnbksy.com,DIRECT</span></span><br><span class="line"></span><br><span class="line"> <span class="string">...</span></span><br></pre></td></tr></table></figure><h2 id="VPN-逻辑的研究"><a href="#VPN-逻辑的研究" class="headerlink" title="VPN 逻辑的研究"></a>VPN 逻辑的研究</h2><p>到这里，我的问题解决了，但是我还是非常好奇，为什么会有这样一个问题出现</p><p>对此，我通过 <code>route print</code>命令，查看了一下我的路由表</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">IPv4 Route Table</span><br><span class="line">===========================================================================</span><br><span class="line">Active Routes:</span><br><span class="line">Network Destination        Netmask          Gateway       Interface  Metric</span><br><span class="line">          0.0.0.0          0.0.0.0      192.168.1.1    192.168.1.112     40</span><br><span class="line">          0.0.0.0          0.0.0.0   25.255.255.254   192.168.191.95  10034</span><br><span class="line">          1.0.0.0        255.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">          2.0.0.0        255.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">          3.0.0.0        255.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">          4.0.0.0        255.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">          5.0.0.0        255.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">          6.0.0.0        255.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">          7.0.0.0        255.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">          8.0.0.0        248.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">         16.0.0.0        240.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">         32.0.0.0        224.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">         64.0.0.0        192.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">     116.6.50.238  255.255.255.255      192.168.1.1    192.168.1.112     41</span><br><span class="line">  116.116.116.116  255.255.255.255      192.168.1.1    192.168.1.112     41</span><br><span class="line">        127.0.0.0        255.0.0.0         On-link         127.0.0.1    331</span><br><span class="line">        127.0.0.1  255.255.255.255         On-link         127.0.0.1    331</span><br><span class="line">  127.255.255.255  255.255.255.255         On-link         127.0.0.1    331</span><br><span class="line">        128.0.0.0        192.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">    172.16.240.10  255.255.255.255       172.25.0.1    172.25.50.204      2</span><br><span class="line">       172.25.0.0    255.255.192.0         On-link     172.25.50.204    257</span><br><span class="line">    172.25.50.204  255.255.255.255         On-link     172.25.50.204    257</span><br><span class="line">    172.25.63.255  255.255.255.255         On-link     172.25.50.204    257</span><br><span class="line">        192.0.0.0        224.0.0.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">      192.168.1.0    255.255.255.0         On-link     192.168.1.112    296</span><br><span class="line">      192.168.1.0    255.255.255.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">      192.168.1.1  255.255.255.255         On-link     192.168.1.112     41</span><br><span class="line">    192.168.1.112  255.255.255.255         On-link     192.168.1.112    296</span><br><span class="line">    192.168.1.255  255.255.255.255         On-link     192.168.1.112    296</span><br><span class="line">    192.168.191.0    255.255.255.0         On-link    192.168.191.95    291</span><br><span class="line">    192.168.191.0    255.255.255.0       172.25.0.1    172.25.50.204      2</span><br><span class="line">   192.168.191.95  255.255.255.255         On-link    192.168.191.95    291</span><br><span class="line">  192.168.191.255  255.255.255.255         On-link    192.168.191.95    291</span><br><span class="line">      221.5.88.88  255.255.255.255      192.168.1.1    192.168.1.112     41</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link         127.0.0.1    331</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link     192.168.1.112    296</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link    192.168.191.95    291</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link     172.25.50.204  10000</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link         127.0.0.1    331</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link     192.168.1.112    296</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link    192.168.191.95    291</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link     172.25.50.204  10000</span><br><span class="line">===========================================================================</span><br><span class="line">Persistent Routes:</span><br><span class="line">  None</span><br></pre></td></tr></table></figure><p>我们可以直接看出来，<code>Gateway</code>为<code>172.25.0.1</code>的便是走了 UIC 校园 VPN 的路由，而<code>Metric</code>则表达出了它的优先级，而<code>192.168.1.*</code>则是我宿舍的本地网络，<code>192.168.191.*</code>是我 Zerotier 的虚拟内网</p><p>这个路由表，并不像他看起来的那样这么好理解，我甚至还需要借助GPT来帮忙解读这个表</p><p>以下是GPT的解读结果：</p><blockquote><p>这些路由条目表示特定的IPv4地址范围是通过VPN隧道传输的。具体的路由如下：<br>128.0.0.0&#x2F;2 覆盖128.0.0.0到191.255.255.255的IP地址范围。<br>192.0.0.0&#x2F;3 覆盖192.0.0.0到223.255.255.255的IP地址范围。<br>64.0.0.0&#x2F;2 覆盖64.0.0.0到127.255.255.255的IP地址范围。<br>32.0.0.0&#x2F;3 覆盖32.0.0.0到63.255.255.255的IP地址范围。<br>16.0.0.0&#x2F;4 覆盖16.0.0.0到31.255.255.255的IP地址范围。<br>8.0.0.0&#x2F;5 覆盖8.0.0.0到15.255.255.255的IP地址范围。<br>1.0.0.0&#x2F;8 覆盖1.0.0.0到1.255.255.255的IP地址范围。<br>2.0.0.0&#x2F;8 覆盖2.0.0.0到2.255.255.255的IP地址范围。<br>3.0.0.0&#x2F;8 覆盖3.0.0.0到3.255.255.255的IP地址范围。<br>4.0.0.0&#x2F;8 覆盖4.0.0.0到4.255.255.255的IP地址范围。<br>5.0.0.0&#x2F;8 覆盖5.0.0.0到5.255.255.255的IP地址范围。<br>6.0.0.0&#x2F;8 覆盖6.0.0.0到6.255.255.255的IP地址范围。<br>7.0.0.0&#x2F;8 覆盖7.0.0.0到7.255.255.255的IP地址范围。<br>172.16.240.10&#x2F;32 表示单个IP地址172.16.240.10通过VPN隧道传输。<br>总结来说，这段配置定义了哪些流量应通过VPN（安全路由）以及哪些流量应通过本地网络（非安全路由）。在这个配置中，除了0.0.0.0&#x2F;0表示的默认所有流量之外，其他一些特定的地址段将会通过VPN进行传输。</p></blockquote><p>那么，我们就可以发现，UIC 的外部 IP 地址 <code>61.143.62.100</code>，是需要通过 VPN 隧道传输，并不能像我们想的那样可以<strong>按需传输</strong>，给了位于校园网内部的防火墙可以拦截的机会</p><p>所以，这也带来了一个问题：在开启 VPN 之后，因为 VPN 的路由表优先级高于本地网络，所以会导致一些本地网络的问题<br>比如无法访问局域网内的设备等</p><p>但是，我又发现，我还可以访问 <code>192.168.1.1</code>，它明明是优先级41的，比2高了许多，为什么还可以访问呢？</p><p>这又得提到另外一个机制了，因为我也不太懂，所以GPT是这么解释的</p><blockquote><p>精确匹配原则:<br>路由表的查找遵循“最长前缀匹配”原则，即最精确匹配的路由条目优先。例如，192.168.1.1 255.255.255.255 的匹配精度高于 192.168.1.0&#x2F;24。<br>因此，当你访问本地地址192.168.1.1时，路由表选择最精确的匹配，即 192.168.1.1 255.255.255.255 On-link 192.168.1.112，而不是通过网关 172.25.0.1。这是为什么你仍然可以访问本地的192.168.1.1，即使有一个低metric值的路由条目存在。  </p></blockquote><h2 id="与虚拟内网-Zerotier-局域网协同使用"><a href="#与虚拟内网-Zerotier-局域网协同使用" class="headerlink" title="与虚拟内网(Zerotier)&#x2F;局域网协同使用"></a>与虚拟内网(Zerotier)&#x2F;局域网协同使用</h2><p>研究完了 VPN 的逻辑，逻辑能力强的人就会发现一个问题：既然VPN的路由表优先级高于本地网络，那么本地内网的设备是不是会优先被路由去了学校里面，导致内网的设备无法访问吗？</p><p>是的，实际操作确实会出现无法访问本地网络设备的情况</p><p>理论上，我们可以通过修改路由表来解决这个问题，然而，我每次修改完貌似都不起作用<br>我尝试过输入<code>route delete 192.168.191.0 172.25.0.1</code>，但是貌似并没有什么用<br>经过一段时间尝试修改路由表，但是依然不生效，有可能是因为 Cisco Anyconnect 会不断覆盖我的路由表，导致了我无法修改，所以放弃了这个方案</p><p>但是，我偶尔又想到了另一条路子：为什么我非要使用 Cisco Anyconnect Client 来连校园 VPN 呢？</p><p>所以，我找到了另一个支持 Anyconnect 协议的开源平替：<a href="https://www.infradead.org/openconnect/">OpenConnect</a><br>单看这个界面，非常的老旧，还都是命令行，非常的难用，所以我又找到基于它的GUI版本：<a href="https://gui.openconnect-vpn.net/">OpenConnect-GUI</a></p><p>这有GUI就很简单啦，使用方法：</p><ol><li>下载好软件，安装</li><li>右上角 File -&gt; Profile -&gt; New Profile</li><li>把<code>v.uic.edu.cn</code>填入<code>Gateway</code>，点<code>Save</code>即可</li></ol><p>下次连接的时候，只需要点<code>Connect</code>，<code>Group</code>选<code>Student</code>，输入自己的账号密码和验证码即可</p><p>这下，我就可以通过 OpenConnect-GUI 来连接校园VPN，而不是 Cisco Anyconnect Client<br>并且，这个软件配置出来的路由表更加合理，不需要经过任何修改就可以实现局域网&#x2F;虚拟内网和校园网的协同使用</p><p>这是我在 OpenConnect-GUI 连接校园 VPN 之后的路由表</p><figure class="highlight text"><figcaption><span>route print</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">IPv4 Route Table</span><br><span class="line">===========================================================================</span><br><span class="line">Active Routes:</span><br><span class="line">Network Destination        Netmask          Gateway       Interface  Metric</span><br><span class="line">          0.0.0.0          0.0.0.0   25.255.255.254   192.168.191.95  10034</span><br><span class="line">          0.0.0.0          0.0.0.0      192.168.1.1    192.168.1.112     40</span><br><span class="line">          1.0.0.0        255.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">          2.0.0.0        255.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">          3.0.0.0        255.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">          4.0.0.0        255.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">          5.0.0.0        255.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">          6.0.0.0        255.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">          7.0.0.0        255.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">          8.0.0.0        248.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">         16.0.0.0        240.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">         32.0.0.0        224.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">         64.0.0.0        192.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">     116.6.50.238  255.255.255.255   25.255.255.254    192.168.1.112     41</span><br><span class="line">        127.0.0.0        255.0.0.0         On-link         127.0.0.1    331</span><br><span class="line">        127.0.0.1  255.255.255.255         On-link         127.0.0.1    331</span><br><span class="line">  127.255.255.255  255.255.255.255         On-link         127.0.0.1    331</span><br><span class="line">        128.0.0.0        192.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">       172.25.0.0    255.255.192.0         On-link     172.25.50.214    261</span><br><span class="line">    172.25.50.214  255.255.255.255         On-link     172.25.50.214    261</span><br><span class="line">    172.25.63.255  255.255.255.255         On-link     172.25.50.214    261</span><br><span class="line">        192.0.0.0        224.0.0.0    172.25.50.214    172.25.50.214      6</span><br><span class="line">      192.168.1.0    255.255.255.0         On-link     192.168.1.112    296</span><br><span class="line">    192.168.1.106  255.255.255.255      192.168.1.1    192.168.1.112     41</span><br><span class="line">    192.168.1.107  255.255.255.255      192.168.1.1    192.168.1.112     41</span><br><span class="line">    192.168.1.112  255.255.255.255         On-link     192.168.1.112    296</span><br><span class="line">    192.168.1.255  255.255.255.255         On-link     192.168.1.112    296</span><br><span class="line">     192.168.43.0    255.255.255.0   192.168.191.32   192.168.191.95    291</span><br><span class="line">    192.168.191.0    255.255.255.0         On-link    192.168.191.95    291</span><br><span class="line">   192.168.191.95  255.255.255.255         On-link    192.168.191.95    291</span><br><span class="line">  192.168.191.255  255.255.255.255         On-link    192.168.191.95    291</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link         127.0.0.1    331</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link    192.168.191.95    291</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link     192.168.1.112    296</span><br><span class="line">        224.0.0.0        240.0.0.0         On-link     172.25.50.214    261</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link         127.0.0.1    331</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link    192.168.191.95    291</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link     192.168.1.112    296</span><br><span class="line">  255.255.255.255  255.255.255.255         On-link     172.25.50.214    261</span><br><span class="line">===========================================================================</span><br><span class="line">Persistent Routes:</span><br><span class="line">  None</span><br></pre></td></tr></table></figure><p>显然合理多了，根据前面提到的“精确匹配原则”，本地的设备就可以正确匹配到本地的小局域网里，不会被大包围路由到学校 VPN 隧道里了</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>这篇文章，记录了我对 UIC 校园 VPN 的研究，以及与 Clash 和虚拟内网的协同使用</p><p>但是我并非专业人士，甚至都不是 FST 的学生，大部分内容都是从网上细碎的片段配合 GPT4o 的解释来理解的，所以文章中可能有错误，欢迎在评论区指正</p>]]></content>
    
    
    <summary type="html">本文包含了关于 UIC 的 Anyconnect VPN 与 Clash 协同使用，校园VPN基本逻辑，和虚拟内网(Zerotier)/局域网协同使用的研究</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
    <category term="UIC" scheme="https://haotian22.top/tags/UIC/"/>
    
  </entry>
  
  <entry>
    <title>PC远程控制软件小横评</title>
    <link href="https://haotian22.top/82a74aad.html"/>
    <id>https://haotian22.top/82a74aad.html</id>
    <published>2024-05-19T07:17:00.000Z</published>
    <updated>2026-04-12T07:17:00.000Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>现在，随着个人智能设备越来越多，各种设备之间的协同操作也变得越来越重要<br>细化到远程控制这一类，其实也有很多的需求，如：</p><ol><li>在外控制电脑办公</li><li>把移动设备在家当成电脑扩展屏</li><li>使用Pad用作电脑的画板</li></ol><p>这篇文章就以iPad和Windows 11的Laptop为例，重点以以上三个方面对比分析以下几款PC远程控制软件的使用体验</p><p>本次第一轮参与选手分别为：RDP(Microsoft)，Spacedesk，Moonlight(Sunshine)<br>（如果以后有机会的话可能会更新更多的参赛选手）</p><span id="more"></span><h2 id="RDP"><a href="#RDP" class="headerlink" title="RDP"></a>RDP</h2><p>纯粹的远程控制软件</p><p>RDP是微软自家的远程桌面协议，对于Windows来说兼容性比较好，而且Windows也自带了RDP服务，所以使用起来比较方便  </p><p>对触摸支持好，支持Apple Pencil压感，延迟还算可以<br><img src="https://s21.ax1x.com/2024/05/19/pkuqKbT.png" alt="Screenshot"><br>性能开销较小，看视频比较流畅，还可以调用移动设备的摄像头和麦克风，以及访问共享文件夹  </p><p>但是不能把它当扩展屏软件来使用  </p><h2 id="Spacedesk"><a href="#Spacedesk" class="headerlink" title="Spacedesk"></a>Spacedesk</h2><p>全面但低效的扩展屏软件<br>有多设备的支持，有原生触摸支持（但是相对应的不支持鼠标），支持Apple Pencil压感，可以通过直接连USB线来减小延迟，可以说是功能非常优秀的软件了<br><img src="https://s21.ax1x.com/2024/05/19/pkuqevq.png" alt="Screenshot"></p><p>在使用USB Cable连接的情况下，平时延迟在100ms左右，但是画面变动幅度大的时候延迟会上升到200ms<br>我估计是因为用了压缩算法导致的延迟不平均</p><p>但是性能很烂，一打开就占用20%的GPU，画面变动幅度大的时候更是能干到25%GPU和20%CPU，同时也因为编解码效率过低导致了延迟很高，同时，也因此导致两边都性能开销非常大，有些时候重度用下来几十分钟电脑和Pad都是烫的</p><h2 id="Moonlight"><a href="#Moonlight" class="headerlink" title="Moonlight"></a>Moonlight</h2><p>偏向于游戏的优化，虽然不能连接USB，但是纯网络的延迟也不是非常高</p><p>不支持原生触摸，导致操作其实很别扭（但是支持鼠标），支持Apple Pencil压感<br>不过在书写的时候，不知道因为什么原因，笔迹经常会传不过去断开，导致书写体验很差<br><img src="https://s21.ax1x.com/2024/05/19/pkuq8PJ.png" alt="Screenshot"><br>后面发现可以把iPad客户端设置为TouchPad模式解决笔迹断开的问题<br>性能开销主要在电脑上，另外因为没有压缩，其实GPU的消耗并不大，5%左右，CPU占30%左右，但是因为不用交给DWM处理（相比于Spacedesk来说），其实总体占用比Spacedesk低点<br>可以配置为不压缩，这样电脑占用基本没有了，延迟也是还算可以的水平</p><hr><p>2026年更新：</p><p>Moonlight 发展出了很多的第三方客户端，也变得好用起来了</p><p><a href="https://github.com/qiin2333/foundation-sunshine">Moonlight-foundation</a> 可以支持模拟虚拟屏幕，做到物理屏息屏远控和扩展屏的效果</p><p>iOS&#x2F;iPadOS 方面，<a href="https://github.com/The-Fried-Fish/VoidLink-previously-moonlight-zwm">Voidlink</a> 补全了原版 Moonlight 的许多缺陷，修复了 Apple Pencil 的笔迹输入的问题，支持了触控输入，并且在性能和易用性上也有了很大的提升，延迟也降低了很多</p><p>另外，如果需要出门在外连接电脑的话，需要自己搭建虚拟网环境，延迟直接取决于搭建的网络环境<br>我目前使用 Tailscale + Aliyun 中国内地 Peer-relay 中转的的方案，延迟大概在 40ms 左右，但是因为 Aliyun 99一年的 VPS 带宽只给到了 3Mbps，看视频&#x2F;玩游戏的时候画面会糊成一团</p><h2 id="网易UU远程"><a href="#网易UU远程" class="headerlink" title="网易UU远程"></a>网易UU远程</h2><p>这个应该是对于新手来说最好的软件了，不用复杂的配置，登录直接就能用，目前来说控制自己的电脑也是免费的</p><p>功能上，它也支持扩展屏和息屏串流的模式，支持触控输入（但是用起来没 Moonlight 第三方的版本那么好）<br>延迟方面，使用官方的免费中转延迟大概在 80ms 左右，但是码率给的挺高的，可以去到 10Mbps，跑 2k 的 iPad 屏幕基本什么没有什么问题</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;现在，随着个人智能设备越来越多，各种设备之间的协同操作也变得越来越重要&lt;br&gt;细化到远程控制这一类，其实也有很多的需求，如：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在外控制电脑办公&lt;/li&gt;
&lt;li&gt;把移动设备在家当成电脑扩展屏&lt;/li&gt;
&lt;li&gt;使用Pad用作电脑的画板&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这篇文章就以iPad和Windows 11的Laptop为例，重点以以上三个方面对比分析以下几款PC远程控制软件的使用体验&lt;/p&gt;
&lt;p&gt;本次第一轮参与选手分别为：RDP(Microsoft)，Spacedesk，Moonlight(Sunshine)&lt;br&gt;（如果以后有机会的话可能会更新更多的参赛选手）&lt;/p&gt;</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>Windows断网自动重连脚本</title>
    <link href="https://haotian22.top/4e4c225c.html"/>
    <id>https://haotian22.top/4e4c225c.html</id>
    <published>2024-05-18T18:07:18.000Z</published>
    <updated>2024-05-18T18:07:18.000Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>不知道为什么，我的Windows电脑经常用着用着，就断网了，具体表现为任务栏现实”No internet access”，实际上Ping内网设备都不通<br>很显然，连内网都有问题的，大概率是电脑&#x2F;Windows驱动的问题，而不是路由器的问题<br>而这个问题，其实也很好解决，把WiFi断开再连接一下就好了</p><p>然而，在我对于远程桌面依赖比较高的情况下，这个问题就比较棘手了——毕竟，断网了，远程桌面也就断了，我就得跑到电脑前去解决这个问题，严重影响了我的工作效率</p><h2 id="网络结果综述"><a href="#网络结果综述" class="headerlink" title="网络结果综述"></a>网络结果综述</h2><p>有人说，可能是电脑的<a href="https://www.zhihu.com/question/27914005/answer/2470199887">WiFi适配器驱动有问题</a>，需要换一个驱动</p><p>有人说，可能是<a href="https://www.zhihu.com/question/28422159">USB和WiFi产生干扰</a>，需要把USB设备和WiFi模块隔开比较远的距离</p><p>还有的人在捣鼓注册表，我根本都看不懂</p><p>这些方案中，有可能是有真正的解决问题的，但是断网这个问题的触发条件太过随机，我也不知道哪个方案是真正有效的，验证起来也毕竟花费时间</p><p>所以，我想到了一个简单的办法——写一个脚本，检测到断网的时候，自动断开WiFi再连接一下，先将就着用着，靠后面脚本的log再看看是什么原因导致的断网</p><h2 id="脚本编写"><a href="#脚本编写" class="headerlink" title="脚本编写"></a>脚本编写</h2><p>说实话，我对写bat真的一窍不通，所以以下部分都是把我的思路表述出来丢给LLM去写的，可能比较粗糙，但是能用就行</p><p><a href="https://github.com/HaoTian22/UIC-Utilities/blob/main/AutoRestartWIFI.bat">脚本在Github上的链接</a></p><p>如果还不懂怎么用这个脚本，可以看该仓库下的README</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>学期结束但是课程内容没完全掌握？来一键归档iSpace！</title>
    <link href="https://haotian22.top/f08b4725.html"/>
    <id>https://haotian22.top/f08b4725.html</id>
    <published>2024-04-30T13:04:52.000Z</published>
    <updated>2024-04-30T13:04:52.000Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>你是否有这样的困扰：学期结束了，但是课程内容还没有完全掌握，想以后从事习惯内容再看的时候找不到资料？</p><p>你是否有这样的烦恼：iSpace上的课程资料太多，想要下载的时候一个一个下载太麻烦？</p><p>你是否有这样的需求：想要将iSpace上的课程资料归档到自己的电脑上，方便查阅？</p><p>如果你有以上的困扰、烦恼和需求，那么这篇文章就是为你准备的！</p><p>本文将介绍两个方便快捷的Chrome插件，帮助你一键归档iSpace上的课程资料，让你的学习更加高效</p><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>iSpace是基于Moodle搭建的学习和课程管理平台,而Moodle,又是一个被广泛使用的开源软件,有不少人为此编写了各种插件</p><p>因此,大部分浏览器上适用于Moodle的插件也适用于iSpace</p><h2 id="软件介绍"><a href="#软件介绍" class="headerlink" title="软件介绍"></a>软件介绍</h2><h3 id="Moodle-Downloader"><a href="#Moodle-Downloader" class="headerlink" title="Moodle Downloader"></a>Moodle Downloader</h3><p>Moodle Downloader是一款Chrome插件,可以在<a href="https://chromewebstore.google.com/detail/moodle-downloader/egdkcpdcopinmhfphdmdagnpogclbpln">Chrome网上应用商店</a>下载</p><p>它的优点有:</p><ul><li>界面简洁,操作简单,上手容易</li><li>下载速度快</li></ul><h3 id="Moodle-Buddy"><a href="#Moodle-Buddy" class="headerlink" title="Moodle Buddy"></a>Moodle Buddy</h3><p>Moodle Buddy是一款Chrome插件,可以在<a href="https://chromewebstore.google.com/detail/moodle-buddy/nomahjpllnbcpbggnpiehiecfbjmcaeo">Chrome网上应用商店</a>下载</p><p>它的优点有:</p><ul><li>功能详细,可以挑选下载的文件,也可以自定义重命名</li></ul><p>但是也有缺点:</p><ul><li>下载某些视频会失败</li></ul><h3 id="Moodle-dl"><a href="#Moodle-dl" class="headerlink" title="Moodle-dl"></a>Moodle-dl</h3><p>Moodle-dl是一款Python脚本,可以在<a href="https://github.com/C0D3D3V/Moodle-DL">GitHub</a>按照上面的说明使用</p><p>但是这是一款命令行程序,不熟悉Python和命令行的同学可能不太容易上手</p><p>优点有:</p><ul><li>可以下载所有文件,包括视频(但是下载Quiz还是有点问题)</li><li>可以选择下载的文件类型(但是不能选择具体文件)</li><li>可以自定义课程重命名(文件夹重命名)</li></ul>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    
    <category term="UIC" scheme="https://haotian22.top/tags/UIC/"/>
    
  </entry>
  
  <entry>
    <title>Google Map澳门半岛渲染出错之探究</title>
    <link href="https://haotian22.top/78681fb.html"/>
    <id>https://haotian22.top/78681fb.html</id>
    <published>2024-03-04T11:30:07.000Z</published>
    <updated>2025-01-05T10:05:32.673Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>事情的起因是这样的……</p><p>近几天和同学去了一次澳门旅游，但是当我们去到大三巴牌坊附近的时候，因为小巷子比较多不会走，打开 Google Map 一看，整个地图就像是被炮弹炸过一样，变得零零碎碎，属于完全不可用的状态</p><img src="https://s11.ax1x.com/2024/03/04/pFDSrcR.jpg" style="width:20%;" alt="破碎地图截图"/><p>而且受到影响的位置不仅仅是大三巴附近，整个澳门半岛的西部都处于渲染错误的状态（但是导航和公交却是基本可用的，会在空白处描出一条线）</p><img src="https://s11.ax1x.com/2024/03/04/pFDpjZ6.jpg" style="width:20%;" alt="破碎地图完整截图"/><p>我们没有办法，只能关掉Google Map，使用其他地图软件来查看。</p><p>后面从澳门回来后，我越想越奇怪：明明我元旦去澳门的时候的地图是正常的啊，为什么这次会变得这么奇怪呢？</p><p>于是，我又把自己的遭遇和其他的网友探讨了一番，得出了一个初步的结论：Google Map 会根据不同地区渲染不同的地图</p><p>经过多次测试，我发现，Google Map 在 Android 手机上，第一个判断地区的方法是看SIM卡</p><p>我尝试了大陆单卡、香港单卡、双卡（大陆在SIM1，香港在SIM2）的情况，结果发现，无论使用什么网络，在大陆单卡或双卡的情况下（即使是开了飞行模式让该卡无信号），地图都会出现破碎的情况；而在使用香港卡的情况下，则会出现正常的地图</p><img src="https://s11.ax1x.com/2024/03/04/pFDpxIO.jpg" style="width:20%;" alt="正常地图截图"/><p>我们再进一步探究，其本质是两个地图之间渲染优先度和地图坐标系的问题</p><p>众所周知，因为一些<del>我也不知道他们在干什么的</del>原因，中国大陆公司制作的地图所使用的都是和国际惯例不同的坐标系，这就导致了地图不同程度的偏移</p><p>而 Google Map 在大陆使用的地图是向大陆公司购买的，遵循了大陆的特殊坐标系，导致了部分地区偏移到了澳门半岛内</p><p>又因为渲染优先性的原因，在使用大陆 SIM 卡时，会优先确保大陆地图的完整性，这使得部分澳门区域被大陆偏移的地图重叠覆盖</p><p>此外，我还发现，<strong>Google Map 的评论系统</strong>在上面提到的“非大陆 SIM 卡”情况下才能正常工作，否则则会弹出无法连接到地图的提示</p><p>而在无卡的情况下，有人推测，也可能会参考网络的IP地址和设备的区域设置，来决定是否使用的地图，但是我没有足够的经验去探究这个问题（<del>懒</del>）</p><p>所以，很显然，最快最简单的解决方法就是<strong>关闭&#x2F;移除大陆的 SIM 卡</strong>，这样就可以正常使用 Google Map 了</p><p>2025.1.5补充：除此之外，懂玩机的用户还可以试试这个使用 Shizuku 的<a href="https://github.com/Ackites/Nrfr">SIM 卡国家码修改工具</a>来改改SIM卡区域使得插上大陆卡正常工作，经过实际测试发现，双卡用户只需要把 SIM1 改成非大陆地区（我改的是香港），关闭 Google Map 后台再打开就可以正常工作了</p><p>Credits:<br>Cover - Generated by Paint Cocreator</p>]]></content>
    
    
    <summary type="html">这篇博客文章探讨了 Google 地图在澳门使用时出现的地图渲染问题。作者发现，在澳门半岛西部，特别是大三巴牌坊附近，Google 地图会出现碎片化、不可用的情况。经过测试，作者得出结论：**Google 地图会根据 SIM 卡地区进行不同的地图渲染。当使用中国大陆 SIM 卡时，即使使用其他网络，地图也会出现错误；而使用香港 SIM 卡时，地图则显示正常。**  文章进一步解释说，这是因为中国大陆使用的地图坐标系与国际标准不同，导致 Google 地图在大陆使用的地图发生偏移，并覆盖了部分澳门区域。同时，Google 地图会优先保证大陆地图的完整性，加剧了澳门地图的渲染问题。文章还指出，评论功能也受到 SIM 卡地区的影响。作者建议，**最简单的方法是移除或关闭大陆 SIM 卡以正常使用 Google 地图**，或者可以通过修改 SIM 卡国家码的方式来解决问题，这对于双卡用户尤为适用。</summary>
    
    
    
    
    <category term="生活" scheme="https://haotian22.top/tags/%E7%94%9F%E6%B4%BB/"/>
    
  </entry>
  
  <entry>
    <title>对于有限度维持中国大陆部分网络环境可访问性的说明</title>
    <link href="https://haotian22.top/252d8e01.html"/>
    <id>https://haotian22.top/252d8e01.html</id>
    <published>2023-10-02T18:33:52.316Z</published>
    <updated>2023-10-02T18:33:52.316Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>在中秋+国庆的长假中，由于未知原因，在2023.9.29起，使用 Vercel 搭建的网站遭到了中国移动的屏蔽（抢发 Reset），到了2023.10.1，更是遭到了中国移动、联通和少部分地区的电信的阻断</p><div align=center><img src="https://z1.ax1x.com/2023/10/03/pPLOtbV.png" style="zoom:5%;" /></div><p>我目前还只是一个学生，具体上面为什么要怎么做，我并不清楚，对于这种现象我也是无能为力<br>国内服务器的话，由于成本等原因，也暂时不考虑（现在这个站近乎开销为0）</p><p>就这样，我在2023.10.3看起来并没有将我站解封之后，运用了一下 Cloudflare 的反代，使得其勉强能够在中国大陆正常访问，但是同样的，经过了反代连接速度有可能会下降，请见谅</p><p><img src="https://z1.ax1x.com/2023/10/03/pPLOaUU.png" alt="CF反代.png"></p><p>至于以后怎么办，只能说能处理我就尽量处理，实在没办法的只能放弃掉中国大陆的访客，让他们自己想办法上来吧</p><p>给了我友联的朋友们发现我网站访问不了了也别以为我关站了，可能只是运营商在搞鬼而已，别把我删了啊</p>]]></content>
    
    
    <summary type="html">Vercel 搭建的网站在 2023.10 期间遭到了中国大陆运营商的部分屏蔽，由于成本问题可能导致一些地方读者无法访问该网站</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>将 AI 和 ics 文件结合的日程管理方式</title>
    <link href="https://haotian22.top/759a00b.html"/>
    <id>https://haotian22.top/759a00b.html</id>
    <published>2023-09-30T11:13:59.233Z</published>
    <updated>2023-09-30T11:13:59.233Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>近年来，随着 ChatGPT 等 LLM 的流行，各种较为简单的工作都可以交给他们，提高了我们的工作效率，在这里，我想分享一种 LLM 的妙用技巧：生成 ics 协助日程管理</p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>这个想法的起源可以追溯到几个星期前，几个星期前，我刚刚进入大学，不得不说，大学的生活和高中的完全不一样，这里没有了班主任去督促我该什么时间做什么，也没有了同班同学可以供我询问。</p><p>因此，只要信息量一大，我就经常容易忘掉事情，甚至将2个同一时间的活动都接了下来导致到时候会非常尴尬。</p><p>所以我就开始用手机上的日历来做日程管理，但是其实这样的方法并不是特别的好，我还要花起码1~2分钟的时间去编写日历，不小心看走眼还容易会写错时间和地点。就这样，我把目光转向了 ChatGPT。</p><p>用了 ChatGPT 之后，它确实能帮我总结和提取重要的信息点，但是新的问题又来了，我如何把它导入到手机日历里面呢？</p><p>我时候就在网上搜索了一会儿，找到了一个叫 <a href="https://icalendar.org/Home.html">iCalendar</a> 的标准，它可以兼容大部分设备，并且我也在 ChatGPT 里面试了一下，可以正常的生成，虽然过程中还是可能出现一些小错误导致时间不对等等，但是后面发现都是因为我的prompt不够详细的导致的。</p><p>因此，我改了又改，试了又试，做出了这篇文章的 prompt</p><h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h2><p>prompt 如下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">在接下来的对话中，我希望你可以根据我的聊天记录生成符合iCalendar File Format RFC 7986的文本，让我复制导入到outlook邮箱中，时区默认为上海，UID默认为10位数的随机字符串，默认设定提前一个小时提醒，其他内容的标准模板如下</span><br><span class="line">BEGIN:VCALENDAR</span><br><span class="line">VERSION:2.0</span><br><span class="line">PRODID:-//ZContent.net//Zap Calendar 1.0//EN</span><br><span class="line">METHOD:PUBLISH</span><br><span class="line">BEGIN:VEVENT</span><br><span class="line">SUMMARY:Abraham Lincoln</span><br><span class="line">UID:c7614cff-3549-4a00-9152-d25cc1fe077d</span><br><span class="line">STATUS:CONFIRMED</span><br><span class="line">DTSTART:20080212</span><br><span class="line">DTEND:20080213</span><br><span class="line">DTSTAMP:20150421T141403</span><br><span class="line">LOCATION:Hodgenville\, Kentucky</span><br><span class="line">DESCRIPTION:Born February 12\, 1809\nSixteenth President (1861-1865)\n\n\n</span><br><span class="line"> \nhttp://AmericanHistoryCalendar.com</span><br><span class="line">END:VEVENT</span><br><span class="line">END:VCALENDAR</span><br><span class="line">仅需生成需要导入的内容，无需生成其他附加说明</span><br></pre></td></tr></table></figure><p>将这个 prompt 输入 ChatGPT，再将各个信息渠道的日程安排全部丢进去，就会自动输出一个可以复制的文本，这时需要新建一个后缀为 ics 的文件，打开就可以直接导入了</p><p>值得注意的是，我这个 prompt 的时区被默认设置为上海。如果你不是在中国的话，你需要自己更改自己时区所在的城市，不然，你的时间设置就会混乱。</p><p>此外，有时候 ChatGPT 不能正确输出 UID 字段，UID 重复会导致先前同一个 UID 的日程被覆盖。因此，在复制之前，你还需要检查一下这个 UID 是不是非常眼熟，以确保 UID 的唯一性</p><p>当然，我的这个方法还有很多可以改进的地方，例如我现在需要手动把聊天记录导入 ChatGPT 才能使用，生成内容后，我也还得自己复制和粘贴。如果各位有什么更好的方法也可以在评论区提一下（尽量可以不用依赖 OpenAI API），希望能将这个方法再改进的更加方便一点吧。</p>]]></content>
    
    
    <summary type="html">使用 AI 生成 ics 文件来管理日程的一种 ChatGPT 妙用</summary>
    
    
    
    
    <category term="生活" scheme="https://haotian22.top/tags/%E7%94%9F%E6%B4%BB/"/>
    
  </entry>
  
  <entry>
    <title>反思：为什么要写博客</title>
    <link href="https://haotian22.top/1333aac3.html"/>
    <id>https://haotian22.top/1333aac3.html</id>
    <published>2023-09-27T06:48:45.680Z</published>
    <updated>2023-09-27T06:48:45.680Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><h2 id="前言：我与博客的经历"><a href="#前言：我与博客的经历" class="headerlink" title="前言：我与博客的经历"></a>前言：我与博客的经历</h2><h3 id="加入博客"><a href="#加入博客" class="headerlink" title="加入博客"></a>加入博客</h3><p>我加入博客的时候正值初三网课，因为看见 Minecraft 游戏群里面大多数人都有一个自己的博客，我闲着无聊，加上网上教程比较完善，便花了两天基本上搞出了一个博客。建博客的初心也非常简单，就是好玩。</p><h3 id="发展期-or-折腾期"><a href="#发展期-or-折腾期" class="headerlink" title="发展期 or 折腾期"></a>发展期 or 折腾期</h3><p>在搭建博客以后，这里就成为了我新手乱改 CSS 的训练场，我将原本的 yilia 主题大动干戈地修改，改了布局，改了界面，改了风格，但是又因为我没有理解原本主题的设计思路，只是按照自己的想法上手改，便改出了许多 bug，元素错位，JS 调用报错等都是常有的事情。但是，基本上我每次来折腾博客都能够玩的不亦乐乎，甚至玩到熬夜2点才睡。</p><h3 id="平静期-or-瓶颈期"><a href="#平静期-or-瓶颈期" class="headerlink" title="平静期 or 瓶颈期"></a>平静期 or 瓶颈期</h3><p>上高中后，因为上的是全宿舍的学校，我平时能用的就只有一台手机，也就只能在后台随便写写文章，基本上没有什么过多的精力去改动页面和其他内容。</p><p>不过，即使有些技术类文章虽然自认为写得不怎么样，但是浏览量却非常高，而一些生活类文章想了很久，却没多少人看</p><p>我也曾经想过要把部分日记脱敏后公开发上来，但是在尝试了几次，发现文章风格和全站的风格都不太搭，后面就没再继续了（可能以后会重启？）</p><p>虽然多的文章也就几百个阅读量，并不能实际给我带来什么利益，我当初也并不是因为想要流量而去建站的，但是这样的现象不禁让我思考：这个博客的到底是为了谁而服务？</p><h2 id="为什么我要写博客"><a href="#为什么我要写博客" class="headerlink" title="为什么我要写博客"></a>为什么我要写博客</h2><p>我可能和很多人的习惯都有些不同，从小学的时候开始，我就基本上有定期写日记的习惯，到2019年，我还把纸质日记变成了电子日记，更方便以后的查阅和储存。因此在我看来，在我博客上写记录生活类的文章，其充分性是有些不足的。毕竟在自己的日记里，就算胡说八道都没有人知道，更不用担心泄露隐私的问题，显然需要比在这里写更加自由的。况且除了一些真正关心我的朋友，几乎没有人会花费大量的时间去阅读我之前的经历……</p><p>那么，是服务他人吗？我觉得是又不完全是。显然现在网络上的博客，大多数都是以技术分享偏多，这类群体显然使用搜索引擎比较多的，遇到的问题可能也比较分散，所以博客能够被搜索到，而且有一定的浏览量，从这方面来说，建一个博客是非常合适的。</p><p>但是我也同时在思考，博客，还有没有其他的出路。在我看来生活分享类的文章，主要集中在知乎和小红书等平台，浏览的方式也大多数也是通过内容平台的算法推送，而不是用户主动发起的搜索。在这种状况下，内容分散的博客就比较难访问到，失去了它的优势。</p><p>当然，我希望能把我日记中的一部份内容搬到我的博客上，听听不同人的分析，听听不同人的看法，但是又担心会不会稀释掉首页进来的技术宅，使得整个博客风格都有点不伦不类</p><p><strong>那么……我写博客的意义何在？</strong></p><p>综合上面的思考，我认为，博客是突破信息茧房的一种方式，是对大数据和算法无声的对抗。在每个平台都用大数据了解用户习惯的2023年，读博客可以了解更多方面的知识，不被算法和权威左右。比如那些网络热点，可以提供一些主流媒体没有报道的角度，又比如一些放在内容平台容易被封号限流的内容，例如关于某些争议事件背后的法律研究。但是可惜的是，很多优质内容依然藏在搜索引擎之后，想要访问到他们还是有一定的难度。</p><p>博客，也是一种交朋友的方式。尽管在2023年，写博客的人相对于其他社交媒体的人数占比会越来越少，但是这也间接筛选了社交圈的品质。到如今还在写博客的人，至少可以表明他们有一定的耐心和恒心，也对自己和周围人的生活有一定的思考。</p><p>博客，也能让我培养学科总结的思维。我想，博客和日记最大的不同之处就在于日记几乎不会出现和学习相关的思维导图、对学科的见解等内容（除了语文和哲学？），虽然我现在还没开始这样做，但是我也了解到有不少让写博客都会在博客上总结自己的上课内容。在将来，我可能也会开始这样的尝试。</p>]]></content>
    
    
    <summary type="html">对我写博客的意义和本博客将来的规划的一些思考</summary>
    
    
    
    
    <category term="随笔" scheme="https://haotian22.top/tags/%E9%9A%8F%E7%AC%94/"/>
    
    <category term="思考" scheme="https://haotian22.top/tags/%E6%80%9D%E8%80%83/"/>
    
  </entry>
  
  <entry>
    <title>时隔两年，再度体验 Windows 11</title>
    <link href="https://haotian22.top/8d55ea46.html"/>
    <id>https://haotian22.top/8d55ea46.html</id>
    <published>2023-09-09T16:40:18.640Z</published>
    <updated>2023-09-09T16:40:18.640Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>Windows 11，作为微软新一代的操作系统，于2021年6月发布</p><p>作为一个喜欢体验新鲜事物的人，在同年的8月，便用我已经比较年迈的华硕 UX31E 通过替换文件强行升级体验到了这最新的操作系统 Windows 11 22000</p><p>而时隔2年的今天，因为这华硕 UX31E 的续航和性能其实已经大打折扣，基本上只能跑办公的 Office 全家桶和浏览网页，因此我又拿到了家人换下来的 Dell XPS 13，作为我大学时期使用的电脑</p><p>这台电脑的配置如下：</p><ul><li>i7-5500U</li><li>8G DDR3 1600MHz</li><li>SAMSUNG SSD PM851 M.2</li></ul><p>而作为一个已经用惯了 Windows 11 的人，没了很多 Windows 11 独有的 Features，其实是用不太惯的，比如快捷控制中心的蓝牙连接，滚轮音量调节，资源管理器的多标签页…</p><p>所以，我想来想去，还是把这台电脑升级了 Windows 11</p><p>说起来，这个决定还是挺冒险的，毕竟这台电脑的官方支持是没支持 Windows 11 的，虽然他们的内核都是NT 10，其他部分的改动也不算太大，理论上很难会出现兼容性问题，不过，这可是我大学期间的主力电脑啊</p><p>如果说两年前尝试 Windows 11 是冒险者般的不顾一切的探索和开拓，那么两年后的这次尝试 Windows 11，则多了一份普通消费者的挑剔与衡量</p><p>为了测试这 Windows 11 是否真的能够成为我的主力系统，我在这次做了一下比较严谨的对比</p><h2 id="续航"><a href="#续航" class="headerlink" title="续航"></a>续航</h2><p>我首先测试的是电池续航，这也是一台笔记本是否能够被带出去的重要考量指标，在我使用 Windows 10 的期间，我大概可以完整耗尽电量的使用时长是8h（打字、浏览网页）。</p><p>到了 Windows 11，我实测看了2.5小时的视频耗电量为46%（因为测视频比较快），这续航和 Windows 10 相比较，最终差距基本仅有半小时左右，还算符合我的预期</p><h2 id="内存"><a href="#内存" class="headerlink" title="内存"></a>内存</h2><p>然后是内存占用情况，毕竟内存不够，系统默认会大量 swap 到硬盘，严重拖慢了系统运行速度，大部分旧机型的性能瓶颈也是在内存</p><p>实测下来，刚开机的时候，内存占用率是完全一样的，意味着差异仅约为10MB</p><p>但是随着系统各项服务和程序的自启动，两个系统的占用还是出现了一些差距：Windows 11 的小部件和 Windows Defender 总共会比 Windows 10 占用多出150MB左右，其实也还算是在可接受范围内吧</p><p>至于后续的优化，其实也并不是特别难，安装一个<code>能源之星X</code>，再在组策略里面禁用掉一堆的收集数据服务和小组件，占用就基本上和 Windows 10 一样了</p><h2 id="噪音"><a href="#噪音" class="headerlink" title="噪音"></a>噪音</h2><p>这个方面是我在之前从未想到过的，毕竟我平时在房间里就一个人基本上还会带上耳机，所以对噪音并不敏感</p><p>我到了大学我宿舍里面并不只有我一个人，过大的噪音，会打扰到同学的休息学习</p><p>在我对比后发现，Windows 11 在这方面对强行升级上来的老机型优化并不友好，即使 CPU 的占用率仅有7%，已经长时间没运行高负载的应用，手摸着电脑也不烫的情况下，风扇依然会以中等转速运转，和 Windows 10 中以低速运转甚至直接关闭风扇的调度策略截然不同。</p><p>正当我有点忍无可忍，准备想按下“回退到 Windows 10”的按钮时，我突然想到，既然我有这个问题，其他人也一定会有人同样受到这个问题的折磨，是我便上网搜索了一下，抢了一个其他的官方支持 Windows 11 的同品牌相似机型的驱动，强行打了上去，果然效果好多了</p><p>虽然最终的效果没有 Windows 10 那样过了1～2分钟就降速来得那么舒服（起码要5分钟），但是最起码的还是能把风扇速度降下来了，不会过于打扰到舍友了</p><hr><p>嗯，想完这么多，其实，只要肯研究，Windows 11 现存的问题还是大部分可以解决的，我也觉得暂时保留着这个 Windows 11 系统了（除非几天后真的发现了更加恶性的问题）</p>]]></content>
    
    
    <summary type="html">在2021年首次体验那个并不完善的 Windows 11 的两年后的今天，再度把 Windows 11 当作主力机的系统，会是什么感受呢？</summary>
    
    
    
    
    <category term="随笔" scheme="https://haotian22.top/tags/%E9%9A%8F%E7%AC%94/"/>
    
  </entry>
  
  <entry>
    <title>真正的生产力：iPad的Drawthings</title>
    <link href="https://haotian22.top/7dd8f297.html"/>
    <id>https://haotian22.top/7dd8f297.html</id>
    <published>2023-08-30T04:25:44.615Z</published>
    <updated>2023-08-30T04:25:44.615Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>这件事还要从我拿到 iPad 但是还没开学的时候说起……</p><h2 id="初见-Drawthings"><a href="#初见-Drawthings" class="headerlink" title="初见 Drawthings"></a>初见 Drawthings</h2><p>近期因为上大学，家里给我准备了一台 iPad Air ，在还没开学的日子里，我就一直在思考：iPad 除了电子笔记之外还能有什么生产力的应用场景？</p><p>于是我便上 v2ex（一个技术交流论坛）上搜寻了许多关于 Ipad 如何用来提高生产力的相关文章，便看到了这个软件</p><p>我兴高采烈地把它从 App Store 下载了下来（应该不限账号区域的），因为我使用的电脑显卡并不算强，内存也不太够，所以从 Stable Diffusion 发布至今，我都还没有在自己的设备上尝试过本地跑图，对下载模型、模型之间的区别等等知识很多也只是一知半解</p><p>一打开软件，映入眼帘的就是一大堆模型的下载页面，有原版的  Stable Diffusion 1.x 2.x XL，也有热门的第三方模型，例如专画二次元的 Anything V3，下载完成就能像类似SD webui那样输入参数来画图了</p><p>Drawthings，利用的是苹果的 CoreML 功能，能调用专门的AI芯片来处理图片，因此即使在移动设备是出图的速度也能接受（512*768的 Anything V3 大概需要30s一张）</p><p>另外还是建议在充着电的时候再开始跑图，画图耗电量挺大的，一张图就能消耗掉1%-2%的电量</p><h2 id="深入使用"><a href="#深入使用" class="headerlink" title="深入使用"></a>深入使用</h2><p>在经过一段时间的使用后，我大概学习到了第三方模型、LORA、Embedded 提示词等用法</p><p>不过需要注意的是，在 Drawthings 上用来画图的模型与原版 SD webui 使用的模型并不完全相同，第三方模型导入后还得经过一次转换变成苹果 CoreML 专用的模型</p><p>由此，就诞生出了模型不兼容的问题</p><p>有些模型，在导入后，出图的效果十分模糊，512px的图片糊的像256px，连加上放大器没有明显改进，我测过有这种情况的模型有：Anything V5&#x2F;ink，AOM3A3，AOM3A2</p><p>以上的模型最好还是不要在 Drawthings 中使用</p><p>另外，因为转了一次模型，储存空间的占用增大也很明显，我明明只导入了10G左右的模型，占用却来到了17G（不包含导入前的原文件），各位需要预留足厚的储存空间</p>]]></content>
    
    
    <summary type="html">iPad使用Drawthings来本地生成AI图片的初体验</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>BUNB(UIC)二期校园联通宽带的安装及自动登录脚本 </title>
    <link href="https://haotian22.top/2b36786b.html"/>
    <id>https://haotian22.top/2b36786b.html</id>
    <published>2023-08-28T01:10:59.560Z</published>
    <updated>2023-08-28T01:10:59.560Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>这篇  Blog 讲述了我大一入学 UIC 时候买宿舍宽带时候踩的一些坑，及后续为了保持为了连接写宽带自动登录脚本的一些研究</p><p>作为一个大学生，在宿舍上网是一件非常平常的事情，而又因为移动网络的不稳定性，其实我没有把握它能够在高峰期一直以比较符合心意的速度发送喝接收数据，因此一条相对而言比较稳定的宽带就成了大学上网的首选</p><p>恰好，UIC 的 T5 和二期 D3 附近都有三大运营商在摆摊销售校园专属套餐，于是我便凑上去看了一下……</p><h2 id="混乱的信息"><a href="#混乱的信息" class="headerlink" title="混乱的信息"></a>混乱的信息</h2><p>在我了解信息的过程中，三大运营商都有人跟我说二期的一条宽带只能连接三个设备，让我们多办一条，虽然在这个智能穿戴设备丰富的年代，拥有超过三个智能设备的人应该不在少数，因此我一开始就在怀疑它的真实性</p><p>不过这个信息对我宽带的选购其实影响还挺大的，它触及到了我的核心问题：到底要办多少个的问题</p><p>但作为一个爱折腾的人，我当然要想研究一下，这背后的原理到底是什么？看有没有办法解决啦</p><p>不过可惜的是，因为刚刚开学还并没有很多人办理了宽带，有些办了的同学也没有说出具体的操作流程让我去判断，所以我并没有方法去实际测试</p><p>就算问运营商的工作人员，他们很多也不愿意说<del>（会影响销量，谁干啊）</del>，即使有些说了的感觉说法也不一样，导致我没有足够的信息判断</p><p>此时，我已经做好了最坏的打算：花上半天自行学习路由器刷写 Openwrt 并自行编写相关的插件</p><h2 id="疯狂的打折"><a href="#疯狂的打折" class="headerlink" title="疯狂的打折"></a>疯狂的打折</h2><p>在我刚到学校的那一天，三个运营商宽带的价格其实是不一样的，电信是 570 ，联通和移动是 720 一年（300M带宽）</p><p>而到了第 2 天，移动改成了 520 ，联通说 720 还能送一个路由器（大概市场价就70左右）或者再送一个套餐</p><p>来到了第 3 天，联通甚至变成了 360 一个套餐，还加上送路由器</p><p>经过以上比较之后，我最终选择了买联通的宽带，理论上套餐包含 300M 下行宽带，手机卡流量 200G 区域、40G 定向、30G 通用（反正都用不完），送了个小米 R4CM 路由器，看起来在买宽带这件事情上，真的会早买早吃亏啊</p><img src="https://s1.ax1x.com/2023/09/10/pPcWEHx.jpg" style="zoom:20%;" alt="到手的流量"/><img src="/img/post/1724426250354.jpg" style="zoom:20%;" alt="到手的套餐"/><p>另外再补充下，经过我并不严谨的调查，其实运营商送的这个小米 R4CM 只是无线速率能到 300M，WAN 口速率应该并不能达到 300M，实际测试下来也只能到 100M 左右，建议办理了 300M 宽带的同学自己买个 200 价位左右的千兆路由器，才有更好的上网速度</p><img src="https://s1.ax1x.com/2023/09/10/pPcWAD1.jpg" style="zoom:30%;" alt="实测网速"/><p>后面换了个 Tplink 的 AX3000，下载能跑满 300M 了，但是上传依然也只有 30M 左右，可能是上下行不对等吧</p><h2 id="忙碌的安装师傅"><a href="#忙碌的安装师傅" class="headerlink" title="忙碌的安装师傅"></a>忙碌的安装师傅</h2><p>在最后一天经过这么多的打折之后，买宽带的人明显增多了很多，我等到了第二天，安装的师傅都还没有来，即使打电话也一直说在通话中</p><p>这时，我看到了联通客服朋友圈里发了个自主安装流程，于是就找舍友去楼下摊位嫖了根网线，自己安装起了宽带</p><div class="note warning flat"><p>我住的楼为 D5，其他楼（已知 D1 是用的 PPPoE 拨号）可能会有些许的差别，请酌情参考</p></div><p><img src="https://s1.ax1x.com/2023/09/03/pPDk6bV.jpg" alt="宽带接口"></p><p>事实上，安装的方式并不复杂，甚至不需要看他们给的安装教程（反而看了的会发现很多不一样的地方）</p><p>简单来说就是：</p><ol><li>插好路由器电源，网线接入 WAN 口（有的标为 Internet，或者高端的可以随便插自适应）</li><li>连接 WIFI 进入路由器后台，设置好名称和密码</li><li>上网模式调为 DHCP（或自动获取）</li><li>断开 WIFI 连接，再连上之后点击弹出的登录页面，登录UIC账号</li><li>再次断开 WIFI ，连上弹出第二种登录页面，输入宽带账号密码（一般为 vip+学号，密码可以在联通 APP 修改）</li></ol><p>经历这几个步骤，其实就能上网了</p><p>不过，不知道什么原因，我在半夜又被断了网，自己折腾了快半个小时还是发现会在登录页面报错 500，最后实在搞不懂去询问客服并给了个学号之后重复步骤4、5又可以上网了（我也不知道他后台配置了什么才恢复的）</p><h2 id="设备限制原理猜想"><a href="#设备限制原理猜想" class="headerlink" title="设备限制原理猜想"></a>设备限制原理猜想</h2><p>根据大家都反馈及自己的观察，我有了以下猜想</p><p>运营商给的教程，其实本来是<strong>希望</strong>把路由器当成一个 AP ，中继网线的信号，由楼层交换机使用 DHCP 进行每个设备的IP分配，并在设备端进行登录，限制登录数为3</p><p>但是网线插 WAN 再分局域网的用法，其实是大部分人最正常的安装方式，这样楼层交换机只会识别到路由器一个设备的 Mac 地址，并且只需要一次登录即可</p><p>看起来，运营商是专门用小众的偏门方法让不懂相关知识的同学们以为是真的有限制设备从而卖多点呢？⊙﹏⊙∥</p><p>另外，其实用一些特殊的路由器来<strong>虚拟多拨</strong>，甚至可以达到一个路由器获得 300M*3 的速度（当然用三个路由器开 3 个 WIFI，每个也都能达到 300M 的速度）</p><h2 id="自动化宽带登录脚本"><a href="#自动化宽带登录脚本" class="headerlink" title="自动化宽带登录脚本"></a>自动化宽带登录脚本</h2><p>据他们所说，以上步骤 4、5 的登录过期时间是 30 天，此后有可能需要手动重新登录</p><p>而作为大学生，平时课业也十分繁忙，至少有半天都会不在宿舍内，需要手动登录的话就非常麻烦，出去了没法登录还会给在宿舍的舍友造成困扰</p><p>因此，我打开浏览器 F12，稍微分析了下数据包（因为是 http 所以能直接读取），看见了以下流程</p><h3 id="第一部分：UIC登录"><a href="#第一部分：UIC登录" class="headerlink" title="第一部分：UIC登录"></a>第一部分：UIC登录</h3><p>Windows登录后会打开 <code>http://www.msftconnecttest.com/redirect</code>的页面，自动跳转到 <code>http://172.29.250.5:30004/byod/byodrs/login/defaultLogin</code>，以POST的方式发送了以下数据（为了保护隐私，部分信息已用*代替）,<strong>不同楼层IP可能会有所不同，需要自己修改下</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;userName&quot;</span><span class="punctuation">:</span> <span class="string">&quot;t33******3&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;userPassword&quot;</span><span class="punctuation">:</span> <span class="string">&quot;一个base64&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;serviceSuffixId&quot;</span><span class="punctuation">:</span> <span class="string">&quot;-1&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;dynamicPwdAuth&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;code&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;codeTime&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;validateCode&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;licenseCode&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;userGroupId&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;validationType&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;guestManagerId&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;shopIdE&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;wlannasid&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>我们需要修改的就是<strong>学号和密码（密码以 base64 编码发送）</strong>，发完这串，认证就基本上完成了，然后就进入了前文说的第5步</p><h3 id="第二部分：联通登录"><a href="#第二部分：联通登录" class="headerlink" title="第二部分：联通登录"></a>第二部分：联通登录</h3><div class="note green icon-padding flat"><i class="note-icon fa-solid fa-globe"></i><p>获取登录页面</p></div><p>在连接到一个新网络的时候，我们是什么也不知道的，根据系统默认的操作，会弹出登录框，点开便会在浏览器打开 <code>http://www.msftconnecttest.com/redirect</code><br>发送 GET 请求后就会得到 302 的回复，获得新的地址<br>在这里，我们可以看见新地址是 <code>http://portal.gd165.com/?wlanuserip=172.29.105.168&amp;wlanacname=&amp;basname=120.80.200.50&amp;ssid=uiczh.edu&amp;vlanid=ethtrunk/10:4001.0</code></p><p>向该地址发送 GET 请求，得到以下回复</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">HTML</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">base</span> <span class="attr">href</span>=<span class="string">&quot;http://portal.gd165.com:80/&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">title</span>&gt;</span>main<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;pragma&quot;</span> <span class="attr">content</span>=<span class="string">&quot;no-cache&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;cache-control&quot;</span> <span class="attr">content</span>=<span class="string">&quot;no-cache&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;expires&quot;</span> <span class="attr">content</span>=<span class="string">&quot;0&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;keywords&quot;</span> <span class="attr">content</span>=<span class="string">&quot;keyword1,keyword2,keyword3&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;description&quot;</span> <span class="attr">content</span>=<span class="string">&quot;This is my page&quot;</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">&lt;link rel=&quot;w&quot; type=&quot;text/css&quot; href=&quot;styles.css&quot;&gt;</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">function</span> <span class="title function_">getBasInfo</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">var</span> url = <span class="variable language_">window</span>.<span class="property">parent</span>.<span class="property">location</span>.<span class="property">href</span>;</span></span><br><span class="line"><span class="language-javascript">  <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;basPushUrl&quot;</span>).<span class="property">value</span> = url;</span></span><br><span class="line"><span class="language-javascript">  <span class="variable language_">document</span>.<span class="property">forms</span>[<span class="number">0</span>].<span class="title function_">submit</span>();</span></span><br><span class="line"><span class="language-javascript"> &#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">body</span> <span class="attr">onload</span>=<span class="string">&quot;getBasInfo()&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;http://portal.gd165.com:80/index.do&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;basPushUrl&quot;</span> <span class="attr">id</span>=<span class="string">&quot;basPushUrl&quot;</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;debugua&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;testmacauth&quot;</span> <span class="attr">value</span>=<span class="string">&quot;false&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>引导我们前往 <code>http://portal.gd165.com:80/index.do</code></p><p>接着可以观察到，浏览器以 POST 发送了以下内容到 <code>http://portal.gd165.com/index.do</code></p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">basPushUrl=http%3A%2F%2Fportal.gd165.com%2F%3Fwlanuserip%3D172.29.104.170%26wlanacname%3D%26basname%3D120.80.200.50%26ssid%3Duiczh.edu%26vlanid%3Dethtrunk%2F10%3A4001.0&amp;debugua=&amp;testmacauth=false</span><br></pre></td></tr></table></figure><p>此外值得一提的是，我尝试使用 Python 的 requests 模块去重现该操作，但是得到的结果都是500错误<br>后面我再研究了下，发现除了 POST 了数据之外，客户端还向服务器发送了如下 headers  </p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7</span><br><span class="line">Cache-Control: max-age=0</span><br><span class="line">Connection: keep-alive</span><br><span class="line">Content-Length: 195</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">DNT: 1</span><br><span class="line">Host: portal.gd165.com</span><br><span class="line">Origin: http://portal.gd165.com</span><br><span class="line">Referer: http://portal.gd165.com/?wlanuserip=172.29.105.168&amp;wlanacname=&amp;basname=120.80.200.50&amp;ssid=uiczh.edu&amp;vlanid=ethtrunk/10:4001.0</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69</span><br></pre></td></tr></table></figure><p>经过多次尝试，最终发现必要的 headers 为 <code>Content-Type</code> 和 <code>User-Agent</code></p><p>将上述 headers 加入脚本后便正常返回了200，解析后是一个 html 文件，内容如下</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">HTML</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;</span> <span class="string">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">base</span> <span class="attr">href</span>=<span class="string">&quot;http://portal.gd165.com:80/&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>联合国际学院<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;pragma&quot;</span> <span class="attr">content</span>=<span class="string">&quot;no-cache&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;cache-control&quot;</span> <span class="attr">content</span>=<span class="string">&quot;no-cache&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;expires&quot;</span> <span class="attr">content</span>=<span class="string">&quot;0&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;description&quot;</span> <span class="attr">content</span>=<span class="string">&quot;gd zhbsd wlan login&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">type</span>=<span class="string">&quot;text/css&quot;</span> <span class="attr">href</span>=<span class="string">&quot;/gd/zhbsd/css/common.css&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">type</span>=<span class="string">&quot;text/css&quot;</span> <span class="attr">href</span>=<span class="string">&quot;/gd/zhbsd/css/index.css&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span> <span class="attr">src</span>=<span class="string">&quot;/common/js/jquery.min.js&quot;</span> &gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span> <span class="attr">src</span>=<span class="string">&quot;/gd/zhbsd/js/login.js&quot;</span> &gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span> <span class="attr">src</span>=<span class="string">&quot;/gd/zhbsd/js/flexible.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;page flex-col justify-between&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;image-wrapper_1 flex-col&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">img</span></span></span><br><span class="line"><span class="tag">                <span class="attr">class</span>=<span class="string">&quot;image_1&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">referrerpolicy</span>=<span class="string">&quot;no-referrer&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">src</span>=<span class="string">&quot;/gd/zhbsd/img/SketchPng7906f93c7a579face959d64fa751a15cab98bc5b16741bf5dd27df658c565449.png&quot;</span></span></span><br><span class="line"><span class="tag">        /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;section_2 flex-col&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;text-wrapper_2 flex-col&quot;</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;text_5&quot;</span>&gt;</span></span><br><span class="line">            使用过程中如有疑问，请联系校网内网络运营商客服156 0286 3828（微信同号）</span><br><span class="line">          <span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">&quot;/login.do&quot;</span> <span class="attr">id</span>=<span class="string">&quot;loginform&quot;</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">  </span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;loginpage&quot;</span> <span class="attr">id</span>=<span class="string">&quot;loginpage&quot;</span> <span class="attr">value</span>=<span class="string">&quot;gd/zhbsd/login.jsp&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;onlinepage&quot;</span> <span class="attr">id</span>=<span class="string">&quot;onlinepage&quot;</span> <span class="attr">value</span>=<span class="string">&quot;gd/zhbsd/online.jsp&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;logoutpage&quot;</span> <span class="attr">id</span>=<span class="string">&quot;logoutpage&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;accountprefixname&quot;</span> <span class="attr">id</span>=<span class="string">&quot;accountprefixname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;accountsuffixname&quot;</span> <span class="attr">id</span>=<span class="string">&quot;accountsuffixname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;pagetype&quot;</span> <span class="attr">id</span>=<span class="string">&quot;pagetype&quot;</span> <span class="attr">value</span>=<span class="string">&quot;0&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;macauth&quot;</span> <span class="attr">id</span>=<span class="string">&quot;macauth&quot;</span> <span class="attr">value</span>=<span class="string">&quot;0&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;accountvalid&quot;</span> <span class="attr">id</span>=<span class="string">&quot;accountvalid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1800&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;customerId&quot;</span> <span class="attr">id</span>=<span class="string">&quot;customerId&quot;</span> <span class="attr">value</span>=<span class="string">&quot;001&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;customerName&quot;</span> <span class="attr">id</span>=<span class="string">&quot;customerName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;campus&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;basName&quot;</span> <span class="attr">id</span>=<span class="string">&quot;basName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;120.80.200.50&quot;</span> /&gt;</span> </span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;basPushUrl&quot;</span> <span class="attr">id</span>=<span class="string">&quot;basPushUrl&quot;</span> <span class="attr">value</span>=<span class="string">&quot;http://portal.gd165.com/?wlanuserip=172.29.104.170&amp;wlanacname=&amp;basname=120.80.200.50&amp;ssid=uiczh.edu&amp;vlanid=ethtrunk/10:4001.0&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;accountName&quot;</span> <span class="attr">id</span>=<span class="string">&quot;accountName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;sendSMS&quot;</span> <span class="attr">id</span>=<span class="string">&quot;sendSMS&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;attrName&quot;</span> <span class="attr">id</span>=<span class="string">&quot;attrName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;ssid&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;attrValue&quot;</span> <span class="attr">id</span>=<span class="string">&quot;attrValue&quot;</span> <span class="attr">value</span>=<span class="string">&quot;[uiczh.edu]&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;realmName&quot;</span> <span class="attr">id</span>=<span class="string">&quot;realmName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;fixedAccountPrefixName&quot;</span> <span class="attr">id</span>=<span class="string">&quot;fixedAccountPrefixName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;errormessage&quot;</span> <span class="attr">id</span>=<span class="string">&quot;errormessage&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;keepAliveTime&quot;</span> <span class="attr">id</span>=<span class="string">&quot;keepAliveTime&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;wlanuserip&quot;</span> <span class="attr">id</span>=<span class="string">&quot;wlanuserip&quot;</span> <span class="attr">value</span>=<span class="string">&quot;172.29.104.170&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;client_type&quot;</span> <span class="attr">id</span>=<span class="string">&quot;client_type&quot;</span> <span class="attr">value</span>=<span class="string">&quot;pz&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;basname&quot;</span> <span class="attr">id</span>=<span class="string">&quot;basname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;120.80.200.50&quot;</span> /&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;setUserOnline&quot;</span> <span class="attr">id</span>=<span class="string">&quot;setUserOnline&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span> /&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userOpenAddress&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userOpenAddress&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;accountType&quot;</span> <span class="attr">id</span>=<span class="string">&quot;accountType&quot;</span> <span class="attr">value</span>=<span class="string">&quot;&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;token&quot;</span> <span class="attr">id</span>=<span class="string">&quot;token&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1a616f38622f1cbd94d4d276f666c9aa&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">name</span>=<span class="string">&quot;checkbox&quot;</span> <span class="attr">id</span>=<span class="string">&quot;checkbox&quot;</span> <span class="attr">value</span>=<span class="string">&quot;0&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;section_1 flex-col&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;section_3 flex-row justify-between&quot;</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;text_1&quot;</span>&gt;</span>宽带账号<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;box_1 flex-col&quot;</span> <span class="attr">id</span>=<span class="string">&quot;username&quot;</span> <span class="attr">name</span>=<span class="string">&quot;username&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;section_4 flex-row justify-between&quot;</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;text_2&quot;</span>&gt;</span>密码登陆<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;password&quot;</span> <span class="attr">class</span>=<span class="string">&quot;group_1 flex-col&quot;</span> <span class="attr">id</span>=<span class="string">&quot;password&quot;</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;section_5 flex-row&quot;</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;errorbox&quot;</span> <span class="attr">class</span>=<span class="string">&quot;errorbox&quot;</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;errormsg&quot;</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;/gd/zhbsd/img/errorpng.png&quot;</span> /&gt;</span></span><br><span class="line">                            登录失败，请检查 用户名或密码</span><br><span class="line">                        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;section_6 flex-row&quot;</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;text-wrapper_1 flex-col&quot;</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;text_4&quot;</span> <span class="attr">onclick</span>=<span class="string">&quot;login()&quot;</span>&gt;</span>点击登陆<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>在这个文件中，我们可以看见我们在下一步要用到的 token<br>这样，我们第一步获取 token 就完成了</p><div class="note green icon-padding flat"><i class="note-icon fa-solid fa-user-plus"></i><p>发送登录信息</p></div><p>取其中的token，再次POST以下数据到 <code>http://portal.gd165.com/login.do</code> ，同样不要忘记了前面的 headers</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">loginpage=gd%2Fzhbsd%2Flogin.jsp&amp;onlinepage=gd%2Fzhbsd%2Fonline.jsp&amp;logoutpage=&amp;accountprefixname=&amp;accountsuffixname=&amp;pagetype=0&amp;macauth=0&amp;accountvalid=1800&amp;customerId=001&amp;customerName=campus&amp;basName=120.80.200.50&amp;basPushUrl=http%3A%2F%2Fportal.gd165.com%2F%3Fwlanuserip%3D172.29.104.170%26wlanacname%3D%26basname%3D120.80.200.50%26ssid%3Duiczh.edu%26vlanid%3Dethtrunk%2F10%3A4001.0&amp;accountName=&amp;sendSMS=&amp;attrName=ssid&amp;attrValue=%5Buiczh.edu%5D&amp;realmName=&amp;fixedAccountPrefixName=&amp;errormessage=&amp;keepAliveTime=&amp;wlanuserip=172.29.104.170&amp;client_type=pz&amp;basname=120.80.200.50&amp;setUserOnline=&amp;userOpenAddress=&amp;accountType=&amp;token=1a616f38622f1cbd94d4d276f666c9aa&amp;checkbox=0&amp;username=vip233******3&amp;password=Q********</span><br></pre></td></tr></table></figure><p>观察可得，我们需要修改的仅有以下内容:</p><ul><li>wlanuserip&#x3D;172.29.104.170 从路由器看</li><li>username&#x3D; “vip”+学号</li><li>token&#x3D;前面拿的</li><li>password&#x3D;宽带密码，自己营业厅查</li></ul><p>这样理论上就登录完成了</p><p>如果是人工浏览器登陆的话，应该还会重定向 (Redirect) 到<code>http://portal.gd165.com/gd/zhbsd/online.jsp</code>展示一个登录成功的信息，但是这对我们自动化登录就没有用了，可以忽略（如果想要调试脚本手动下线的话还是可以浏览器打开这个然后点下线按钮的）</p><p>对此，我写出的自动化脚本如下（仅针对联通，其他运营商前半部分应该能用，后半部分得自己改改）</p><iframe frameborder="0" scrolling="no" style="width:98%; height:2089px;" allow="clipboard-write" src="https://emgithub.com/iframe.html?target=https%3A%2F%2Fgithub.com%2FHaoTian22%2FUIC-Utilities%2Fblob%2Fmain%2FChinaUnion-broadband-Auth.py&style=github&type=code&showBorder=on&showLineNumbers=on&showFileMeta=on&showFullPath=on&showCopy=on"></iframe><p>如果看不见的话点<a href="https://github.com/HaoTian22/UIC-Utilities/blob/main/ChinaUnion-broadband-Auth.py">这里</a></p><p>当然，由于各种原因，我无法去反复测试，这仅仅只是一次抓包的结果，建议在动手前自己在抓包一次对比我的数据以确保无差异</p><h2 id="延申阅读-UIC的另类用法系列-“Life-Hack-of-UIC”-series"><a href="#延申阅读-UIC的另类用法系列-“Life-Hack-of-UIC”-series" class="headerlink" title="延申阅读 - UIC的另类用法系列 (“Life Hack of UIC” series)"></a>延申阅读 - UIC的另类用法系列 (“Life Hack of UIC” series)</h2><p><a href="https://blog.steven53.top/p/%E5%AE%81%E7%9B%BE%E4%BB%A4%E7%89%8Cdkey-token%E8%BD%AC%E6%8D%A2%E4%B8%BA%E6%A0%87%E5%87%86totp/">宁盾令牌自定义</a></p><p><a href="https://uichcc.com/timetable-to-bg/">课表导入日历</a></p>]]></content>
    
    
    <summary type="html">新生在BUNB(UIC)二期校园安装联通宽带的小记录及遇到的问题，与研究宽带自动登录脚本的过程</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
    <category term="UIC" scheme="https://haotian22.top/tags/UIC/"/>
    
  </entry>
  
  <entry>
    <title>Qin F21 Pro折腾日志</title>
    <link href="https://haotian22.top/792aaaef.html"/>
    <id>https://haotian22.top/792aaaef.html</id>
    <published>2023-08-18T00:10:44.656Z</published>
    <updated>2023-11-24T01:02:46.221Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>今年6月，为了高考而战的高中之旅终于走到了终点，这台为了躲避学校智能手机监管+限制我手机使用时间的多亲Qin F21 Pro也正式完成了它作为学生手机的历史使命，摇身一变成为了我的刷机练习备用机，踏上了不断折腾的新旅途……</p><h2 id="前期理论"><a href="#前期理论" class="headerlink" title="前期理论"></a>前期理论</h2><p>这台Qin F21 Pro搭载了联发科的低端处理器，出厂系统为阉割版的Android 11，采用vab分区，支持Project Treble，这意味着它具有很高的可玩性</p><p>几乎任何2022年以前的MTK处理器，都有一定的漏洞，可以通过COM口+MTKclient的方式解锁Bootloader和刷机，我使用的是mlgmxyys大佬基于MTKclient制作的<a href="https://forum.xda-developers.com/t/tools-mod-scripts-mlgmxyysds-qin-f21-pro-unlock-tool.4368277/">解锁脚本</a>，经过解锁过程中不断的插线拔线的几次尝试后，终于是把bootloader的成功解锁了（虽然说解锁过程中出现了一点意外导致备份文件没有生成，以后可能锁不回去了）</p><p>接下来，就是进Recovery了，这台机子因为没有音量键，和平常手机进入Recovery的方法并不相同，也顺便简单说明下</p><p>开机按住<strong>挂断键</strong>、左上角的<strong>Q键</strong>和左下角的*<strong>键</strong>，按住数好每7s左右就<strong>稍微松一下挂断键</strong>（不然长时间按挂断会导致强制重启），机子在经过Orange State阶段的时候也照样这样做，过了Orange State就能进入一个显示No command的界面，接着按住<strong>挂断键，再短按上键</strong>，就可以进入Recovery</p><p>另外刷写GSI时，因为super分区仅有4GB，因此<strong>只会用到A槽或者B槽</strong>，另一个槽基本上没有空间塞备用系统了，因此更新和刷写的时候都要小心下，别刷错槽了</p><h2 id="TWRP"><a href="#TWRP" class="headerlink" title="TWRP"></a>TWRP</h2><p>TWRP作为刷机工具中大有名气的Recovery，肯定受到了我第一时间的关注</p><p>但是可惜的是，因为Qin F21 Pro这机型总体来说还是比较小众，并没有多少开发者愿意适配TWRP</p><p>虽然网上也流传着一些第三方的TWRP，但是Bug多多，最严重的就是fastboot模式插上电脑不识别，导致无法在fastbootd里刷写system和调整分区大小</p><p>如果你不小心刷了这些有Bug的TWRP，你可以刷回<a href="https://haotian22.lanzoue.com/ilelC15p0wed">原厂boot</a>来解决</p><p>说到这里，顺带提下刷机的几种模式：SPtool（高通则为9008）、bootloader模式、fastbootd模式<br>这三种刷机的范围从大到小，前两种是刷写宏观的，最后一种是刷写微观的</p><div align=center><img src="https://s1.ax1x.com/2023/08/20/pP8z9IJ.png" width = 50% alt=fastbootd模式></div><div align=center><img src="https://s1.ax1x.com/2023/08/20/pP8zFR1.png" style="zoom:25%;" /><img src="https://s1.ax1x.com/2023/08/20/pP8zkxx.png" style="zoom:25%;" /><div class="img-alt is-center">bootloader模式</div></div><p>这句话当然很难理解，所以我这里给了两张图<br>可以明显看出来，bootloader模式和fastbootd模式可以操作的范围是不同的</p><p>因此我们只能在fastbootd模式中才可以刷写system分区</p><h2 id="Magisk"><a href="#Magisk" class="headerlink" title="Magisk"></a>Magisk</h2><p>这台F21Pro和其他机型安装Magisk的方式都差不多，可以使用mtkclient或则带userdebug的GSI进入adb自己提取Boot或者使用我前面提供的原厂Boot修补即可，接着就是熟知的进入bootloader然后 <code>fastboot flash boot_a xxx.img</code>（注意这里a还是b要自己判断下）</p><p>顺带介绍下mtkclient和GSI提取boot的使用方法</p><p><strong>mtkclient</strong></p><p>首先下载<a href="https://github.com/bkerler/mtkclient/releases/">软件</a>，根据github上的readme文件所示，输入 <code>python mtk r boot,vbmeta boot.img,vbmeta.img</code>即可<br>更多玩法请见<a href="https://github.com/bkerler/mtkclient">readme</a>所示</p><p><strong>userdebug-GSI</strong></p><p>事实上，有些GSI并不提供userdebug的版本，需要自己找找合适的GSI<br>此处的GSI也能通过DSU临时安装来获取boot</p><p>安装完成后，输入以下指令</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">adb shell</span><br><span class="line">su</span><br><span class="line">cd /dev/block/by-name/</span><br><span class="line">ls -l boot_a</span><br></pre></td></tr></table></figure><p>就会得到boot_a存在的位置<br>最后把这个位置复制下，输入</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dd if=&lt;前面给出的位置&gt; of=/sdcard/boot.img</span><br></pre></td></tr></table></figure><p>然后就能在sdcard目录下找到提取出来的boot了</p><h2 id="通用-Bug-及修复"><a href="#通用-Bug-及修复" class="headerlink" title="通用 Bug 及修复"></a>通用 Bug 及修复</h2><h3 id="键盘背光灯问题（关闭背光灯）"><a href="#键盘背光灯问题（关闭背光灯）" class="headerlink" title="键盘背光灯问题（关闭背光灯）"></a>键盘背光灯问题（关闭背光灯）</h3><p>以下代码通过adb或者root后的XposedEdge执行均可（开启就把0换成1）</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">echo 0 &gt; /sys/class/leds/mt6370_pmu_led1/brightness</span><br><span class="line">chmod 000 /sys/class/leds/mt6370_pmu_led1/brightness</span><br></pre></td></tr></table></figure><p>另外这里有一份调好了的XposedEdge<a href="https://haotian22.lanzoue.com/iZx1q15sa8ad">配置文件</a>，支持以下内容，可以自行根据需要下载</p><ul><li>双击Q键解锁</li><li>短按返回键返回，长按多任务试图</li><li>长按8和0调整音量</li><li>默认关闭键盘灯（需要开启root权限）</li></ul><h3 id="蓝牙问题"><a href="#蓝牙问题" class="headerlink" title="蓝牙问题"></a>蓝牙问题</h3><p>设置 - Phh Treble Settings - Misc feature - Use System Wide BT HAL</p><h3 id="Google-Play认证"><a href="#Google-Play认证" class="headerlink" title="Google Play认证"></a>Google Play认证</h3><p>在手机上安装 <code>DeviceID</code>或者 <code>Dev Check</code>，在软件中找到 <code>GMS服务框架ID</code>，复制并填入<a href="https://www.google.com/android/uncertified/">认证注册</a>页面的方框中（可能需要代理及自己的Google账号，理论上能注册100个）<br>过大概1h之后，在设置-应用中清除GMS框架的全部数据，再次打开应该就可以正常使用了</p><h3 id="GPS定位"><a href="#GPS定位" class="headerlink" title="GPS定位"></a>GPS定位</h3><p>说起来奇怪，我刷了不下3个GSI，每个GSI都将我的定位定到了东南亚，打开 GPS Test 发现一颗卫星也搜不到，看起来网络融合定位也失效了，目前还没找到修复的方法，希望大佬给点指导</p><p>emmm后面再看貌似又好了，其实什么也没动，奇怪……</p><div align=center><img src="https://s1.ax1x.com/2023/08/20/pP8tYMn.png" width = 50% alt=OpenStreetMap的定位></div><h3 id="T9键盘相关修复"><a href="#T9键盘相关修复" class="headerlink" title="T9键盘相关修复"></a>T9键盘相关修复</h3><p>T9键盘部分功能无法使用：桌面按下数字按键快速拨号</p><p>大部分 GSI 需要修改键盘映射来正确识别按键，可以尝试用 <code>system/usr/keylayout/Generic.kl</code>的原版文件替换掉 GSI 中同路径的文件（记得备份），注意需要将文件权限改为 644 才能正常读取（但是有些 GSI 的 &#x2F;system 分区是 read-only 的，那就没办法了）</p><p>如果没有原版镜像的可以<a href="https://haotian22.lanzoue.com/inyMO1fsm69c">这里</a>自取一份 <code>Generic.kl</code>的压缩包</p><p>大部分按键默认只能作为输入按钮，失去了原版系统中的特殊功能，但是所有按键均可以后期通过 XposedEdge 按键映射来恢复它本来有的功能，或自己添加新功能（见上面XposedEdge 部分）</p><h3 id="充电问题"><a href="#充电问题" class="headerlink" title="充电问题"></a>充电问题</h3><p>在充电状态下开机 GSI 会导致误识别为充电状态，导致电源管理策略错误耗电量激增</p><p>因此在开机前最好先把电源线拔出</p><h3 id="VoLTE"><a href="#VoLTE" class="headerlink" title="VoLTE"></a>VoLTE</h3><p>大部分 GSI 默认都是 VoLTE 不可用，可以尝试修复：<br>进入 Phh Treble Settings - IMS feature<br>点击 Install IMS APK for MediaTek R vender<br>打开下面两个开关  </p><p>好，这时候打开飞行模式再关闭一下，重新联网，VoLTE就能用了</p><p><strong>Bonus</strong></p><p>如果想要和 Box4magisk&#x2F;Box for Root 一起用的话，需要加相关的排除设置才能正常使用 VoLTE&#x2F;VoWiFi<br>需要的可以自行去相关 Repo 的 Issue 里面搜索，关键词 <code>vowifi</code> 和 <code>volte</code> 都搜一下应该能看见（有些在 Closed 的列表里，搜的时候选一下）</p><h2 id="系统测评"><a href="#系统测评" class="headerlink" title="系统测评"></a>系统测评</h2><p>既然想要折腾，就少不了刷写各种 GSI 系统了，每个系统都会有独特的体验，又因为是 GSI 是通用镜像没特殊适配，每个系统又都有自己独特的Bug</p><p>当然，在刷写之前，必备的理论知识也是不可少的，基本流程如下</p><div class="note warning flat"><p>为了新系统能够正常载入，以下命令的2、3行会<strong>清除系统所有用户数据</strong>，有需要请先备份</p></div><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">adb reboot fastboot</span><br><span class="line">fastboot erase userdata</span><br><span class="line">fastboot erase cache</span><br><span class="line">fastboot flash system xxxx.img</span><br><span class="line">fastboot reboot</span><br></pre></td></tr></table></figure><p>下面就来浏览各个系统，权衡利弊，选出自己心意的ROM吧</p><h3 id="Pixel-Experience"><a href="#Pixel-Experience" class="headerlink" title="Pixel Experience"></a>Pixel Experience</h3><p>相信每个搞机玩家，都对Pixel的类原生有一定的向往，它拥有 Pixel 手机上几乎所有的体验，包括Google助理、多任务视图提取文本等一众实用功能，非常吸引人</p><p>因为这台手机支持刷写GSI的原因，我选择了在Github下载<a href="https://github.com/ponces/treble_build_pe/releases/">PixelExperience_Plus_arm64-ab-slim-13.0-20230713-UNOFFICIAL.img.xz</a>（不选其他的是因为system可能不够大导致刷不进去，大概最大在3.6G左右）</p><p>然后就是fastboot一条龙</p><p>虽然PixelExperience的名头听起来很响，然而实际用起来，Bug还是不少的</p><p>大概有这些：</p><ul><li>无法设置锁屏密码（会导致不断软重启，需要清data恢复）</li><li>开机的Google logo无法显示</li><li>无法在“壁纸与样式”中更换本地壁纸</li><li>相机里不能直接打开相册</li><li>键盘灯默认无法关闭（已在通用 Bug 中说明）</li><li>T9键盘按键无法使用：（已在通用 Bug 中说明）</li></ul><p>神奇的是，Google logo 和壁纸的 Bug 在我之前使用 DSU 的相同包测试的时候是没有的，不知道是怎么弄成这样的，所以测试的时候最好还是直接刷了测试，免得 DSU 和实际表现不一致</p><p>总的来说，个人认为这个包是难以日用的</p><h3 id="ArrowOS"><a href="#ArrowOS" class="headerlink" title="ArrowOS"></a>ArrowOS</h3><p>ArrowOS，在外界大多数评价来看，是比较流畅和省电的系统，在F21Pro上也一样，从刷机到使用1天基本上很少出现掉帧卡顿的情况</p><p>我使用的是<a href="https://github.com/naz664/ArrowOS_gsi/releases">ArrowOS-13.1-arm64_bgN-Unofficial.img.xz</a>，后期也升级到了 <a href="https://github.com/naz664/ArrowOS_gsi/releases/download/v2023.10.28/ArrowOS-13.1-a64_bgN-slim-Unofficial.img.xz">v2023.10.28 的版本</a>，都可以正常使用</p><div align=center><img src="https://s1.ax1x.com/2023/08/20/pP8d7h8.png" width = 30% alt=ArrowOS的桌面></div><p>但是还是会有一些痛点：</p><ul><li>无法设置锁屏密码（会导致不断软重启，需要清data恢复）</li><li>默认桌面启动器、Google电话的部分UI缩放倍数有问题，导致一些文字会被图标遮挡或被裁掉1&#x2F;4（可以设置修改界面大小解决，但是其他软件按钮也会相应变小）</li><li>键盘灯默认无法开启（已在通用 Bug 中说明）</li><li>T9键盘按键无（已在通用 Bug 中说明）</li><li>VoLTE 默认失效（已在通用 Bug 中说明）</li></ul><p>相比与上面的PE，这个还算是能日用的</p><h3 id="exTHmUI"><a href="#exTHmUI" class="headerlink" title="exTHmUI"></a>exTHmUI</h3><p>使用的是酷安上一个大佬提供的<a href="https://rom.laoleic4-world.top/exod/%E9%9D%9E%E5%AE%98%E6%96%B9%E7%BC%96%E8%AF%91ROM/GSI%EF%BC%88%E5%BC%82%E5%B8%B8%E6%9D%82%E4%B9%B1%EF%BC%89/exTHmUI-11-AB-bvN-2.4GB-vndklite-Phh-Treble.7z?preview">exTHmUI-11-AB-bvN-2.4GB-vndklite-Phh-Treble.7z</a>，由朋友帮忙测试</p><p>这个包虽然说安卓11，但是有一个很大的优势：<strong>支持锁屏密码</strong></p><p>虽然说还是会有一定的Bug，但是相比起来还是算轻微了</p><ul><li>键盘灯默认无法关闭（已在通用 Bug 中说明）</li></ul><h3 id="Project-Elixir"><a href="#Project-Elixir" class="headerlink" title="Project Elixir"></a>Project Elixir</h3><p>使用的是<a href="https://www.pling.com/p/1960767/">ProjectElixir-3.10-arm64-bgN-13.0-20230805-1655-OFFICIAL.img.xz</a>，因为之前觉得ArrowOS挺好用，就留下来了，接下来用的都是DSU来测试，可能会有一点小的差别</p><p>然而，当我满怀信心装上DSU-Sideloader准备开测的时候……却发现它一启动就进fastboot，根本没办法进系统，看来这个系统是和我无缘了啊（有再想验证的朋友可以帮忙实机刷system给点反馈）</p><p>后面我又不死心，国庆假期又尝试了一下他们的最新版 <a href="https://www.pling.com/p/1960767/https%3A%2F%2Fprivate.projectelixiros.com%2Fthirteen%2Fgsi%2FProjectElixir_3.12_arm64_bgN-13.0-20230927-1740-OFFICIAL.img.xz">ProjectElixir-3.12-arm64-bgN-13.0-20230927-1740-OFFICIAL.img.xz</a>，出乎意料的是，竟然它能够正常启动了（但是后来证明，基本上就只有这一个版本是可以用的）。</p><p>那么，按照惯例，来测特性。Project Elixir的优点，我觉得可以分为三类：好看，好听，好用</p><p>先说<strong>好看</strong>，在众多类原生 ROM 当中，它给的自定义选项在目前测过的 ROM 里面是最多的了，桌面设置里面图标、搜索、甚至最近任务都能自定义，锁屏、状态栏、快捷菜单的自定义程度也是超高的。即使拿到手什么也不干，用默认的字体和默认的壁纸，我依然可以说它就是最好看的类原生系统。</p><p>然后来说说<strong>好听</strong>，在默认状态安装下，会自动打开点击和锁屏提示音，它没有用 AOSP 原本那种老掉牙的提示音，而是全部自己重制了一遍，让我听着就非常有质感。</p><p><strong>好用</strong>，在于众多堪比国产系统的本地化，什么国产系统的三指滑动截屏、游戏空间、应用多开、息屏手势、电池温度监控等全学过来了，对于用惯了国产系统的人来说应该是最合适的选择了。</p><p>因此，在这巨大的优势下，一些小 Bug 可能就显得没那么显眼了。在我的测试中，独有的小 Bug 貌似只有一个：<strong>无法显示开机动画</strong>，就只是在开机的时候会<strong>黑白闪烁</strong>有点辣眼睛而已。</p><p>其他的 Bug 也就这些，在同行衬托下算很好的系统了</p><ul><li>无法设置锁屏密码（会导致不断软重启，需要清data恢复）</li><li>键盘灯默认无法开启（已在通用 Bug 中说明）</li><li>T9按键问题（已在通用 Bug 中说明）</li><li>VoLTE 失效（中国联通测试，已在通用 Bug 中说明）</li></ul><div class="gallery-container" data-type="data" data-button="" data-limit="10" data-first="10">    <div class="gallery-items">[{"url":"https://z1.ax1x.com/2023/10/11/pPzyylT.png","alt":"","title":""},{"url":"https://z1.ax1x.com/2023/10/11/pPzyDf0.png","alt":"","title":""},{"url":"https://z1.ax1x.com/2023/10/11/pPzy66U.png","alt":"","title":""},{"url":"https://z1.ax1x.com/2023/10/11/pPzyspV.png","alt":"","title":""},{"url":"https://z1.ax1x.com/2023/10/11/pPzyjAA.png","alt":"","title":""},{"url":"https://z1.ax1x.com/2023/10/11/pPzyO7d.png","alt":"","title":""}]</div>  </div><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>这其实是我刷机之旅的第一站，此前我输入知道大致的刷机流程，但是因为手边只有一台红米的主力机，为了确保正常生活不被影响，一直不敢放开胆子去随便刷<br>另外，一上来就上手多亲这种小众的、没多少教程、没ROM适配的机型，全部自己摸索还是难度挺大的<br>所以，非常感谢酷安及多亲交流群中的各位大佬，虽然他们有时候会被我的新手胡乱的操作气疯，因为我一些必备知识缺少而感到无语，但是不管怎样，他们仍然是我入门刷机过程中非常重要的老师<br>其实，即使到现在，我依然还有很多概念没理解，比如什么底包、设备树、Super扩容……当然，我也会继续学习，把不懂的搞懂</p><p>最后，这台手机因为折腾的人比较少，我常常无法判断ROM中的Bug是我自己的偶发事件，还是本身就有的必然事件<br>如果有人愿意折腾且得到和我测试中不一样结果的，欢迎在下方评论区反馈，我将会不定时更新系统评测章节中的内容</p>]]></content>
    
    
    <summary type="html">多亲Qin F21 Pro的玩机日志</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>proxy-providers的使用详解</title>
    <link href="https://haotian22.top/bca01b6c.html"/>
    <id>https://haotian22.top/bca01b6c.html</id>
    <published>2023-04-01T08:31:15.000Z</published>
    <updated>2023-04-01T08:31:15.000Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><div class="note warning flat"><p>本文仅提供部份配置文件的参考指导，请勿用其来实施违反法律法规的行为，本人也不会在任何渠道提供网络相关的支持</p></div><h2 id="基本介绍"><a href="#基本介绍" class="headerlink" title="基本介绍"></a>基本介绍</h2><p>自从一款<mark class="hl-label default">以C开头的软件（下简称C软件）</mark>提供了虚拟网卡上网的功能后，它就变成了数十万网民必备的网络工具。<del>(这么说应该懂的都能懂了吧)</del><br>大多数人只会用由其衍生的众多GUI，选择直接导入网上购买的配置文件，但是却鲜少有人知道如何手动自定义<mark class="hl-label default">C软件</mark>，让其按照这里想要的方法运行。<br>下面，我就来介绍一下自定义该软件的一个重要步骤——配置proxy-providers。</p><p>proxy-providers可以看作是不同配置文件之间的桥梁，它可以引入甚至自动定时更新网上购买的配置文件中的服务器，但却又不引入其他配置，比如DNS之类的，给了其他部分我们自定义的机会。<br>并且最重要的是，它是C软件内核上就原生支持的一个功能，不用给每一个GUI都写一个单独的配置文件来支持各种独占的特性，可以说是一劳永逸了。<br>然而，这个功能却鲜少有GUI能够自动生成，基本上需要我们从头完全手动编写，而目前网上的教程也不是很详细，因此就来分享下我配置该功能时的一些经验。<br>在配置一下项目之前你需要首先编写配置文件中的其他部分，因为其他部分相对来说比较简单，在网上直接复制下来的也可以用所以我在这里就不提供了。另外也需要懂得yaml的相关语法，避免配置文件出错无法运行软件。</p><h2 id="引入配置"><a href="#引入配置" class="headerlink" title="引入配置"></a>引入配置</h2><p>好，废话说完了，我们直接开始吧<br>proxy-providers的基本格式如下：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">proxy-providers:</span></span><br><span class="line">  <span class="attr">Name:</span> <span class="comment">#组名</span></span><br><span class="line">    <span class="attr">type:</span> <span class="string">http</span> <span class="comment"># url订阅的方式</span></span><br><span class="line">    <span class="attr">path:</span> <span class="string">./profiles/Name.yml</span> <span class="comment"># 配置文件缓存的位置</span></span><br><span class="line">    <span class="attr">url:</span> <span class="string">https://example.com/</span> <span class="comment"># 网络上配置文件的位置</span></span><br><span class="line">    <span class="attr">interval:</span> <span class="number">172800</span> <span class="comment"># 自动更新时间</span></span><br><span class="line">    <span class="attr">health-check:</span> <span class="comment"># 健康检测，检测失败就不会在自动选择中用该组代理</span></span><br><span class="line">      <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">http://www.gstatic.com/generate_204</span></span><br><span class="line">      <span class="attr">interval:</span> <span class="number">3600</span> <span class="comment"># 检测间隔</span></span><br></pre></td></tr></table></figure><p>类似的，如果要引用多个网络配置，则在Name的同级再写一个Name2之类的，并把path中的Name也改成Name2，避免文件重复，例如：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">proxy-providers:</span></span><br><span class="line">  <span class="attr">Name:</span> <span class="comment">#组名</span></span><br><span class="line">    <span class="attr">type:</span> <span class="string">http</span> <span class="comment"># url订阅的方式</span></span><br><span class="line">    <span class="attr">path:</span> <span class="string">./profiles/Name.yml</span> <span class="comment"># 配置文件缓存的位置</span></span><br><span class="line">    <span class="attr">url:</span> <span class="string">https://example.com/</span> <span class="comment"># 网络上配置文件的位置</span></span><br><span class="line">    <span class="attr">interval:</span> <span class="number">172800</span> <span class="comment"># 自动更新时间</span></span><br><span class="line">    <span class="attr">health-check:</span> <span class="comment"># 健康检测，检测失败就不会在自动选择中用该组代理</span></span><br><span class="line">      <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">http://www.gstatic.com/generate_204</span></span><br><span class="line">      <span class="attr">interval:</span> <span class="number">3600</span> <span class="comment"># 检测间隔</span></span><br><span class="line">  <span class="attr">Name2:</span> <span class="comment">#组名2</span></span><br><span class="line">    <span class="attr">type:</span> <span class="string">http</span> <span class="comment"># url订阅的方式</span></span><br><span class="line">    <span class="attr">path:</span> <span class="string">./profiles/Name2.yml</span> <span class="comment"># 配置文件缓存的位置</span></span><br><span class="line">    <span class="attr">url:</span> <span class="string">https://example.com/</span> <span class="comment"># 网络上配置文件的位置</span></span><br><span class="line">    <span class="attr">interval:</span> <span class="number">172800</span> <span class="comment"># 自动更新时间</span></span><br><span class="line">    <span class="attr">health-check:</span> <span class="comment"># 健康检测，检测失败就不会在自动选择中用该组代理</span></span><br><span class="line">      <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">http://www.gstatic.com/generate_204</span></span><br><span class="line">      <span class="attr">interval:</span> <span class="number">3600</span> <span class="comment"># 检测间隔</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>至此，网络配置文件就引入完成了</p><h2 id="使用配置文件——分组"><a href="#使用配置文件——分组" class="headerlink" title="使用配置文件——分组"></a>使用配置文件——分组</h2><p>想要使用刚刚引入的(多个)网络上的配置文件，需要给他们分组，基本的组别<code>select</code>如下：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">proxy-groups:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Proxy</span></span><br><span class="line">  <span class="attr">type:</span> <span class="string">select</span></span><br><span class="line">  <span class="attr">proxies:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">A</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">B</span></span><br><span class="line">  <span class="attr">use:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">Name</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">Name2</span></span><br></pre></td></tr></table></figure><p>在这个示例中，出现了<code>proxies</code>和<code>use</code>这两个字段<br>按照原本的配置文件，<code>proxies</code>字段用来引入前面指定的单个节点，我们就可以在Proxy这个组里面选单个节点使用了<br>但是，我们因为用了 proxy-providers ，导致没有<code>proxies</code>，那么就需要使用到<code>use</code><br><code>use</code>就是指引入某个 proxy-providers 中的所有节点放在当前组，类似这样<br><img src="https://s1.ax1x.com/2023/04/01/ppWwgr6.png" alt="ppWwgr6.png"><br>而<code>proxies</code>则通常在此时用来“超链接”到其他的组别，比如我第二个组名叫<code>自动选择</code>，就会提供一个<code>自动选择</code>的按钮，类似这样<br><img src="https://s1.ax1x.com/2023/04/01/ppWwIGd.png" alt="img"><br>至于最后会使用到的是哪个节点，就最终看<code>自动选择</code>组中选择的项了<br>当然，<code>proxies</code>里面还可以填<code>DIRECT</code>或者<code>REJECT</code>这两个关键字，实现点一点就直连或者断网的效果</p><p>至于其他的组别类型，建议自行参考官方文档<br>按我的习惯，一般是将全部按钮放一个组，包含不同服务商的<code>自动选择</code>和<code>手动选择</code>按钮，不同服务商的服务器分开放几个组，每个服务商分别设一个<code>手动选择</code>和一个<code>自动选择</code>组，最后全部节点放一起来一个<code>故障转移</code>组</p><h2 id="分流规则"><a href="#分流规则" class="headerlink" title="分流规则"></a>分流规则</h2><p>个人认为<a href="https://github.com/Loyalsoldier/">这里</a>有有关的仓库，里面的说明已经足够详细，直接复制下来使用即可<br>认为还不够的话，可以参考官方文档来编写域名和IP等单个规则<br>需要注意的是写规则的时候，需要走代理的组名要根据你在前面分的组相吻合，不能无脑直接复制</p>]]></content>
    
    
    <summary type="html">这篇文章详细介绍了如何使用proxy-providers来配置，包括引入和使用配置文件，分组和分流规则</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>不要使用Cloudflare做无保护的反代</title>
    <link href="https://haotian22.top/8c2524cd.html"/>
    <id>https://haotian22.top/8c2524cd.html</id>
    <published>2022-12-09T14:37:02.000Z</published>
    <updated>2022-12-11T06:57:50.000Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>近期，我的Cloudflare账号因为做Onedrive的反向代理加速下载而被暂停，被暂停的理由是使用cf进行钓鱼网络欺诈。我花了几天，在不同的论坛上询问了许多的网友，才终于明白了我的账户到底发生了什么。</p><h2 id="开端"><a href="#开端" class="headerlink" title="开端"></a>开端</h2><p>自从2022年年初以来，我便搭建了Onemanager的网盘，并挂上了我的Micrsoft E5号，方便我在学校的时候能够通过学校电脑访问到我的文件。</p><p>但是众所周知，Onedrive在国内的下载速度一直非常一般。为了提速，我在网上找来了通用的Cloudflare Worker代码，为我的Sharepoint(Onedrive)设置了反向代理，通过cf来加速在中国大陆的下载速度。</p><p>2022年11月15日，我用来做反向代理的Cloudflare Worker收到了1.3k的请求，我本来以为这并不会发生什么，毕竟他的免费用量有100k。<br><a href="https://imgse.com/i/zRcS3R"><img src="https://s1.ax1x.com/2022/12/09/zRcS3R.md.jpg" alt="zRcS3R.md.jpg"></a></p><p>但是随即，我便收到了一封来自Netcraft的举报邮件，内容大意是说我的网站涉及钓鱼欺诈，Cloudflare也随即将我的账号暂停（禁止添加新域名，现有域名不影响）。<br><a href="https://imgse.com/i/zRc9jx"><img src="https://s1.ax1x.com/2022/12/09/zRc9jx.md.jpg" alt="zRc9jx.md.jpg"></a><a href="https://imgse.com/i/zRcpg1"><img src="https://s1.ax1x.com/2022/12/09/zRcpg1.md.jpg" alt="zRcpg1.md.jpg"></a></p><p>那时因为是在工作日，而我被封控在学校，用手机的时间较少，所以并没有特别在意。</p><h2 id="争论"><a href="#争论" class="headerlink" title="争论"></a>争论</h2><p>到了12月，我的联考结束了，我也有时间去处理这件事情。我向客服申诉了，我用Cloudflare是用来加速中国大陆的下载速度，主观上并没有欺骗任何人，拒绝承认我违反了他们的服务条款（事实上服务条款也没有禁止用作反代，只是禁止用于欺诈）。然而客服还是认定我涉及了网络欺诈钓鱼，违反了他们的条款，拒绝给我解封。<br><a href="https://imgse.com/i/zWwFXD"><img src="https://s1.ax1x.com/2022/12/09/zWwFXD.md.jpg" alt="zWwFXD.md.jpg"></a><br><a href="https://imgse.com/i/zfVJ5n"><img src="https://s1.ax1x.com/2022/12/10/zfVJ5n.md.jpg" alt="zfVJ5n.md.jpg"></a></p><p>对于一个没有付费的用户，我也不奢求他们会给我什么，也不指望他们能用领着工资的客服为我服务，只能自认倒霉。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>在本次事件发生之后，我询问了各种论坛上的网友。虽然遇到过这样情况的人不多，但是还是有几位热心网友回复了我的疑问。</p><p>首先就是欺诈的判定理由，根据网友们的分析和推测，认为是因为<strong>我的网站和原本的官网长得非常的相似</strong>导致被判定为仿冒官网。然而对于任何一个反代站点来说，所有的内容都是在源网站上获取，并不会改动任何的内容。因此和源网站相似，这一点是不可避免的。</p><p>那是否意味着，任何的反向代理都不能用Cloudflare托管了呢？倒也未必。因为举报我欺诈的公司并不位于中国，而我的加速的目标仅仅只是中国的下载速度。因此我们可以通过一个非常简单的方法：<code>限制地区访问</code>来解决这个问题。我们可以进入到我们自己域名的管理页面，找到 <code>安全性</code>选项，点击 <code>WAF</code>，便可以限制特定地区或者IP等的访问，不符合的地区可以全部封禁。这样即使我的使用量比较多，但因为他们的公司不在中国（应该总部在英国），他们也发现不了我的证据，从取证途径上避免了被举报。</p><p>再者，如果这个反代站点只是我们自己个人使用，我们可以添加Basic Auth来阻止其他人访问，代码如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 替换成你想镜像的站点</span></span><br><span class="line"><span class="keyword">const</span> upstream = <span class="string">&#x27;google.com&#x27;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 如果那个站点有专门的移动适配站点，否则保持和上面一致</span></span><br><span class="line"><span class="keyword">const</span> upstream_mobile = <span class="string">&#x27;m.google.com&#x27;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 密码访问</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">const</span> openAuth = <span class="literal">false</span></span><br><span class="line"><span class="keyword">const</span> username = <span class="string">&#x27;username&#x27;</span></span><br><span class="line"><span class="keyword">const</span> password = <span class="string">&#x27;password&#x27;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 你希望禁止哪些国家访问</span></span><br><span class="line"><span class="keyword">const</span> blocked_region = [<span class="string">&#x27;RU&#x27;</span>]</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 禁止自访问</span></span><br><span class="line"><span class="keyword">const</span> blocked_ip_address = [<span class="string">&#x27;0.0.0.0&#x27;</span>, <span class="string">&#x27;127.0.0.1&#x27;</span>]</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 替换成你想镜像的站点</span></span><br><span class="line"><span class="keyword">const</span> replace_dict = &#123;</span><br><span class="line">    <span class="string">&#x27;$upstream&#x27;</span>: <span class="string">&#x27;$custom_domain&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;//google.com&#x27;</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">unauthorized</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Unauthorized&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">headers</span>: &#123;</span><br><span class="line">      <span class="string">&#x27;WWW-Authenticate&#x27;</span>: <span class="string">&#x27;Basic realm=&quot;goindex&quot;&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>: <span class="string">&#x27;*&#x27;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">status</span>: <span class="number">401</span></span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">parseBasicAuth</span>(<span class="params">auth</span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="title function_">atob</span>(auth.<span class="title function_">split</span>(<span class="string">&#x27; &#x27;</span>).<span class="title function_">pop</span>()).<span class="title function_">split</span>(<span class="string">&#x27;:&#x27;</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">      <span class="keyword">return</span> [];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">doBasicAuth</span>(<span class="params">request</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> auth = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Authorization&#x27;</span>);</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">if</span> (!auth || !<span class="regexp">/^Basic [A-Za-z0-9._~+/-]+=*$/i</span>.<span class="title function_">test</span>(auth)) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">const</span> [user, pass] = <span class="title function_">parseBasicAuth</span>(auth);</span><br><span class="line">  <span class="keyword">return</span> user === username &amp;&amp; pass === password;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">fetchAndApply</span>(<span class="params">request</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (request.<span class="property">method</span> === <span class="string">&#x27;OPTIONS&#x27;</span>) <span class="comment">// allow preflight request</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;&#x27;</span>, &#123;</span><br><span class="line">      <span class="attr">status</span>: <span class="number">200</span>,</span><br><span class="line">      <span class="attr">headers</span>: &#123;</span><br><span class="line">        <span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>: <span class="string">&#x27;*&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;Access-Control-Allow-Headers&#x27;</span>: <span class="string">&#x27;*&#x27;</span>,</span><br><span class="line">        <span class="string">&#x27;Access-Control-Allow-Methods&#x27;</span>: <span class="string">&#x27;GET, POST, PUT, HEAD, OPTIONS&#x27;</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">if</span> (openAuth &amp;&amp; !<span class="title function_">doBasicAuth</span>(request)) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">unauthorized</span>();</span><br><span class="line">  &#125;</span><br><span class="line">    <span class="keyword">const</span> region = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;cf-ipcountry&#x27;</span>).<span class="title function_">toUpperCase</span>();</span><br><span class="line">    <span class="keyword">const</span> ip_address = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;cf-connecting-ip&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> user_agent = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;user-agent&#x27;</span>);</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">let</span> response = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">let</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(request.<span class="property">url</span>);</span><br><span class="line">    <span class="keyword">let</span> url_host = url.<span class="property">host</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (url.<span class="property">protocol</span> == <span class="string">&#x27;http:&#x27;</span>) &#123;</span><br><span class="line">        url.<span class="property">protocol</span> = <span class="string">&#x27;https:&#x27;</span></span><br><span class="line">        response = <span class="title class_">Response</span>.<span class="title function_">redirect</span>(url.<span class="property">href</span>);</span><br><span class="line">        <span class="keyword">return</span> response;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">await</span> <span class="title function_">device_status</span>(user_agent)) &#123;</span><br><span class="line">        upstream_domain = upstream</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        upstream_domain = upstream_mobile</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    url.<span class="property">host</span> = upstream_domain;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> (blocked_region.<span class="title function_">includes</span>(region)) &#123;</span><br><span class="line">        response = <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Access denied: WorkersProxy is not available in your region yet.&#x27;</span>, &#123;</span><br><span class="line">            <span class="attr">status</span>: <span class="number">403</span></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span>(blocked_ip_address.<span class="title function_">includes</span>(ip_address))&#123;</span><br><span class="line">        response = <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&#x27;Access denied: Your IP address is blocked by WorkersProxy.&#x27;</span>, &#123;</span><br><span class="line">            <span class="attr">status</span>: <span class="number">403</span></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125; <span class="keyword">else</span>&#123;</span><br><span class="line">        <span class="keyword">let</span> method = request.<span class="property">method</span>;</span><br><span class="line">        <span class="keyword">let</span> request_headers = request.<span class="property">headers</span>;</span><br><span class="line">        <span class="keyword">let</span> new_request_headers = <span class="keyword">new</span> <span class="title class_">Headers</span>(request_headers);</span><br><span class="line"> </span><br><span class="line">        new_request_headers.<span class="title function_">set</span>(<span class="string">&#x27;Host&#x27;</span>, upstream_domain);</span><br><span class="line">        new_request_headers.<span class="title function_">set</span>(<span class="string">&#x27;Referer&#x27;</span>, url.<span class="property">href</span>);</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">let</span> original_response = <span class="keyword">await</span> <span class="title function_">fetch</span>(url.<span class="property">href</span>, &#123;</span><br><span class="line">            <span class="attr">method</span>: method,</span><br><span class="line">            <span class="attr">headers</span>: new_request_headers</span><br><span class="line">        &#125;)</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">let</span> original_response_clone = original_response.<span class="title function_">clone</span>();</span><br><span class="line">        <span class="keyword">let</span> original_text = <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">let</span> response_headers = original_response.<span class="property">headers</span>;</span><br><span class="line">        <span class="keyword">let</span> new_response_headers = <span class="keyword">new</span> <span class="title class_">Headers</span>(response_headers);</span><br><span class="line">        <span class="keyword">let</span> status = original_response.<span class="property">status</span>;</span><br><span class="line"> </span><br><span class="line">        new_response_headers.<span class="title function_">set</span>(<span class="string">&#x27;access-control-allow-origin&#x27;</span>, <span class="string">&#x27;*&#x27;</span>);</span><br><span class="line">        new_response_headers.<span class="title function_">set</span>(<span class="string">&#x27;access-control-allow-credentials&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line">        new_response_headers.<span class="title function_">delete</span>(<span class="string">&#x27;content-security-policy&#x27;</span>);</span><br><span class="line">        new_response_headers.<span class="title function_">delete</span>(<span class="string">&#x27;content-security-policy-report-only&#x27;</span>);</span><br><span class="line">        new_response_headers.<span class="title function_">delete</span>(<span class="string">&#x27;clear-site-data&#x27;</span>);</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">const</span> content_type = new_response_headers.<span class="title function_">get</span>(<span class="string">&#x27;content-type&#x27;</span>);</span><br><span class="line">        <span class="keyword">if</span> (content_type.<span class="title function_">includes</span>(<span class="string">&#x27;text/html&#x27;</span>) &amp;&amp; content_type.<span class="title function_">includes</span>(<span class="string">&#x27;UTF-8&#x27;</span>)) &#123;</span><br><span class="line">            original_text = <span class="keyword">await</span> <span class="title function_">replace_response_text</span>(original_response_clone, upstream_domain, url_host);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            original_text = original_response_clone.<span class="property">body</span></span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        response = <span class="keyword">new</span> <span class="title class_">Response</span>(original_text, &#123;</span><br><span class="line">            status,</span><br><span class="line">            <span class="attr">headers</span>: new_response_headers</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> response;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="title function_">addEventListener</span>(<span class="string">&#x27;fetch&#x27;</span>, <span class="function"><span class="params">event</span> =&gt;</span> &#123;</span><br><span class="line">    event.<span class="title function_">respondWith</span>(<span class="title function_">fetchAndApply</span>(event.<span class="property">request</span>).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(err);</span><br><span class="line">      <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(err.<span class="property">stack</span>), &#123;</span><br><span class="line">        <span class="attr">status</span>: <span class="number">500</span>,</span><br><span class="line">        <span class="attr">headers</span>: &#123;</span><br><span class="line">          <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;));</span><br><span class="line">&#125;)</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">replace_response_text</span>(<span class="params">response, upstream_domain, host_name</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> text = <span class="keyword">await</span> response.<span class="title function_">text</span>()</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">var</span> i, j;</span><br><span class="line">    <span class="keyword">for</span> (i <span class="keyword">in</span> replace_dict) &#123;</span><br><span class="line">        j = replace_dict[i]</span><br><span class="line">        <span class="keyword">if</span> (i == <span class="string">&#x27;$upstream&#x27;</span>) &#123;</span><br><span class="line">            i = upstream_domain</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (i == <span class="string">&#x27;$custom_domain&#x27;</span>) &#123;</span><br><span class="line">            i = host_name</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">if</span> (j == <span class="string">&#x27;$upstream&#x27;</span>) &#123;</span><br><span class="line">            j = upstream_domain</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (j == <span class="string">&#x27;$custom_domain&#x27;</span>) &#123;</span><br><span class="line">            j = host_name</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">let</span> re = <span class="keyword">new</span> <span class="title class_">RegExp</span>(i, <span class="string">&#x27;g&#x27;</span>)</span><br><span class="line">        text = text.<span class="title function_">replace</span>(re, j);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> text;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">device_status</span> (<span class="params">user_agent_info</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> agents = [<span class="string">&quot;Android&quot;</span>, <span class="string">&quot;iPhone&quot;</span>, <span class="string">&quot;SymbianOS&quot;</span>, <span class="string">&quot;Windows Phone&quot;</span>, <span class="string">&quot;iPad&quot;</span>, <span class="string">&quot;iPod&quot;</span>];</span><br><span class="line">    <span class="keyword">var</span> flag = <span class="literal">true</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> v = <span class="number">0</span>; v &lt; agents.<span class="property">length</span>; v++) &#123; <span class="keyword">if</span> (user_agent_info.<span class="title function_">indexOf</span>(agents[v]) &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            flag = <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> flag;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>希望我的经历能给大家提个醒，意识到反向代理并不是能随便使用，希望大家不要再因此而造成cf账户使用限制。</p><h2 id="更多"><a href="#更多" class="headerlink" title="更多"></a>更多</h2><p>有群友报告，一个WordPress生成的Procces.zip也于近期遭到了Netcraft的举报，并且此用户在WAF设置了海外IP需要检验浏览器确保是真人访问的选项，目前被举报原因尚不明确。</p>]]></content>
    
    
    <summary type="html">用Cloudflare反代而导致账户被暂停？这里有比较详细的解析可供参考</summary>
    
    
    
    
    <category term="电脑" scheme="https://haotian22.top/tags/%E7%94%B5%E8%84%91/"/>
    
  </entry>
  
  <entry>
    <title>疫情这三年</title>
    <link href="https://haotian22.top/7f4b80c7.html"/>
    <id>https://haotian22.top/7f4b80c7.html</id>
    <published>2022-12-09T14:23:58.000Z</published>
    <updated>2022-12-11T08:59:48.000Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" class="aplayer-secondary-style-marker" href="/assets/css/APlayer.min.css"><script src="/assets/js/APlayer.min.js" class="aplayer-secondary-script-marker"></script><p>随着新冠病毒的传染率逐渐升高，致死率逐渐降低，各省各市原本的防疫政策已经收效甚微。疫情已经影响了中国持续三年，在这三年之内中国的经济受到重创，频繁的封控既增加了医护人员的工作量，也增加了市民的时间成本。于是近日，国家先是发布了“防疫二十条”，禁止大规模的影响市民正常生活，再发布了“防疫新十条”，逐步解除各省市防疫措施，把新冠当成一种普通的传染病来看待。大规模核酸取消了，封控区制度取消了，甚至连健康码也取消了，宣告着中国的疫情时代结束了。在老师宣布今后大概率不会再有统一的核酸检测的时候，我的心里还是稍微有一点感触的，既有对生活正常化开心，也有对未来新冠需要自己处理治疗的担忧。</p><p>回顾疫情这三年，2019年冬天，武汉爆发疫情时，我们有对未知疫情的恐慌，有对武汉市民的担忧，也有对相关工作人员瞒报感染病例的愤怒。到后来，各省医护人员连夜赶往武汉，支援武汉抗疫。我们对它的认识也从不会人传人、有限人传人，到确认人传人。这些信息令我们逐步相信这场疫情与我们的生活息息相关。而在武汉爆发疫情的半个月后，我所在的城市也作出了响应，推迟了上学的时间。那是我经历过的最长的寒假。当然，我在这寒假里并不是一无所获，我利用这难得的假期发展了我的兴趣，学会了很多关于电脑的各方面知识。随后，我们便开始了网课，这是疫情之下催生的新型上课形态，我们谁也没有经历过。我们慢慢的摸索，慢慢的适应。虽然不能与同学见面，无法交流学习心得，上课的学习效率也一直提不高，经常会被各种消息干扰。但无论怎么说，这确实是当时疫情形态下学习的唯一解决方法。</p><p>第二年春，全国疫情已经逐步得到控制，在连续14天没有新增的感染者后，我们初三年级率先返回了学校，统一做了一次核酸。还记得，那时的我，既有与许久未见的同学见面的兴奋，也有第一次做核酸的紧张，甚至在做完核酸后，我们同学还一起聚在一起，讨论做核酸的感受。另外，我经过近两个月的学习，已经许久没有到外面呼吸过新鲜的空气，头发已经长的能遮住眉毛，我趁机去剪了个头发，为正常生活的到来做准备。几天后，我们就返回了校园，不同的是，我们被要求一个班的人分开两个课室坐，课室之间用教室电脑的腾讯会议来连接。初三下学期，本来是中考冲刺的关键阶段。而这疫情的到来，虽然打乱了我们的学习计划，但同样也减轻了我的学习压力，让我不用每天为了做不完作业而烦恼，有了更多自主学习的时间，也让我本来高度紧张的心得以舒缓。初三下学期，我们是孤独的，我们因为要中考而成为最早回校的年级，也因中考延期而成为学校最后放暑假的年级。</p><p>2021年夏，疫情再次爆发，虽然新增感染最多的时候也只有近百个，但是政府采取了最严格的管理措施，不少行政区直接封区，禁止人员流动。我也因为家住芳村而被封控了一个月。这是我上高中以来的第一次网课，但是当时我所在的高中采用的是录播课的方案，效果可能并没有直播课那么理想，导致我在此期间学习到的很多知识都是一知半解的状态，比如数学中的概率统计和排列组合。坐在窗边，望着家对面高中门口一批批乘坐出租车穿过封控区，到达学校参加高考的学生，让我不禁想象我未来高考时的样子。这个暑假，我第一次接种了新冠疫苗，在奥体中心的疫苗接种点见到了两个多月未见的同学，这也让我第一次感觉到自己的健康有了保障。接种疫苗，对于我来说，不过就是在其后的两天内有些喉咙痛，需要疯狂喝水，其余并没有什么太大的感觉。</p><p>时间来到了2022年。这一年，便民核酸点迅速普及，各社区都构建起了“15&#x2F;30分钟核酸圈”，核酸似乎变得理所当然，成为了生活的一部分。也是在这一年，新冠的各种变种开始在中国出现，传染性逐渐增强，很多城市都防不胜防。夏天，上海出现了大规模的疫情，日增几千例。而秋冬全国各地都爆发了疫情，每日新增从几百到几千不等。这一年，也因为防控范围过大的原因，已经开始引起了人们的不满，各地都爆发了相关的抗议运动。而我，在夏天经历了又一轮的长达一个月的网课之后，近两个月被封在学校封闭管理，虽然每天都核酸都是阴性，但也一直没能回家。</p><p>疫情结束了，我们封闭已久的生活也即将解放了。疫情这三年，带走了不少人周游全球的梦想，带走了不少人的生计，带走了不少人的投资，甚至带走了不少人的生命。我对这些被影响的人民感到由衷地同情和理解。但疫情，也给我们带来了一些东西，带来了无接触行业的发展，给民众带来了对自身健康的关注，给政府带来了防止病毒大规模传播的实战经验，给企业带来了远程办公等多形式的办公方式。</p><p>疫情结束了，新生活也即将开始。我们歌颂在疫情期间无私付出的所有工作人员和志愿者，感恩疫情期间互帮互助的邻里和同学，缅怀被新冠夺取生命的人们，铭记这段紧张但又团结一心共同奋斗的特殊时期。疫情结束了，从今往后，我们要自己管理好自己的健康状态，保持良好的生活习惯，做自己健康的第一责任人。最后，祝愿大家都能在疫情结束的新生活里身体健康，万事如意，保重~</p>]]></content>
    
    
      
      
        
        
    <summary type="html"></summary>
        
      
    
    
    
    
    <category term="随笔" scheme="https://haotian22.top/tags/%E9%9A%8F%E7%AC%94/"/>
    
  </entry>
  
</feed>
