<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>搬砖日记</title>
    <link>https://www.banzhuanriji.com/</link>
    
    <image>
      <url>https://www.banzhuanriji.com/icon.ico</url>
      <title>搬砖日记</title>
      <link>https://www.banzhuanriji.com/</link>
    </image>
    
    <atom:link href="https://www.banzhuanriji.com/rss.xml" rel="self" type="application/rss+xml"/>
    
    <description>白天给代码写对象，深夜给自己写日记</description>
    <pubDate>Tue, 07 Apr 2026 10:31:48 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>一个简单的带统计的短链接Workers</title>
      <link>https://www.banzhuanriji.com/posts/short-link-workers/</link>
      <guid>https://www.banzhuanriji.com/posts/short-link-workers/</guid>
      <pubDate>Wed, 04 Feb 2026 08:32:47 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;今天配合 AI 写了一个简单的带统计的短链接中间页程序，部署在 Cloudflare Workers 上，配合 KV 存储实现。不仅能实现长链接转短链接，还能记录每一次点击的次数。&lt;/p&gt;
&lt;p&gt;简单的说，就是部署在Work</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>今天配合 AI 写了一个简单的带统计的短链接中间页程序，部署在 Cloudflare Workers 上，配合 KV 存储实现。不仅能实现长链接转短链接，还能记录每一次点击的次数。</p><p>简单的说，就是部署在Worker上的，通过KV储存链接和次数，每次访问都会刷新KV的短链接程序。用<code>pico.min.css</code>优化了一些样式的显示。并且做了简单的管理功能。</p><h3 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h3><pre><code class="hljs javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {  <span class="hljs-keyword">async</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-params">request, env, ctx</span>) {    <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> <span class="hljs-title function_">URL</span>(request.<span class="hljs-property">url</span>);    <span class="hljs-keyword">const</span> path = url.<span class="hljs-property">pathname</span>;    <span class="hljs-keyword">if</span> (path === <span class="hljs-string">'/admin'</span> || path.<span class="hljs-title function_">startsWith</span>(<span class="hljs-string">'/admin/'</span>)) {      <span class="hljs-keyword">return</span> <span class="hljs-title function_">handleAdmin</span>(request, env);    }    <span class="hljs-keyword">const</span> shortCode = path.<span class="hljs-title function_">slice</span>(<span class="hljs-number">1</span>);    <span class="hljs-keyword">if</span> (shortCode &amp;&amp; shortCode !== <span class="hljs-string">'favicon.ico'</span> &amp;&amp; shortCode !== <span class="hljs-string">''</span>) {      <span class="hljs-keyword">return</span> <span class="hljs-title function_">handleRedirect</span>(shortCode, env, ctx);    }    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Response</span>(<span class="hljs-string">'Short Link Service is Running.'</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">200</span> });  }};<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">handleRedirect</span>(<span class="hljs-params">shortCode, env, ctx</span>) {  <span class="hljs-keyword">const</span> key = <span class="hljs-string">`link:<span class="hljs-subst">${shortCode}</span>`</span>;  <span class="hljs-keyword">const</span> dataStr = <span class="hljs-keyword">await</span> env.<span class="hljs-property">SHORT_LINKS</span>.<span class="hljs-title function_">get</span>(key);    <span class="hljs-keyword">if</span> (!dataStr) {    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Response</span>(<span class="hljs-string">'链接不存在或已被删除'</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">404</span> });  }    <span class="hljs-keyword">const</span> data = <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">parse</span>(dataStr);    ctx.<span class="hljs-title function_">waitUntil</span>((<span class="hljs-title function_">async</span> () =&gt; {    data.<span class="hljs-property">visits</span> = (data.<span class="hljs-property">visits</span> || <span class="hljs-number">0</span>) + <span class="hljs-number">1</span>;    <span class="hljs-keyword">await</span> env.<span class="hljs-property">SHORT_LINKS</span>.<span class="hljs-title function_">put</span>(key, <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(data));  })());    <span class="hljs-keyword">return</span> <span class="hljs-title class_">Response</span>.<span class="hljs-title function_">redirect</span>(data.<span class="hljs-property">originalUrl</span>, <span class="hljs-number">302</span>);}<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">handleAdmin</span>(<span class="hljs-params">request, env</span>) {  <span class="hljs-keyword">const</span> auth = request.<span class="hljs-property">headers</span>.<span class="hljs-title function_">get</span>(<span class="hljs-string">'Authorization'</span>);  <span class="hljs-keyword">if</span> (!auth) {    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Response</span>(<span class="hljs-string">'Unauthorized'</span>, {       <span class="hljs-attr">status</span>: <span class="hljs-number">401</span>,       <span class="hljs-attr">headers</span>: { <span class="hljs-string">'WWW-Authenticate'</span>: <span class="hljs-string">'Basic realm="Admin"'</span> }     });  }  <span class="hljs-keyword">const</span> credentials = <span class="hljs-title function_">atob</span>(auth.<span class="hljs-title function_">slice</span>(<span class="hljs-number">6</span>)).<span class="hljs-title function_">split</span>(<span class="hljs-string">':'</span>);  <span class="hljs-keyword">if</span> (credentials[<span class="hljs-number">1</span>] !== env.<span class="hljs-property">ADMIN_PASSWORD</span>) {    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Response</span>(<span class="hljs-string">'密码错误'</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">403</span> });  }  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> <span class="hljs-title function_">URL</span>(request.<span class="hljs-property">url</span>);  <span class="hljs-keyword">if</span> (request.<span class="hljs-property">method</span> === <span class="hljs-string">'POST'</span> &amp;&amp; url.<span class="hljs-property">pathname</span> === <span class="hljs-string">'/admin/create'</span>) {    <span class="hljs-keyword">const</span> formData = <span class="hljs-keyword">await</span> request.<span class="hljs-title function_">formData</span>();    <span class="hljs-keyword">const</span> originalUrl = formData.<span class="hljs-title function_">get</span>(<span class="hljs-string">'originalUrl'</span>);    <span class="hljs-keyword">let</span> shortCode = formData.<span class="hljs-title function_">get</span>(<span class="hljs-string">'customCode'</span>) || <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>().<span class="hljs-title function_">toString</span>(<span class="hljs-number">36</span>).<span class="hljs-title function_">substring</span>(<span class="hljs-number">2</span>, <span class="hljs-number">8</span>);    <span class="hljs-keyword">if</span> (!originalUrl || !originalUrl.<span class="hljs-title function_">startsWith</span>(<span class="hljs-string">'http'</span>)) {      <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Response</span>(<span class="hljs-string">'URL 格式不正确'</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">400</span> });    }    <span class="hljs-keyword">await</span> env.<span class="hljs-property">SHORT_LINKS</span>.<span class="hljs-title function_">put</span>(<span class="hljs-string">`link:<span class="hljs-subst">${shortCode}</span>`</span>, <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({      originalUrl,      <span class="hljs-attr">visits</span>: <span class="hljs-number">0</span>,      <span class="hljs-attr">createdAt</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>().<span class="hljs-title function_">toLocaleString</span>(<span class="hljs-string">'zh-CN'</span>, { <span class="hljs-attr">timeZone</span>: <span class="hljs-string">'Asia/Shanghai'</span> })    }));        <span class="hljs-keyword">return</span> <span class="hljs-title class_">Response</span>.<span class="hljs-title function_">redirect</span>(<span class="hljs-string">`<span class="hljs-subst">${url.origin}</span>/admin`</span>, <span class="hljs-number">303</span>);  }  <span class="hljs-keyword">if</span> (url.<span class="hljs-property">pathname</span> === <span class="hljs-string">'/admin/delete'</span>) {    <span class="hljs-keyword">const</span> code = url.<span class="hljs-property">searchParams</span>.<span class="hljs-title function_">get</span>(<span class="hljs-string">'code'</span>);    <span class="hljs-keyword">if</span> (code) <span class="hljs-keyword">await</span> env.<span class="hljs-property">SHORT_LINKS</span>.<span class="hljs-title function_">delete</span>(<span class="hljs-string">`link:<span class="hljs-subst">${code}</span>`</span>);    <span class="hljs-keyword">return</span> <span class="hljs-title class_">Response</span>.<span class="hljs-title function_">redirect</span>(<span class="hljs-string">`<span class="hljs-subst">${url.origin}</span>/admin`</span>, <span class="hljs-number">303</span>);  }  <span class="hljs-keyword">const</span> list = <span class="hljs-keyword">await</span> env.<span class="hljs-property">SHORT_LINKS</span>.<span class="hljs-title function_">list</span>({ <span class="hljs-attr">prefix</span>: <span class="hljs-string">'link:'</span> });  <span class="hljs-keyword">const</span> links = [];  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> list.<span class="hljs-property">keys</span>) {    <span class="hljs-keyword">const</span> val = <span class="hljs-keyword">await</span> env.<span class="hljs-property">SHORT_LINKS</span>.<span class="hljs-title function_">get</span>(key.<span class="hljs-property">name</span>);    <span class="hljs-keyword">if</span> (val) {      <span class="hljs-keyword">const</span> data = <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">parse</span>(val);      links.<span class="hljs-title function_">push</span>({        <span class="hljs-attr">code</span>: key.<span class="hljs-property">name</span>.<span class="hljs-title function_">replace</span>(<span class="hljs-string">'link:'</span>, <span class="hljs-string">''</span>),        ...data      });    }  }  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Response</span>(<span class="hljs-title function_">renderAdminPage</span>(links), {    <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'text/html;charset=UTF-8'</span> }  });}<span class="hljs-keyword">function</span> <span class="hljs-title function_">renderAdminPage</span>(<span class="hljs-params">links</span>) {  <span class="hljs-keyword">const</span> rows = links.<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">link</span> =&gt;</span> <span class="hljs-string">`</span><span class="hljs-string">    &lt;tr&gt;</span><span class="hljs-string">      &lt;td&gt;&lt;a href="/<span class="hljs-subst">${link.code}</span>" target="_blank"&gt;/<span class="hljs-subst">${link.code}</span>&lt;/a&gt;&lt;/td&gt;</span><span class="hljs-string">      &lt;td style="word-break: break-all;"&gt;&lt;small&gt;<span class="hljs-subst">${link.originalUrl}</span>&lt;/small&gt;&lt;/td&gt;</span><span class="hljs-string">      &lt;td&gt;&lt;mark&gt;<span class="hljs-subst">${link.visits}</span>&lt;/mark&gt;&lt;/td&gt;</span><span class="hljs-string">      &lt;td&gt;&lt;small&gt;<span class="hljs-subst">${link.createdAt || <span class="hljs-string">'未知'</span>}</span>&lt;/small&gt;&lt;/td&gt;</span><span class="hljs-string">      &lt;td&gt;&lt;a href="/admin/delete?code=<span class="hljs-subst">${link.code}</span>" onclick="return confirm('确定删除吗？')" style="color: #e53935;"&gt;删除&lt;/a&gt;&lt;/td&gt;</span><span class="hljs-string">    &lt;/tr&gt;</span><span class="hljs-string">  `</span>).<span class="hljs-title function_">join</span>(<span class="hljs-string">''</span>);  <span class="hljs-keyword">return</span> <span class="hljs-string">`</span><span class="hljs-string">  &lt;!DOCTYPE html&gt;</span><span class="hljs-string">  &lt;html lang="zh"&gt;</span><span class="hljs-string">  &lt;head&gt;</span><span class="hljs-string">    &lt;meta charset="UTF-8"&gt;</span><span class="hljs-string">    &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;</span><span class="hljs-string">    &lt;title&gt;短链接管理后台&lt;/title&gt;</span><span class="hljs-string">    &lt;link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/picocss/1.5.13/pico.min.css"&gt;</span><span class="hljs-string">    &lt;style&gt;</span><span class="hljs-string">      body { padding: 20px 0; }</span><span class="hljs-string">      .container { max-width: 900px; }</span><span class="hljs-string">      .header { margin-bottom: 40px; text-align: center; }</span><span class="hljs-string">      mark { font-weight: bold; padding: 2px 8px; border-radius: 4px; }</span><span class="hljs-string">    &lt;/style&gt;</span><span class="hljs-string">  &lt;/head&gt;</span><span class="hljs-string">  &lt;body&gt;</span><span class="hljs-string">    &lt;main class="container"&gt;</span><span class="hljs-string">      &lt;div class="header"&gt;</span><span class="hljs-string">        &lt;h1&gt;🔗 Short Link Admin&lt;/h1&gt;</span><span class="hljs-string">        &lt;p&gt;轻量、高效的 Cloudflare Workers 短链接生成器&lt;/p&gt;</span><span class="hljs-string">      &lt;/div&gt;</span><span class="hljs-string">      &lt;article&gt;</span><span class="hljs-string">        &lt;header&gt;&lt;strong&gt;新建短链接&lt;/strong&gt;&lt;/header&gt;</span><span class="hljs-string">        &lt;form action="/admin/create" method="POST"&gt;</span><span class="hljs-string">          &lt;div class="grid"&gt;</span><span class="hljs-string">            &lt;input type="url" name="originalUrl" placeholder="粘贴长链接 (https://...)" required&gt;</span><span class="hljs-string">            &lt;input type="text" name="customCode" placeholder="自定义短码 (选填)"&gt;</span><span class="hljs-string">            &lt;button type="submit"&gt;立即创建&lt;/button&gt;</span><span class="hljs-string">          &lt;/div&gt;</span><span class="hljs-string">        &lt;/form&gt;</span><span class="hljs-string">      &lt;/article&gt;</span><span class="hljs-string">      &lt;figure&gt;</span><span class="hljs-string">        &lt;table role="grid"&gt;</span><span class="hljs-string">          &lt;thead&gt;</span><span class="hljs-string">            &lt;tr&gt;</span><span class="hljs-string">              &lt;th&gt;短码&lt;/th&gt;</span><span class="hljs-string">              &lt;th&gt;原始链接&lt;/th&gt;</span><span class="hljs-string">              &lt;th&gt;点击量&lt;/th&gt;</span><span class="hljs-string">              &lt;th&gt;创建时间&lt;/th&gt;</span><span class="hljs-string">              &lt;th&gt;操作&lt;/th&gt;</span><span class="hljs-string">            &lt;/tr&gt;</span><span class="hljs-string">          &lt;/thead&gt;</span><span class="hljs-string">          &lt;tbody&gt;</span><span class="hljs-string">            <span class="hljs-subst">${rows || <span class="hljs-string">'&lt;tr&gt;&lt;td colspan="5" style="text-align:center;"&gt;暂无数据&lt;/td&gt;&lt;/tr&gt;'</span>}</span></span><span class="hljs-string">          &lt;/tbody&gt;</span><span class="hljs-string">        &lt;/table&gt;</span><span class="hljs-string">      &lt;/figure&gt;</span><span class="hljs-string">    &lt;/main&gt;</span><span class="hljs-string">  &lt;/body&gt;</span><span class="hljs-string">  &lt;/html&gt;</span><span class="hljs-string">  `</span>;}</code></pre><hr><h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h3><ol><li>KV空间我命名的是SHORT_LINKS，你可以自己改</li><li>环境变量需要有ADMIN_PASSWORD用来储存管理密码</li><li>注意绑定WORKER和KV</li><li>第一次打开/admin，提示输入账户和密码，只输入密码即可！</li><li>免费的KV每天的PUT次数好像是有限制的，并且还有很多问题。小玩具，不用太在意。</li></ol><p>你可以点击这里跳转本文章： <a href="https://link.1tb.site/short-link">https://link.1tb.site/short-link</a></p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%BB%9F%E8%AE%A1/">统计</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Cloudflare/">Cloudflare</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Serverless/">Serverless</category>
      
      <category domain="https://www.banzhuanriji.com/tags/JavaScript/">JavaScript</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%9F%AD%E9%93%BE%E6%8E%A5/">短链接</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Workers/">Workers</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/short-link-workers/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>美丽小废物——Nuphy Node 75 LP</title>
      <link>https://www.banzhuanriji.com/life/nuphy-node-75-lp/</link>
      <guid>https://www.banzhuanriji.com/life/nuphy-node-75-lp/</guid>
      <pubDate>Fri, 19 Dec 2025 06:35:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;blockquote&gt;
&lt;p&gt;如果你能忍受时不时断连，正在游戏的时候键盘失效，正在工作的时候狼狈地去重置键盘，那么Nuphy键盘是一个不错的选择！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我在11月20日夜间偶然刷到了Nuph</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><blockquote><p>如果你能忍受时不时断连，正在游戏的时候键盘失效，正在工作的时候狼狈地去重置键盘，那么Nuphy键盘是一个不错的选择！</p></blockquote><p>我在11月20日夜间偶然刷到了Nuphy的键盘，感觉外观不错，并且看起来适合工作（码字，写代码）。于是在其官方直播间购买了一款Nuiphy Node 75 LP(Low-Profile 矮轴)的键盘，花费399。</p><p>2天后，周末到货，我专门去公司把键盘拿回家想体验一下。</p><p>对比我现在用的IKBC的85键（当时买的也是400元左右），看起来漂亮了很多，很适合办公。但是一摸上手就感觉不对。完全就是儿童电话玩具的的反馈… 或许是矮轴的原因？又或者我习惯了现在的键盘。我不确定。不过可以确定的是按键很松动，不像100块以上的产品。</p><p>稍微总结一下它的优点：</p><ol><li>看起来漂亮</li><li>三模</li><li>web驱动</li><li>键位合理，键距也合理</li></ol><p>缺点呢，缺点可太多了</p><p><a href="/img/nuphy-node-75-lp/1.png" data-fancybox="gallery" data-caption="是你让我说缺点的奥"><img src="/img/nuphy-node-75-lp/1.png" alt="是你让我说缺点的奥"></a></p><ol><li>按键非常松动。我不知道这么形容一款键盘合不合适？每个键左右晃动幅度很大。</li><li>空格下只有一颗灯珠。上面看会 B 两边发黑。坐直了会看到一个耀眼的 B🤣 （询问客服后告知设计如此）。现在只能关了使用，因为太丑了。</li><li>用了不到1个月（还差一天），断连3次，我快要崩溃了！</li><li>细看+上手很廉价。有点像磨砂质感的小家电。（个人观点）</li></ol><p><a href="/img/nuphy-node-75-lp/2.webp" data-fancybox="gallery" data-caption="是你让我说缺点的奥"><img src="/img/nuphy-node-75-lp/2.webp" alt="是你让我说缺点的奥"></a></p><p><a href="/img/nuphy-node-75-lp/3.webp" data-fancybox="gallery" data-caption="是你让我说缺点的奥"><img src="/img/nuphy-node-75-lp/3.webp" alt="是你让我说缺点的奥"></a></p><hr><p>到目前位置，我视图解决问题的方案以及处理结果</p><ol><li>联系抖音店铺客服</li></ol><blockquote><p>我以为是机器人，因为每次都是让我重置</p></blockquote><ol start="2"><li>邮件联系官方</li></ol><blockquote><p>石沉大海</p></blockquote><hr><h2 id="这里是SEO部分"><a href="#这里是SEO部分" class="headerlink" title="这里是SEO部分"></a>这里是SEO部分</h2></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/life/">生活</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E9%94%AE%E7%9B%98/">NuPhy 键盘</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-Air75-V2/">NuPhy Air75 V2</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-Air60/">NuPhy Air60</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-Air96/">NuPhy Air96</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-Halo75/">NuPhy Halo75</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-Halo65/">NuPhy Halo65</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-Halo96/">NuPhy Halo96</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-Field75/">NuPhy Field75</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%9F%AE%E8%BD%B4%E6%9C%BA%E6%A2%B0%E9%94%AE%E7%9B%98/">矮轴机械键盘</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E4%BC%98%E7%BC%BA%E7%82%B9/">NuPhy 优缺点</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E7%BC%BA%E7%82%B9/">NuPhy 缺点</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E9%81%BF%E9%9B%B7/">NuPhy 避雷</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%88%AB%E4%B9%B0-NuPhy/">别买 NuPhy</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E6%99%BA%E5%95%86%E7%A8%8E/">NuPhy 智商税</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E7%BF%BB%E8%BD%A6/">NuPhy 翻车</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E5%94%AE%E5%90%8E%E6%80%8E%E4%B9%88%E6%A0%B7/">NuPhy 售后怎么样</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E8%B4%A8%E9%87%8F%E9%97%AE%E9%A2%98/">NuPhy 质量问题</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E5%BB%B6%E8%BF%9F/">NuPhy 延迟</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E6%96%AD%E8%BF%9E/">NuPhy 断连</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E7%9C%9F%E5%AE%9E%E6%B5%8B%E8%AF%84/">NuPhy 真实测评</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E6%B7%B1%E5%BA%A6%E6%B5%8B%E8%AF%84/">NuPhy 深度测评</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E4%BD%BF%E7%94%A8%E6%84%9F%E5%8F%97/">NuPhy 使用感受</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-vs-Keychron/">NuPhy vs Keychron</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy-%E5%80%BC%E5%BE%97%E4%B9%B0%E5%90%97/">NuPhy 值得买吗</category>
      
      <category domain="https://www.banzhuanriji.com/tags/2025%E5%B9%B4%E6%9C%BA%E6%A2%B0%E9%94%AE%E7%9B%98%E6%8E%A8%E8%8D%90%E4%B8%8E%E4%B8%8D%E6%8E%A8%E8%8D%90/">2025年机械键盘推荐与不推荐</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy%E9%94%AE%E7%9B%98%E5%A5%BD%E7%94%A8%E5%90%97/">NuPhy键盘好用吗</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy%E7%9F%AE%E8%BD%B4%E7%BC%BA%E7%82%B9/">NuPhy矮轴缺点</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy%E5%BB%B6%E8%BF%9F%E9%AB%98/">NuPhy延迟高</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy%E6%BC%8F%E7%94%B5/">NuPhy漏电</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy%E5%9B%BA%E4%BB%B6%E6%9B%B4%E6%96%B0%E5%A4%B1%E8%B4%A5/">NuPhy固件更新失败</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy%E6%80%A7%E4%BB%B7%E6%AF%94/">NuPhy性价比</category>
      
      <category domain="https://www.banzhuanriji.com/tags/NuPhy%E5%B9%B3%E6%9B%BF%E9%94%AE%E7%9B%98%E5%BB%BA%E8%AE%AE/">NuPhy平替键盘建议</category>
      
      
      <comments>https://www.banzhuanriji.com/life/nuphy-node-75-lp/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>当我决定重构项目时</title>
      <link>https://www.banzhuanriji.com/work/when-i-need-to-redevelop-an-app/</link>
      <guid>https://www.banzhuanriji.com/work/when-i-need-to-redevelop-an-app/</guid>
      <pubDate>Thu, 04 Dec 2025 14:55:09 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;守门人&quot;&gt;&lt;a href=&quot;#守门人&quot; class=&quot;headerlink&quot; title=&quot;守门人&quot;&gt;&lt;/a&gt;守门人&lt;/h2&gt;&lt;p&gt;上一位守门人匆匆离开。&lt;/p&gt;
&lt;p&gt;我被派来独守这座城堡，整个城堡外布满枯死的藤</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><h2 id="守门人"><a href="#守门人" class="headerlink" title="守门人"></a>守门人</h2><p>上一位守门人匆匆离开。</p><p>我被派来独守这座城堡，整个城堡外布满枯死的藤蔓，又或者那根本就是缝缝补补后的巨大裂痕。</p><p>我在大厅找到了一卷羊皮，上面密密麻麻刻满文字，杂乱无章，像已失传的咒文语法，互相嵌套。好在仔细分辨还能读懂些字。这些字的时间有远有近，能看出来有人一直在往上写什么东西。不知为何，重开一页再写不是更好吗？叠起来让人难以辨认，像一锅反复加热的老汤，上面布满凝固的油膜。</p><p>我从心里开始恐惧和反感。我想转身离开，但我似乎没有选择。城主给的赏金虽丰厚，却明码标价只够买一副上好的棺材板。我确实来了。</p><h2 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h2><p>几个日夜后我在城堡中醒来，不知为何没日没夜在这古老城堡的残垣断壁上雕刻一束束优美的线条，偶尔也会被要求用刚送来的彩色缎子，覆盖住那些称得上憔悴的砖头。看起来格格不入但还算有点意思。不过偶尔我也会被要求做一些清理蛀虫的工作，简单，枯燥。可我的工作就是这些。</p><h2 id="重构"><a href="#重构" class="headerlink" title="重构"></a>重构</h2><p>夜深人静的夜晚，我巡逻走完今天的最后一趟，再次翻看那本羊皮卷。我似乎有点头绪！</p><p>我将第一页写满内容的羊皮纸撕了下来，努力辨识后抄录在后面的空页上。身后似乎传来声音，我没有在意。蛛网拖着灰烬飘在我的头上，我挠了几次，也不知摆下去了没有。</p><p>到第二页，这一页看起来文字太多了，甚至重重叠叠，以至于整张纸几乎是黑色的，我不知应该怎么处理它。带我来的人、上一个守门人、还有给我工作的人都没有通知我应不应该这么做，我撕掉了它。一块地板翘了起来——又或许它根本就是被上层掉落的碎石砸烂的！可在这种古老的城堡里砖石掉落应该也是常事。我没有在意。</p><p>然后是第三页，第四页…直到我手抄的那一页，前面的内容全被我从这厚重的羊皮纸上撕掉。我想我在未来的时间会有办法让它的内容更完整地展示出来。我选择回去休息。</p><p>后来的每一天，我在角楼上小心翼翼地剥离那些寄生的藤蔓，用坚固的钢梁替换掉那些腐朽的木头。每替换一块砖，我都要停下来，侧耳倾听塔楼的呼吸。如果呼吸变得急促，我就立刻停手，安抚躁动的魔力；如果呼吸平稳，我就继续。</p><p>我似乎忘记羊皮卷的事情，我没有在意。将来有很多时日让我去仔细分辨和抄录。</p><h2 id="巨龙"><a href="#巨龙" class="headerlink" title="巨龙"></a>巨龙</h2><p>我认为自己的工作循序渐进有条不紊。直到楼顶的铃铛狂响，不断向下蹦出红色弹幕。这铃铛非常笨重，肯定不是风吹动的。似乎是有什么东西要从城堡内破壳而出。我的师傅告诉我这是危险的情况。</p><p>在我没有反应过来的时候，一条巨龙从城堡底部飞出，还试图将它彻底撞碎。还好这不是我的第一份工作，我有对付巨龙的经验。至少是口头相传的经验。</p><p>我收起所有的工具，从背包拿出一只彩色的钩子，这是黑市买来的舶来品。当然，本地也有好货！可我觉得这只钩子更合我手。这守门人界人人都有的彩色钩子，是由一条条链接构成的。我将钩子往地面一敲，裂开一道缝隙，趁缝隙未闭合，抛向空中，这钩子幻化成无数铁链，耗费了点时间，但确实牢牢捆住这头恶龙！</p><p>它被困住了。我从背包取出一只猫头朝它扔了过去。我被告知这猫头可以从中召唤以前很厉害的人，他们将自己开源心血无私地存放在这只猫头内。他们会帮助我。猫头确实生效了，不过我没看到什么人，只是跳出很多经文一道道飘在羊皮卷上。看起来确实厉害，因为那巨龙似乎开始哀嚎。</p><p>……</p><p>我取出最近在守门人界好评极高的可以与人对话的手电筒。</p><p>“只需要打开手电筒，就可以完美收复任何巨兽！”</p><p>手电筒说明书的第一页是这么写的。实际上这是另一个守门人的评价，没人知道这句话为什么被放在说明书的第一页。</p><p>我拨动手电筒的开关，瞬间光明覆盖了整个世界。我想这就是我下单时，商家告诉我的“氛围”吧！他说这支手电筒可以杀死任何从虫子到大山一样的巨兽，而且免费让我使用。</p><h2 id="尾声"><a href="#尾声" class="headerlink" title="尾声"></a>尾声</h2><p>风停了。废塔的藤蔓在月光下悄悄抽出了新芽。我转身，听见身后传来细微的、几乎不可闻的铃铛声——不是报警，而是心跳。</p><p>现在，城堡的铜环门上刻了新的花纹，我在最下面刻了一行小字：BUG FIXED V11.0 prerelease</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/work/">工作</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%BC%80%E5%8F%91/">开发</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%9A%8F%E7%AC%94/">随笔</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%AC%94%E8%AE%B0/">笔记</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%B7%A5%E4%BD%9C/">工作</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%87%8D%E6%9E%84/">重构</category>
      
      
      <comments>https://www.banzhuanriji.com/work/when-i-need-to-redevelop-an-app/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>一个简单的百度收录推送工具</title>
      <link>https://www.banzhuanriji.com/blog/baidu-indexing-push-tool/</link>
      <guid>https://www.banzhuanriji.com/blog/baidu-indexing-push-tool/</guid>
      <pubDate>Tue, 18 Nov 2025 03:27:27 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;TLDR&quot;&gt;&lt;a href=&quot;#TLDR&quot; class=&quot;headerlink&quot; title=&quot;TLDR;&quot;&gt;&lt;/a&gt;TLDR;&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;百度搜索资源平台 &lt;a href=&quot;http</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><h2 id="TLDR"><a href="#TLDR" class="headerlink" title="TLDR;"></a>TLDR;</h2><blockquote><p>百度搜索资源平台 <a href="https://ziyuan.baidu.com/linksubmit/index">https://ziyuan.baidu.com/linksubmit/index</a></p></blockquote><p>如果你有兴趣，你可以点击下面的地址尝试： <a href="https://push.banzhuanriji.com/">https://push.banzhuanriji.com/</a> </p><h2 id="功能介绍"><a href="#功能介绍" class="headerlink" title="功能介绍"></a>功能介绍</h2><p>在百度提供的API提交方案中，提供了PHP推送方案实例，简单改一下，现在可以做到的功能是：</p><p>输入sitemap或者feed地址（支持RSS和Atom），然后点击解析内容之后，会推送最新的10条内容到百度。</p><h2 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h2><ul><li>因为部分站点sitemap在更新的时候会刷新所有页面的时间，因此推荐使用FEED解析。</li><li>现在百度每天只支持推送10条地址。</li><li>推送内容会根据百度的推送算法进行排序，因此推送的内容会按照百度的排序进行推送。</li><li>推送完成后，会返回推送的结果，包括成功的数量和失败的数量。</li><li><strong>注意域名需要和KEY一致</strong> ，如下图中所示，每个域名有自己的KEY。</li></ul><p><a href="/img/baidu-indexing-push-tool/1.jpg" data-fancybox="gallery" data-caption="注意域名需要和KEY一致"><img src="/img/baidu-indexing-push-tool/1.avif" alt="注意域名需要和KEY一致" title="选取红框内的内容"></a></p><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>下面是代码的gist链接，包括PHP和HTML+JS的版本。HTML版本你可能需要解决跨域问题！当然你也可以修改一下使用RSS2JSON服务进行解析。</p><p><a href="https://gist.github.com/hoytzhang/6522a721d7797b3fe9f2dcc2dc205cf8">PHP版本</a></p><p><a href="https://gist.github.com/hoytzhang/74f19c214a0d5a447a7057d11f6d01a9">HTML+JS版本</a></p><p><a href="https://push.banzhuanriji.com/">我部署的PHP版本</a></p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/blog/">博客</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%99%BE%E5%BA%A6%E6%90%9C%E7%B4%A2%E8%B5%84%E6%BA%90%E5%B9%B3%E5%8F%B0/">百度搜索资源平台</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%93%BE%E6%8E%A5%E6%8F%90%E4%BA%A4/">链接提交</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%99%BE%E5%BA%A6%E6%8E%A8%E9%80%81API/">百度推送API</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Sitemap/">Sitemap</category>
      
      <category domain="https://www.banzhuanriji.com/tags/RSS/">RSS</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Atom/">Atom</category>
      
      <category domain="https://www.banzhuanriji.com/tags/FEED%E8%A7%A3%E6%9E%90/">FEED解析</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%BD%91%E7%AB%99%E6%94%B6%E5%BD%95/">网站收录</category>
      
      <category domain="https://www.banzhuanriji.com/tags/SEO%E5%B7%A5%E5%85%B7/">SEO工具</category>
      
      <category domain="https://www.banzhuanriji.com/tags/PHP%E6%8E%A8%E9%80%81%E6%96%B9%E6%A1%88/">PHP推送方案</category>
      
      
      <comments>https://www.banzhuanriji.com/blog/baidu-indexing-push-tool/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>给博客的图片添加一个漂亮的图片描述</title>
      <link>https://www.banzhuanriji.com/blog/a-fancy-image-desc-showing/</link>
      <guid>https://www.banzhuanriji.com/blog/a-fancy-image-desc-showing/</guid>
      <pubDate>Mon, 17 Nov 2025 04:44:47 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;效果&quot;&gt;&lt;a href=&quot;#效果&quot; class=&quot;headerlink&quot; title=&quot;效果&quot;&gt;&lt;/a&gt;效果&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;/img/a-fancy-image-desc-showing/pexe</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><h2 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h2><p><a href="/img/a-fancy-image-desc-showing/pexels-pixabay-247599.jpg" data-fancybox="gallery" data-caption="2025年11月17日 11点50分"><img src="/img/a-fancy-image-desc-showing/pexels-pixabay-247599.avif" alt="2025年11月17日 11点50分" title="图片来自 pixabay"></a></p><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h3 id="实现内容"><a href="#实现内容" class="headerlink" title="实现内容"></a>实现内容</h3><ol><li>等待DOM完全加载</li><li>获取所有的IMG标签</li><li>展示所有的IMG描述内容</li></ol><h3 id="我美化了什么"><a href="#我美化了什么" class="headerlink" title="我美化了什么"></a>我美化了什么</h3><ol><li>鼠标移上显示，避免遮挡图片内容，同样避免破坏版面</li><li>给文字背景毛玻璃效果</li><li>给毛玻璃动态背景颜色，颜色提取图片主色作为背景颜色</li><li>给字体一点描边，增加极端背景色下的可读性</li></ol><h3 id="实现代码"><a href="#实现代码" class="headerlink" title="实现代码"></a>实现代码</h3><pre><code class="hljs plaintext">document.addEventListener('DOMContentLoaded', function () {    const mainContent = document.querySelector('.post-content, .article-content');    if (!mainContent) {        return;    }    mainContent.querySelectorAll('img').forEach(img =&gt; {        const title = img.getAttribute('title');        const alt = img.getAttribute('alt');        if (!title &amp;&amp; !alt) {            return;         }        img.crossOrigin = 'anonymous';        const customElement = document.createElement('div');        customElement.setAttribute('class', 'article-image-wrapper');        customElement.style.display = 'none';         const figcaption = document.createElement('figcaption');        figcaption.setAttribute('class', 'image-info-overlay');        let infoHTML = '';        if (alt) {            infoHTML += `&lt;p class="image-alt-text"&gt;${alt}&lt;/p&gt;`;        }        if (title) {            infoHTML += `&lt;p class="image-title-text"&gt;${title}&lt;/p&gt;`;        }        figcaption.innerHTML = infoHTML;        img.parentNode.insertBefore(customElement, img);        customElement.appendChild(img);        customElement.appendChild(figcaption);                customElement.addEventListener('mouseover', () =&gt; {            customElement.classList.add('is-hovering');        });        customElement.addEventListener('mouseout', () =&gt; {            customElement.classList.remove('is-hovering');        });        img.addEventListener('load', function () {            customElement.style.display = 'inline-block';                         if (isSameOrigin(img.src)) {                const canvas = document.createElement('canvas');                const rgbColor = getImageAverageColor(canvas, img);                figcaption.style.backgroundColor = rgbColor;            } else {                figcaption.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';            }        });        img.addEventListener('error', function () {            customElement.remove();         });    });    function isSameOrigin(url) {        try {            const imgUrl = new URL(url);            return imgUrl.origin === window.location.origin;        } catch (e) {            return true;        }    }        function getImageAverageColor(canvas, img) {        try {            canvas.width = img.naturalWidth;            canvas.height = img.naturalHeight;            const context = canvas.getContext("2d");            context.drawImage(img, 0, 0, canvas.width, canvas.height);            const data = context.getImageData(0, 0, canvas.width, canvas.height).data;            let r = 0, g = 0, b = 0;            const pixelCount = data.length / 4;            for (let i = 0; i &lt; data.length; i += 4) {                r += data[i];                g += data[i + 1];                 b += data[i + 2];             }                        r = Math.round(r / pixelCount);            g = Math.round(g / pixelCount);            b = Math.round(b / pixelCount);            return `rgba(${r}, ${g}, ${b}, 0.3)`;        } catch (e) {            return 'rgba(0, 0, 0, 0.7)';        }    }});# css部分.article-image-wrapper {position: relative;display: inline-block;overflow: hidden}.article-image-wrapper img {display: block;max-width: 100%;height: auto}.image-info-overlay {position: absolute;bottom: 0;left: 0;    right: 0;padding-left: 10px;padding-bottom: 2px;padding-top: 2px;border-radius: 0px 0px 4px 4px;color: white;backdrop-filter: blur(5px);box-sizing: border-box;transform: translateY(100%);transition: opacity .3s ease-out, transform .3s ease-out}.article-image-wrapper.is-hovering .image-info-overlay {opacity: 1;transform: translateY(0)}.image-info-overlay p {margin: 5px 0;line-height: 1;text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);color: #ffffff;}.image-alt-text{font-size: 0.8rem;}.image-title-text{font-size: 1.1rem;}</code></pre><h3 id="下面是比较详细的解释"><a href="#下面是比较详细的解释" class="headerlink" title="下面是比较详细的解释"></a>下面是比较详细的解释</h3><p>代码在 DOM 内容完全加载后执行，它遍历文章中的所有 <code>&lt;img&gt;</code> 标签，并对那些设置了 <code>title</code> 或 <code>alt</code> 属性的图片执行以下操作：</p><ul><li>图片包装与结构化：<ul><li>将图片用一个新的 <code>&lt;div&gt;</code> 元素（类名为 <code>article-image-wrapper</code>）包裹起来，并将其初始设置为隐藏 (<code>display: 'none'</code>)。</li><li>在包裹元素内，为图片添加一个 <code>figcaption</code> 元素（类名为 <code>image-info-overlay</code>），用于显示图片的 <code>alt</code> 和 <code>title</code> 信息。</li></ul></li><li>信息显示（Alt/Title）：<ul><li>从 <code>&lt;img&gt;</code> 标签中获取 <code>alt</code> 和 <code>title</code> 属性值，并将它们格式化为 <code>&lt;p&gt;</code> 标签，放入 <code>figcaption</code> 元素中。</li></ul></li><li>交互效果：<ul><li>为图片包裹元素添加鼠标悬停监听器，在悬停时添加/移除 <code>is-hovering</code> 类，以便通过 CSS 实现悬停时的视觉效果。</li></ul></li><li>图片加载成功后的处理：<ul><li>当图片加载成功后，将包裹元素显示出来 (<code>display: 'inline-block'</code>)。</li><li>尝试获取图片的平均颜色：<ul><li>如果是同源图片，则使用 <code>&lt;canvas&gt;</code> 元素计算图片的平均 RGB 颜色，并将此颜色设置为 <code>figcaption</code> 的背景色（带有 $0.3$ 的透明度）。</li><li>如果是跨域或计算失败（包括同源计算失败），则设置默认的深色背景（<code>rgba(0, 0, 0, 0.7)</code>）。</li></ul></li></ul></li><li>跨域设置与错误处理：<ul><li>将图片元素的 <code>crossOrigin</code> 属性设置为 <code>'anonymous'</code>，以支持跨域图片在 <code>&lt;canvas&gt;</code> 上进行颜色计算。</li><li>如果图片加载失败，则移除整个图片包裹元素。</li></ul></li></ul><h2 id="fancybox"><a href="#fancybox" class="headerlink" title="fancybox"></a>fancybox</h2><p>另外点击图片是有灯箱效果的，我使用的是fancybox3，首先你需要引入fancybox的css和js文件，然后在你的JS中添加如下代码：</p><pre><code class="hljs plaintext">'use strict';const cheerio = require('cheerio');hexo.extend.filter.register('after_post_render', function(data) {    if (!data.content) return data;    const $ = cheerio.load(data.content, {        decodeEntities: false     });    $('img:not(a img)').each(function() {        const $img = $(this);        const src = $img.attr('src');        const alt = $img.attr('alt');                if (!src) return;        const $a = $('&lt;a&gt;')            .attr('href', src)             .attr('data-fancybox', 'gallery')             .attr('data-caption', alt || '');         $img.wrap($a);    });    data.content = $.html();    return data;});</code></pre><p>因为博客的图片我基本都从原图（jpg）格式转换为了avif格式。所以如果你希望点击图片展示的灯箱为原图（大尺寸原图），你可以使用以下的代码，把原图路径替换以下</p><pre><code class="hljs plaintext">$('img:not(a img)').each(function() {    const $img = $(this);    const originalSrc = $img.attr('src');     const newSrc = originalSrc.replace(/\.avif$/, '.jpg');     console.log(newSrc);    const alt = $img.attr('alt');        if (!newSrc) return;    const $a = $('&lt;a&gt;')        .attr('href', newSrc)         .attr('data-fancybox', 'gallery')         .attr('data-caption', alt || '');     $img.wrap($a);});</code></pre></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/blog/">博客</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%9B%BE%E7%89%87%E6%8F%8F%E8%BF%B0%E6%98%BE%E7%A4%BA%E6%95%88%E6%9E%9C/">图片描述显示效果</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%9B%BE%E7%89%87%E6%82%AC%E5%81%9C%E4%BA%A4%E4%BA%92/">图片悬停交互</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%9B%BE%E7%89%87%E4%B8%BB%E8%89%B2%E6%8F%90%E5%8F%96/">图片主色提取</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Fancybox-%E7%81%AF%E7%AE%B1%E6%95%88%E6%9E%9C/">Fancybox 灯箱效果</category>
      
      <category domain="https://www.banzhuanriji.com/tags/JavaScript-%E5%9B%BE%E7%89%87%E5%A4%84%E7%90%86/">JavaScript 图片处理</category>
      
      <category domain="https://www.banzhuanriji.com/tags/IMG-%E6%A0%87%E7%AD%BE-alt-title-%E5%B1%9E%E6%80%A7%E5%B1%95%E7%A4%BA/">IMG 标签 alt/title 属性展示</category>
      
      <category domain="https://www.banzhuanriji.com/tags/CSS-%E6%AF%9B%E7%8E%BB%E7%92%83%E8%83%8C%E6%99%AF%E6%95%88%E6%9E%9C/">CSS 毛玻璃背景效果</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%90%8C%E6%BA%90%E5%9B%BE%E7%89%87%E9%A2%9C%E8%89%B2%E8%AE%A1%E7%AE%97/">同源图片颜色计算</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%B7%A8%E5%9F%9F%E5%9B%BE%E7%89%87%E5%A4%84%E7%90%86%E6%96%B9%E6%A1%88/">跨域图片处理方案</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Hexo-%E5%9B%BE%E7%89%87%E7%81%AF%E7%AE%B1%E9%85%8D%E7%BD%AE/">Hexo 图片灯箱配置</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%BC%A0%E6%A0%87%E6%82%AC%E5%81%9C%E5%9B%BE%E7%89%87%E4%BF%A1%E6%81%AF%E6%98%BE%E7%A4%BA/">鼠标悬停图片信息显示</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Canvas-%E8%8E%B7%E5%8F%96%E5%9B%BE%E7%89%87%E5%B9%B3%E5%9D%87%E8%89%B2/">Canvas 获取图片平均色</category>
      
      
      <comments>https://www.banzhuanriji.com/blog/a-fancy-image-desc-showing/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>我想看电影</title>
      <link>https://www.banzhuanriji.com/life/life-movie-watching-dilemma/</link>
      <guid>https://www.banzhuanriji.com/life/life-movie-watching-dilemma/</guid>
      <pubDate>Tue, 28 Oct 2025 17:14:04 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;我已经好久没有去电影院看电影了。&lt;/p&gt;
&lt;p&gt;甚至好久没有看完一部电影了。&lt;/p&gt;
&lt;p&gt;不过我对电影的要求还蛮多的。&lt;/p&gt;
&lt;p&gt;首先故事要完整吧。不能搞得莫名其妙的开始又莫名其妙的结束。剧情不能说经得起推敲，但也应该</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>我已经好久没有去电影院看电影了。</p><p>甚至好久没有看完一部电影了。</p><p>不过我对电影的要求还蛮多的。</p><p>首先故事要完整吧。不能搞得莫名其妙的开始又莫名其妙的结束。剧情不能说经得起推敲，但也应该有前后因果。尤其讨厌没有技术还故弄玄虚的导演。</p><p>其次演员演技需要在线。因此我不爱看爱情片。爱情片就是莫名其妙的开始谈恋爱，然后歇斯底里或者决然地分手。分分合合几个过程最后包饺子或者遗憾离场。也不爱看警匪片，警匪片我看不出演技。所有人的表情几乎就几个：挤成川字眉心大喊大叫，嘻嘻哈哈尬笑圆场，要么用最浮夸的演技演个变态，还有经典的面瘫装高手。额外点名：刘诗诗，周迅，刘亦菲，王传君。这几个演员火了之后，演什么都一个表情。刘诗诗甚至结婚都是那个经典表情。</p><p>配音很重要。很多演员甚至不会自己配音，依然会专门找个港台腔的配音模仿自己的声音。太别扭了。不懂在装什么玩意。</p><p>还有我的原因：似乎没有完整的时间，项目的不稳定，导致我需要做一个随时应答机器人。不是没有看电影的时间，只是影院不能暂停。</p><p>稍微总结了一下：我想去影院看一部故事完整，演技在线的爱情片和现代警匪片以外的电影。</p><p>挺难。</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/life/">生活</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%9A%8F%E7%AC%94/">随笔</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%94%B5%E5%BD%B1/">电影</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%A7%82%E5%BD%B1%E4%BD%93%E9%AA%8C/">观影体验</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%BC%94%E5%91%98%E6%BC%94%E6%8A%80/">演员演技</category>
      
      
      <comments>https://www.banzhuanriji.com/life/life-movie-watching-dilemma/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>修改HEXO网站的RSS地址</title>
      <link>https://www.banzhuanriji.com/blog/Modify-the-RSS-URL-of-the-HEXO-website/</link>
      <guid>https://www.banzhuanriji.com/blog/Modify-the-RSS-URL-of-the-HEXO-website/</guid>
      <pubDate>Sat, 11 Oct 2025 03:25:23 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;blockquote&gt;
&lt;p&gt;以下方案对于 hexo-generator-feed 插件和 hexo-feed 插件通用，不过我目前使用的是hexo-generator-feed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因为之</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><blockquote><p>以下方案对于 hexo-generator-feed 插件和 hexo-feed 插件通用，不过我目前使用的是hexo-generator-feed</p></blockquote><p>因为之前使用的动态框架，RSS地址是 <a href="https://banzhuanriji.com/feed/">https://banzhuanriji.com/feed/</a> ，更换为hexo之后，使用hexo-generator-feed插件，RSS地址变成：</p><p><a href="https://banzhuanriji.com/atom.xml">https://banzhuanriji.com/atom.xml</a><br><a href="https://banzhuanriji.com/rss.xml">https://banzhuanriji.com/rss.xml</a></p><p>这不是我想要的，我想保持 <a href="https://banzhuanriji.com/feed/">https://banzhuanriji.com/feed/</a> 这个地址。首先看官方文档 ：<a href="https://www.npmjs.com/package/hexo-generator-feed">https://www.npmjs.com/package/hexo-generator-feed</a> ，配置的格式大概如下：</p><pre><code class="hljs plaintext">feed:  type:    - atom    - rss2  path:    - atom.xml    - rss2.xml  limit: 20  hub:  content:  content_limit: 140  content_limit_delim: ' '  order_by: -date  icon: icon.png  autodiscovery: true  template:</code></pre><p>也就是说，你是可以自定义地址的。</p><p>但是如果你的地址修改为例如 domain.com/feed/ ，它会<strong>直接下载</strong>这个xml文件而不是打开访问。通过插件配置的话，这里似乎没有什么好的解决方案。</p><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><p>我是部署在腾讯云 edgeone 的 pages 服务上的。他是类似vercel的服务。同样也和vercel一样支持一些自定义行文，你只需要创建<code>edgeone.json</code>文件即可。</p><p>其中支持redirects和rewrites，下面是我第一次写的文件</p><pre><code class="hljs plaintext">{  "rewrites": [    {      "source": "/feed",      "destination": "/rss.xml"    }  ],  "headers": [    {      "source": "/feed",      "headers": [        {          "key": "Content-Type",          "value": "application/xml; charset=utf-8"        }      ]    }  ]}</code></pre><p>这里会有一个问题，就是如果访问 <a href="https://banzhuanriji.com/feed/">https://banzhuanriji.com/feed/</a> ，是会404的，只可以访问 <a href="https://banzhuanriji.com/feed">https://banzhuanriji.com/feed</a></p><p>但是在feed后添加<code>/</code>，系统会认为这是个文件夹，也不可用。所以就要用下面的两个方案：</p><h4 id="1-重定向"><a href="#1-重定向" class="headerlink" title="1. 重定向"></a>1. 重定向</h4><pre><code class="hljs plaintext">{  "redirects": [    {      "source": "/feed/",      "destination": "/feed",      "statusCode": 301    }  ],  "rewrites": [    {      "source": "/feed",      "destination": "/rss.xml"    }  ],  "headers": [    {      "source": "/feed",      "headers": [        {          "key": "Content-Type",          "value": "application/xml; charset=utf-8"        }      ]    },    {      "source": "/rss.xml",      "headers": [        {          "key": "Content-Type",          "value": "application/xml; charset=utf-8"        }      ]    }  ]}</code></pre><p>它的逻辑打开就是之前的重写方案，然后添加一个重定向方案。但是浏览器会提示太多redirects，直接访问失败。</p><h4 id="2-最终方案，捕捉所有feed的地址"><a href="#2-最终方案，捕捉所有feed的地址" class="headerlink" title="2. 最终方案，捕捉所有feed的地址"></a>2. 最终方案，捕捉所有feed的地址</h4><pre><code class="hljs plaintext">{  "rewrites": [    {      "source": "/feed/*",      "destination": "/rss.xml"    }  ],  "headers": [    {      "source": "/feed/*",      "headers": [        {          "key": "Content-Type",          "value": "application/xml; charset=utf-8"        }      ]    }  ]}</code></pre><p>这个方案终于可行，但是有一个问题，就是这个方案会匹配所有feed下的请求到你指定的文件。(不过至少可用了😄</p><blockquote><p>如果你有一定的阅读逻辑，你可以点击这里查看文档 <a href="https://edgeone.cloud.tencent.com/pages/document/162936771610066944">https://edgeone.cloud.tencent.com/pages/document/162936771610066944</a></p></blockquote></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/blog/">博客</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/hexo/">hexo</category>
      
      <category domain="https://www.banzhuanriji.com/tags/blog/">blog</category>
      
      <category domain="https://www.banzhuanriji.com/tags/rss/">rss</category>
      
      <category domain="https://www.banzhuanriji.com/tags/atom/">atom</category>
      
      <category domain="https://www.banzhuanriji.com/tags/rss%E5%9C%B0%E5%9D%80/">rss地址</category>
      
      
      <comments>https://www.banzhuanriji.com/blog/Modify-the-RSS-URL-of-the-HEXO-website/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>穷鬼养鱼实录——准备篇</title>
      <link>https://www.banzhuanriji.com/life/The-Poor-Mans-Fish-Farming-Story/</link>
      <guid>https://www.banzhuanriji.com/life/The-Poor-Mans-Fish-Farming-Story/</guid>
      <pubDate>Fri, 05 Sep 2025 02:11:08 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;blockquote&gt;
&lt;p&gt;多次出发的养鱼新手决定再次出发。这次决定不折磨小鱼，更不折磨自己。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; ti</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><blockquote><p>多次出发的养鱼新手决定再次出发。这次决定不折磨小鱼，更不折磨自己。</p></blockquote><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>所有的养鱼佬都知道。养鱼从来不是 “烧钱大赛”，反而更像一场考验智慧和耐心的小游戏。你不需要动辄上万的专业设备，也不用追求进口的稀有鱼种，只要找对方法，几十块钱也能打造出一个漂亮的桌面小世界。​</p><p>下面分享一次我这次准备的养鱼工作和经历</p><h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2><h3 id="要养的鱼"><a href="#要养的鱼" class="headerlink" title="要养的鱼"></a>要养的鱼</h3><p>首先确定要养什么鱼，是大鱼还是小鱼，是咸水还是淡水，是否是热带鱼。这些内容决定了我们之后要购买和配置的装备。</p><p>我本人喜欢小型鱼，例如灯鱼或者斗鱼之类的淡水小鱼，不容易挂，皮实。</p><p>新手推荐养的鱼基本就是这些个种类：孔雀鱼，斑马鱼，玛丽鱼，斗鱼，草金鱼，鳑鲏，中国斗鱼，鹦鹉鱼。</p><p>这些基本都是小熊鱼类，对氧气的要求不高。但是饲养密度不宜过大，且斗鱼或其他爱好互相攻击的鱼类不可混养。</p><h3 id="鱼缸选择"><a href="#鱼缸选择" class="headerlink" title="鱼缸选择"></a>鱼缸选择</h3><blockquote><p>以下内容仅适合小体系鱼（&lt;5CM）</p></blockquote><h4 id="单缸内鱼儿的最高密度"><a href="#单缸内鱼儿的最高密度" class="headerlink" title="单缸内鱼儿的最高密度"></a>单缸内鱼儿的最高密度</h4><p>按照体积计算</p><ul><li>如果是没那么活泼（游速不快）的小鱼，推荐1-1.5L/1条的密度</li><li>如果是活泼的小鱼，推荐1.5-2L/1条的密度</li><li>斗鱼（尤其是雄性斗鱼）需要单独饲养</li></ul><p>按照水面积计算</p><ul><li>150cm²/1条，例如30cm*20cm的鱼缸，可以养4-5条小鱼</li><li>若是需要肺部呼吸的小鱼（斗鱼，鳑鲏等。不过斗鱼不可混养）则可适当多养</li></ul><h4 id="缸体选择"><a href="#缸体选择" class="headerlink" title="缸体选择"></a>缸体选择</h4><ul><li><strong>不推荐</strong>热弯鱼缸，新手可选亚克力鱼缸（同样不推荐），推荐<strong>超白鱼缸</strong></li><li>不推荐15cm及以下的小缸</li><li>别盲目挑战大缸</li></ul><h4 id="缸体方向"><a href="#缸体方向" class="headerlink" title="缸体方向"></a>缸体方向</h4><p>我认为缸体方向基本是由造景和鱼的习性决定的。如果没啥造景需求，我个人推荐20-35cm的小方缸。但如果你有造景的打算，缸体的方向选择就得好好琢磨了。</p><ul><li><p><strong>方缸</strong>如果你想做立体感强的造景，比如模仿山峰、峡谷，或者用石头、沉木堆叠出层次感，方缸的纵深感会给你更大的发挥空间。它能把焦点集中在造景本身，非常适合单养一条斗鱼，鱼和景能完美融合。</p></li><li><p><strong>长缸</strong>更适合**“线性”的造景**。如果你想打造一条小路，一片草原，或者想看鱼儿在水中来回巡游，长缸无疑是更好的选择。它能更好地表现出前景、中景、后景的层次感，视觉上更开阔，让活泼的小鱼（比如斑马鱼、孔雀鱼）有更长的游动空间。</p></li></ul><p>另外提一句，<strong>不推荐新手挑战高缸（高度超过40cm）</strong>。虽然看着气派，但水压大，对过滤要求高，清理和维护都非常麻烦，成本也会翻倍。</p><p>不管选长缸还是方缸，尽量选“带盖子”的款式。一来能防止小鱼跳缸，二来能减少水分蒸发，保持水质稳定，还能挡住灰尘。</p><p>总结一下，<strong>造景方向决定缸体方向</strong>。想做“山水”就选方缸，想做“平原”就选长缸。我自己用的是一个30cm的小方缸，养了几条灯鱼，配了点水草，桌面空间有限，方缸刚好，看着也清爽。</p><p>个人总结：</p><ul><li>长缸（矩形缸）:自然水景缸，荷兰缸，溪流缸</li><li>方缸（正方形或近似方形的缸）:莫斯缸，珊瑚礁缸（海水缸）</li><li>长缸和方缸都适用: 原生缸，三湖慈鲷缸，亚马逊/南美缸</li></ul><h3 id="过滤系统选择"><a href="#过滤系统选择" class="headerlink" title="过滤系统选择"></a>过滤系统选择</h3><h4 id="过滤的本质"><a href="#过滤的本质" class="headerlink" title="过滤的本质"></a>过滤的本质</h4><p>所有的过滤器，无论价格高低，最终目的都是为了三个字：<strong>“养水”</strong>。水好了，鱼才能活得滋润。而养水，最重要的是培养硝化细菌，这些细菌能把鱼的排泄物分解成无毒物质。所以，我们选择过滤器，并不是要选最贵的，而是要选能“养住”硝化细菌的。</p><h4 id="穷鬼过滤方案"><a href="#穷鬼过滤方案" class="headerlink" title="穷鬼过滤方案"></a>穷鬼过滤方案</h4><blockquote><p>穷鬼过滤器的选择，基本原则就是：能用、便宜、占地小。</p></blockquote><p>对于20-35cm的小缸，我强烈推荐两种超高性价比的过滤器：</p><ul><li><p><strong>水妖精（气动生化棉过滤器）</strong></p><ul><li><p><strong>原理</strong>需要搭配一个气泵，通过气泡上浮带动水流，将水吸入过滤棉，同时提供氧气。</p></li><li><p><strong>优点</strong>便宜到爆，一个只要几块钱。同时兼具物理过滤和生化过滤功能，非常适合小缸和斗鱼这类对水流要求不高的鱼。而且它还能打氧，一箭双雕。</p></li><li><p><strong>缺点</strong>体积稍大，置于缸底，个人感觉很丑，影响美观。气泵会有噪音，需要选择静音款。</p></li></ul></li><li><p><strong>瀑布过滤（外挂过滤器）</strong></p><ul><li><p><strong>原理</strong>挂在鱼缸壁上，像个小瀑布一样把水吸入，经过过滤棉和滤材再流回缸内。</p></li><li><p><strong>优点</strong>美观，占用缸内空间小。过滤效果比水妖精略好，水流也比较柔和。</p></li><li><p><strong>缺点</strong>需要定期清理滤棉，成本略高于水妖精。</p></li></ul></li></ul><p>如果你想兼顾美观和过滤效果，选瀑布过滤，小长缸结合造景或石头，可以有溪流效果；如果你只想用最少的钱达到目的，水妖精是你的不二之选。</p><h3 id="灯具选择"><a href="#灯具选择" class="headerlink" title="灯具选择"></a>灯具选择</h3><h4 id="灯具的作用"><a href="#灯具的作用" class="headerlink" title="灯具的作用"></a>灯具的作用</h4><p>很多人觉得灯具就是个照明的，其实不然。它除了让你更好地欣赏鱼儿，还能促进水草生长，有些特殊的灯光甚至能让鱼儿的颜色更鲜艳。</p><h4 id="穷鬼灯具方案"><a href="#穷鬼灯具方案" class="headerlink" title="穷鬼灯具方案"></a>穷鬼灯具方案</h4><blockquote><p>咱们养鱼，主要以观赏和照明为主，不考虑养那种对光照要求极高的“草缸”。所以，灯具的选择可以非常简单粗暴。</p></blockquote><ul><li><p><strong>选择原则</strong>够亮、显色好、便宜。</p></li><li><p><strong>推荐方案</strong></p><ul><li><p><strong>小夹灯</strong>某宝上十几块钱就能买到，夹在鱼缸边上，小巧不占地方。</p></li><li><p><strong>二手LED台灯</strong>如果你家里有闲置的LED台灯，直接拿来用就好。</p></li></ul></li><li><p><strong>注意事项</strong></p><ul><li><p>注意灯光的色温，推荐5000K-8000K的白光，显色效果比较好。</p></li><li><p>注意光照时长，每天开灯8小时左右就够了，避免爆藻（绿藻泛滥）。</p></li></ul></li></ul><h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>接下来就是造景了，这部分也是最能发挥创意的环节。我目前的进度刚到购买鱼缸。以上仅供参考。</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/life/">生活</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%B1%BC/">鱼</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%96%97%E9%B1%BC/">斗鱼</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%B1%BC%E7%BC%B8/">鱼缸</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%80%A0%E6%99%AF/">造景</category>
      
      
      <comments>https://www.banzhuanriji.com/life/The-Poor-Mans-Fish-Farming-Story/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>服务器自动封禁ip脚本</title>
      <link>https://www.banzhuanriji.com/posts/server-ban-ip-script/</link>
      <guid>https://www.banzhuanriji.com/posts/server-ban-ip-script/</guid>
      <pubDate>Thu, 14 Aug 2025 05:07:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;pre&gt;&lt;code class=&quot;hljs plaintext&quot;&gt;#!/bin/bash

LOG_PATH=&quot;/usr/local/nginx/logs/access.log&quot;
BLACKLIST_FILE=&quot;/usr/loc</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><pre><code class="hljs plaintext">#!/bin/bashLOG_PATH="/usr/local/nginx/logs/access.log"BLACKLIST_FILE="/usr/local/nginx/conf/default.d/deny_nginx.conf"TMP_IP_FILE="/root/all_suspicious_ips_1000.txt"LINES=5000  # 检查的日志行数THRESHOLD=10    # 攻击次数阈值echo "[*] 正在分析最近 $LINES 行 Nginx 日志..."# 1. 提取攻击关键词的 IPtail -n $LINES "$LOG_PATH" | \grep -Ei "wget|curl|base64|eval|union|select|insert|cmd=|/etc/passwd|../../|shell|php" | \awk '{print $1}' | sort | uniq -c | sort -nr &gt; "$TMP_IP_FILE"if [ ! -s "$TMP_IP_FILE" ]; then    echo "[+] 未发现可疑 IP，无需封禁。"    exit 0fi# 2. 创建黑名单文件（如果没有）if [ ! -f "$BLACKLIST_FILE" ]; then    touch "$BLACKLIST_FILE"fiecho "[*] 满足封禁条件（次数 ≥ $THRESHOLD）的 IP："while read count ip; do    if [ "$count" -ge "$THRESHOLD" ]; then        if grep -q "deny $ip;" "$BLACKLIST_FILE"; then            echo "[-] $ip 已在黑名单中（$count 次），跳过。"        else            echo "[+] 封禁 $ip（攻击次数：$count）"            echo "deny $ip;" &gt;&gt; "$BLACKLIST_FILE"        fi    fidone &lt; "$TMP_IP_FILE"# 4. 检查并重载 Nginxecho "[*] 检查 Nginx 配置..."if /usr/local/nginx/sbin/nginx -t; then    echo "[*] 配置无误，重新加载 Nginx..."    /usr/local/nginx/sbin/nginx -s reload &amp;&amp; echo "[+] Nginx 已重新加载。"else    echo "[!] Nginx 配置错误，请手动检查！"fi# 5. 清理rm -f "$TMP_IP_FILE"</code></pre></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/">服务器</category>
      
      <category domain="https://www.banzhuanriji.com/tags/CDN/">CDN</category>
      
      <category domain="https://www.banzhuanriji.com/tags/SERVER/">SERVER</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%84%9A%E6%9C%AC/">脚本</category>
      
      <category domain="https://www.banzhuanriji.com/tags/LINUX/">LINUX</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%94%BB%E5%87%BB%E9%98%B2%E5%BE%A1/">攻击防御</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/server-ban-ip-script/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>我使用nextjs写的一个新的博客框架</title>
      <link>https://www.banzhuanriji.com/posts/new-blog-with-nextjs/</link>
      <guid>https://www.banzhuanriji.com/posts/new-blog-with-nextjs/</guid>
      <pubDate>Mon, 11 Aug 2025 00:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;我已经厌倦了后端不断地被人扫描和攻击，以及无聊的垃圾评论。导出时发现wordpress的导出插件简直难用至极。&lt;/p&gt;
&lt;p&gt;博客本身是我用作记录的地方。各种框架眼花缭乱，使用成本过高。当前的框架是我用V0生成后自己修改。&lt;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>我已经厌倦了后端不断地被人扫描和攻击，以及无聊的垃圾评论。导出时发现wordpress的导出插件简直难用至极。</p><p>博客本身是我用作记录的地方。各种框架眼花缭乱，使用成本过高。当前的框架是我用V0生成后自己修改。</p><p>如果你有兴趣的话：</p><pre><code class="hljs plaintext">{  "name": "blog",  "version": "0.1.0",  "private": true,  "scripts": {    "dev": "next dev",    "build": "next build",    "start": "next start",    "lint": "next lint"  },  "dependencies": {    "@hookform/resolvers": "^3.9.1",    "@radix-ui/react-accordion": "1.2.2",    "@radix-ui/react-alert-dialog": "1.1.4",    "@radix-ui/react-aspect-ratio": "1.1.1",    "@radix-ui/react-avatar": "1.1.2",    "@radix-ui/react-checkbox": "1.1.3",    "@radix-ui/react-collapsible": "1.1.2",    "@radix-ui/react-context-menu": "2.2.4",    "@radix-ui/react-dialog": "1.1.4",    "@radix-ui/react-dropdown-menu": "2.1.4",    "@radix-ui/react-hover-card": "1.1.4",    "@radix-ui/react-label": "2.1.1",    "@radix-ui/react-menubar": "1.1.4",    "@radix-ui/react-navigation-menu": "1.2.3",    "@radix-ui/react-popover": "1.1.4",    "@radix-ui/react-progress": "1.1.1",    "@radix-ui/react-radio-group": "1.2.2",    "@radix-ui/react-scroll-area": "1.2.2",    "@radix-ui/react-select": "2.1.4",    "@radix-ui/react-separator": "1.1.1",    "@radix-ui/react-slider": "1.2.2",    "@radix-ui/react-slot": "1.1.1",    "@radix-ui/react-switch": "1.1.2",    "@radix-ui/react-tabs": "1.1.2",    "@radix-ui/react-toast": "1.2.4",    "@radix-ui/react-toggle": "1.1.1",    "@radix-ui/react-toggle-group": "1.1.1",    "@radix-ui/react-tooltip": "1.1.6",    "@tailwindcss/typography": "latest",    "autoprefixer": "^10.4.20",    "class-variance-authority": "^0.7.1",    "clsx": "^2.1.1",    "cmdk": "1.0.4",    "date-fns": "latest",    "embla-carousel-react": "8.5.1",    "fs": "latest",    "gray-matter": "latest",    "input-otp": "1.4.1",    "lucide-react": "^0.454.0",    "mdx": "latest",    "next": "15.2.4",    "next-mdx-remote": "latest",    "next-themes": "latest",    "path": "latest",    "react": "^19",    "react-day-picker": "9.7.0",    "react-dom": "^19",    "react-hook-form": "^7.54.1",    "react-resizable-panels": "^2.1.7",    "recharts": "2.15.0",    "sonner": "^1.7.1",    "tailwind-merge": "^2.5.5",    "tailwindcss-animate": "^1.0.7",    "vaul": "^1.1.2",    "zod": "^3.24.1"  },  "devDependencies": {    "@types/node": "^22",    "@types/react": "^19",    "@types/react-dom": "^19",    "postcss": "^8",    "tailwindcss": "^3.4.17",    "typescript": "^5"  }}</code></pre></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%90%AC%E7%A0%96%E6%97%A5%E8%AE%B0/">搬砖日记</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/new-blog-with-nextjs/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>部分省份无法访问在线服务的解决方案</title>
      <link>https://www.banzhuanriji.com/posts/fix-network-issues/</link>
      <guid>https://www.banzhuanriji.com/posts/fix-network-issues/</guid>
      <pubDate>Sat, 02 Aug 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h3 id=&quot;2025年8月15日更新&quot;&gt;&lt;a href=&quot;#2025年8月15日更新&quot; class=&quot;headerlink&quot; title=&quot;2025年8月15日更新&quot;&gt;&lt;/a&gt;2025年8月15日更新&lt;/h3&gt;&lt;p&gt;忘记了多域</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><h3 id="2025年8月15日更新"><a href="#2025年8月15日更新" class="headerlink" title="2025年8月15日更新"></a>2025年8月15日更新</h3><p>忘记了多域名方案。为了避免出现IP/域名污染，或者被基站拉黑的情况，建议使用多域名方案。实际上这种方案成本低，速度快(不考虑备案时间的前提下)，简单，效率高。</p><hr><p>周末被反应<strong>国内</strong>的服务<strong>福建省</strong>出现无法调用的情况，心中大概知道什么问题。这个问题经常出现，尤其是在福建，江苏，河南等省份。</p><p>下面是简单的解决方案，分别为：HTTPS(SSL)，CDN，ipv6，组建集群，客户端指定DNS</p><h3 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h3><p>大部分国内的服务加上证书可以解决很多问题，没错这是真实情况…</p><h3 id="CDN"><a href="#CDN" class="headerlink" title="CDN"></a>CDN</h3><p>最优的解决方案，目前可以查询到上面三个省份均有节点的服务商：</p><ol><li><p>阿里云</p></li><li><p>腾讯云</p></li><li><p>七牛云<br>其它服务商暂时没有查询，具体可以咨询官网客服。如果是前后端分离的项目，推荐购买接口加速的CDN就可以了。至此这个方案基本可以解决所有国内地区的访问难题！</p></li></ol><h3 id="ipv6"><a href="#ipv6" class="headerlink" title="ipv6"></a>ipv6</h3><p>现在国内云厂商是提供免费ipv6的，且绝大部分用户实际上设备和网络状况均支持ipv6，如果可以使用ipv6进行访问也可以解决很大程度的DNS污染问题。</p><h3 id="后端集群"><a href="#后端集群" class="headerlink" title="后端集群"></a>后端集群</h3><p>在访问不到的地区购置服务器，组建集群，亦可解决问题，但是依然需要考虑被重复封禁的问题以及客户端因为地理位置解析不精准或者缓存等原因，并未选择最优线路的方案；亦或者选择的最优路线根本就是访问不到的路线。所以这个方案被排除在最后！（这里只是以解决访问问题为例，而非其他原因）</p><h3 id="客户端方案：指定可访问的DNS"><a href="#客户端方案：指定可访问的DNS" class="headerlink" title="客户端方案：指定可访问的DNS"></a>客户端方案：指定可访问的DNS</h3><p>部分运营商会存在白名单/黑名单的情况，当然我们的备案服务和国内IP暂时可以排除黑名单的问题。但是不排除运营商DNS存在污染情况。如果定位不到问题，不妨让客户端多加一点逻辑。首先是检测哪个DNS服务访问最快，以Android端为例，以下用到第三方库版本分别为：OKHttp3(4.13.2)，dnsJava(3.5.2)，下面为具体逻辑代码：</p><pre><code class="hljs plaintext">object DnsLatencyTester {    // DNS服务器列表    private val dnsServers = listOf(        //并非越多越好，下面只是国内流行且高可用的DNS地址，另外还有360的DNS地址，具体情况请按需添加        "223.5.5.5",    // 阿里公共DNS        "223.6.6.6",    // 阿里公共DNS        "119.29.29.29", // 腾讯公共DNS        "119.28.28.28", // 腾讯公共DNS        "180.76.76.76", // 百度公共DNS        "114.114.114.114", // 114DNS纯净版        "114.114.115.115", // 114DNS纯净版    )    // 测试API地址，协商你们的任意可访问服务地址    private const val TEST_URL = ""    private const val TIMEOUT_MS = 5000L    /**     * 测试所有DNS服务器的延迟并返回最快的一个     */    suspend fun findFastestDns(context: Context): String? = withContext(Dispatchers.IO) {        // 为每个DNS创建异步测试任务        val deferredResults = dnsServers.map { dns -&gt;            async { testDnsLatency(dns) to dns }        }        // 等待所有测试完成并过滤掉超时的结果        val results = deferredResults.awaitAll()            .filter { it.first != -1L }            .sortedBy { it.first }        // 返回延迟最低的DNS        results.firstOrNull()?.second    }    /**     * 测试单个DNS服务器的延迟     * @return 延迟时间(毫秒)，-1表示超时或失败     */    private suspend fun testDnsLatency(dnsServer: String): Long = withContext(Dispatchers.IO) {        return@withContext try {            // 创建自定义DNS            val customDns = object : Dns {                override fun lookup(hostname: String): List&lt;InetAddress&gt; {                    try {                        // 使用指定DNS服务器解析域名                        val addresses = InetAddress.getAllByName(hostname)                        return addresses.toList()                    } catch (e: UnknownHostException) {                        // 如果解析失败，尝试直接使用IP连接                        return listOf(InetAddress.getByName(dnsServer))                    }                }            }            // 配置OkHttpClient            val client = OkHttpClient.Builder()                .dns(customDns)                .connectTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)                .readTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)                .writeTimeout(TIMEOUT_MS, TimeUnit.MILLISECONDS)                .build()            // 创建请求            val request = Request.Builder()                .url(TEST_URL)                .head() // 使用HEAD请求减少数据传输                .build()            // 记录开始时间            val startTime = System.currentTimeMillis()            // 发送请求            client.newCall(request).execute().close()            // 计算延迟时间            System.currentTimeMillis() - startTime        } catch (e: Exception) {            // 发生异常时返回-1            -1L        }    }}</code></pre><p>可以在闪屏页调用(注意实际用户体验)：</p><pre><code class="hljs plaintext">lifecycleScope.launch {    val fastestDns = DnsLatencyTester.findFastestDns(binding.imageViewcontent.context)    if (fastestDns != null) {        Log.i("DNS_TEST", "最快的DNS服务器: $fastestDns")        SPUtils.getInstance().put("fastestDns", fastestDns)        getInApp()    } else {        Log.e("DNS_TEST", "所有DNS服务器测试失败")        SPUtils.getInstance().put("fastestDns", "")        getInApp()    }}</code></pre><p>OKHttp3的使用示例：</p><pre><code class="hljs plaintext">var customDns: Dns = Dns.SYSTEM // 默认使用系统 DNSval fastestDns = SPUtils.getInstance().getString("fastestDns")if (fastestDns.isNotEmpty()) {    try {        customDns = CustomDns(fastestDns)    } catch (e: UnknownHostException) {        e.printStackTrace()        customDns = Dns.SYSTEM    }}val okHttpClientBuilder = OkHttpClient().newBuilder().apply {    connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)    readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)    writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)    dns(customDns)    addInterceptor(MInterceptor())    addInterceptor(DataEncryptInterceptor())</code></pre><p>中间存在的<code>CustomDNS</code>代码如下：</p><pre><code class="hljs plaintext">class CustomDns(dnsServer: String) : Dns {    private var resolver: SimpleResolver? = null    init {        try {            // 使用自定义的DNS服务器地址            this.resolver = SimpleResolver(dnsServer)        } catch (e: UnknownHostException) {            throw IllegalArgumentException("Invalid DNS server address: $dnsServer", e)        }    }    @Throws(UnknownHostException::class)    override fun lookup(hostname: String): List&lt;InetAddress&gt; {        try {            // 使用dnsjava进行解析            val name = Name("$hostname.")            val record: Record = Record.newRecord(name, Type.A, DClass.IN)            val query = Message.newQuery(record)            val response = resolver!!.send(query)            val addresses: MutableList&lt;InetAddress&gt; = ArrayList()            if (response.rcode == Rcode.NOERROR) {                val records: Array&lt;Record&gt; = response.getSectionArray(Section.ANSWER)                for (r in records) {                    if (r is ARecord) {                        val a = r as ARecord                        addresses.add(a.address)                    }                }            }            if (addresses.isEmpty()) {                throw UnknownHostException("No address found for $hostname")            }            return addresses        } catch (e: Exception) {            // 捕获所有dnsjava的异常，并转换为UnknownHostException            throw UnknownHostException("DNS lookup failed for " + hostname + ": " + e.message)        }    }}</code></pre><hr><p>以上就是我目前可以想到的全部解决方案，综合之后我个人建议的排序为：</p><p>CDN&gt;DNS&gt;集群，(ipv6以及HTTPS为默认配置😄)</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%BC%80%E5%8F%91/">开发</category>
      
      <category domain="https://www.banzhuanriji.com/tags/CDN/">CDN</category>
      
      <category domain="https://www.banzhuanriji.com/tags/APP/">APP</category>
      
      <category domain="https://www.banzhuanriji.com/tags/DNS/">DNS</category>
      
      <category domain="https://www.banzhuanriji.com/tags/dnsjava/">dnsjava</category>
      
      <category domain="https://www.banzhuanriji.com/tags/ipv6/">ipv6</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%8A%A0%E9%80%9F/">加速</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%8F%AF%E7%94%A8%E6%80%A7/">可用性</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%9B%86%E7%BE%A4/">集群</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/fix-network-issues/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Android 12的启动白屏简单适配方案</title>
      <link>https://www.banzhuanriji.com/posts/android-12-splashscreen/</link>
      <guid>https://www.banzhuanriji.com/posts/android-12-splashscreen/</guid>
      <pubDate>Thu, 24 Jul 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h3 id=&quot;TL-DR&quot;&gt;&lt;a href=&quot;#TL-DR&quot; class=&quot;headerlink&quot; title=&quot;TL;DR&quot;&gt;&lt;/a&gt;TL;DR&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;导入&lt;code&gt;implementation &#39;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><h3 id="TL-DR"><a href="#TL-DR" class="headerlink" title="TL;DR"></a>TL;DR</h3><ol><li><p>导入<code>implementation 'androidx.core:core-splashscreen:1.0.1'</code></p></li><li><p>继承主题 <code>Theme.ScreenSplash</code>，继承的主题可以设置前景和背景以及时间（最大500），类似icon</p></li><li><p>使用主题</p></li></ol><blockquote><p>在国产大厂的APP上，每一个Feature，每一个模块，每一个按钮，甚至每一个不可交互的地方，它都有出生的意义：广告位。</p><p>闪屏页的战略地位不言而喻😄</p></blockquote><p>在 Android 12（SDK 31）之前，应用的启动画面（Splash Screen）一直是个令人头疼的问题。开发者们不得不绞尽脑汁，通过自定义 Activity 主题、设置 <code>windowBackground</code> 或者创建一个独立的 Splash Activity 来模拟启动效果。</p><p>不仅需要作为天然的广告位，这个一闪而过页面承载太多东西了。你的所有需要注册的内容，所有内容的完整性检查，服务器判断，DNS解析。当然还有广告的加载以及用户的手有没有抖动…</p><p>虽然目前看来体验不尽人意，适配寥寥无几，不过当初Android12似乎真的想改变这些（当然不止这些，更多的可能是体验统一的问题），所以带来一个原生，更高效的解决方案。抛开这些开发决定不了的内容，下面我简单记录一下自己适配这个SplashScreen，当然这也是我第一次使用这个特性。</p><h2 id="核心概念与-Theme-SplashScreen-属性详解"><a href="#核心概念与-Theme-SplashScreen-属性详解" class="headerlink" title="核心概念与 Theme.SplashScreen 属性详解"></a>核心概念与 <code>Theme.SplashScreen</code> 属性详解</h2><p>Android 12 的启动画面不再是应用自身绘制的 View，而是由<strong>系统根据主题配置生成并管理</strong>。你的启动 Activity 会首先应用一个继承自 <code>Theme.SplashScreen</code> 的主题，系统会根据该主题的属性来渲染启动画面，并在应用准备就绪后平滑过渡到应用真正的界面。下面是我在网上找到的VerseAPP的动画闪屏页（你也可以下载查看teelgram的动画效果）：</p><p><a href="/img/Verse.gif" data-fancybox="gallery" data-caption=""><img src="/img/Verse.gif"></a></p><p>以下是 <code>Theme.SplashScreen</code> 主题及其关键属性的详细解析：</p><h4 id="1-父主题：Theme-SplashScreen"><a href="#1-父主题：Theme-SplashScreen" class="headerlink" title="1. 父主题：Theme.SplashScreen"></a>1. 父主题：<code>Theme.SplashScreen</code></h4><ul><li><strong>作用：</strong> 这是 Android 12+ 系统提供的启动画面基础主题。你的自定义启动主题<strong>必须继承</strong>这个主题，才能享受到系统级别的启动画面管理和动画效果。</li></ul><h4 id="2-背景属性：windowSplashScreenBackground"><a href="#2-背景属性：windowSplashScreenBackground" class="headerlink" title="2. 背景属性：windowSplashScreenBackground"></a>2. 背景属性：<code>windowSplashScreenBackground</code></h4><p><strong>类型：</strong> Drawable 引用（<code>@drawable/</code> 或 <code>@color/</code>）</p><p><strong>作用：</strong> 定义启动画面的背景。这是替换传统”白屏”的关键。</p><p><strong>自定义方案：</strong></p><ul><li><p><strong>纯色：</strong> 最简单也是最高效的方式，直接引用一个颜色资源，如 <code>&lt;item name="windowSplashScreenBackground"&gt;@color/your_brand_color&lt;/item&gt;</code>。</p></li><li><p><strong>渐变色：</strong> 创建一个 <code>shape</code> Drawable，并在其中定义 <code>gradient</code> 标签，实现平滑的颜色过渡。</p></li><li><p><strong>图片作为背景（慎用，推荐 LayerList）：</strong> 虽然可以直接引用一张图片 (<code>@drawable/your_image</code>)，但通常不推荐直接将一张大图作为背景，因为它可能导致屏幕适配问题、文件尺寸增大和内存开销。</p></li><li><p><strong>LayerList 组合背景</strong></p></li></ul><h4 id="3-图标属性：windowSplashScreenAnimatedIcon"><a href="#3-图标属性：windowSplashScreenAnimatedIcon" class="headerlink" title="3. 图标属性：windowSplashScreenAnimatedIcon"></a>3. 图标属性：<code>windowSplashScreenAnimatedIcon</code></h4><ul><li><p><strong>类型：</strong> Drawable 引用（<code>@drawable/</code> 或 <code>@mipmap/</code>）</p></li><li><p><strong>作用：</strong> 定义在启动画面中心显示的图标或动画。</p></li><li><p><strong>可选动画类型：</strong></p></li><li><p><strong>Animated Vector Drawable (AVD)</strong>：</p><ul><li><p><strong>格式：</strong> XML (<code>.xml</code>)，定义了矢量图的动画。</p><ul><li><p><strong>优点：</strong> <strong>官方推荐</strong>，文件小巧，可缩放不失真，性能优秀，可以实现复杂的矢量动画。</p></li><li><p><strong>创建：</strong> 复杂动画通常需要手动编写 XML 或借助工具。</p></li></ul></li><li><p><strong>Animation Drawable：</strong></p></li><li><p><strong>格式：</strong> XML (<code>.xml</code>)，引用一系列帧图片。</p><ul><li><p><strong>优点：</strong> 简单易懂，适合简单的帧动画。</p></li><li><p><strong>缺点：</strong> 每一帧都是一张图片，文件体积大，内存占用高，缩放可能失真。适用于帧数非常少且简单的动画。</p></li></ul></li><li><p><strong>自适应图标 (Adaptive Icon)：</strong></p></li><li><p><strong>格式：</strong> 通常是矢量图，由前景层 (<code>@mipmap/ic_launcher_foreground</code>) 和背景层 (<code>@mipmap/ic_launcher_background</code>) 组成。</p><ul><li><p><strong>优点：</strong> 系统原生支持，自动适应不同形状的图标蒙版，无需额外动画即可平滑缩放。</p></li><li><p><strong>最常用方案：</strong> 如果没有自定义动画需求，直接使用你的自适应图标前景层即可，例如：<code>&lt;item name="windowSplashScreenAnimatedIcon"&gt;@mipmap/ic_launcher_foreground&lt;/item&gt;</code>。</p></li></ul></li></ul></li></ul><h4 id="4-动画持续时间：windowSplashScreenAnimationDuration"><a href="#4-动画持续时间：windowSplashScreenAnimationDuration" class="headerlink" title="4. 动画持续时间：windowSplashScreenAnimationDuration"></a>4. 动画持续时间：<code>windowSplashScreenAnimationDuration</code></h4><ul><li><p><strong>类型：</strong> 整数（毫秒）</p></li><li><p><strong>作用：</strong> 定义 <code>windowSplashScreenAnimatedIcon</code> 中图标动画的持续时间。系统会在这个时间结束后开始淡出启动画面。</p></li><li><p><strong>注意：</strong> 你的动画设计应尽量在这个持续时间内完成，以避免动画被截断或过早结束。建议值为 200ms 到 1000ms 之间，保持快速且流畅。</p></li></ul><h4 id="5-品牌-Logo：windowSplashScreenBrandDrawable-可选"><a href="#5-品牌-Logo：windowSplashScreenBrandDrawable-可选" class="headerlink" title="5. 品牌 Logo：windowSplashScreenBrandDrawable (可选)"></a>5. 品牌 Logo：<code>windowSplashScreenBrandDrawable</code> (可选)</h4><ul><li><p><strong>类型：</strong> Drawable 引用</p></li><li><p><strong>作用：</strong> 在启动画面底部显示一个可选的品牌 Logo。</p></li><li><p><strong>位置：</strong> 这个 Logo 会固定显示在启动画面的底部，不会随图标一起动画。</p></li><li><p><strong>用处：</strong> 适合展示公司或产品的额外品牌标识。</p></li></ul><h4 id="6-核心属性：postSplashScreenTheme"><a href="#6-核心属性：postSplashScreenTheme" class="headerlink" title="6. 核心属性：postSplashScreenTheme"></a>6. 核心属性：<code>postSplashScreenTheme</code></h4><ul><li><p><strong>类型：</strong> Style 引用（<code>@style/</code>）</p></li><li><p><strong>作用：</strong> **这是最重要的属性！**它指定了启动画面结束后，Activity 应该切换到哪个主题来渲染你的应用界面。</p></li><li><p><strong>重要性：</strong> 如果没有正确设置这个属性，你的 Activity 在启动画面消失后，可能会显示错误的样式，甚至出现界面空白或闪烁。务必将其指向你应用正常运行时所使用的主要主题。</p></li></ul><hr><h3 id="二、应用开发实践：从零开始配置"><a href="#二、应用开发实践：从零开始配置" class="headerlink" title="二、应用开发实践：从零开始配置"></a>二、应用开发实践：从零开始配置</h3><p>让我们通过一个完整的示例，一步步将 Android 12 的启动画面集成到你的应用中。</p><h4 id="1-确保你的项目兼容-Android-12-SDK-31"><a href="#1-确保你的项目兼容-Android-12-SDK-31" class="headerlink" title="1: 确保你的项目兼容 Android 12 (SDK 31+)"></a>1: 确保你的项目兼容 Android 12 (SDK 31+)</h4><p>首先，在你的 <code>build.gradle (Module: app)</code> 文件中，确保 <code>compileSdk</code> 和 <code>targetSdk</code> 至少是 31：</p><pre><code class="hljs plaintext">android {    compileSdk 31 // 或更高版本    defaultConfig {        targetSdk 31 // 或更高版本        // ...    }    // ...}</code></pre><h4 id="2-添加-Splash-Screen-库依赖"><a href="#2-添加-Splash-Screen-库依赖" class="headerlink" title="2. 添加 Splash Screen 库依赖"></a>2. 添加 Splash Screen 库依赖</h4><pre><code class="hljs plaintext">dependencies {    // ... 其他依赖    implementation 'androidx.core:core-splashscreen:1.0.1' }</code></pre><h4 id="3-定义你的应用主题"><a href="#3-定义你的应用主题" class="headerlink" title="3. 定义你的应用主题"></a>3. 定义你的应用主题</h4><p>在 <code>res/values/themes.xml</code> (和 <code>res/values-night/themes.xml</code>，用于深色模式) 中定义应用主主题。这将是 <code>postSplashScreenTheme</code> 指向的主题。</p><pre><code class="hljs plaintext">&lt;resources&gt;    &lt;style name="Theme.MyAwesomeApp" parent="Theme.MaterialComponents.DayNight.NoActionBar"&gt;        &lt;item name="colorPrimary"&gt;#6200EE&lt;/item&gt;        &lt;item name="colorPrimaryVariant"&gt;#3700B3&lt;/item&gt;        &lt;item name="colorOnPrimary"&gt;#FFFFFF&lt;/item&gt;        &lt;item name="colorSecondary"&gt;#03DAC6&lt;/item&gt;        &lt;item name="colorSecondaryVariant"&gt;#018786&lt;/item&gt;        &lt;item name="colorOnSecondary"&gt;#000000&lt;/item&gt;        &lt;item name="android:statusBarColor"&gt;?attr/colorPrimaryVariant&lt;/item&gt;        &lt;item name="android:navigationBarColor"&gt;@color/black&lt;/item&gt;        &lt;item name="android:windowBackground"&gt;@color/white&lt;/item&gt;        &lt;/style&gt;&lt;/resources&gt;&lt;resources&gt;    &lt;style name="Theme.MyAwesomeApp" parent="Theme.MaterialComponents.DayNight.NoActionBar"&gt;        &lt;item name="colorPrimary"&gt;#BB86FC&lt;/item&gt;        &lt;item name="colorPrimaryVariant"&gt;#3700B3&lt;/item&gt;        &lt;item name="colorOnPrimary"&gt;#000000&lt;/item&gt;        &lt;item name="colorSecondary"&gt;#03DAC6&lt;/item&gt;        &lt;item name="colorSecondaryVariant"&gt;#03DAC6&lt;/item&gt;        &lt;item name="colorOnSecondary"&gt;#000000&lt;/item&gt;        &lt;item name="android:statusBarColor"&gt;?attr/colorPrimaryVariant&lt;/item&gt;        &lt;item name="android:navigationBarColor"&gt;@color/black&lt;/item&gt;        &lt;item name="android:windowBackground"&gt;@color/dark_gray&lt;/item&gt;    &lt;/style&gt;&lt;/resources&gt;</code></pre><h4 id="4-准备启动画面背景（渐变色和Logo）"><a href="#4-准备启动画面背景（渐变色和Logo）" class="headerlink" title="4. 准备启动画面背景（渐变色和Logo）"></a>4. 准备启动画面背景（渐变色和Logo）</h4><p>我们创建一个 <code>LayerList</code> 来实现一个包含渐变背景和底部品牌Logo的启动画面。（实际上不推荐 用渐变色，我更推荐telegram或者X的方案，纯色背景+AVD/静态LOGO）</p><pre><code class="hljs plaintext">&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;layer-list xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"&gt;    &lt;item&gt;        &lt;shape android:shape="rectangle"&gt;            &lt;gradient                android:angle="270"                android:startColor="#6200EE"                android:endColor="#03DAC6"                android:type="linear" /&gt;        &lt;/shape&gt;    &lt;/item&gt;    &lt;item android:bottom="32dp"&gt; &lt;bitmap            android:src="ic_my_company_logo"            android:gravity="bottom'center_horizontal" /&gt;    &lt;/item&gt;&lt;/layer-list&gt;</code></pre><p><strong>注意：</strong></p><ul><li><p><code>@drawable/ic_my_company_logo</code> 应该是你的 Logo 图片（Vector Drawable 或 Bitmap）。</p></li><li><p><code>android:bottom</code> 可以调整 Logo 的位置。</p></li><li><p><code>android:gravity="bottom'center_horizontal"</code> 将 Logo 放置在底部中央。</p></li></ul><h4 id="5-准备启动画面动画图标（AVD-示例）"><a href="#5-准备启动画面动画图标（AVD-示例）" class="headerlink" title="5. 准备启动画面动画图标（AVD 示例）"></a>5. 准备启动画面动画图标（AVD 示例）</h4><p>假设你已经有一个名为 <code>ic_animated_logo.xml</code> 的 Animated Vector Drawable。</p><pre><code class="hljs plaintext">&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;animated-vector xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"    android:drawable="@drawable/ic_static_logo"&gt; &lt;target android:name="group_name_in_static_logo"&gt; &lt;propertyValuesHolder            android:propertyName="rotation"            android:valueFrom="0"            android:valueTo="360"            android:valueType="floatType"            android:duration="1000"            android:interpolator="@android:interpolator/fast_out_slow_in" /&gt;    &lt;/target&gt;&lt;/animated-vector&gt;</code></pre><p><strong>如果不想使用自定义动画，直接使用自适应图标前景部分：<code>@mipmap/ic_launcher_foreground</code>。</strong></p><h4 id="6-定义启动画面主题"><a href="#6-定义启动画面主题" class="headerlink" title="6. 定义启动画面主题"></a>6. 定义启动画面主题</h4><p>现在，在 <code>res/values/themes.xml</code> (和 <code>res/values-night/themes.xml</code>) 中定义你的启动主题，并引用我们准备好的 Drawable。</p><pre><code class="hljs plaintext">&lt;resources&gt;    &lt;style name="Theme.MyAwesomeApp.SplashScreen" parent="Theme.SplashScreen"&gt;        &lt;item name="windowSplashScreenBackground"&gt;@drawable/splash_layer_bg&lt;/item&gt;        &lt;item name="windowSplashScreenAnimatedIcon"&gt;@drawable/ic_animated_logo&lt;/item&gt;        &lt;item name="windowSplashScreenAnimationDuration"&gt;1000&lt;/item&gt; &lt;item name="postSplashScreenTheme"&gt;@style/Theme.MyAwesomeApp&lt;/item&gt;    &lt;/style&gt;&lt;/resources&gt;&lt;resources&gt;    &lt;style name="Theme.MyAwesomeApp.SplashScreen" parent="Theme.SplashScreen"&gt;        &lt;item name="windowSplashScreenBackground"&gt;@color/dark_splash_bg_color&lt;/item&gt;        &lt;item name="windowSplashScreenAnimatedIcon"&gt;@drawable/ic_animated_logo_dark&lt;/item&gt;        &lt;item name="windowSplashScreenAnimationDuration"&gt;1000&lt;/item&gt;        &lt;item name="postSplashScreenTheme"&gt;@style/Theme.MyAwesomeApp&lt;/item&gt;    &lt;/style&gt;&lt;/resources&gt;</code></pre><h4 id="7-在-AndroidManifest-xml-中应用主题"><a href="#7-在-AndroidManifest-xml-中应用主题" class="headerlink" title="7. 在 AndroidManifest.xml 中应用主题"></a>7. 在 <code>AndroidManifest.xml</code> 中应用主题</h4><p>在 <code>AndroidManifest.xml</code> 中，将 <code>Theme.MyAwesomeApp.SplashScreen</code> 主题应用到启动 Activity（通常是 <code>MainActivity</code>，也有可能是<code>SplashActivity</code>之类的）。</p><pre><code class="hljs plaintext">&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;manifest xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"    xmlns:tools="[http://schemas.android.com/tools](http://schemas.android.com/tools)"&gt;    &lt;application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/Theme.MyAwesomeApp"&gt; &lt;activity            android:name=".MainActivity"            android:exported="true"            android:theme="@style/Theme.MyAwesomeApp.SplashScreen"&gt; &lt;intent-filter&gt;                &lt;action android:name="android.intent.action.MAIN" /&gt;                &lt;category android:name="android.intent.category.LAUNCHER" /&gt;            &lt;/intent-filter&gt;        &lt;/activity&gt;        &lt;activity android:name=".OtherActivity"            android:theme="@style/Theme.MyAwesomeApp"/&gt;    &lt;/application&gt;&lt;/manifest&gt;</code></pre><h4 id="8-在-MainActivity-中安装启动画面"><a href="#8-在-MainActivity-中安装启动画面" class="headerlink" title="8. 在 MainActivity 中安装启动画面"></a>8. 在 <code>MainActivity</code> 中安装启动画面</h4><p>最后，在启动 Activity 的 <code>onCreate()</code> 方法中调用 <code>installSplashScreen()</code>。<strong>这是启用系统启动画面 API 的核心步骤。</strong></p><pre><code class="hljs plaintext">// MainActivity.ktimport android.os.Bundleimport androidx.appcompat.app.AppCompatActivityimport androidx.core.splashscreen.SplashScreen.Companion.installSplashScreenimport kotlinx.coroutines.Dispatchersimport kotlinx.coroutines.delayimport kotlinx.coroutines.withContextimport androidx.lifecycle.lifecycleScopeimport kotlinx.coroutines.launchclass MainActivity : AppCompatActivity() {    private var isContentReady = false // 用于控制启动画面何时消失    override fun onCreate(savedInstanceState: Bundle?) {        // 1. 调用 installSplashScreen() 必须在 super.onCreate() 之前        val splashScreen = installSplashScreen()        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        // 2. 延迟启动画面消失，直到内容准备就绪        splashScreen.setKeepOnScreenCondition {            !isContentReady // 当 isContentReady 为 false 时，启动画面会一直显示        }        // 3. 模拟数据加载或应用初始化        loadAppContent()    }    private fun loadAppContent() {        lifecycleScope.launch(Dispatchers.IO) {            // 模拟耗时的初始化操作，例如网络请求、数据库加载等            delay(3000) // 模拟 3 秒的加载时间            // 数据加载完成            isContentReady = true            withContext(Dispatchers.Main) {                // 在这里可以执行数据加载完成后的 UI 更新或跳转操作                // 例如：navigateToHome()            }        }    }}</code></pre><p><strong>Java 示例(AI转换的代码，应该咩问题)：</strong></p><pre><code class="hljs plaintext">// MainActivity.javaimport android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;import androidx.core.splashscreen.SplashScreen;import android.os.Handler;import android.os.Looper;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class MainActivity extends AppCompatActivity {    private boolean isContentReady = false; // 用于控制启动画面何时消失    @Override    protected void onCreate(Bundle savedInstanceState) {        // 1. 调用 installSplashScreen() 必须在 super.onCreate() 之前        SplashScreen splashScreen = SplashScreen.Companion.installSplashScreen(this);        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // 2. 延迟启动画面消失，直到内容准备就绪        splashScreen.setKeepOnScreenCondition(() -&gt; !isContentReady);        // 3. 模拟数据加载或应用初始化        loadAppContent();    }    private void loadAppContent() {        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();        executor.schedule(() -&gt; {            // 模拟耗时的初始化操作            isContentReady = true; // 数据加载完成            new Handler(Looper.getMainLooper()).post(() -&gt; {                // 在主线程执行数据加载完成后的 UI 更新或跳转操作            });        }, 3, TimeUnit.SECONDS); // 模拟 3 秒的加载时间    }}</code></pre></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/Android-12/">Android 12</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Android%E5%BC%80%E5%8F%91/">Android开发</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Animated-Vector-Drawable/">Animated Vector Drawable</category>
      
      <category domain="https://www.banzhuanriji.com/tags/App%E5%BC%80%E5%8F%91/">App开发</category>
      
      <category domain="https://www.banzhuanriji.com/tags/java/">java</category>
      
      <category domain="https://www.banzhuanriji.com/tags/Kotlin/">Kotlin</category>
      
      <category domain="https://www.banzhuanriji.com/tags/LayerList/">LayerList</category>
      
      <category domain="https://www.banzhuanriji.com/tags/SplashScreen/">SplashScreen</category>
      
      <category domain="https://www.banzhuanriji.com/tags/UI-UX/">UI/UX</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE/">主题配置</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%90%AF%E5%8A%A8%E7%94%BB%E9%9D%A2/">启动画面</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%B9%BF%E5%91%8A%E4%BD%8D/">广告位</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%BC%80%E5%8F%91/">开发</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%87%AA%E9%80%82%E5%BA%94%E5%9B%BE%E6%A0%87/">自适应图标</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/android-12-splashscreen/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Wordpress发不出去通知邮件的解决方案</title>
      <link>https://www.banzhuanriji.com/posts/wordpress-mail-sender/</link>
      <guid>https://www.banzhuanriji.com/posts/wordpress-mail-sender/</guid>
      <pubDate>Sun, 25 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;TL;DR&lt;/p&gt;
&lt;p&gt;wordpress国内服务器访问不到发件服务器，所以经过综合考虑之后，选择采用第三方插件和第三方邮箱通过SMTP发送邮件。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;起因&quot;&gt;&lt;a href=&quot;#起因&quot; cl</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>TL;DR</p><p>wordpress国内服务器访问不到发件服务器，所以经过综合考虑之后，选择采用第三方插件和第三方邮箱通过SMTP发送邮件。</p><hr><h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>我转移到wordpress之后，之前搭建在纽约的服务器上，邮件是没什么问题的。评论和被评论都会收到邮件通知。但是正常转移到杭州的服务器上之后发现收不到任何邮件了，包括不限于修改密码，邮箱，用户操作，评论和被评论的通知邮件。</p><h2 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h2><p>❌期初我以为是因为服务器商封禁了邮件发送端口。但是我在防火墙打开了SMTP端口(25，465&nbsp;，587)的出站之后发现还是不行。</p><p>❌那就要考虑邮件是不是被服务商拦截的，询问客服之后告知不是，同时被告知如果发送垃圾邮件会被封禁。</p><p>✔️最后我检查之前的邮件，发现是来自wp.com的邮件。我并未安装jetpack，但是邮件依旧不是来自我的站点而是通过wordpress的服务器发送（猜测是需要访问一下WP的接口而非使用PHP的<code>mail()</code>方法发送的邮件）。</p><h2 id="尝试解决"><a href="#尝试解决" class="headerlink" title="尝试解决"></a>尝试解决</h2><p>问题明确之后就很容易解决了。下面是几个直接方案：</p><ol><li>通过一些方案访问WP.COM</li></ol><ul><li><p>代理</p><ul><li><p>HOSTS</p></li><li><p>更换服务器</p></li><li><p>修改DNS（或许可行？）</p></li><li><p>利用wordpress的第三方插件访问WP网络</p></li></ul></li></ul><ol start="2"><li>修改发件邮箱</li></ol><ul><li><p>修改mail()方法</p><ul><li>利用第三方插件</li></ul></li></ul><blockquote><p>因为我不想改代码了，也不想被警告，经过我1/3秒的思考，我觉得利用第三方插件，即使他们就是一个SMTP发送邮件的方案却做得又大又重，我似乎没有更多其它选择。</p></blockquote><p>我最后选择了Post SMTP，这是唯一一个SMTP插件，比较流行，看起来没那么重，且貌似不会打扰我的邮件插件。另外不推荐在 VPS 上运行本地 SMTP 服务器（配置复杂，送达率低）。</p><p>推荐使用QQ/foxmail邮箱做发件邮箱。所有的插件使用outlook都需要会员，outlook自带的SMTP貌似不可用了。我根据网上的教程设置了SMTP，打开了双重验证，然后在下方寻找应用密码。因为outlook在登录时似乎需要使用应用密码而不是账户密码。但是设置了双重验证，貌似又需要认证，永远提示认证失败。后来查了一下，说是之后会禁用第三方SMTP…奇奇怪怪的东西。另外我也不清楚这个是否会放到corn队列了，并且corn是否会堆积…对WP了解的不多。</p><p>所以，用FOXMAIL算啦！开通”POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务”之后，或许一个授权码用作登录即可。记得要勾选”<strong>SMTP 发信后保存到服务器</strong>“！</p><p>本身在传家宝上搭WP是为了方便，现在反而产生了更多的不方便。</p><h2 id="其他小问题"><a href="#其他小问题" class="headerlink" title="其他小问题"></a>其他小问题</h2><ul><li>插件提示存在屏蔽词或者被判断为垃圾内容，如下提示：</li></ul><blockquote><p>The mail may contain inappropriate words or content.</p></blockquote><p>此时你应该在插件中找到<strong>发送方式（Mailer Type）</strong>，修改为<code>PHPMailer</code></p><ul><li>发送失败，提示信息中存在如下字样：</li></ul><blockquote><p>Mail from address must be same as authorization user.</p></blockquote><p>此时你应该在插件中寻找**发件地址（From Address）**设置，然后修改文SMTP登录账号的邮箱。并且勾选”<strong>禁止其他插件/主题修改此内容</strong>“选项</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/wordpress/">wordpress</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%BC%AB%E8%B0%88/">漫谈</category>
      
      <category domain="https://www.banzhuanriji.com/tags/email/">email</category>
      
      <category domain="https://www.banzhuanriji.com/tags/foxmail/">foxmail</category>
      
      <category domain="https://www.banzhuanriji.com/tags/OUTLOOK/">OUTLOOK</category>
      
      <category domain="https://www.banzhuanriji.com/tags/SMTP/">SMTP</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%8F%92%E4%BB%B6/">插件</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%82%AE%E4%BB%B6/">邮件</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/wordpress-mail-sender/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Pocket给我的失望与启示</title>
      <link>https://www.banzhuanriji.com/posts/pocket-will-shut-down/</link>
      <guid>https://www.banzhuanriji.com/posts/pocket-will-shut-down/</guid>
      <pubDate>Fri, 23 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h2 id=&quot;TL-DR&quot;&gt;&lt;a href=&quot;#TL-DR&quot; class=&quot;headerlink&quot; title=&quot;TL;DR&quot;&gt;&lt;/a&gt;TL;DR&lt;/h2&gt;&lt;p&gt;这似乎是一个经典的互联网产品悲剧循环：&lt;/p&gt;
&lt;blockquo</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><h2 id="TL-DR"><a href="#TL-DR" class="headerlink" title="TL;DR"></a>TL;DR</h2><p>这似乎是一个经典的互联网产品悲剧循环：</p><blockquote><p>其他产品同类出现&gt; 导致用户流失 &gt; 更新不积极，市场定位偏差，没有突出买点以及差异化feature，固收基础功能以及紧缩的免费用户权限&gt; 加深市场竞争与用户流失&gt;Mozilla 战略调整&gt;宣布关停</p></blockquote><p>现在，如果做不到样样精通，还没有极端差异化的宣传噱头，似乎只有这一个剧本了。</p><hr><h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p><a href="/pocket-twitter.webp" data-fancybox="gallery" data-caption=""><img src="/pocket-twitter.webp"></a></p><p>当我听说 Mozilla 将在 2025 年 7 月 8 日关闭 Pocket 时，心里既不意外又有些唏嘘。作为一个曾经长期使用 Pocket 的免费用户，我一直觉得它的功能像个漂亮的”收藏夹”。Pocket 的关闭让我开始思考：是什么让这个”稍后阅读”工具走到尽头？</p><h2 id="Pocket-停止运营的背景"><a href="#Pocket-停止运营的背景" class="headerlink" title="Pocket 停止运营的背景"></a>Pocket 停止运营的背景</h2><p>2025 年 5 月 23 日，Mozilla 宣布 Pocket 将于 2025 年 7 月 8 日停止运营，同时关闭的还有其评论真伪分析工具 Fakespot（宣布今年7月1日关闭）。Mozilla 表示，关闭是为了集中资源发展 Firefox 浏览器。具体的安排如下：</p><ul><li><p><strong>服务终止</strong>：2025 年 7 月 8 日，Pocket 的 Web 端、移动端应用和浏览器扩展将全部停止。从 5 月 22 日起，用户无法下载应用或新购 Premium 订阅。</p></li><li><p><strong>数据导出</strong>：我需要在 2025 年 10 月 8 日前通过 Pocket 的导出页面备份文章，包括链接、标题、笔记和高亮，否则数据将永久丢失。</p></li><li><p><strong>连带关闭</strong>：Fakespot 的关闭表明 Mozilla 正在收缩非核心业务。</p></li></ul><h2 id="Pocket-为何让我失望"><a href="#Pocket-为何让我失望" class="headerlink" title="Pocket 为何让我失望"></a>Pocket 为何让我失望</h2><p>作为 Pocket 的免费用户，我一直觉得它的功能非常有限。Pocket 允许我保存网页和文章（或者说是链接）以便稍后阅读，但缺乏离线保存和下载网页内容的功能。这意味着，一旦网站失效或链接更改，我保存的内容就成了死链接，毫无用处。我曾保存过一篇教程，但网站下线后，Pocket 只能显示一个无用的标题，形同”残废收藏夹”。</p><p>相比之下，我用 Notion 搭配 Notion Web Clipper 就能轻松保存网页的完整内容，包括图片和格式化文本，还能添加笔记、标签，甚至整合到我的知识库中。不仅Notion，其他各种剪藏工具（<a href="https://chromewebstore.google.com/detail/web-clipper/mhfbofiokmppgdliakminbgdgcmbhbac">Web Clipper</a>不错）+同步工具都不错，你可以使用juplin（同样提供剪藏工具）+<a href="https://infini-cloud.net/en/">teracloud</a>（我的邀请码 <strong>NKM4G</strong> ）的搭配。为什么我推荐使用笔记工具？就像我之前在博客<a href="https://banzhuanriji.com/essay/how-to-take-notes.html#:~:text=%E8%AE%B0%E7%AC%94%E8%AE%B0%E7%9A%84%E7%9B%AE%E7%9A%84%E5%B9%B6%E9%9D%9E%E5%8D%95%E7%BA%AF%E4%B8%BA%E4%BA%86%E8%AE%B0%E5%BD%95%EF%BC%8C%E8%80%8C%E6%98%AF%E4%B8%BA%E4%BA%86%E5%A4%8D%E7%94%A8%E3%80%82">《如何记笔记》</a> 中有写：<strong>记笔记的目的并非单纯为了记录，而是为了复用。</strong> </p><p>或许你可以反驳，我需要的并不是一款”稍后读”软件而是笔记软件。或许是这样的，但是这两个需求并不冲突。如果你确实”稍后读”了收藏的内容，单纯地欣赏便罢了。若是还想记录下来，岂不是又要重复操作。所以带有我还是推荐带有全文搜索功能的笔记软件。</p><h2 id="导致-Pocket-关闭的连带效应"><a href="#导致-Pocket-关闭的连带效应" class="headerlink" title="导致 Pocket 关闭的连带效应"></a>导致 Pocket 关闭的连带效应</h2><p>Pocket 的关闭不是偶然，而是由一系列连带效应导致的，从竞品崛起到 Mozilla 的战略调整，每一步都让 Pocket 走向终结。</p><h3 id="竞品崛起引发用户流失"><a href="#竞品崛起引发用户流失" class="headerlink" title="竞品崛起引发用户流失"></a>竞品崛起引发用户流失</h3><p>Notion、Obsidian、Raindrop.io 和 Instapaper 等工具的出现让我和许多用户看到了更好的选择。Notion 提供了强大的笔记和协作功能，Obsidian 的双向链接适合知识管理，Raindrop.io 则在书签管理上更直观。这些工具的功能全面且不断更新，吸引了大量 Pocket 用户。X 平台上，不少用户表示因为竞品更强大而放弃了 Pocket。</p><h3 id="更新滞后与市场定位偏差"><a href="#更新滞后与市场定位偏差" class="headerlink" title="更新滞后与市场定位偏差"></a>更新滞后与市场定位偏差</h3><p>Pocket 的功能更新停滞不前，博客上最后一次提到新功能是在 2023 年。它的核心功能仅限于保存链接和阅读，缺乏 AI 摘要、深度笔记整合等差异化特性。免费用户像我一样，权限受限，无法使用标签管理或离线阅读，体验大打折扣。Pocket 的定位也模糊不清，既不如浏览器书签简单，也不如笔记工具强大，形同”半吊子”产品。</p><h3 id="加剧的市场竞争与用户流失"><a href="#加剧的市场竞争与用户流失" class="headerlink" title="加剧的市场竞争与用户流失"></a>加剧的市场竞争与用户流失</h3><p>功能停滞和定位偏差让 Pocket 在竞争中节节败退。竞品不断推出新功能，比如 Notion 的 AI 工具和 Obsidian 的插件生态，而 Pocket 却毫无进展。X 平台上的用户反馈也反映了类似的不满：界面陈旧、功能单一、标签管理繁琐。这些问题导致用户流失加剧，Pocket 的商业价值进一步下降。</p><h3 id="Mozilla-战略调整"><a href="#Mozilla-战略调整" class="headerlink" title="Mozilla 战略调整"></a>Mozilla 战略调整</h3><p>面对用户流失，Mozilla 的资源分配向 Firefox 倾斜。Firefox 需应对 Chrome 的竞争，迫使 Mozilla 放弃非核心项目。Pocket 与 Mozilla 的核心使命（隐私保护、开放互联网）关联度低，财务压力下，关闭 Pocket 和 Fakespot 成为必然选择。</p><h3 id="最终关闭决定"><a href="#最终关闭决定" class="headerlink" title="最终关闭决定"></a>最终关闭决定</h3><p>竞品崛起引发用户流失，功能滞后和定位偏差加剧竞争劣势，最终迫使 Mozilla 宣布关闭 Pocket。这个连带效应清晰地解释了 Pocket 从流行工具到被淘汰的轨迹。</p><h2 id="所以"><a href="#所以" class="headerlink" title="所以"></a>所以</h2><p>无论什么软件，数据可以无限制导出是最重要滴。Pocket 的关闭源于竞品崛起、用户流失、功能滞后、定位偏差和 Mozilla 战略调整的连带效应。作为免费用户，我早已因 Pocket 的局限性转向 Notion 等更强大的工具。这次经历让我意识到，选择数字工具时必须注重其功能完整性和长期稳定性。Pocket 的”稍后阅读”时代结束了，但它提醒我和所有用户：数据备份和工具选择需要更加谨慎。未来，工具开发者也应吸取教训，通过持续创新和清晰定位赢得用户信任。</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/notion/">notion</category>
      
      <category domain="https://www.banzhuanriji.com/tags/POCKET/">POCKET</category>
      
      <category domain="https://www.banzhuanriji.com/tags/teracloud/">teracloud</category>
      
      <category domain="https://www.banzhuanriji.com/tags/web-clipper/">web clipper</category>
      
      <category domain="https://www.banzhuanriji.com/tags/webdav/">webdav</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E4%BA%91%E5%90%8C%E6%AD%A5/">云同步</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%95%B0%E6%8D%AE%E5%AF%BC%E5%87%BA/">数据导出</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%BC%AB%E8%B0%88/">漫谈</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%A8%8D%E5%90%8E%E8%AF%BB/">稍后读</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%89%B4%E8%97%8F/">鉴藏</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/pocket-will-shut-down/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>三十而立，JAVA生日快乐！</title>
      <link>https://www.banzhuanriji.com/posts/java-turning-30/</link>
      <guid>https://www.banzhuanriji.com/posts/java-turning-30/</guid>
      <pubDate>Thu, 22 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;当一款一出生就颇具竞争力，甚至在每个榜单都名列前茅的编程语言持续更新到30周年，它已经不只是一门编程语言，一个学科，一项技术了。它是一个时代的标志。&lt;/p&gt;
&lt;h2 id=&quot;Java-技术演进之路与时代回响&quot;&gt;&lt;a href</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>当一款一出生就颇具竞争力，甚至在每个榜单都名列前茅的编程语言持续更新到30周年，它已经不只是一门编程语言，一个学科，一项技术了。它是一个时代的标志。</p><h2 id="Java-技术演进之路与时代回响"><a href="#Java-技术演进之路与时代回响" class="headerlink" title="Java 技术演进之路与时代回响"></a>Java 技术演进之路与时代回响</h2><p>1995 年 5 月 23 日，Sun Microsystems 发布了 Java 语言，谁也没想到这个诞生于小型家电控制项目的编程语言，会在接下来的三十年里重塑整个软件开发生态。从 Web 时代的 Servlet 到移动互联网的 Android，从大数据领域的 Hadoop 到云原生时代的 Kubernetes，Java 始终站在技术变革的潮头。今天，在 Java 迎来三十周年生日之际，让我们回溯那些改变技术史的里程碑时刻。</p><h2 id="一、”一次编写，到处运行”-的传奇起点"><a href="#一、”一次编写，到处运行”-的传奇起点" class="headerlink" title="一、”一次编写，到处运行” 的传奇起点"></a>一、”一次编写，到处运行” 的传奇起点</h2><p>Java 的诞生源于 Sun 公司 “Green Team” 的一个冷门项目 – 为智能电视、机顶盒等设备开发编程语言。詹姆斯・高斯林（James Gosling）带领团队设计出 Oak 语言（Java 前身），却因市场时机未到陷入沉寂。直到互联网浪潮袭来，Oak 凭借 “Write Once, Run Anywhere”（WORA）的跨平台特性，在浏览器插件领域找到突破口。1995 年发布的 Java 1.0 定义了核心特性：字节码、虚拟机（JVM）、垃圾回收机制，这些设计让 Java 程序能够在不同操作系统上以相同行为运行，彻底改变了软件开发的部署模式。</p><p>1996 年，第一个 Java 开发工具包（JDK 1.0）正式发布，包含 AWT 图形库与 Applet 技术。Applet 允许 Java 程序嵌入网页运行，引发了第一次 Java 热潮。尽管后来因安全问题逐渐被淘汰，但它验证了 Java 在网络应用领域的潜力。</p><h2 id="二、企业级开发的统治时代"><a href="#二、企业级开发的统治时代" class="headerlink" title="二、企业级开发的统治时代"></a>二、企业级开发的统治时代</h2><p>1998 年，Java 2 平台的发布标志着 Java 正式进军企业级应用领域。Java 2 平台分为标准版（J2SE）、企业版（J2EE）和微型版（J2ME），其中 J2EE 通过 EJB（Enterprise JavaBeans）、Servlet、JSP 等技术，为分布式应用开发提供了完整解决方案。IBM、Oracle 等巨头纷纷加入 Java 阵营，Java EE 成为构建银行核心系统、电商平台的事实标准，支撑起全球 80% 以上的企业级应用开发。</p><p>2004 年，Java 5（代号 Tiger）的发布堪称 Java 史上的重大飞跃。泛型、自动装箱 / 拆箱、枚举类型、可变参数等特性的引入，让 Java 从单纯的面向对象语言进化为更现代化的编程语言。同年，Spring 框架 1.0 发布，以轻量级容器和依赖注入理念革新了企业级开发模式，与 Java EE 形成互补，共同奠定了 Java 在企业级市场的统治地位。</p><h2 id="三、移动革命与开源觉醒"><a href="#三、移动革命与开源觉醒" class="headerlink" title="三、移动革命与开源觉醒"></a>三、移动革命与开源觉醒</h2><p>2007 年，苹果发布 iPhone，智能手机时代拉开帷幕。而 Java 早已提前布局，J2ME 曾是功能机时代的主流开发平台。2008 年，谷歌推出基于 Linux 内核和 Java 的 Android 系统，将 Java 推向移动开发的巅峰。虽然 Android 后来改用 Kotlin 作为官方推荐语言，但 Java 至今仍是安卓开发者的重要工具，全球数十亿台设备上运行着 Java 编写的应用。</p><p>2006 年，Sun 宣布 Java 开源，成立 OpenJDK 社区。这一决策打破了商业闭源的限制，激发了全球开发者的创造力。Apache Harmony、IBM J9 等替代 JVM 项目涌现，OpenJDK 逐步成为 Java 的参考实现。2010 年 Oracle 收购 Sun 后，围绕 Java 版权与开源协议的争议不断，但社区力量最终推动 Java 走向更开放的生态。</p><h2 id="四、云原生时代的涅槃重生"><a href="#四、云原生时代的涅槃重生" class="headerlink" title="四、云原生时代的涅槃重生"></a>四、云原生时代的涅槃重生</h2><p>2011 年起，Java 进入快速迭代周期，每半年发布一个新版本。Java 8 引入的 Lambda 表达式与 Stream API，让函数式编程范式融入传统 OOP 体系，极大提升了代码简洁性与并行处理能力；Java 11 成为首个 LTS（长期支持）版本，精简模块化系统并移除过时特性，标志着 Java 向轻量化转型。</p><p>随着容器化与微服务兴起，Java 凭借 Spring Cloud、Quarkus 等框架，以及 GraalVM 即时编译技术，在云原生领域焕发新生。Kubernetes 项目的核心组件 Kubelet、kube-apiserver 均采用 Java 开发，印证了其在分布式系统领域的卓越性能与稳定性。</p><h2 id="五、下一个三十年：Java-的无限可能"><a href="#五、下一个三十年：Java-的无限可能" class="headerlink" title="五、下一个三十年：Java 的无限可能"></a>五、下一个三十年：Java 的无限可能</h2><p>站在三十周年的节点，Java 生态早已超越编程语言本身，成为覆盖开发、部署、运维全生命周期的技术体系。如今，Java 正积极拥抱 AI 与 Web3 领域，通过 Project Loom 虚拟线程优化高并发场景，探索与机器学习框架的深度集成。OpenJDK 社区持续推进 JVM 性能优化，让 Java 在边缘计算、Serverless 等新兴领域保持竞争力。</p><p>从智能家电到数据中心，从桌面应用到云端服务，Java 用三十年时间证明了 “技术生命力在于持续进化”。对于全球 1000 万 Java 开发者而言，这不仅是一门编程语言的生日，更是一个时代技术精神的缩影。未来，随着 Java 22 计划引入结构化并发、虚拟线程成熟化等重磅特性，这个 “永远年轻” 的语言仍将书写新的传奇。</p><hr><h2 id="Java重要版本更新列表"><a href="#Java重要版本更新列表" class="headerlink" title="Java重要版本更新列表"></a>Java重要版本更新列表</h2><blockquote><p>由GROK.COM生成</p></blockquote><h3 id="1-Java-1-0（1996-年-1-月）"><a href="#1-Java-1-0（1996-年-1-月）" class="headerlink" title="1. Java 1.0（1996 年 1 月）"></a>1. <strong>Java 1.0（1996 年 1 月）</strong></h3><ul><li><p>定义核心特性，如字节码、虚拟机（JVM）、垃圾回收机制，实现 “Write Once, Run Anywhere” 跨平台运行。</p></li><li><p>发布第一个 Java 开发工具包（JDK 1.0），包含 AWT 图形库与 Applet 技术。</p></li></ul><h3 id="2-Java-1-1（1997-年-2-月）"><a href="#2-Java-1-1（1997-年-2-月）" class="headerlink" title="2. Java 1.1（1997 年 2 月）"></a>2. <strong>Java 1.1（1997 年 2 月）</strong></h3><ul><li><p>引入内部类，增强代码封装与组织性。</p></li><li><p>加入反射机制，支持运行时检查和操作类、方法、字段。</p></li><li><p>诞生 JDBC，方便 Java 程序与数据库交互。</p></li></ul><h3 id="3-Java-2-平台（1998-年）"><a href="#3-Java-2-平台（1998-年）" class="headerlink" title="3. Java 2 平台（1998 年）"></a>3. <strong>Java 2 平台（1998 年）</strong></h3><ul><li>分为标准版（J2SE）、企业版（J2EE）和微型版（J2ME）。其中 J2EE 通过 EJB、Servlet、JSP 等技术，为分布式应用开发提供完整解决方案。</li></ul><h3 id="4-Java-5（2004-年-9-月）"><a href="#4-Java-5（2004-年-9-月）" class="headerlink" title="4. Java 5（2004 年 9 月）"></a>4. <strong>Java 5（2004 年 9 月）</strong></h3><ul><li><p>引入泛型，提升类型安全性与代码复用性。</p></li><li><p>实现自动装箱 / 拆箱，简化基本数据类型与包装类的转换。</p></li><li><p>新增枚举类型，方便定义常量集合。</p></li><li><p>支持可变参数，使方法参数数量更灵活。</p></li></ul><h3 id="5-Java-7（2011-年-7-月）"><a href="#5-Java-7（2011-年-7-月）" class="headerlink" title="5. Java 7（2011 年 7 月）"></a>5. <strong>Java 7（2011 年 7 月）</strong></h3><ul><li><p>引入 try - with - resources 语句，简化资源管理。</p></li><li><p>钻石操作符<code>（&lt;&gt;）</code>自动推断泛型类型参数。</p></li><li><p>Fork/Join 框架提升并行处理大量数据的效率。</p></li><li><p>NIO 升级到 NIO.2，新增异步 I/O 和文件系统 API。</p></li></ul><h3 id="6-Java-8（2014-年-3-月）"><a href="#6-Java-8（2014-年-3-月）" class="headerlink" title="6. Java 8（2014 年 3 月）"></a>6. <strong>Java 8（2014 年 3 月）</strong></h3><ul><li><p>引入 Lambda 表达式，支持函数式编程范式。</p></li><li><p>推出 Stream API，提升代码简洁性与并行处理能力。</p></li><li><p>允许为接口方法添加默认方法体。</p></li><li><p>引入日期时间应用程序接口（date time API）。</p></li></ul><h3 id="7-Java-9（2017-年-9-月）"><a href="#7-Java-9（2017-年-9-月）" class="headerlink" title="7. Java 9（2017 年 9 月）"></a>7. <strong>Java 9（2017 年 9 月）</strong></h3><ul><li><p>引入模块化系统（Project Jigsaw），解决类路径问题，提高代码可维护性。</p></li><li><p>提供 Javadoc，支持在 API 文档中进行搜索，输出兼容 HTML5 标准。</p></li><li><p>在 List、Set、Map 接口中，静态工厂方法可创建不可变实例。</p></li><li><p>内置轻量级 JSON API。</p></li></ul><h3 id="8-Java-10（2018-年-3-月）"><a href="#8-Java-10（2018-年-3-月）" class="headerlink" title="8. Java 10（2018 年 3 月）"></a>8. <strong>Java 10（2018 年 3 月）</strong></h3><ul><li><p>带来局部变量类型推断（var 关键字），简化代码声明。</p></li><li><p>提升线程间通信效率的线程本地握手机制。</p></li><li><p>将 JDK 多个代码仓库合并到一个储存库。</p></li></ul><h3 id="9-Java-11（2018-年-9-月）"><a href="#9-Java-11（2018-年-9-月）" class="headerlink" title="9. Java 11（2018 年 9 月）"></a>9. <strong>Java 11（2018 年 9 月）</strong></h3><ul><li><p>成为首个 LTS（长期支持）版本。</p></li><li><p>精简模块化系统，移除过时特性。</p></li><li><p>引入 NestMembers 属性和 NestHost 属性。</p></li><li><p>支持 TLS 1.3 协议。</p></li></ul><h3 id="10-Java-17（2021-年-9-月）"><a href="#10-Java-17（2021-年-9-月）" class="headerlink" title="10. Java 17（2021 年 9 月）"></a>10. <strong>Java 17（2021 年 9 月）</strong></h3><ul><li><p>引入密封类，限制类的继承层次，增强代码安全性。</p></li><li><p>恢复浮点语义，为伪随机数发生器（PRNG）提供新接口类型。</p></li><li><p>增加 macOS AArch64 端口，删除 Applet API、远程方法调用（RMI）激活机制，强封装 JDK 内部。</p></li></ul></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/java/">java</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%BC%80%E5%8F%91/">开发</category>
      
      <category domain="https://www.banzhuanriji.com/tags/java30%E5%91%A8%E5%B9%B4/">java30周年</category>
      
      <category domain="https://www.banzhuanriji.com/tags/jdk/">jdk</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%91%A8%E5%B9%B4/">周年</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/">编程语言</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/java-turning-30/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>基于Nextjs的说说程序</title>
      <link>https://www.banzhuanriji.com/posts/microblog-by-nextjs/</link>
      <guid>https://www.banzhuanriji.com/posts/microblog-by-nextjs/</guid>
      <pubDate>Sun, 18 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;h3 id=&quot;TL-DR&quot;&gt;&lt;a href=&quot;#TL-DR&quot; class=&quot;headerlink&quot; title=&quot;TL;DR&quot;&gt;&lt;/a&gt;TL;DR&lt;/h3&gt;&lt;p&gt;点这里看效果：&lt;a href=&quot;https://ss.banzhu</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><h3 id="TL-DR"><a href="#TL-DR" class="headerlink" title="TL;DR"></a>TL;DR</h3><p>点这里看效果：<a href="https://ss.banzhuanriji.com/"> https://ss.banzhuanriji.com</a></p><p>发布，查看</p><hr><p>一代人有一代人的QQ空间要踩 XD ，可是QQ空间怎么少的了说说呢。而且发长文会带动一切RSS订阅用户，偶尔想当个动态/朋友圈发的话，太打扰人了。</p><p>所以我想到了两种方案：</p><ul><li><p>RSS避免某个分类的文章，把这个分类当做说说来发。但我想了想，似乎在function里加一些方法直接控制数据更好用一点，而且样式制作可以直接在CSS里修改，不影响其他文章样式内容。所以wordpress的方案又分为两种</p></li><li><p>不经过RSS的分类</p><ul><li>在wordpress的function中创建独立的方法内容</li></ul></li><li><p>创建一个独立的说说页面</p></li></ul><p>但是目前wordpress的数据库已经够复杂，冗余过于夸张了。并且之后如果我不希望使用wordpress的话，如何迁移？所以决定使用独立的方案。</p><p>第一想到的就是目前已经存在的有没有可用的。第一个想到的就是<a href="https://miantiao.me/">面条</a>大佬的<a href="https://github.com/ccbikai/BroadcastChannel">BroadcastChannel</a> ，把TG频道做数据来源。实话实说挺好用的。不过样式不可控，可能需要自己修改，且一些TG的内容样式不支持。所以我就采用了Nextjs+neon数据库的方案写了这个程序。</p><h3 id="功能"><a href="#功能" class="headerlink" title="功能"></a>功能</h3><ul><li><p>浏览内容，分页</p></li><li><p>鉴权登录</p></li><li><p>发布内容</p></li></ul><p>忽略了内容修改的功能，因为要做修改的话可能需要在首页做登录判断，然后在布局上做一些按钮预留。想了想暂时不做这个了</p><h3 id="特色"><a href="#特色" class="headerlink" title="特色"></a>特色</h3><p>如果可以成为特色的话…</p><ul><li><p>全部白嫖，白嫖！</p></li><li><p>结构超级简单</p></li><li><p>Markdown支持</p></li></ul><h3 id="预览"><a href="#预览" class="headerlink" title="预览"></a>预览</h3><p><a href="/img/image-2.png" data-fancybox="gallery" data-caption=""><img src="/img/image-2.png"></a></p><h3 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h3><p>如果你有兴趣可以查看这里： <a href="https://ss.banzhuanriji.com/">https://ss.banzhuanriji.com</a></p><p>暂时没有提供下载，等我完善之后在github上发出来XD。比较感兴趣的话也可以联系我，我会发给你一份源码： m#hoytzhang.com 或者在文章下面留言 ；D</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%BC%80%E5%8F%91/">开发</category>
      
      <category domain="https://www.banzhuanriji.com/tags/vercel/">vercel</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%8D%9A%E5%AE%A2/">博客</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%89%8D%E7%AB%AF/">前端</category>
      
      <category domain="https://www.banzhuanriji.com/tags/neon/">neon</category>
      
      <category domain="https://www.banzhuanriji.com/tags/next/">next</category>
      
      <category domain="https://www.banzhuanriji.com/tags/nextjs/">nextjs</category>
      
      <category domain="https://www.banzhuanriji.com/tags/QQ%E7%A9%BA%E9%97%B4/">QQ空间</category>
      
      <category domain="https://www.banzhuanriji.com/tags/serverless/">serverless</category>
      
      <category domain="https://www.banzhuanriji.com/tags/twitter/">twitter</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%AF%B4%E8%AF%B4/">说说</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/microblog-by-nextjs/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>如何为wordpress的文章添加阅读量</title>
      <link>https://www.banzhuanriji.com/posts/show-read-count-on-wordpress/</link>
      <guid>https://www.banzhuanriji.com/posts/show-read-count-on-wordpress/</guid>
      <pubDate>Wed, 14 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;要在 WordPress 上实现文章阅读统计（跟踪每篇文章的阅读次数或页面浏览量），可以借助插件或自定义代码。以下是几种常见的方法和工具，如果使用代码请注意文章内容。&lt;/p&gt;
&lt;h3 id=&quot;方法一：使用插件实现文章阅读统计</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>要在 WordPress 上实现文章阅读统计（跟踪每篇文章的阅读次数或页面浏览量），可以借助插件或自定义代码。以下是几种常见的方法和工具，如果使用代码请注意文章内容。</p><h3 id="方法一：使用插件实现文章阅读统计"><a href="#方法一：使用插件实现文章阅读统计" class="headerlink" title="方法一：使用插件实现文章阅读统计"></a>方法一：使用插件实现文章阅读统计</h3><ol><li><strong>MonsterInsights</strong></li></ol><ul><li>MonsterInsights 是最受欢迎的 Google Analytics 插件之一，可以直接在 WordPress 仪表板中查看每篇文章的页面浏览量、访客行为、跳出率等数据。通过其 Page Insights 扩展，还可以查看单篇文章的详细统计（如页面浏览量、停留时间等）。<strong>必须绑定GA。</strong></li></ul><ol start="2"><li><strong>WP Statistics</strong></li></ol><ul><li>WP Statistics 是一个隐私友好的分析插件，符合 GDPR 要求，无需外部账户，直接在 WordPress 数据库中存储数据。它可以跟踪每篇文章的访问量，并提供详细的图表和分类分析。不过<strong>最顶上那个评论似乎说明了一些问题</strong>，我没尝试这个插件，观望一下。</li></ul><ol start="3"><li><strong>Post Views Counter</strong></li></ol><ul><li>一个轻量级插件，专门用于显示文章、页面或自定义内容的浏览次数。它支持通过 PHP、JavaScript 或 REST API 跟踪数据，并允许自定义计数器的显示位置和样式。</li></ul><ol start="4"><li><strong>Jetpack Stats</strong></li></ol><ul><li>Jetpack 的统计模块提供文章的浏览量、热门内容、流量来源等数据，适合 WordPress.com 用户或安装了 Jetpack 的自托管站点。免费用户可查看<strong>过去 7 天</strong>的统计，付费计划解锁更多功能。</li></ul><ol start="5"><li><strong>Independent Analytics</strong></li></ol><ul><li>一个专为 WordPress 设计的免费分析插件，加载速度快，符合 GDPR。它可以自动记录文章的访问量，并按类别显示统计数据。</li></ul><ol start="6"><li><strong>如果你恰好财力雄厚，你可以使用一些主题的pro版本自带的功能</strong></li></ol><ul><li>这里就不对赘述了，例如我使用的blocksy主题，在设置页面左侧点击blocksy，设置中文章元数据打开显示即可。</li></ul><h3 id="方法二：插件之短码插件-推荐"><a href="#方法二：插件之短码插件-推荐" class="headerlink" title="方法二：插件之短码插件(推荐)"></a>方法二：插件之短码插件(推荐)</h3><ol><li><strong>Post Views for Jetpack</strong></li></ol><ul><li>提供短码，可以在文章、页面或小工具中显示各种统计数据。以下部分代码复制于这个插件的讨论区： <a href="https://wordpress.org/support/topic/way-to-display-views-in-blocksy-post-meta/">https://wordpress.org/support/topic/way-to-display-views-in-blocksy-post-meta/</a></li></ul><p>这个插件如何在blocksy中使用？请在你的<code>function.php</code>中添加以下代码 （<strong>注意把<code>[sbs_views]</code> 修改为你上面短码插件中约定的短码</strong>）：</p><pre><code class="hljs plaintext">add_filter( 'blocksy:archive:render-card-layer', function ( $output, $single_component) {if ( 'post_meta' !== $single_component['id'] ) {return $output;}$post_views = do_shortcode( '&lt;span style="background-color: initial; font-family: inherit; text-align: initial;"&gt;[sbs_views]&lt;/span&gt;' );$output = str_replace( '&lt;/li&gt;&lt;/ul&gt;', '&lt;/li&gt;&lt;li class="post-views"&gt;' . $post_views . '&lt;/li&gt;&lt;/ul&gt;', $output );return $output;}, 11, 2 );</code></pre><h3 id="方法三：自定义代码实现阅读统计"><a href="#方法三：自定义代码实现阅读统计" class="headerlink" title="方法三：自定义代码实现阅读统计"></a>方法三：自定义代码实现阅读统计</h3><p>在你的主题的<code>function.php</code>中添加以下代码：</p><pre><code class="hljs plaintext">// 记录文章浏览量function set_post_views($postID) {    $count_key = 'post_views_count';    $count = get_post_meta($postID, $count_key, true);    if ($count == '') {        $count = 0;        delete_post_meta($postID, $count_key);        add_post_meta($postID, $count_key, '0');    } else {        $count++;        update_post_meta($postID, $count_key, $count);    }}// 在单篇文章页面记录浏览量function track_post_views($postID) {    if (!is_single()) return;    if (empty($postID)) {        global $post;        $postID = $post-&gt;ID;    }    set_post_views($postID);}add_action('wp_head', 'track_post_views');// 显示文章浏览量function get_post_views($postID) {    $count_key = 'post_views_count';    $count = get_post_meta($postID, $count_key, true);    if ($count == '') {        delete_post_meta($postID, $count_key);        add_post_meta($postID, $count_key, '0');        return "0 Views";    }    return $count . ' Views';}</code></pre><p>在需要使用的地方添加：</p><pre><code class="hljs plaintext">echo get_post_views(get_the_ID());</code></pre><p>如果需要在blocksy主题中使用：</p><pre><code class="hljs plaintext">add_filter( 'blocksy:archive:render-card-layer', function ( $output, $single_component ) {    if ( 'post_meta' !== $single_component['id'] ) {        return $output;    }    $output = str_replace( '&lt;/li&gt;&lt;/ul&gt;', '&lt;/li&gt;&lt;li class="post-views"&gt;' . get_post_views(get_the_ID()) . '&lt;/li&gt;&lt;/ul&gt;', $output );    return $output;}, 10, 2 );</code></pre><hr><p>注意上面所有的代码部分，可能会造成不可回溯的内容。</p><p>部分可能会在你数据库的<code>前缀_postmeta</code>表中创建很多key为<code>post_views_count</code> 的数据，介意的话可以使用第三方插件或者自己手动修改。另外注意，有的主题不允许修改<code>functions.php</code>的代码，你复制代码保存失败时，可以按 <code>ctrl</code>+ <code>shift</code> + <code>v</code> 粘贴。</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E4%B8%BB%E9%A2%98/">主题</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/">服务器</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%89%8D%E7%AB%AF/">前端</category>
      
      <category domain="https://www.banzhuanriji.com/tags/wordpress/">wordpress</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%BB%9F%E8%AE%A1/">统计</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%8F%92%E4%BB%B6/">插件</category>
      
      <category domain="https://www.banzhuanriji.com/tags/count/">count</category>
      
      <category domain="https://www.banzhuanriji.com/tags/jetpack/">jetpack</category>
      
      <category domain="https://www.banzhuanriji.com/tags/view-count/">view count</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%B5%8F%E8%A7%88%E9%87%8F/">浏览量</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%82%B9%E5%87%BB%E9%87%8F/">点击量</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%AE%A1%E6%95%B0/">计数</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%98%85%E8%AF%BB%E8%AE%A1%E6%95%B0/">阅读计数</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/show-read-count-on-wordpress/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>家里种的月季花</title>
      <link>https://www.banzhuanriji.com/posts/flowers-i-planting/</link>
      <guid>https://www.banzhuanriji.com/posts/flowers-i-planting/</guid>
      <pubDate>Tue, 13 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;/img/1747197673690.webp&quot; data-fancybox=&quot;gallery&quot; data-caption=&quot;&quot;&gt;&lt;img src=&quot;/img/1747197673690.webp&quot;&gt;&lt;/a</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p><a href="/img/1747197673690.webp" data-fancybox="gallery" data-caption=""><img src="/img/1747197673690.webp"></a><br><a href="/img/1747197673705.webp" data-fancybox="gallery" data-caption=""><img src="/img/1747197673705.webp"></a><br><a href="/img/1747197673698.webp" data-fancybox="gallery" data-caption=""><img src="/img/1747197673698.webp"></a></p><p>家里养的月季开的非常漂亮，发了朋友圈之后被问怎么种的。就是家里空地（农村小院）上种的，没有特别照料和施肥。不仅种在土地上的花，花盆里的花也开的很漂亮。总结了一下，大概是这几点会注意：</p><h4 id="光照，绝对充足的光照"><a href="#光照，绝对充足的光照" class="headerlink" title="光照，绝对充足的光照"></a>光照，绝对充足的光照</h4><p>如果你没有额外施肥，那么光照就不应该吝啬。太阳大的晴天可以放到室外阳光直射的地方。有的花甚至光照够一定的时间才会开花，才会有花芽！除了一些特别的植物，绝大部分都喜欢被阳光直射。</p><h4 id="按照习性浇水"><a href="#按照习性浇水" class="headerlink" title="按照习性浇水"></a>按照习性浇水</h4><p>这些月季是三五天浇一次的，但是没有特别照顾。旁边就是菜地，基本都是浇完菜顺带水管冲一下。这里需要注意：<strong>温度高的时候不要浇花或者作物</strong>，会导致根系烫伤，或者温差也会对植物造成伤害。</p><p>在过强的光照或者温度较高环境下，植物会蔫蔫的，就像下图，这是一株种在花盆里的<strong>蓝</strong>花草，此时请勿直接浇水，可以等太阳落山或者吃完晚饭后适当浇水或者浸泡花盆。</p><p><a href="/img/74da32ce841b54de.webp" data-fancybox="gallery" data-caption=""><img src="/img/74da32ce841b54de.webp"></a></p><h4 id="适当修剪"><a href="#适当修剪" class="headerlink" title="适当修剪"></a>适当修剪</h4><p>还是小学学过的那些，平常可以修剪，留老桩（如果不会可以去抖音搜索一下）。生长期可以按照你的想法去顶枝，让他更茂盛，因为顶枝非常吃养料。</p><p>最后附上高清图片 ;D</p><p><a href="/img/c89e5d6f40c5f585.webp" data-fancybox="gallery" data-caption=""><img src="/img/c89e5d6f40c5f585.webp"></a></p><p><a href="/img/f5a96513f63e1035.webp" data-fancybox="gallery" data-caption=""><img src="/img/f5a96513f63e1035.webp"></a></p><p><a href="/img/6306a24d9b56fc80.webp" data-fancybox="gallery" data-caption=""><img src="/img/6306a24d9b56fc80.webp"></a></p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%9A%8F%E7%AC%94/">随笔</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E4%BF%AE%E5%89%AA/">修剪</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%85%89%E7%85%A7/">光照</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%86%9C%E6%9D%91%E5%B0%8F%E9%99%A2/">农村小院</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%96%BD%E8%82%A5/">施肥</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%9C%88%E5%AD%A3/">月季</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%A0%B9%E7%B3%BB%E7%83%AB%E4%BC%A4/">根系烫伤</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%A4%8D%E7%89%A9%E4%B9%A0%E6%80%A7/">植物习性</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%B5%87%E6%B0%B4/">浇水</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%94%9F%E6%B4%BB/">生活</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%9B%B8%E5%86%8C/">相册</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%A7%8D%E6%A4%8D/">种植</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%80%81%E6%A1%A9/">老桩</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E9%A1%B6%E6%9E%9D/">顶枝</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/flowers-i-planting/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>从Typecho安全平移到Wordpress</title>
      <link>https://www.banzhuanriji.com/posts/move-blog-to-wordpress/</link>
      <guid>https://www.banzhuanriji.com/posts/move-blog-to-wordpress/</guid>
      <pubDate>Sun, 11 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;这里不比较Typecho与Wordpress的好坏。实际上优缺点都很明显。但如果你没有其他想法，只是想单纯写写内容，Notebook才是最棒的选择。我只是想把加的各位朋友的友链放在除了&lt;a href=&quot;https://ban</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>这里不比较Typecho与Wordpress的好坏。实际上优缺点都很明显。但如果你没有其他想法，只是想单纯写写内容，Notebook才是最棒的选择。我只是想把加的各位朋友的友链放在除了<a href="https://banzhuanriji.com/links">友链页</a>以外的其他页面，那貌似只能放在sidebar了，所以选择了一个双栏的杂志主题。后来想了想，直接换wordpress得了。</p><h4 id="1-导出数据"><a href="#1-导出数据" class="headerlink" title="1. 导出数据"></a>1. 导出数据</h4><p>数据导出当然使用的是<a href="https://github.com/sunxiyuan/ByeTyp">ByTyp</a>，但是我记得之前第一次安装是有什么问题的，貌似是PHP版本不对还是什么东西，忘记了，不过我记得我修改了一些东西。如果你会有这个问题并且你发现搜索不到解决方案，你可以点下面的按钮下载我的备份：</p><div class="wp-block-file">[ByeTyp_3zCNM](https://banzhuanriji.com/wp-content/uploads/2025/05/ByeTyp_3zCNM.zip)[下载](https://banzhuanriji.com/wp-content/uploads/2025/05/ByeTyp_3zCNM.zip)</div>#### 2. 备份<p>备份你需要做以下备份</p><ul><li><p>下载Typecho的所有文件内容</p></li><li><p>下载Typecho的数据库备份文件</p></li><li><p>尝试新建数据库并导入数据库备份文件查看是否可以导入</p></li><li><p>使用Typecho的备份功能下载备份文件</p></li><li><p>检查以上备份</p></li></ul><h4 id="3-安装Wordpress和导入数据"><a href="#3-安装Wordpress和导入数据" class="headerlink" title="3. 安装Wordpress和导入数据"></a>3. 安装Wordpress和导入数据</h4><p>因为我后端使用的是宝塔，所以有一键部署。我的域名是<a href="https://banzhuanriji.com/">banzhuanriji.com</a>，我新建的网站绑定的域名为abc(这里你自己设置).banzhuanriji.com，然后所有的操作都是在这个网站上进行的。<br><a href="/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250512204757_11.png" data-fancybox="gallery" data-caption=""><img src="/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20250512204757_11.png"></a></p><p>工具-导入-立即安装，安装完成后会显示【运行导入器】，然后选择上面ByTyp导出的文件即可，选择接受用户即可。</p><h4 id="4-修改域名"><a href="#4-修改域名" class="headerlink" title="4. 修改域名"></a>4. 修改域名</h4><ol><li><p>检查上面的备份内容</p></li><li><p>wordpress后台，设置-常规：WordPress 地址（URL）和 站点地址（URL）修改为你的地址</p></li><li><p>修改网站文件夹名称，也就是删除原来的 banzhuanriji.com，把abc.banzhuangriji.com，修改为banzhuanriji.com</p></li><li><p>重启Nginx</p></li></ol><h4 id="5-安装需要的插件"><a href="#5-安装需要的插件" class="headerlink" title="5. 安装需要的插件"></a>5. 安装需要的插件</h4><p>我是所有都设置好之后才修改域名的，现在我点击主题的自定义，就会先显示几条错误提示，再显示自定义网页页面。错误内容如下：</p><pre><code class="hljs plaintext">Warning: Undefined array key "mp_featuredimg_1" in /www/wwwroot/banzhuanriji.com/wp-includes/class-wp-customize-widgets.php on line 1130Warning: Trying to access array offset on value of type null in /www/wwwroot/banzhuanriji.com/wp-includes/class-wp-customize-widgets.php on line 1130Warning: Undefined array key "mp_featuredimg_1" in /www/wwwroot/banzhuanriji.com/wp-includes/class-wp-customize-widgets.php on line 1131Warning: Trying to access array offset on value of type null in /www/wwwroot/banzhuanriji.com/wp-includes/class-wp-customize-widgets.php on line 1131Warning: Undefined array key "mp_featuredimg_1" in /www/wwwroot/banzhuanriji.com/wp-includes/class-wp-customize-widgets.php on line 603Warning: Trying to access array offset on value of type null in /www/wwwroot/banzhuanriji.com/wp-includes/class-wp-customize-widgets.php on line 603</code></pre><p>貌似是Blocky插件的问题，到现在我都不知道怎么解决…</p><h4 id="6-其他"><a href="#6-其他" class="headerlink" title="6. 其他"></a>6. 其他</h4><p>关于安装的插件和主题，有兴趣的话可以查看<a href="https://banzhuanriji.com/about">关于</a>页面。</p><p>如果你没有想使用Wordpress，那么我推荐你使用<a href="https://github.com/AlanDecode/Typecho-Plugin-Tp2MD">Tp2MD</a>，可以导出到Markdown文件，你经过简单的修改可以直接在一些hexo，hugo，nextjs或者astro等可以使用Markdown文件的博客系统。</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E4%B8%BB%E9%A2%98/">主题</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/">服务器</category>
      
      <category domain="https://www.banzhuanriji.com/tags/PHP/">PHP</category>
      
      <category domain="https://www.banzhuanriji.com/tags/typecho/">typecho</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%8D%9A%E5%AE%A2/">博客</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%89%8D%E7%AB%AF/">前端</category>
      
      <category domain="https://www.banzhuanriji.com/tags/wordpress/">wordpress</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%AF%BC%E5%85%A5/">导入</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%95%B0%E6%8D%AE/">数据</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%96%87%E7%AB%A0/">文章</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%A8%8B%E5%BA%8F/">程序</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E8%BD%AC%E7%A7%BB/">转移</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/move-blog-to-wordpress/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>堵不如疏，用LLMS.TXT对ai爬虫进行引导</title>
      <link>https://www.banzhuanriji.com/posts/llmstxt/</link>
      <guid>https://www.banzhuanriji.com/posts/llmstxt/</guid>
      <pubDate>Sun, 04 May 2025 16:00:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;最近发现网站访问量异常。脚标的”当前浏览次数”数字异常。看了一下后台数据貌似是被刷流量了？搜索了一下ip才发现是被ai爬虫爬的。吐槽一下阿里云的ECS，CPU到70%就直接卡死了。面对ai爬虫，2C2G的小机感觉压力好大。想</description>
          
        
      
      
      
      <content:encoded><![CDATA[<html><head></head><body><p>最近发现网站访问量异常。脚标的”当前浏览次数”数字异常。看了一下后台数据貌似是被刷流量了？搜索了一下ip才发现是被ai爬虫爬的。吐槽一下阿里云的ECS，CPU到70%就直接卡死了。面对ai爬虫，2C2G的小机感觉压力好大。想起来之前读的ruanyifeng的 <a href="https://www.ruanyifeng.com/blog/2025/03/weekly-issue-343.html">科技爱好者周刊（第 343 期）：如何阻止 AI 爬虫</a> ，里面提到了两种防止ai爬虫的方案：</p><ul><li>Cloudflare</li><li>Anubis</li></ul><p>其中Anubis的逻辑大概是：</p><blockquote><p>页面会在用户的浏览器上，执行一段 JS 程序，进行大量的数学计算。直到计算答案正确，才可以访问目标网站。</p><p>这个过程有时很耗时，可能需要1～2分钟。<br>……<br>那么，Anubis 到底让爬虫计算什么？</p><p>具体来说，就是下面这行代码，计算一个哈希值。</p><p>const hash = await sha256(<code>${challenge}${nonce}</code>);</p><p>可以看到，它就是用 SHA256 算法，计算一个字符串的哈希值。</p><p>这个字符串由两部分组成，第一部分challenge，由用户的一些公开信息连接而成，包括用户的 IP 地址、浏览器 user-agent 字段、当前日期、Anubis 的公钥等。</p><p>第二部分nonce，表示迭代次数，第一次计算就是1，第二次计算就是2，以此类推。</p><p>Anubis 的默认设定是，计算出来的哈希值的前五位必须都为0，否则 nonce 自动加1，再次进行计算，直到满足要求为止。</p><p>有时，可能需要计算几百万次，才能得到合格的哈希值。熟悉比特币的同学，应该一眼看出来了，这就是比特币的算法。比特币是非常耗费算力的，所以 Anubis 也能很有效地消耗爬虫的 CPU。</p></blockquote><p>但是这对一个个人网站实在太无厘头了！文章最开始提到了使用<code>robots.txt</code>来拒绝爬虫，但貌似AI的爬虫都不遵守<code>robots.txt</code>的内容… 经过我的搜索了解，我找到了<code>llms.txt</code> ，你可以理解为这是面对ai的<code>robots.txt</code> ，它可以大幅度减少ai爬虫对资源的无意义消耗。这里是本站点的 <a href="https://banzhuanriji.com/llms.txt">LLMs.txt</a></p><p>下面我讲简单介绍一下<code>llms.txt</code>，以及如何使用它。</p><hr><h2 id="llms-txt-的作用"><a href="#llms-txt-的作用" class="headerlink" title="llms.txt 的作用"></a>llms.txt 的作用</h2><p>llms.txt 似乎是一种新兴的网站标准，旨在为大型语言模型（LLMs）提供一个简洁的总结，帮助它们快速获取网站的核心信息。它通常是一个 Markdown 文件，放在网站根目录（如 /llms.txt），包含网站的背景、指南和指向详细文档的链接。这对于 LLMs 来说非常有用，因为它们的上下文窗口有限，无法处理整个网站的复杂 HTML 结构。研究表明，它特别适用于需要快速访问技术文档和 API 的场景，如软件开发环境。</p><h2 id="如何使用-llms-txt"><a href="#如何使用-llms-txt" class="headerlink" title="如何使用 llms.txt"></a>如何使用 llms.txt</h2><p>对于网站所有者，可以按照以下步骤创建和使用 llms.txt：</p><ul><li><p>创建文件: 在网站根目录创建一个名为 <code>llms.txt</code> 的文件，使用 Markdown 格式编写。</p></li><li><p>添加内容: 包括标题（H1）、摘要（使用 blockquote）、可选的详细部分和链接。例如：</p><h1 id="My-Website"><a href="#My-Website" class="headerlink" title="My Website"></a>My Website</h1><blockquote><p>This is a brief summary of what my website offers.<br>Here are some key points:</p></blockquote><ul><li>It provides <a href="https://example.com/api.md">API documentation</a></li><li>It includes <a href="https://example.com/tutorials.md">tutorials</a></li></ul></li><li><p>提供 Markdown 版本: 为关键页面提供 Markdown 版本，通过在 URL 后加 .md 实现。</p></li><li><p>使用工具: 可以利用如  <a href="http://llmstxt.firecrawl.dev/">llms.txt 生成器</a> 自动生成文件，简化过程。</p></li></ul><p>对于 LLMs，系统会检查网站是否有 <code>/llms.txt</code> 文件，并使用其中的信息快速了解网站，通过链接找到更多详情。</p><h2 id="关于周边"><a href="#关于周边" class="headerlink" title="关于周边"></a>关于周边</h2><p>为什么我上面会提到<strong>大幅度减少</strong>呢？因为这是一个新的民间协议，是一个新生的，约定俗成的内容。面对蓬勃发展的ai产业，很多产品经理不会要求自家ai爬虫遵守规则的。</p><p>llms.txt 是一种 2024 年 9 月由 Jeremy Howard 提出的网站标准，旨在增强大型语言模型（LLMs）对网站内容的理解和利用，特别是在推理阶段。其设计初衷是解决 LLMs 上下文窗口有限的问题，使其能够高效处理网站信息，而无需解析复杂的 HTML 结构。</p><p>llms.txt 的主要作用是为网站提供一个结构化、简洁的 LLM 友好内容入口。证据倾向于认为，它通过提供简短的摘要、背景信息和链接，帮助 LLMs 快速了解网站的目的和内容，避免处理复杂的网页元素如导航、广告和 JavaScript。这对于 LLMs 来说尤为重要，因为它们的上下文窗口通常无法容纳整个网站的全部内容。</p><h2 id="使用方法与结构"><a href="#使用方法与结构" class="headerlink" title="使用方法与结构"></a>使用方法与结构</h2><p>对于网站所有者，创建和使用 llms.txt 的方法如下：</p><h3 id="创建文件："><a href="#创建文件：" class="headerlink" title="创建文件："></a>创建文件：</h3><ul><li>在网站根目录创建一个名为 <code>llms.txt</code> 的文件。</li><li>使用 Markdown 格式编写，确保内容适合人类阅读，也适合 LLMs 解析。</li></ul><h3 id="文件结构："><a href="#文件结构：" class="headerlink" title="文件结构："></a>文件结构：</h3><ul><li><p>标题（H1）：必须包含项目或网站的名称，例如 <code># 搬砖日记</code> 。</p></li><li><p>摘要：使用 blockquote 格式提供简短描述，例如 <code>&gt; 白天给代码写对象，深夜给自己写日记</code> 。</p></li><li><p>详细部分（可选）：可以包括段落或列表，但不使用额外的标题，例如：</p><p>Here are some key points about my website:</p><ul><li>It provides <a href="https://example.com/api.md">API documentation</a></li><li>It includes <a href="https://example.com/tutorials.md">tutorials</a></li></ul></li><li><p>文件列表（可选）：使用 H2 标题分隔，包含超链接和可选说明，例如：</p><h2 id="Resources"><a href="#Resources" class="headerlink" title="Resources"></a>Resources</h2><ul><li><a href="https://example.com/guide.md">Detailed Guide</a>: Comprehensive user manual</li></ul></li><li><p>“Optional”部分（可选）：用于次要信息，LLMs 可以选择跳过，例如：</p><h2 id="Optional"><a href="#Optional" class="headerlink" title="Optional"></a>Optional</h2><ul><li><a href="https://example.com/more.md">Additional Resources</a></li></ul></li><li><p>为网站的关键页面提供 Markdown 版本，你可以参考这里： <a href="https://docs.fastht.ml/">https://docs.fastht.ml/</a></p></li></ul><hr><p>如果你储存的txt文件在访问时出现中文乱码，那么你应该修改服务器配置：</p><h3 id="Nginx"><a href="#Nginx" class="headerlink" title="Nginx"></a>Nginx</h3><pre><code class="hljs plaintext"># Serve .txt files with the correct Content-Typelocation ~ \.txt$ {    default_type text/plain;    charset utf-8;    # Ensure charset is specified as UTF-8}</code></pre><h3 id="Apache"><a href="#Apache" class="headerlink" title="Apache"></a>Apache</h3><pre><code class="hljs plaintext"># Ensure the default charset is set to UTF-8    AddDefaultCharset UTF-8    # Configure specific file types with UTF-8 charset    &lt;FilesMatch "\.(txt)$"&gt;        ForceType 'text/plain; charset=UTF-8'    &lt;/FilesMatch&gt;</code></pre><p>以上均为需要在配置文件中新添加的内容，请勿覆盖原有内容</p><hr><p>最近Github多次从多个技术层面对大陆ip/用户进行了筛选封锁，据说是被CSDN的<strong>搬空Github</strong>给整的… 无论如何，虽然我不是ai从业者，但是如果恰好有相关的朋友看到这里，我给了一些小建议：</p><ul><li>在访问网站时，首先检查是否存在 <code>/llms.txt</code> 文件。</li><li>使用文件中的信息快速了解网站的目的，并通过提供的链接找到详细内容，例如 API 文档或教程。</li><li>可以结合工具如 <code>llms_txt2ctx</code> 解析文件，生成适合 LLMs 的上下文。</li></ul><p>毕竟前台页面是给人看的。如果有winwin的方案，何乐而不为呢？</p></body></html>]]></content:encoded>
      
      
      <category domain="https://www.banzhuanriji.com/categories/posts/">默认</category>
      
      
      <category domain="https://www.banzhuanriji.com/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/">服务器</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E5%89%8D%E7%AB%AF/">前端</category>
      
      <category domain="https://www.banzhuanriji.com/tags/ai/">ai</category>
      
      <category domain="https://www.banzhuanriji.com/tags/llm/">llm</category>
      
      <category domain="https://www.banzhuanriji.com/tags/llms/">llms</category>
      
      <category domain="https://www.banzhuanriji.com/tags/llms-txt/">llms.txt</category>
      
      <category domain="https://www.banzhuanriji.com/tags/%E7%88%AC%E8%99%AB/">爬虫</category>
      
      
      <comments>https://www.banzhuanriji.com/posts/llmstxt/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>