<?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>Eucalyptus</title>
    <link>https://blog.mingliangstar.com/</link>
    
    <image>
      <url>https://blog.mingliangstar.com/icon.png</url>
      <title>Eucalyptus</title>
      <link>https://blog.mingliangstar.com/</link>
    </image>
    
    <atom:link href="https://blog.mingliangstar.com/rss.xml" rel="self" type="application/rss+xml"/>
    
    <description>一个记录建站折腾历程与生活碎片的个人博客，分享技术踩坑心得、工具推荐，以及日常里的微小确幸。在这里，代码与烟火气并存。</description>
    <pubDate>Mon, 13 Apr 2026 06:54:03 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>anzhiyu主题新添文章卡片样式</title>
      <link>https://blog.mingliangstar.com/2026/04/13/anzhiyu%E4%B8%BB%E9%A2%98%E6%96%B0%E6%B7%BB%E6%96%87%E7%AB%A0%E5%8D%A1%E7%89%87%E6%A0%B7%E5%BC%8F/</link>
      <guid>https://blog.mingliangstar.com/2026/04/13/anzhiyu%E4%B8%BB%E9%A2%98%E6%96%B0%E6%B7%BB%E6%96%87%E7%AB%A0%E5%8D%A1%E7%89%87%E6%A0%B7%E5%BC%8F/</guid>
      <pubDate>Mon, 13 Apr 2026 06:19:46 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;这份教程，记录了我为 AnZhiYu</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>这份教程，记录了我为 AnZhiYu 主题添加横向卡片样式的全部过程。代码不多，但每一处都仔细调整过：斜切的视觉平衡、移动端的适配、分页后的稳定性……甚至强迫自己解决了偶数页布局错乱的 bug。</p><p>代码不是束缚，是自由的工具。愿你的博客，也能长出属于自己的姿态。</p><h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><p>文件路径分布</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">blog/                          # Hexo 博客根目录</span><br><span class="line">├── themes/</span><br><span class="line">│   └── anzhiyu/                    # AnZhiYu 主题目录</span><br><span class="line">│       ├── layout/                 # 布局模板目录</span><br><span class="line">│       │   ├── includes/           # 包含组件目录</span><br><span class="line">│       │   │   └── mixins/         # mixins 组件目录</span><br><span class="line">│       │   │       └── post-ui-horizontal.pug    # ← 横向卡片 Pug 模板</span><br><span class="line">│       │   └── index.pug           # ← 首页布局文件（调用横向卡片）</span><br><span class="line">│       └── ...                     # 其他主题文件</span><br><span class="line">├── source/                         # 源文件目录（会被复制到 public）</span><br><span class="line">│   └── cdn/                        # CDN 资源目录</span><br><span class="line">│       └── css/</span><br><span class="line">│           └── horizontal-card.css # ← 横向卡片样式文件（你提供的 CSS）</span><br><span class="line">└── ...                             # 其他博客文件</span><br></pre></td></tr></table></figure><p>新建post-ui-horizontal.pug</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br></pre></td><td class="code"><pre><span class="line">mixin postUIHorizontal()</span><br><span class="line">  - let maxDate = 0</span><br><span class="line">  each item in site.posts.data</span><br><span class="line">    if item.date &gt; maxDate</span><br><span class="line">      - maxDate = item.date</span><br><span class="line"></span><br><span class="line">  .horizontal-post-list</span><br><span class="line">    each article, index in page.posts.data</span><br><span class="line">      - let link = article.link || article.path</span><br><span class="line">      - let title = article.title || _p(&#x27;no_title&#x27;)</span><br><span class="line">      - let post_cover = article.cover</span><br><span class="line">      - let desc = article.description || article.excerpt || &#x27;&#x27;</span><br><span class="line">      - let category = article.categories.data[0]</span><br><span class="line">      - let dateStr = date(article.date, &#x27;MM-DD&#x27;)</span><br><span class="line">      - let wc = wordcount(article.content)</span><br><span class="line">      - const new_post = is_current(&#x27;/&#x27;) &amp;&amp; (maxDate === article.date)</span><br><span class="line">      // 判断左右位置：偶数左边，奇数右边</span><br><span class="line">      - let isLeft = index % 2 === 0</span><br><span class="line">      </span><br><span class="line">      article.recent-post-item.horizontal-card(class=isLeft ? &#x27;image-right&#x27; : &#x27;image-left&#x27; onclick=`pjax.loadUrl(&#x27;$&#123;url_for(link)&#125;&#x27;)`)</span><br><span class="line">        // 图片在左（奇数卡片）</span><br><span class="line">        if !isLeft &amp;&amp; post_cover &amp;&amp; theme.cover.index_enable</span><br><span class="line">          .post-cover</span><br><span class="line">            a(href=url_for(link) title=title)</span><br><span class="line">              img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src=&#x27;`+ url_for(theme.error_img.post_page) + `&#x27;` alt=title loading=&quot;lazy&quot;)</span><br><span class="line">        </span><br><span class="line">        // 无图片占位（奇数卡片）</span><br><span class="line">        if !isLeft &amp;&amp; !(post_cover &amp;&amp; theme.cover.index_enable)</span><br><span class="line">          .post-cover.no-image</span><br><span class="line">            a(href=url_for(link) title=title)</span><br><span class="line">              .cover-placeholder</span><br><span class="line">        </span><br><span class="line">        // 内容区</span><br><span class="line">        .post-content</span><br><span class="line">          .post-content-top</span><br><span class="line">            .post-tips</span><br><span class="line">              if (is_home() &amp;&amp; (article.top || article.sticky &gt; 0))</span><br><span class="line">                span.article-meta.sticky-warp</span><br><span class="line">                  i.anzhiyufont.anzhiyu-icon-thumbtack.sticky</span><br><span class="line">                  span.sticky= _p(&#x27;sticky&#x27;)</span><br><span class="line">            </span><br><span class="line">            a.post-title(href=url_for(link) title=title)= title</span><br><span class="line"></span><br><span class="line">          .post-meta-wrap</span><br><span class="line">            if (theme.post_meta.page.date_type)</span><br><span class="line">              span.post-meta-date</span><br><span class="line">                if (theme.post_meta.page.date_type === &#x27;both&#x27;)</span><br><span class="line">                  i.anzhiyufont.anzhiyu-icon-calendar-alt(style=`$&#123;theme.post_meta.page.date_format===&quot;simple&quot; ? &quot;display:none&quot;:&quot;&quot;&#125;`)</span><br><span class="line">                  span.article-meta-label=_p(&#x27;post.created&#x27;)</span><br><span class="line">                  time.post-meta-date-created(datetime=date_xml(article.date) title=_p(&#x27;post.created&#x27;) + &#x27; &#x27; + full_date(article.date) time=full_date(article.date))=date(article.date, config.date_format)</span><br><span class="line">                  span.article-meta-separator</span><br><span class="line">                  i.anzhiyufont.anzhiyu-icon-history(style=`font-size: 15px; $&#123;theme.post_meta.page.date_format===&quot;simple&quot; ? &quot;display:none&quot;:&quot;&quot;&#125;`)</span><br><span class="line">                  span.article-meta-label=_p(&#x27;post.updated&#x27;)</span><br><span class="line">                  time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p(&#x27;post.updated&#x27;) + &#x27; &#x27; + full_date(article.updated) time=full_date(article.updated))=date(article.updated, config.date_format)</span><br><span class="line">                else</span><br><span class="line">                  - let data_type_updated = theme.post_meta.page.date_type === &#x27;updated&#x27;</span><br><span class="line">                  - let date_type = data_type_updated ? &#x27;updated&#x27; : &#x27;date&#x27;</span><br><span class="line">                  - let date_type_other = data_type_updated ? &#x27;date&#x27; : &#x27;updated&#x27;</span><br><span class="line">                  - let date_icon = data_type_updated ? &#x27;anzhiyu-icon-history&#x27; :&#x27;anzhiyu-icon-calendar-days&#x27;</span><br><span class="line">                  - let date_title = data_type_updated ? _p(&#x27;post.updated&#x27;) : _p(&#x27;post.created&#x27;)</span><br><span class="line">                  - let date_title_other = data_type_updated ? _p(&#x27;post.created&#x27;) : _p(&#x27;post.updated&#x27;)</span><br><span class="line">                  i.anzhiyufont(class=date_icon style=`font-size: 15px; $&#123;theme.post_meta.page.date_format===&quot;simple&quot; ? &quot;display:none&quot;:&quot;&quot;&#125;`)</span><br><span class="line">                  span.article-meta-label=date_title</span><br><span class="line">                  time(datetime=date_xml(article[date_type]) title=date_title + &#x27; &#x27; + full_date(article[date_type])  time=full_date(article[date_type]))=date(article[date_type], config.date_format)</span><br><span class="line">                  time(datetime=date_xml(article[date_type_other]), class=&quot;time_hidden&quot;, title=date_title_other + &#x27; &#x27; + full_date(article[date_type_other]) time=full_date(article[date_type_other]))=date(article[date_type_other], config.date_format)</span><br><span class="line">            </span><br><span class="line">            if (theme.post_meta.page.tags &amp;&amp; article.tags.data.length &gt; 0)</span><br><span class="line">              span.article-meta.tags</span><br><span class="line">                each item, index in article.tags.data</span><br><span class="line">                  a(href=url_for(item.path) event.cancelbubble onclick=&quot;window.event.cancelBubble=true;&quot;).article-meta__tags</span><br><span class="line">                    span </span><br><span class="line">                      i.anzhiyufont.anzhiyu-icon-hashtag</span><br><span class="line">                      =item.name</span><br><span class="line">            </span><br><span class="line">            mixin countBlockHorizontal</span><br><span class="line">              - needLoadCountJs = true</span><br><span class="line">              span.article-meta</span><br><span class="line">                span.article-meta-separator</span><br><span class="line">                i.eucalyptus.icon-comments</span><br><span class="line">                if block</span><br><span class="line">                  block</span><br><span class="line">                span.article-meta-label= &#x27; &#x27; + _p(&#x27;card_post_count&#x27;)</span><br><span class="line">            </span><br><span class="line">            if theme.comments.card_post_count</span><br><span class="line">              case theme.comments.use[0]</span><br><span class="line">                when &#x27;Valine&#x27;</span><br><span class="line">                  +countBlockHorizontal</span><br><span class="line">                    a(href=url_for(link) + &#x27;#post-comment&#x27;)</span><br><span class="line">                      span.valine-comment-count(data-xid=url_for(link))</span><br><span class="line">                        i.anzhiyufont.anzhiyu-icon-spinner.anzhiyu-spin</span><br><span class="line">                when &#x27;Waline&#x27;</span><br><span class="line">                  +countBlockHorizontal</span><br><span class="line">                    a(href=url_for(link) + &#x27;#post-comment&#x27;)</span><br><span class="line">                      span.waline-comment-count(id=url_for(link))</span><br><span class="line">                        i.anzhiyufont.anzhiyu-icon-spinner.anzhiyu-spin</span><br><span class="line">                when &#x27;Twikoo&#x27;</span><br><span class="line">                  +countBlockHorizontal</span><br><span class="line">                    a.twikoo-count(href=url_for(link) + &#x27;#post-comment&#x27; tabindex=&quot;-1&quot;)</span><br><span class="line">                      i.anzhiyufont.anzhiyu-icon-spinner.anzhiyu-spin</span><br><span class="line">                when &#x27;Artalk&#x27;</span><br><span class="line">                  +countBlockHorizontal</span><br><span class="line">                    a(href=url_for(link) + &#x27;#post-comment&#x27;)</span><br><span class="line">                      span.artalk-count(data-page-key=url_for(link))</span><br><span class="line">                        i.anzhiyufont.anzhiyu-icon-spinner.anzhiyu-spin</span><br><span class="line"></span><br><span class="line">          case theme.index_post_content.method</span><br><span class="line">            when false</span><br><span class="line">              - break</span><br><span class="line">            when 1</span><br><span class="line">              .post-desc!= article.description</span><br><span class="line">            when 2</span><br><span class="line">              if article.description</span><br><span class="line">                .post-desc!= article.description</span><br><span class="line">              else</span><br><span class="line">                - const content = strip_html(article.content)</span><br><span class="line">                - let expert = content.substring(0, theme.index_post_content.length) </span><br><span class="line">                - content.length &gt; theme.index_post_content.length ? expert += &#x27; ...&#x27; : &#x27;&#x27;</span><br><span class="line">                .post-desc!= expert</span><br><span class="line">            default</span><br><span class="line">              - const content = strip_html(article.content)</span><br><span class="line">              - let expert = content.substring(0, theme.index_post_content.length) </span><br><span class="line">              - content.length &gt; theme.index_post_content.length ? expert += &#x27; ...&#x27; : &#x27;&#x27;</span><br><span class="line">              .post-desc!= expert</span><br><span class="line"></span><br><span class="line">        // 图片在右（偶数卡片）</span><br><span class="line">        if isLeft &amp;&amp; post_cover &amp;&amp; theme.cover.index_enable</span><br><span class="line">          .post-cover</span><br><span class="line">            a(href=url_for(link) title=title)</span><br><span class="line">              img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src=&#x27;`+ url_for(theme.error_img.post_page) + `&#x27;` alt=title loading=&quot;lazy&quot;)</span><br><span class="line">        </span><br><span class="line">        // 无图片占位（偶数卡片）</span><br><span class="line">        if isLeft &amp;&amp; !(post_cover &amp;&amp; theme.cover.index_enable)</span><br><span class="line">          .post-cover.no-image</span><br><span class="line">            a(href=url_for(link) title=title)</span><br><span class="line">              .cover-placeholder</span><br><span class="line"></span><br><span class="line">      if theme.ad &amp;&amp; theme.ad.index</span><br><span class="line">        if (index + 1) % 3 == 0</span><br><span class="line">          .horizontal-card.ads-wrap!=theme.ad.index</span><br></pre></td></tr></table></figure><p>修改index.pug</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">extends includes/layout.pug</span><br><span class="line"></span><br><span class="line">block content</span><br><span class="line">  include ./includes/mixins/post-ui.pug</span><br><span class="line">  </span><br><span class="line">  // 关键：include 必须在顶层，不能放在 if 里面</span><br><span class="line">  include ./includes/mixins/post-ui-horizontal.pug</span><br><span class="line">  </span><br><span class="line">  #recent-posts.recent-posts</span><br><span class="line">    include includes/categoryGroup.pug</span><br><span class="line">    </span><br><span class="line">    if theme.home_card_style === &#x27;horizontal&#x27;</span><br><span class="line">      +postUIHorizontal()</span><br><span class="line">    else</span><br><span class="line">      +postUI</span><br><span class="line">    </span><br><span class="line">    include includes/pagination.pug</span><br></pre></td></tr></table></figure><p>新建horizontal-card.css</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br></pre></td><td class="code"><pre><span class="line">/* ========== 变量定义 ========== */</span><br><span class="line">:root &#123;</span><br><span class="line">    --card-bg: #1a1a2e;</span><br><span class="line">    --card-bg-alt: #16213e;</span><br><span class="line">    --theme-color: #e94560;</span><br><span class="line">    --skew-width: 60px;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* ========== 基础卡片样式 ========== */</span><br><span class="line">.horizontal-card &#123;</span><br><span class="line">    display: flex;</span><br><span class="line">    flex-direction: row;</span><br><span class="line">    width: 100%;</span><br><span class="line">    height: 260px;</span><br><span class="line">    border-radius: 16px;</span><br><span class="line">    overflow: hidden;</span><br><span class="line">    background: var(--card-bg);</span><br><span class="line">    box-shadow: 0 8px 32px rgba(0,0,0,0.3);</span><br><span class="line">    transition: all 0.4s ease;</span><br><span class="line">    cursor: pointer;</span><br><span class="line">    position: relative;</span><br><span class="line">    margin-bottom: 32px;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card:hover &#123;</span><br><span class="line">    transform: translateY(-6px);</span><br><span class="line">    box-shadow: 0 16px 48px rgba(233, 69, 96, 0.15);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* ========== 内容区域基础 ========== */</span><br><span class="line">.horizontal-card .post-content &#123;</span><br><span class="line">    width: calc(58% - 0px);</span><br><span class="line">    flex: 0 0 calc(58% - 0px);</span><br><span class="line">    max-width: calc(58% - 0px);</span><br><span class="line">    padding: 32px 40px;</span><br><span class="line">    display: flex;</span><br><span class="line">    flex-direction: column;</span><br><span class="line">    justify-content: space-between;</span><br><span class="line">    position: relative;</span><br><span class="line">    z-index: 2;</span><br><span class="line">    min-width: 0;</span><br><span class="line">    overflow: hidden;</span><br><span class="line">    box-sizing: border-box;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card .post-title &#123;</span><br><span class="line">    font-size: 1.6rem;</span><br><span class="line">    font-weight: 700;</span><br><span class="line">    line-height: 1.3;</span><br><span class="line">    display: -webkit-box;</span><br><span class="line">    -webkit-line-clamp: 2;</span><br><span class="line">    -webkit-box-orient: vertical;</span><br><span class="line">    overflow: hidden;</span><br><span class="line">    margin-bottom: 4px;</span><br><span class="line">    word-break: break-word;</span><br><span class="line">    overflow-wrap: break-word;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card .post-desc &#123;</span><br><span class="line">    font-size: 1rem;</span><br><span class="line">    line-height: 1.8;</span><br><span class="line">    display: -webkit-box;</span><br><span class="line">    -webkit-line-clamp: 2;</span><br><span class="line">    -webkit-box-orient: vertical;</span><br><span class="line">    overflow: hidden;</span><br><span class="line">    margin-top: 12px;</span><br><span class="line">    word-break: break-word;</span><br><span class="line">    overflow-wrap: break-word;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* ========== 图片区域基础 ========== */</span><br><span class="line">.horizontal-card .post-cover &#123;</span><br><span class="line">    width: calc(42% - 0px);</span><br><span class="line">    flex: 0 0 calc(42% - 0px);</span><br><span class="line">    max-width: calc(42% - 0px);</span><br><span class="line">    min-width: 320px;</span><br><span class="line">    height: 100%;</span><br><span class="line">    position: relative;</span><br><span class="line">    overflow: hidden;</span><br><span class="line">    box-sizing: border-box;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card .post-cover img &#123;</span><br><span class="line">    width: 100%;</span><br><span class="line">    height: 100%;</span><br><span class="line">    object-fit: cover;</span><br><span class="line">    transition: transform 0.6s ease;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card:hover .post-cover img &#123;</span><br><span class="line">    transform: scale(1.1);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* ========== 图片在右边 + 斜切线 ========== */</span><br><span class="line">.horizontal-card.image-right &#123;</span><br><span class="line">    background: linear-gradient(135deg, var(--card-bg) 0%, var(--card-bg-alt) 100%);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card.image-right .post-content &#123;</span><br><span class="line">    order: 1;</span><br><span class="line">    padding-right: 80px;</span><br><span class="line">    clip-path: polygon(</span><br><span class="line">        0 0, </span><br><span class="line">        calc(100% - var(--skew-width)) 0, </span><br><span class="line">        100% 100%, </span><br><span class="line">        0 100%</span><br><span class="line">    );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card.image-right .post-cover &#123;</span><br><span class="line">    order: 2;</span><br><span class="line">    clip-path: polygon(</span><br><span class="line">        var(--skew-width) 0, </span><br><span class="line">        100% 0, </span><br><span class="line">        100% 100%, </span><br><span class="line">        0 100%</span><br><span class="line">    );</span><br><span class="line">    margin-left: calc(var(--skew-width) * -1);</span><br><span class="line">    margin-right: calc(var(--skew-width) * -1);</span><br><span class="line">    width: calc(42% + var(--skew-width)) !important;</span><br><span class="line">    flex: 0 0 calc(42% + var(--skew-width)) !important;</span><br><span class="line">    max-width: calc(42% + var(--skew-width)) !important;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* ========== 图片在左边 + 斜切线 ========== */</span><br><span class="line">.horizontal-card.image-left &#123;</span><br><span class="line">    background: linear-gradient(225deg, var(--card-bg) 0%, var(--card-bg-alt) 100%);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card.image-left .post-content &#123;</span><br><span class="line">    order: 2;</span><br><span class="line">    padding-left: 80px;</span><br><span class="line">    clip-path: polygon(</span><br><span class="line">        var(--skew-width) 0, </span><br><span class="line">        100% 0, </span><br><span class="line">        100% 100%, </span><br><span class="line">        0 100%</span><br><span class="line">    );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.horizontal-card.image-left .post-cover &#123;</span><br><span class="line">    order: 1;</span><br><span class="line">    clip-path: polygon(</span><br><span class="line">        0 0, </span><br><span class="line">        calc(100% - var(--skew-width)) 0, </span><br><span class="line">        100% 100%, </span><br><span class="line">        0 100%</span><br><span class="line">    );</span><br><span class="line">    margin-right: calc(var(--skew-width) * -1);</span><br><span class="line">    margin-left: calc(var(--skew-width) * -1);</span><br><span class="line">    width: calc(42% + var(--skew-width)) !important;</span><br><span class="line">    flex: 0 0 calc(42% + var(--skew-width)) !important;</span><br><span class="line">    max-width: calc(42% + var(--skew-width)) !important;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* 第一张卡片距离顶部增加间距 */</span><br><span class="line">.horizontal-card:first-child &#123;</span><br><span class="line">    margin-top: 32px;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* ========== 响应式适配 ========== */</span><br><span class="line">@media screen and (max-width: 768px) &#123;</span><br><span class="line">    .horizontal-card,</span><br><span class="line">    .horizontal-card.image-left,</span><br><span class="line">    .horizontal-card.image-right &#123;</span><br><span class="line">        flex-direction: column;</span><br><span class="line">        height: auto;</span><br><span class="line">        margin-bottom: 28px;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    .horizontal-card .post-content,</span><br><span class="line">    .horizontal-card.image-left .post-content,</span><br><span class="line">    .horizontal-card.image-right .post-content &#123;</span><br><span class="line">        width: 100%;</span><br><span class="line">        flex: none;</span><br><span class="line">        max-width: 100%;</span><br><span class="line">        padding: 24px;</span><br><span class="line">        order: 2;</span><br><span class="line">        clip-path: none;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    .horizontal-card.image-left .post-cover,</span><br><span class="line">    .horizontal-card.image-right .post-cover &#123;</span><br><span class="line">        width: 100% !important;</span><br><span class="line">        flex: none !important;</span><br><span class="line">        max-width: 100% !important;</span><br><span class="line">        min-width: auto;</span><br><span class="line">        height: 220px;</span><br><span class="line">        order: 1;</span><br><span class="line">        margin: 0 !important;</span><br><span class="line">        clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>_config.anzhiyu.yml调用自定义horizontal-card.css</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">inject:</span><br><span class="line">  head:</span><br><span class="line">    # 自定义css</span><br><span class="line">    ...</span><br><span class="line">    - &lt;link rel=&quot;stylesheet&quot; href=&quot;/cdn/css/horizontal-card.css&quot;&gt;</span><br></pre></td></tr></table></figure><p>_config.anzhiyu.yml中使用新的文章卡片样式，建议添加article_double_row之后</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"></span><br><span class="line"># 首页双栏显示</span><br><span class="line">article_double_row: true</span><br><span class="line"></span><br><span class="line"># 文章卡片样式: default | horizontal</span><br><span class="line">home_card_style: horizontal</span><br><span class="line"></span><br><span class="line">...</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Hexo/">Hexo</category>
      
      <category domain="https://blog.mingliangstar.com/categories/Hexo/anzhiyu/">anzhiyu</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Hexo/">Hexo</category>
      
      <category domain="https://blog.mingliangstar.com/tags/anzhiyu/">anzhiyu</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/04/13/anzhiyu%E4%B8%BB%E9%A2%98%E6%96%B0%E6%B7%BB%E6%96%87%E7%AB%A0%E5%8D%A1%E7%89%87%E6%A0%B7%E5%BC%8F/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>anzhiyu主题侧边栏添加访客信息</title>
      <link>https://blog.mingliangstar.com/2026/04/12/anzhiyu%E4%B8%BB%E9%A2%98%E4%BE%A7%E8%BE%B9%E6%A0%8F%E6%B7%BB%E5%8A%A0%E8%AE%BF%E5%AE%A2%E4%BF%A1%E6%81%AF/</link>
      <guid>https://blog.mingliangstar.com/2026/04/12/anzhiyu%E4%B8%BB%E9%A2%98%E4%BE%A7%E8%BE%B9%E6%A0%8F%E6%B7%BB%E5%8A%A0%E8%AE%BF%E5%AE%A2%E4%BF%A1%E6%81%AF/</guid>
      <pubDate>Sun, 12 Apr 2026 15:15:45 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>博客是写在网上的日记，但总有人悄悄路过。</p><p>侧边栏那个小小的卡片，它会尝试获取你的大致位置（不精确到门牌号，只是城市和距离），然后告诉博主：你离我多少公里，此刻是早安、午安还是晚安。</p><p>代码不多，但花了不少心思：多 API 降级、PJAX 兼容、距离计算、时间问候……甚至为了不泄露隐私，全程只使用公开的 IP 地理服务。</p><p>如果你是安知鱼主题的用户，可以直接照搬；如果你用其他主题，改改选择器也能用。</p><h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><p>文件路径</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">blog/</span><br><span class="line">├── themes/</span><br><span class="line">│   └── anzhiyu/                    </span><br><span class="line">│       ├── layout/                 </span><br><span class="line">│       │   ├── includes/           </span><br><span class="line">│       │   │   └── widget/         </span><br><span class="line">│       │   │       └── card_welcome.pug </span><br><span class="line">│       │   │       └── index.pug                      </span><br><span class="line">├── source/                        </span><br><span class="line">│   └── cdn/                        </span><br><span class="line">│       └── css/</span><br><span class="line">│       │   └── welcome.css</span><br><span class="line">│       └── js/</span><br><span class="line">│           └── welcome.js</span><br><span class="line">└── ...                             </span><br></pre></td></tr></table></figure><p><font style="color:#000000;background-color:rgba(255, 255, 255, 0.05);">新建card_welcome.pug</font></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">.card-widget.card-welcome</span><br><span class="line">  .card-content</span><br><span class="line">    .item-headline</span><br><span class="line">      i.fas.fa-map-marker-alt</span><br><span class="line">    #welcome-info(style=&quot;min-height: 100px; display: flex; align-items: center; justify-content: center;&quot;)</span><br><span class="line">      .loading-spinner</span><br><span class="line">        i.fas.fa-spinner.fa-spin</span><br><span class="line">        |  正在定位...</span><br></pre></td></tr></table></figure><p>修改index.pug</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">#aside-content.aside-content</span><br><span class="line">  //- post</span><br><span class="line">  if is_post()</span><br><span class="line">    - const tocStyle = page.toc_style_simple</span><br><span class="line">    - const tocStyleVal = tocStyle === true || tocStyle === false ? tocStyle : theme.toc.style_simple</span><br><span class="line">    if showToc &amp;&amp; tocStyleVal</span><br><span class="line">      .sticky_layout</span><br><span class="line">        include ./card_post_toc.pug</span><br><span class="line">    else</span><br><span class="line">      !=partial(&#x27;includes/widget/card_author&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">      !=partial(&#x27;includes/widget/card_announcement&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">      </span><br><span class="line">      // 添加访客信息卡片（公告下面）</span><br><span class="line">      !=partial(&#x27;includes/widget/card_welcome&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">      </span><br><span class="line">      !=partial(&#x27;includes/widget/card_weixin&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">      !=partial(&#x27;includes/widget/card_top_self&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">      .sticky_layout</span><br><span class="line">        if showToc</span><br><span class="line">          include ./card_post_toc.pug</span><br><span class="line">        !=partial(&#x27;includes/widget/card_recent_post&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">        !=partial(&#x27;includes/widget/card_ad&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">  else</span><br><span class="line">    //- page</span><br><span class="line">    !=partial(&#x27;includes/widget/card_author&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">    !=partial(&#x27;includes/widget/card_announcement&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">    </span><br><span class="line">    // 添加访客信息卡片（公告下面）</span><br><span class="line">    !=partial(&#x27;includes/widget/card_welcome&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">    </span><br><span class="line">    !=partial(&#x27;includes/widget/card_weixin&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">    !=partial(&#x27;includes/widget/card_top_self&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">    !=partial(&#x27;includes/widget/card_categories&#x27;, &#123;&#125;, &#123;cache: true&#125;)  </span><br><span class="line"></span><br><span class="line">    .sticky_layout</span><br><span class="line">      if showToc</span><br><span class="line">        include ./card_post_toc.pug</span><br><span class="line">      .card-widget</span><br><span class="line">        !=partial(&#x27;includes/widget/card_ad&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">        !=partial(&#x27;includes/widget/card_tags&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">        !=partial(&#x27;includes/widget/card_archives&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">        !=partial(&#x27;includes/widget/card_webinfo&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br><span class="line">      !=partial(&#x27;includes/widget/card_bottom_self&#x27;, &#123;&#125;, &#123;cache: true&#125;)</span><br></pre></td></tr></table></figure><p>新建welcome.js</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br></pre></td><td class="code"><pre><span class="line">// 使用 IIFE 避免全局污染</span><br><span class="line">(function() &#123;</span><br><span class="line">    // 标记是否已经获取过 IP 信息（当前会话内只获取一次即可）</span><br><span class="line">    let ipInfoLoaded = false;</span><br><span class="line">    let cachedHTML = null;</span><br><span class="line"></span><br><span class="line">    const fetchIpInfo = async () =&gt; &#123;</span><br><span class="line">        const welcomeInfo = document.querySelector(&#x27;#welcome-info&#x27;);</span><br><span class="line">        if (!welcomeInfo) return;</span><br><span class="line">        </span><br><span class="line">        // 如果已经加载过，直接恢复缓存的内容</span><br><span class="line">        if (ipInfoLoaded &amp;&amp; cachedHTML) &#123;</span><br><span class="line">            welcomeInfo.innerHTML = cachedHTML;</span><br><span class="line">            return;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 显示加载状态</span><br><span class="line">        welcomeInfo.innerHTML = &#x27;&lt;div class=&quot;loading&quot;&gt;&lt;i class=&quot;fas fa-spinner fa-spin&quot;&gt;&lt;/i&gt; 定位中...&lt;/div&gt;&#x27;;</span><br><span class="line">        </span><br><span class="line">        // 备用 API 列表（ipinfo.io 在国内可能被拦截，放在后面）</span><br><span class="line">        const apis = [</span><br><span class="line">            &#123; </span><br><span class="line">                url: &#x27;https://api.ip.sb/geoip&#x27;, </span><br><span class="line">                parser: (d) =&gt; (&#123;</span><br><span class="line">                    country: d.country,</span><br><span class="line">                    region: d.region,</span><br><span class="line">                    city: d.city,</span><br><span class="line">                    loc: d.latitude &amp;&amp; d.longitude ? `$&#123;d.latitude&#125;,$&#123;d.longitude&#125;` : null</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">                url: &#x27;https://ipapi.co/json/&#x27;,</span><br><span class="line">                parser: (d) =&gt; (&#123;</span><br><span class="line">                    country: d.country_code,</span><br><span class="line">                    region: d.region,</span><br><span class="line">                    city: d.city,</span><br><span class="line">                    loc: d.latitude &amp;&amp; d.longitude ? `$&#123;d.latitude&#125;,$&#123;d.longitude&#125;` : null</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">                url: &#x27;https://ipinfo.io/json&#x27;,</span><br><span class="line">                parser: (d) =&gt; (&#123;</span><br><span class="line">                    country: d.country,</span><br><span class="line">                    region: d.region,</span><br><span class="line">                    city: d.city,</span><br><span class="line">                    loc: d.loc</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;</span><br><span class="line">        ];</span><br><span class="line">        </span><br><span class="line">        let data = null;</span><br><span class="line">        </span><br><span class="line">        for (const api of apis) &#123;</span><br><span class="line">            try &#123;</span><br><span class="line">                const controller = new AbortController();</span><br><span class="line">                const timeout = setTimeout(() =&gt; controller.abort(), 3000);</span><br><span class="line">                </span><br><span class="line">                const res = await fetch(api.url, &#123; </span><br><span class="line">                    signal: controller.signal,</span><br><span class="line">                    headers: &#123; &#x27;Accept&#x27;: &#x27;application/json&#x27; &#125;</span><br><span class="line">                &#125;);</span><br><span class="line">                clearTimeout(timeout);</span><br><span class="line">                </span><br><span class="line">                if (res.ok) &#123;</span><br><span class="line">                    const raw = await res.json();</span><br><span class="line">                    data = api.parser(raw);</span><br><span class="line">                    break;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; catch (e) &#123;</span><br><span class="line">                continue;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 渲染内容</span><br><span class="line">        if (data) &#123;</span><br><span class="line">            const &#123; country, region, city, loc &#125; = data;</span><br><span class="line">            const [lat, lng] = loc ? loc.split(&#x27;,&#x27;).map(Number) : [];</span><br><span class="line">            </span><br><span class="line">            const myLat = 31.707754;</span><br><span class="line">            const myLng = 119.825873;</span><br><span class="line">            const dist = (lat &amp;&amp; lng) ? calculateDistance(lng, lat, myLng, myLat) : null;</span><br><span class="line">            </span><br><span class="line">            const location = country === &quot;CN&quot; || country === &quot;China&quot; </span><br><span class="line">                ? `$&#123;region || &#x27;&#x27;&#125; $&#123;city || &#x27;&#x27;&#125;`.trim() </span><br><span class="line">                : (country || &#x27;地球&#x27;);</span><br><span class="line">            </span><br><span class="line">            cachedHTML = `</span><br><span class="line">                &lt;div class=&quot;welcome-content&quot;&gt;</span><br><span class="line">                    &lt;p&gt;欢迎来自 &lt;span class=&quot;location&quot;&gt;$&#123;location || &#x27;神秘星球&#x27;&#125;&lt;/span&gt; 的道友 💖&lt;/p&gt;</span><br><span class="line">                    $&#123;dist ? `&lt;p&gt;距博主约 &lt;span class=&quot;distance&quot;&gt;$&#123;dist&#125;&lt;/span&gt; 公里&lt;/p&gt;` : &#x27;&#x27;&#125;</span><br><span class="line">                    &lt;p class=&quot;greeting&quot;&gt;$&#123;getTimeGreeting()&#125;&lt;/p&gt;</span><br><span class="line">                &lt;/div&gt;</span><br><span class="line">            `;</span><br><span class="line">            ipInfoLoaded = true;</span><br><span class="line">            welcomeInfo.innerHTML = cachedHTML;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            cachedHTML = `</span><br><span class="line">                &lt;div class=&quot;welcome-content&quot;&gt;</span><br><span class="line">                    &lt;p&gt;🎉 欢迎来到我的博客！&lt;/p&gt;</span><br><span class="line">                    &lt;p class=&quot;greeting&quot;&gt;$&#123;getTimeGreeting()&#125;&lt;/p&gt;</span><br><span class="line">                &lt;/div&gt;</span><br><span class="line">            `;</span><br><span class="line">            ipInfoLoaded = true;</span><br><span class="line">            welcomeInfo.innerHTML = cachedHTML;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    const calculateDistance = (lng1, lat1, lng2, lat2) =&gt; &#123;</span><br><span class="line">        if (!lat1 || !lng1 || !lat2 || !lng2) return null;</span><br><span class="line">        const R = 6371;</span><br><span class="line">        const rad = Math.PI / 180;</span><br><span class="line">        const dLat = (lat2 - lat1) * rad;</span><br><span class="line">        const dLon = (lng2 - lng1) * rad;</span><br><span class="line">        const a = Math.sin(dLat/2) ** 2 + Math.cos(lat1 * rad) * Math.cos(lat2 * rad) * Math.sin(dLon/2) ** 2;</span><br><span class="line">        return Math.round(R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)));</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    const getTimeGreeting = () =&gt; &#123;</span><br><span class="line">        const hour = new Date().getHours();</span><br><span class="line">        if (hour &lt; 6) return &quot;It&#x27;s late, pay attention to rest 🌙&quot;;</span><br><span class="line">        if (hour &lt; 12) return &quot;Good morning, start your day. ☀️&quot;;</span><br><span class="line">        if (hour &lt; 18) return &quot;Good afternoon. Good work. ☕&quot;;</span><br><span class="line">        return &quot;Good evening. May you have a good mood. 🌆&quot;;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    // ===== 初始化策略 =====</span><br><span class="line">    </span><br><span class="line">    // 1. 首次加载</span><br><span class="line">    if (document.readyState === &#x27;loading&#x27;) &#123;</span><br><span class="line">        document.addEventListener(&#x27;DOMContentLoaded&#x27;, fetchIpInfo);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        fetchIpInfo();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 2. 安知鱼主题 PJAX 事件（关键）</span><br><span class="line">    // 安知鱼使用 pjax:complete，但 footer 不刷新，所以需要手动恢复内容</span><br><span class="line">    document.addEventListener(&#x27;pjax:complete&#x27;, () =&gt; &#123;</span><br><span class="line">        // PJAX 完成后，检查 welcome-info 是否存在</span><br><span class="line">        setTimeout(() =&gt; &#123;</span><br><span class="line">            const welcomeInfo = document.querySelector(&#x27;#welcome-info&#x27;);</span><br><span class="line">            if (welcomeInfo) &#123;</span><br><span class="line">                if (cachedHTML &amp;&amp; ipInfoLoaded) &#123;</span><br><span class="line">                    // 已经有缓存，直接恢复</span><br><span class="line">                    welcomeInfo.innerHTML = cachedHTML;</span><br><span class="line">                &#125; else &#123;</span><br><span class="line">                    // 首次或缓存丢失，重新获取</span><br><span class="line">                    fetchIpInfo();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, 100); // 延迟确保 DOM 已更新</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    // 3. 浏览器前进/后退按钮</span><br><span class="line">    window.addEventListener(&#x27;popstate&#x27;, () =&gt; &#123;</span><br><span class="line">        setTimeout(() =&gt; &#123;</span><br><span class="line">            const welcomeInfo = document.querySelector(&#x27;#welcome-info&#x27;);</span><br><span class="line">            if (welcomeInfo &amp;&amp; cachedHTML &amp;&amp; ipInfoLoaded) &#123;</span><br><span class="line">                welcomeInfo.innerHTML = cachedHTML;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;, 100);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure><p>新建welcome.css</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">.card-welcome .item-headline i &#123;</span><br><span class="line">    color: #4dabf7;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .card-welcome #welcome-info &#123;</span><br><span class="line">    color: var(--anzhiyu-fontcolor);</span><br><span class="line">    text-align: center;</span><br><span class="line">    padding: 15px;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .card-welcome #welcome-info .loading &#123;</span><br><span class="line">    font-size: 14px;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .card-welcome #welcome-info .loading i &#123;</span><br><span class="line">    margin-right: 8px;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .card-welcome .welcome-content .location &#123;</span><br><span class="line">    color: #ffd700;</span><br><span class="line">    font-weight: bold;</span><br><span class="line">    font-size: 16px;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .card-welcome .welcome-content .distance &#123;</span><br><span class="line">    color: #4dabf7;</span><br><span class="line">    font-weight: bold;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .card-welcome .welcome-content .ip-address &#123;</span><br><span class="line">    font-size: 12px;</span><br><span class="line">    opacity: 0.7;</span><br><span class="line">    margin-top: 5px;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  .card-welcome .welcome-content .greeting &#123;</span><br><span class="line">    font-size: 14px;</span><br><span class="line">    line-height: 1.5;</span><br><span class="line">    opacity: 0.95;</span><br><span class="line">    letter-spacing: 0.3px;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p><font style="color:rgb(76, 73, 72);background-color:rgba(255, 255, 255, 0.9);">_config.anzhiyu.yml 调用自定义 welcome.css和welcome.js</font></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">inject:</span><br><span class="line">  head:</span><br><span class="line">    # 自定义css</span><br><span class="line">    ...</span><br><span class="line">    - &lt;link rel=&quot;stylesheet&quot; href=&quot;/cdn/css/welcome.css&quot;&gt;</span><br><span class="line">    ...</span><br><span class="line"> </span><br><span class="line">  bottom:</span><br><span class="line">    # 自定义js</span><br><span class="line">    ...</span><br><span class="line">    - &lt;script defer src=&quot;/cdn/js/welcome.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">    ...</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Hexo/">Hexo</category>
      
      <category domain="https://blog.mingliangstar.com/categories/Hexo/anzhiyu/">anzhiyu</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Hexo/">Hexo</category>
      
      <category domain="https://blog.mingliangstar.com/tags/anzhiyu/">anzhiyu</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/04/12/anzhiyu%E4%B8%BB%E9%A2%98%E4%BE%A7%E8%BE%B9%E6%A0%8F%E6%B7%BB%E5%8A%A0%E8%AE%BF%E5%AE%A2%E4%BF%A1%E6%81%AF/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>PostgreSQL基础命令</title>
      <link>https://blog.mingliangstar.com/2026/04/04/PostgreSQL%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4/</link>
      <guid>https://blog.mingliangstar.com/2026/04/04/PostgreSQL%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4/</guid>
      <pubDate>Sat, 04 Apr 2026 08:48:13 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;常用命令说明&quot;&gt;&lt;a href=&quot;#常用命令说明&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="常用命令说明"><a href="#常用命令说明" class="headerlink" title="常用命令说明"></a>常用命令说明</h2><table><thead><tr><th>序号</th><th>操作</th><th>命令</th></tr></thead><tbody><tr><td>1</td><td>列出所有数据库</td><td>\l</td></tr><tr><td>2</td><td>列出数据库中所有的表</td><td>\d</td></tr><tr><td>3</td><td>显示指定表的结构</td><td>\d table_name</td></tr><tr><td>4</td><td>列出所有的帮助命令</td><td>?</td></tr><tr><td>5</td><td>列出数据库中所有的索引</td><td>\di</td></tr><tr><td>6</td><td>列出数据库中所有的view</td><td>\dv</td></tr><tr><td>7</td><td>sql命令帮助</td><td>\h</td></tr><tr><td>8</td><td>退出连接</td><td>\q</td></tr><tr><td>9</td><td>切换到指定的数据库</td><td>\c [database_name]</td></tr><tr><td>10</td><td>显示当前数据库和用户</td><td>\c</td></tr><tr><td>11</td><td>显示客户端的连接信息</td><td>\conninfo</td></tr><tr><td>12</td><td>显示所有用户</td><td>\du</td></tr><tr><td>13</td><td>显示数据库中的schema</td><td>\dn</td></tr><tr><td>14</td><td>显示字符集</td><td>\encoding</td></tr><tr><td>15</td><td>执行sql文件</td><td>\i mydb.sql</td></tr><tr><td>16</td><td>扩展展示信息，相当于MySQL中的\G</td><td>\x</td></tr><tr><td>17</td><td>将下一条sql执行结果导入文件中</td><td>\o &#x2F;opt&#x2F;test.txt</td></tr></tbody></table><h3 id="进阶命令"><a href="#进阶命令" class="headerlink" title="进阶命令"></a>进阶命令</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#查看复制状态，master执行</span><br><span class="line">select client_addr, state, sent_lsn, flush_lsn, sync_state from pg_stat_replication;</span><br><span class="line"></span><br><span class="line">#查看延迟，slave执行</span><br><span class="line">select pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();</span><br></pre></td></tr></table></figure><h2 id="登陆命令"><a href="#登陆命令" class="headerlink" title="登陆命令"></a>登陆命令</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -h 172.16.0.2 -p 5432 -U postgres -d 数据库名 -W</span><br></pre></td></tr></table></figure><ul><li>-h #数据库所在的IP地址</li><li>-p #（默认5432）数据库的监听端口</li><li>-U #用户名</li><li>-d #数据库名称</li><li>-W#指示 psql 命令在连接数据库时强制提示输入密码</li></ul><h2 id="PG状态管理"><a href="#PG状态管理" class="headerlink" title="PG状态管理"></a>PG状态管理</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pg_ctl start/status/stop</span><br><span class="line">systemctl start/status/stop postgresql-16</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/PostgreSQL/">PostgreSQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/PostgreSQL/">PostgreSQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/04/04/PostgreSQL%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>PostgreSQL 16.3中复制槽的配置</title>
      <link>https://blog.mingliangstar.com/2026/04/01/PostgreSQL-16-3%E4%B8%AD%E5%A4%8D%E5%88%B6%E6%A7%BD%E7%9A%84%E9%85%8D%E7%BD%AE/</link>
      <guid>https://blog.mingliangstar.com/2026/04/01/PostgreSQL-16-3%E4%B8%AD%E5%A4%8D%E5%88%B6%E6%A7%BD%E7%9A%84%E9%85%8D%E7%BD%AE/</guid>
      <pubDate>Wed, 01 Apr 2026 08:52:43 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;复制槽（Replication Slot）是数据库（如</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>复制槽（Replication Slot）是数据库（如 PostgreSQL）中用于保障主从复制数据一致性与安全性的核心机制，它通过在主库上为每个从库建立一个持久的状态记录点，强制主库保留该从库尚未确认接收的 WAL（预写日志），从而防止因日志过早被清理而导致从库断连后无法继续同步；简单来说，它就像一根“安全绳”，确保即使从库长时间离线或网络中断，重新连接后也能无缝续传缺失的数据，避免主从数据出现不可修复的断层。</p><p>流复制的配置不在做过多的缀述，直接基于之前搭建的流式复制配置复制槽，</p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>首先在主库上创建物理复制槽</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#创建</span><br><span class="line">select pg_create_physical_replication_slot(&#x27;demo_slot&#x27;, true);</span><br><span class="line">#查询</span><br><span class="line">select * from pg_replication_slots;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260401/1.avif"></p><p>然后再去备库配置连接信息，由于使用的是 PostgreSQL 16.3 的搭建的流式复制，故直接在postgresql.auto.conf中配置</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#在postgresql.auto.conf中添加</span><br><span class="line">primary_slot_name = &#x27;demo_slot&#x27;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260401/2.avif"></p><p>最后重启备库后，在主库查看slot的状态，active&#x3D;true的话说明slot已经被激活</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260401/3.avif"></p><table><thead><tr><th>字段名</th><th>含义与解释</th></tr></thead><tbody><tr><td><code>slot_name</code></td><td>槽的名称。这是你创建槽时指定的唯一标识符，例如你的 <code>demo_slot</code>在配置主从连接 (<code>primary_slot_name</code>) 时会用到它。</td></tr><tr><td><code>plugin</code></td><td>插件名称。<br/>• 如果是 物理复制 (Physical)，此值为 <code>&lt;null&gt;</code>   • 如果是 逻辑复制 (Logical)，这里会显示使用的输出插件名，如 <code>pgoutput</code>, <code>test_decoding</code>等。</td></tr><tr><td><code>slot_type</code></td><td>槽的类型。   • <code>physical</code>: 用于流复制备库（Standby）。   • <code>logical</code>: 用于逻辑解码或逻辑订阅（Logical Subscription）。</td></tr><tr><td><code>datoid</code></td><td>数据库 OID。仅对逻辑复制槽有效，表示该槽关联的数据库 ID。物理复制槽与此无关，所以是 <code>&lt;null&gt;</code>。</td></tr><tr><td><code>database</code></td><td>数据库名称。同上，仅对逻辑复制槽有效，显示关联的数据库名。</td></tr><tr><td><code>temporary</code></td><td>是否为临时槽。   • <code>True</code>: 临时槽，当创建它的会话结束时自动删除。   • <code>False</code>: 持久化槽，重启后依然存在（你的 <code>demo_slot</code>就是这种）。</td></tr><tr><td><code>active</code></td><td>是否活跃。   • <code>True</code>: 表示有一个备库或客户端正连接并使用这个槽（你的情况）。   • <code>False</code>: 槽存在但没人用。如果长期为 False，说明备库断连了，需要检查网络或配置。</td></tr><tr><td><code>active_pid</code></td><td>活跃进程的 PID。显示主库上哪个后端进程（Walsender）正在服务这个槽。你的 <code>79803</code>就是那个进程的 ID。可以用 <code>SELECT * FROM pg_stat_activity WHERE pid = 79803;</code>查看该进程详情。</td></tr><tr><td><code>xmin</code></td><td>事务 ID 下限。仅对逻辑复制槽有意义。表示为了防止逻辑解码所需的事务快照被清理，系统必须保留的最早事务 ID。物理复制槽通常为 <code>&lt;null&gt;</code>。</td></tr><tr><td><code>catalog_xmin</code></td><td>目录事务 ID 下限。仅对逻辑复制槽有意义。类似 <code>xmin</code>，但是针对系统目录表的变更。</td></tr><tr><td><code>restart_lsn</code></td><td>重启 LSN (Log Sequence Number) ⭐这是物理复制最重要的字段。它表示：“从这个位置开始的 WAL 日志，我都还没确认备库收到了，所以主库绝对不能删除这些日志”。随着备库不断确认接收，这个值会向后推进。</td></tr><tr><td><code>confirmed_flush_lsn</code></td><td>已确认刷新的 LSN。仅对逻辑复制有效。表示逻辑订阅者已经成功处理并重放到的位置。物理复制槽此值为 <code>&lt;null&gt;</code>。</td></tr><tr><td><code>wal_status</code></td><td>WAL 日志状态。   • <code>reserved</code>: 正常状态，表示槽正在保留 WAL 日志。   • <code>lost</code>: 警告状态！表示槽需要的 WAL 日志已经被主库清理掉了，复制将中断，需要重新做基础备份。</td></tr><tr><td><code>safe_wal_size</code></td><td>安全的 WAL 大小。估算值，表示在当前状态下，主库还能安全地生成多少 WAL 日志而不会触发 <code>wal_status = &#39;lost&#39;</code>。如果这个值变成负数，说明已经很危险了。</td></tr><tr><td><code>two_phase</code></td><td>是否支持两阶段提交。仅对逻辑复制槽有效。如果为 <code>True</code>，表示该槽可以复制两阶段提交（PREPARE TRANSACTION）的事务。</td></tr><tr><td><code>conflicting</code></td><td>是否存在冲突。仅对逻辑复制槽有效。如果在解码过程中遇到无法解决的冲突（比如表结构不一致），这里会标记为 <code>True</code>。</td></tr></tbody></table></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/PostgreSQL/">PostgreSQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/PostgreSQL/">PostgreSQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/04/01/PostgreSQL-16-3%E4%B8%AD%E5%A4%8D%E5%88%B6%E6%A7%BD%E7%9A%84%E9%85%8D%E7%BD%AE/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Docker基础命令速查指南：从入门到实践</title>
      <link>https://blog.mingliangstar.com/2026/03/26/Docker%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4%E9%80%9F%E6%9F%A5%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%AE%9E%E8%B7%B5/</link>
      <guid>https://blog.mingliangstar.com/2026/03/26/Docker%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4%E9%80%9F%E6%9F%A5%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%AE%9E%E8%B7%B5/</guid>
      <pubDate>Thu, 26 Mar 2026 08:38:58 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;Docker是什么？&quot;&gt;&lt;a href=&quot;#Docker是什么？&quot; class=&quot;headerlink&quot; title=&quot;Docker是什么？&quot;&gt;&lt;/a&gt;&lt;strong&gt;&lt;font</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="Docker是什么？"><a href="#Docker是什么？" class="headerlink" title="Docker是什么？"></a><strong><font style="color:#fe2c24;">Docker是什么？</font></strong></h2><p>“Docker”一词指代了多个概念，包括开源社区项目、开源项目使用的工具、主导支持此类项目的公司 Docker Inc.，以及该公司官方支持的工具。这些技术和公司的同名可能会造成混淆。</p><p>以下简要说明 Docker 以便区分：</p><ul><li>IT 软件”Docker”是支持创建和使用 Linux® 容器的容器化技术。</li><li>开源 Docker 社区致力于改进这类技术，并免费提供给所有用户，使之获益。</li><li>Docker Inc. 公司凭借 Docker 社区产品起家，主要负责提升社区版本的安全性，并将技术进步与广大技术社区分享。此外，它还专门对这些技术产品进行完善和安全固化，以服务于企业客户。</li><li>借助 Docker，您可将容器当做轻巧、模块化的虚拟机来使用。同时，您还将获得高度灵活性，实现对容器的高效创建、部署及复制，并在环境之间迁移它们，从而有助于您针对云来优化应用。</li></ul><h1 id="镜像管理"><a href="#镜像管理" class="headerlink" title="镜像管理"></a>镜像管理</h1><h2 id="搜索镜像"><a href="#搜索镜像" class="headerlink" title="搜索镜像"></a>搜索镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker search 镜像的名字</span><br></pre></td></tr></table></figure><h2 id="拉取镜像"><a href="#拉取镜像" class="headerlink" title="拉取镜像"></a>拉取镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull 镜像的名字</span><br></pre></td></tr></table></figure><h2 id="查看本地镜像"><a href="#查看本地镜像" class="headerlink" title="查看本地镜像"></a>查看本地镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">docker images </span><br><span class="line">docker image ls</span><br><span class="line">docker images -q 只列出镜像的id</span><br><span class="line">docker images --format “&#123;&#123;.ID&#125;&#125;--&#123;&#123;.Repository&#125;&#125;” 格式化显示镜像</span><br><span class="line">docker images --format “ table &#123;&#123;.ID&#125;&#125;\t&#123;&#123;.Repository&#125;&#125;\t&#123;&#123;.Tag&#125;&#125;&quot; 以表格形式显示</span><br></pre></td></tr></table></figure><h2 id="删除镜像"><a href="#删除镜像" class="headerlink" title="删除镜像"></a>删除镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker rmi 镜像id</span><br><span class="line">批量删除镜像</span><br><span class="line">docker rmi `docker images -qa`</span><br></pre></td></tr></table></figure><h2 id="导入镜像"><a href="#导入镜像" class="headerlink" title="导入镜像"></a>导入镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#导入打包后的镜像</span><br><span class="line">docker image load -i /opt/centos7.8.2003.tar   </span><br><span class="line">#导入打包压缩后的镜像</span><br><span class="line">zstd -dc /opt/centos-stream9.tar.zst | docker image load</span><br></pre></td></tr></table></figure><h2 id="导出镜像"><a href="#导出镜像" class="headerlink" title="导出镜像"></a>导出镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">#打包</span><br><span class="line">docker image save centos-stream9:cs9 &gt; /opt/centos-stream9.tar</span><br><span class="line">#打包并压缩</span><br><span class="line">docker image save centos-stream9:cs9 | zstd -o /opt/centos-stream9.tar.zst</span><br><span class="line"></span><br><span class="line">#注意：打包时会占用临时空间</span><br></pre></td></tr></table></figure><h2 id="查看镜像详细信息"><a href="#查看镜像详细信息" class="headerlink" title="查看镜像详细信息"></a>查看镜像详细信息</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker image inspect 镜像id</span><br></pre></td></tr></table></figure><h2 id="查看一个镜像的历史"><a href="#查看一个镜像的历史" class="headerlink" title="查看一个镜像的历史"></a>查看一个镜像的历史</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">docker history [OPTIONS] IMAGE</span><br><span class="line"></span><br><span class="line">#OPTIONS</span><br><span class="line">--no-trunc：显示完整命令（默认会截断长命令）</span><br><span class="line">-q：只显示镜像 ID</span><br><span class="line">--format：自定义输出格式（比如只关心大小）</span><br></pre></td></tr></table></figure><h1 id="容器管理"><a href="#容器管理" class="headerlink" title="容器管理"></a>容器管理</h1><h2 id="启动容器"><a href="#启动容器" class="headerlink" title="启动容器"></a>启动容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">docker run  -p 85:80 nginx   //容器的端口映射85是宿主机的端口，80是容器的端口</span><br><span class="line">docker run  -p 0.0.0.0:85:80 nginx   #只做ipv4地址端口映射</span><br><span class="line">docker run  -P nginx  随机端口映射</span><br><span class="line">docker run - it --rm  -d --name test  --ip 192.168.159.152 容器id/名字 bash/sh  </span><br><span class="line">        -i 交互式命令操作</span><br><span class="line">        -t 开启一个终端</span><br><span class="line">        bash 在进入容器后执行的命令  //其实就相当于shell解释器</span><br><span class="line">        --rm  容器挂了后自动删除容器记录</span><br><span class="line">        -d 在后台运行</span><br><span class="line">        --name test 给容器起一个名字叫test</span><br><span class="line">        --restart=always  //容器挂了后自动重启</span><br><span class="line">        --net     //网桥名字</span><br><span class="line">        --ip     //分配容器的ip</span><br><span class="line">        --cups=0.5  //限制cpu的使用率</span><br><span class="line">        --privileged=true  //表示启用容器的超级权限，启用超级权限的时候需要以/usr/sbin/init命令启动不然超级权限不会生效</span><br></pre></td></tr></table></figure><p>注意事项：</p><ul><li><p>docker run 等于创建加启动，如果镜像不存在在本地则会去下载镜像</p></li><li><p>容器内的进程必须处于前台运行状态，否则容器会直接退出</p></li><li><p>如果容器内，什么事也不做，容器也会挂掉，容器内，必须有一个进程在前台运行，&#x2F;&#x2F;例如docker run nginx 容器会直接挂掉</p></li></ul><h2 id="进入容器"><a href="#进入容器" class="headerlink" title="进入容器"></a>进入容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec -it 容器id bash   //进入正在运行的容器</span><br></pre></td></tr></table></figure><h2 id="查看运行的容器"><a href="#查看运行的容器" class="headerlink" title="查看运行的容器"></a>查看运行的容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker ps</span><br></pre></td></tr></table></figure><h2 id="查看停止的容器"><a href="#查看停止的容器" class="headerlink" title="查看停止的容器"></a>查看停止的容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker ps -a</span><br></pre></td></tr></table></figure><h2 id="容器的重启、停止、启动"><a href="#容器的重启、停止、启动" class="headerlink" title="容器的重启、停止、启动"></a>容器的重启、停止、启动</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker restart/stop/start 容器id</span><br></pre></td></tr></table></figure><h2 id="查看容器的详细信息"><a href="#查看容器的详细信息" class="headerlink" title="查看容器的详细信息"></a>查看容器的详细信息</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker container inspect 容器id</span><br></pre></td></tr></table></figure><h2 id="查看容器端口转发情况"><a href="#查看容器端口转发情况" class="headerlink" title="查看容器端口转发情况"></a>查看容器端口转发情况</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker port 容器id</span><br></pre></td></tr></table></figure><h2 id="查看容器内进程信息"><a href="#查看容器内进程信息" class="headerlink" title="查看容器内进程信息"></a>查看容器内进程信息</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker top 容器id</span><br></pre></td></tr></table></figure><h2 id="查看容器内资源"><a href="#查看容器内资源" class="headerlink" title="查看容器内资源"></a>查看容器内资源</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker stats 容器id</span><br></pre></td></tr></table></figure><h2 id="查看容器的具体信息"><a href="#查看容器的具体信息" class="headerlink" title="查看容器的具体信息"></a>查看容器的具体信息</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker inspecet 容器id</span><br></pre></td></tr></table></figure><h2 id="传输本地文件到容器中"><a href="#传输本地文件到容器中" class="headerlink" title="传输本地文件到容器中"></a>传输本地文件到容器中</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker cp 本地文件路径 容器ID:容器中的存储路径</span><br></pre></td></tr></table></figure><h2 id="传输容器中的文件到本地"><a href="#传输容器中的文件到本地" class="headerlink" title="传输容器中的文件到本地"></a>传输容器中的文件到本地</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker cp 容器ID:容器中的路径 本地存储路径</span><br></pre></td></tr></table></figure><h2 id="退出容器"><a href="#退出容器" class="headerlink" title="退出容器"></a>退出容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">exit</span><br></pre></td></tr></table></figure><h2 id="只删除容器，volume保留"><a href="#只删除容器，volume保留" class="headerlink" title="只删除容器，volume保留"></a>只删除容器，volume保留</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker rm 容器id</span><br><span class="line">#强制删除容器</span><br><span class="line">docker rm -f 容器id</span><br></pre></td></tr></table></figure><h2 id="阻塞容器"><a href="#阻塞容器" class="headerlink" title="阻塞容器"></a>阻塞容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#用于阻塞docker容器，并在容器退出是打印退出码，当容器不在运行的时候，直接输出0；可以用来监控容器是否正常退出</span><br><span class="line">docke wait 容器ID/容器名字</span><br></pre></td></tr></table></figure><h2 id="删除容器，同时删除volume"><a href="#删除容器，同时删除volume" class="headerlink" title="删除容器，同时删除volume"></a>删除容器，同时删除volume</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker rm -v 容器ID </span><br><span class="line">docker rm --volumes 容器ID</span><br></pre></td></tr></table></figure><h2 id="查看容器资源使用情况"><a href="#查看容器资源使用情况" class="headerlink" title="查看容器资源使用情况"></a>查看容器资源使用情况</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker stats &lt;container_name_or_id&gt;</span><br></pre></td></tr></table></figure><h2 id="容器打包成镜像"><a href="#容器打包成镜像" class="headerlink" title="容器打包成镜像"></a>容器打包成镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]</span><br><span class="line"></span><br><span class="line">docker commit -a &#x27;LML&#x27; -m &#x27;This is a container image&#x27;  容器ID  容器打包后的镜像名字:标签 </span><br><span class="line">Option功能</span><br><span class="line">-a指定新镜像作者</span><br><span class="line">-c使用 Dockerfile 指令来创建镜像</span><br><span class="line">-m提交生成镜像的说明信息</span><br><span class="line">-p在 commit 时，将容器暂停|</span><br></pre></td></tr></table></figure><h2 id="容器打包成tar包"><a href="#容器打包成tar包" class="headerlink" title="容器打包成tar包"></a>容器打包成tar包</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker save -o tar包名称.tar 待打包镜像名称:待打包镜像版本</span><br><span class="line">演示：</span><br><span class="line">docker save -o mysql-lml-docker.tar mysql-lml-docker:v1.0</span><br></pre></td></tr></table></figure><h2 id="tar包载入镜像"><a href="#tar包载入镜像" class="headerlink" title="tar包载入镜像"></a>tar包载入镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker load [OPTIONS] tar包名称.tar</span><br><span class="line">演示：</span><br><span class="line">docker load -i mysql-lml-docker.tar</span><br></pre></td></tr></table></figure><h1 id="日志管理"><a href="#日志管理" class="headerlink" title="日志管理"></a>日志管理</h1><h2 id="查看容器日志"><a href="#查看容器日志" class="headerlink" title="查看容器日志"></a>查看容器日志</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">所有日志</span><br><span class="line">docker logs 容器id</span><br><span class="line">相当于tail -f，实时的刷新日志</span><br><span class="line">docker logs -f 容器id</span><br></pre></td></tr></table></figure><h1 id="网络管理"><a href="#网络管理" class="headerlink" title="网络管理"></a>网络管理</h1><h2 id="列出所有网桥"><a href="#列出所有网桥" class="headerlink" title="列出所有网桥"></a>列出所有网桥</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network ls</span><br></pre></td></tr></table></figure><h2 id="查看网络信息"><a href="#查看网络信息" class="headerlink" title="查看网络信息"></a>查看网络信息</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network inspect 网络类型</span><br></pre></td></tr></table></figure><h2 id="创建新的网桥"><a href="#创建新的网桥" class="headerlink" title="创建新的网桥"></a>创建新的网桥</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network create --subnet=192.168.159.0/24 NetTest</span><br></pre></td></tr></table></figure><h2 id="删除创建的网桥"><a href="#删除创建的网桥" class="headerlink" title="删除创建的网桥"></a>删除创建的网桥</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network rm net_name</span><br></pre></td></tr></table></figure><h2 id="将容器加入自建网络中"><a href="#将容器加入自建网络中" class="headerlink" title="将容器加入自建网络中"></a>将容器加入自建网络中</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network connect 网络名称 容器名称</span><br></pre></td></tr></table></figure><h2 id="将容器退出自建网络中"><a href="#将容器退出自建网络中" class="headerlink" title="将容器退出自建网络中"></a>将容器退出自建网络中</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network disconnect 网络名称 容器名称</span><br></pre></td></tr></table></figure><h1 id="命名卷管理"><a href="#命名卷管理" class="headerlink" title="命名卷管理"></a>命名卷管理</h1><h2 id="列出所有的volume"><a href="#列出所有的volume" class="headerlink" title="列出所有的volume"></a>列出所有的volume</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume ls</span><br></pre></td></tr></table></figure><h2 id="删除未使用的volume"><a href="#删除未使用的volume" class="headerlink" title="删除未使用的volume"></a>删除未使用的volume</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume prune</span><br></pre></td></tr></table></figure><h2 id="查看volume信息"><a href="#查看volume信息" class="headerlink" title="查看volume信息"></a>查看volume信息</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume inspect 命名卷名字</span><br></pre></td></tr></table></figure><h2 id="删除volume"><a href="#删除volume" class="headerlink" title="删除volume"></a>删除volume</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume rm 命名卷的卷名</span><br></pre></td></tr></table></figure><h2 id="创建volume"><a href="#创建volume" class="headerlink" title="创建volume"></a>创建volume</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume create 命名卷名字</span><br></pre></td></tr></table></figure><h1 id="进阶命令"><a href="#进阶命令" class="headerlink" title="进阶命令"></a>进阶命令</h1><h2 id="查看所有的容器和镜像大小"><a href="#查看所有的容器和镜像大小" class="headerlink" title="查看所有的容器和镜像大小"></a>查看所有的容器和镜像大小</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker system df</span><br></pre></td></tr></table></figure><h2 id="回收悬空的镜像"><a href="#回收悬空的镜像" class="headerlink" title="回收悬空的镜像"></a>回收悬空的镜像</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker image prune -a</span><br></pre></td></tr></table></figure><h2 id="删除所有已停用的容器"><a href="#删除所有已停用的容器" class="headerlink" title="删除所有已停用的容器"></a>删除所有已停用的容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker container prune</span><br></pre></td></tr></table></figure><h2 id="回收孤儿卷（无容器使用）"><a href="#回收孤儿卷（无容器使用）" class="headerlink" title="回收孤儿卷（无容器使用）"></a>回收孤儿卷（无容器使用）</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume prune</span><br></pre></td></tr></table></figure><h2 id="批量删除（网络，数据卷，镜像…）"><a href="#批量删除（网络，数据卷，镜像…）" class="headerlink" title="批量删除（网络，数据卷，镜像…）"></a>批量删除（网络，数据卷，镜像…）</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker system prune        # 仅中间层 + 停止容器</span><br><span class="line">docker system prune -a     # 再加“无用”镜像</span><br><span class="line">docker system prune -a --volumes  # 连无用卷一起</span><br></pre></td></tr></table></figure><h2 id="启停全部容器"><a href="#启停全部容器" class="headerlink" title="启停全部容器"></a>启停全部容器</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker stop/start $(docker ps -aq -f &quot;status=running/exited/created/paused&quot;)</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/03/26/Docker%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4%E9%80%9F%E6%9F%A5%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%AE%9E%E8%B7%B5/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Hexo网站地图生成与百度主动推送</title>
      <link>https://blog.mingliangstar.com/2026/03/01/sitemap/</link>
      <guid>https://blog.mingliangstar.com/2026/03/01/sitemap/</guid>
      <pubDate>Sun, 01 Mar 2026 10:43:45 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;h3 id=&quot;安装插件&quot;&gt;&lt;a</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="网站地图生成"><a href="#网站地图生成" class="headerlink" title="网站地图生成"></a>网站地图生成</h2><h3 id="安装插件"><a href="#安装插件" class="headerlink" title="安装插件"></a>安装插件</h3><p>在 Hexo 站点根目录执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-generator-sitemap --save</span><br></pre></td></tr></table></figure><h3 id="配置-config-yml"><a href="#配置-config-yml" class="headerlink" title="配置 _config.yml"></a>配置 _config.yml</h3><p>编辑 Hexo 根目录的 <code>_config.yml</code> 文件，添加以下配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 站点地图配置</span></span><br><span class="line"><span class="attr">sitemap:</span></span><br><span class="line">  <span class="attr">path:</span> <span class="string">sitemap.xml</span></span><br><span class="line">  <span class="comment"># 可选参数</span></span><br><span class="line">  <span class="attr">priority:</span> <span class="number">0.5</span>        <span class="comment"># 页面优先级，范围 0.0-1.0</span></span><br><span class="line">  <span class="attr">changefreq:</span> <span class="string">daily</span>    <span class="comment"># 更新频率：always/hourly/daily/weekly/monthly/yearly/never</span></span><br><span class="line">  <span class="attr">lastmod:</span> <span class="literal">true</span>        <span class="comment"># 是否包含最后修改时间</span></span><br><span class="line">  <span class="attr">tags:</span> <span class="literal">true</span>           <span class="comment"># 是否包含标签页</span></span><br><span class="line">  <span class="attr">categories:</span> <span class="literal">true</span>     <span class="comment"># 是否包含分类页</span></span><br></pre></td></tr></table></figure><p><strong>注意</strong>：确保 <code>_config.yml</code> 中的 <code>url</code> 配置正确，站点地图会基于这个 URL 生成完整链接 ：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># URL 配置（必须正确设置）</span></span><br><span class="line"><span class="attr">url:</span> <span class="string">https://images.mingliangstar.com</span></span><br><span class="line"><span class="attr">root:</span> <span class="string">/</span></span><br><span class="line"><span class="attr">permalink:</span> <span class="string">:year/:month/:day/:title/</span></span><br></pre></td></tr></table></figure><h3 id="生成站点地图"><a href="#生成站点地图" class="headerlink" title="生成站点地图"></a>生成站点地图</h3><p>执行生成命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo clean &amp;&amp; hexo generate</span><br></pre></td></tr></table></figure><p>生成后会在 <code>public/</code> 目录下创建文件：<code>sitemap.xml</code> </p><h2 id="百度主动推送"><a href="#百度主动推送" class="headerlink" title="百度主动推送"></a>百度主动推送</h2><h3 id="1-安装插件"><a href="#1-安装插件" class="headerlink" title="1. 安装插件"></a>1. 安装插件</h3><p>在 Hexo 站点根目录下执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-baidu-url-submit --save</span><br></pre></td></tr></table></figure><h3 id="2-获取百度-Token"><a href="#2-获取百度-Token" class="headerlink" title="2. 获取百度 Token"></a>2. 获取百度 Token</h3><ol><li>访问 <a href="https://ziyuan.baidu.com/site">百度搜索资源平台</a></li><li>注册&#x2F;登录并添加你的网站</li><li>进入 <strong>站点管理 → 资源提交 → 链接提交 → 主动推送(实时)</strong></li><li>找到推送接口地址，复制 <code>token=</code> 后面的字符串</li></ol><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260301/1.avif"></p><h3 id="3-修改站点配置"><a href="#3-修改站点配置" class="headerlink" title="3. 修改站点配置"></a>3. 修改站点配置</h3><p>编辑 Hexo 根目录的 <code>_config.yml</code>，添加以下配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 百度主动推送配置</span></span><br><span class="line"><span class="attr">baidu_url_submit:</span></span><br><span class="line">  <span class="attr">count:</span> <span class="number">10</span>              <span class="comment"># 提交最新的多少个链接（默认200）</span></span><br><span class="line">  <span class="attr">host:</span> <span class="string">images.mingliangstar.com</span>  <span class="comment"># 在百度站长平台注册的域名（不含 http/https）</span></span><br><span class="line">  <span class="attr">token:</span> <span class="string">your_token_here</span>  <span class="comment"># 你的百度推送密钥（不要泄露！）</span></span><br><span class="line">  <span class="attr">path:</span> <span class="string">baidu_urls.txt</span>    <span class="comment"># 生成的链接文件路径（默认即可）</span></span><br></pre></td></tr></table></figure><p><strong>注意</strong>：<code>host</code> 字段不要带 <code>http://</code> 或 <code>https://</code>，只需要纯域名 。</p><h3 id="4-添加部署配置"><a href="#4-添加部署配置" class="headerlink" title="4. 添加部署配置"></a>4. 添加部署配置</h3><p>在 <code>_config.yml</code> 的 <code>deploy</code> 部分添加推送类型：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">deploy:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">type:</span> <span class="string">baidu_url_submitter</span>    <span class="comment"># 添加这一行</span></span><br></pre></td></tr></table></figure><p>如果有多个部署目标，确保每个 <code>type</code> 前都有 <code>- </code> 。</p><h3 id="5-验证配置"><a href="#5-验证配置" class="headerlink" title="5. 验证配置"></a>5. 验证配置</h3><p>执行部署命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo clean &amp;&amp; hexo generate &amp;&amp; hexo deploy</span><br></pre></td></tr></table></figure><p>推送成功后会显示下述信息：</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260301/2.avif"></p><p>blog</p><h2 id="手动提交"><a href="#手动提交" class="headerlink" title="手动提交"></a>手动提交</h2><p>手动提交可以参考之前写的这篇文章</p><p><a href="https://blog.mingliangstar.com/2023/05/08/%E7%BD%91%E7%AB%99%E6%8F%90%E4%BA%A4%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/">网站提交搜索引擎</a></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/SEO/">SEO</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/SEO/%E7%BD%91%E7%AB%99%E5%9C%B0%E5%9B%BE/">网站地图</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/SEO/">SEO</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E7%BD%91%E7%AB%99%E5%9C%B0%E5%9B%BE/">网站地图</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/03/01/sitemap/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Hexo中字体的引入与压缩</title>
      <link>https://blog.mingliangstar.com/2026/02/13/%E5%AD%97%E4%BD%93%E7%9A%84%E5%BC%95%E5%85%A5%E4%B8%8E%E5%8E%8B%E7%BC%A9/</link>
      <guid>https://blog.mingliangstar.com/2026/02/13/%E5%AD%97%E4%BD%93%E7%9A%84%E5%BC%95%E5%85%A5%E4%B8%8E%E5%8E%8B%E7%BC%A9/</guid>
      <pubDate>Fri, 13 Feb 2026 07:58:51 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;引入tff字体&quot;&gt;&lt;a href=&quot;#引入tff字体&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="引入tff字体"><a href="#引入tff字体" class="headerlink" title="引入tff字体"></a>引入tff字体</h2><blockquote><p>本文中涉及的文件没有的话再对应的目录下创建即可</p></blockquote><p>首先，找一个你喜欢的字体。你可以在一些网站上免费下载。下载完之后，把那个.ttf格式的文件放到你网站根目录下的&#x2F;source&#x2F;fonts文件夹里。</p><p><a href="https://www.maoken.com/all-fonts">免费字体下载大全，可免费商用中文字体一览表 - 猫啃网</a></p><p>接下来，你需要把下面的代码加到&#x2F;source&#x2F;css&#x2F;custom.css文件里，这样就可以引入字体了。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">@font-face &#123;</span><br><span class="line">  font-family: <span class="string">&#x27;BailuFeiYun&#x27;</span>;</span><br><span class="line">  src: url(<span class="string">&#x27;/fonts/BailuFeiYu.ttf&#x27;</span>) format(<span class="string">&#x27;truetype&#x27;</span>); </span><br><span class="line">  font-weight: normal;</span><br><span class="line">  font-style: normal;</span><br><span class="line">  font-display: swap;  /* 关键：防止闪烁，先显示后备字体 */</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>记得在_config.anzhiyu.yml文件里加上custom.css，并且设置一下“# Global font settings”那部分。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;/css/custom.css&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://images.mingliangstar.com/images/20260213/1.avif"></p><p><img src="https://images.mingliangstar.com/images/20260213/2.avif"></p><p>最后一步就是清理缓存，然后重新生成就行了。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br></pre></td></tr></table></figure><h2 id="tff转换woff2"><a href="#tff转换woff2" class="headerlink" title="tff转换woff2"></a>tff转换woff2</h2><p>.ttf字体文件有时候会很大，这样会让网站加载变慢。为了解决这个问题，你可以把.ttf文件转换成.woff2格式，这种格式的文件更小，加载更快。你可以在一些免费的在线网站上完成这个转换。</p><p><a href="https://cloudconvert.com/ttf-to-woff2">TTF to WOFF2 | CloudConvert</a></p><p>记得改一下这里的代码。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">@font-face &#123;</span><br><span class="line">  font-family: &#x27;BailuFeiYun&#x27;;</span><br><span class="line">  src: url(&#x27;/fonts/BailuFeiYu.woff2&#x27;) format(&#x27;woff2&#x27;),</span><br><span class="line">       url(&#x27;/fonts/BailuFeiYun.ttf&#x27;) format(&#x27;truetype&#x27;); </span><br><span class="line">  font-weight: normal;</span><br><span class="line">  font-style: normal;</span><br><span class="line">  font-display: swap;  /* 关键：防止闪烁，先显示后备字体 */</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="字体压缩"><a href="#字体压缩" class="headerlink" title="字体压缩"></a>字体压缩</h2><p>如果你引用了*.woff2格式的字体文件，但网站加载还是很慢，那可能就得考虑压缩字体了——可以用字蛛（font-spider）这个工具。</p><p>1、安装字蛛</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 全局安装</span></span><br><span class="line">npm install font-spider -g</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证安装</span></span><br><span class="line">font-spider --version</span><br></pre></td></tr></table></figure><p>2、准备工作目录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建工作目录</span></span><br><span class="line"><span class="built_in">mkdir</span> font-spider-work</span><br><span class="line"><span class="built_in">cd</span> font-spider-work</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建必要文件</span></span><br><span class="line"><span class="built_in">touch</span> index.html</span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="built_in">source</span>/fonts</span><br><span class="line"></span><br><span class="line"><span class="comment"># 放入原字体</span></span><br><span class="line"><span class="built_in">cp</span> /source/fonts/BailuFeiYun.ttf <span class="built_in">source</span>/fonts/</span><br></pre></td></tr></table></figure><p>3、建一个index.html文件，在里面放上你博客要用的所有字体。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html&gt;</span><br><span class="line"></span><br><span class="line">&lt;<span class="built_in">head</span>&gt;</span><br><span class="line">    &lt;meta charset=<span class="string">&quot;UTF-8&quot;</span>&gt;</span><br><span class="line">    &lt;title&gt;Font Spider&lt;/title&gt;</span><br><span class="line">    &lt;style&gt;</span><br><span class="line">        @font-face &#123;</span><br><span class="line">            font-family: <span class="string">&#x27;BailuFeiYun&#x27;</span>;</span><br><span class="line">            src: url(<span class="string">&#x27;../source/fonts/BailuFeiYun.ttf&#x27;</span>) format(<span class="string">&#x27;truetype&#x27;</span>);</span><br><span class="line">            font-weight: normal;</span><br><span class="line">            font-style: normal;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        .font-test &#123;</span><br><span class="line">            font-family: <span class="string">&#x27;BailuFeiYun&#x27;</span>;</span><br><span class="line">            font-size: 16px;</span><br><span class="line">            line-height: 1.8;</span><br><span class="line">        &#125;</span><br><span class="line">    &lt;/style&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line"></span><br><span class="line">&lt;body&gt;</span><br><span class="line">    &lt;div class=<span class="string">&quot;font-test&quot;</span>&gt;</span><br><span class="line">        &lt;!-- 把你博客的所有文字放这里 --&gt;</span><br><span class="line">        首页文章归档分类标签友链关于</span><br><span class="line">        技术分享HexoWordPress建站心路</span><br><span class="line">        上一篇下一篇打赏作者复制链接</span><br><span class="line">        猫笔千锤岁月长啃文万遍见真功</span><br><span class="line">        &lt;!-- 继续添加更多文字... --&gt;</span><br><span class="line"></span><br><span class="line">        &lt;!-- 常用标点符号 --&gt;</span><br><span class="line">        ，。！？、；：<span class="string">&quot; &quot;</span> <span class="string">&#x27; &#x27;</span> （）《》【】… — ～ · ｜</span><br><span class="line"></span><br><span class="line">        &lt;!-- 常用英文和数字 --&gt;</span><br><span class="line">        abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789</span><br><span class="line"></span><br><span class="line">        &lt;!-- 你的博客标题/昵称（如果有特殊字） --&gt;</span><br><span class="line">        安知鱼 白路飞云 手写体 博客 笔记 技术 生活 随笔</span><br><span class="line"></span><br><span class="line">        &lt;!-- 从你的文章提取的高频文字（复制几篇文章的标题和摘要） --&gt;</span><br><span class="line">        &lt;!-- 这里粘贴你几篇文章的标题和内容中的汉字 --&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line"></span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure><p>4、执行压缩</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">font-spider index.html</span><br></pre></td></tr></table></figure><p><img src="https://images.mingliangstar.com/images/20260213/3.avif"></p><p>最后，只需要在custom.css文件里加入压缩后的字体就行了。</p><h2 id="压缩脚本"><a href="#压缩脚本" class="headerlink" title="压缩脚本"></a>压缩脚本</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/env python3</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="string">&quot;&quot;</span><span class="string">&quot;</span></span><br><span class="line"><span class="string">Hexo 博客字体压缩脚本 - 动态完整版</span></span><br><span class="line"><span class="string">扫描汉字、英文、数字、标点</span></span><br><span class="line"><span class="string">&quot;</span><span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">import os</span><br><span class="line">import re</span><br><span class="line">import sys</span><br><span class="line">import yaml</span><br><span class="line">import json</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def extract_chars_from_file(filepath, skip_comments=False):</span><br><span class="line">    <span class="string">&quot;&quot;</span><span class="string">&quot;从文件提取所有字符（汉字、英文、数字、标点）&quot;</span><span class="string">&quot;&quot;</span></span><br><span class="line">    try:</span><br><span class="line">        with open(filepath, <span class="string">&#x27;r&#x27;</span>, encoding=<span class="string">&#x27;utf-8&#x27;</span>, errors=<span class="string">&#x27;ignore&#x27;</span>) as f:</span><br><span class="line">            content = f.read()</span><br><span class="line">            </span><br><span class="line">            <span class="comment"># 如果需要过滤注释（YAML 文件）</span></span><br><span class="line">            <span class="keyword">if</span> skip_comments:</span><br><span class="line">                lines = content.split(<span class="string">&#x27;\n&#x27;</span>)</span><br><span class="line">                content = <span class="string">&#x27;\n&#x27;</span>.<span class="built_in">join</span>([line <span class="keyword">for</span> line <span class="keyword">in</span> lines <span class="keyword">if</span> not line.strip().startswith(<span class="string">&#x27;#&#x27;</span>)])</span><br><span class="line">            </span><br><span class="line">            chars = <span class="built_in">set</span>()</span><br><span class="line">            </span><br><span class="line">            <span class="comment"># 1. 汉字</span></span><br><span class="line">            chars.update(re.findall(r<span class="string">&#x27;[\u4e00-\u9fa5]&#x27;</span>, content))</span><br><span class="line">            </span><br><span class="line">            <span class="comment"># 2. 英文字母（大小写）</span></span><br><span class="line">            chars.update(re.findall(r<span class="string">&#x27;[a-zA-Z]&#x27;</span>, content))</span><br><span class="line">            </span><br><span class="line">            <span class="comment"># 3. 数字</span></span><br><span class="line">            chars.update(re.findall(r<span class="string">&#x27;[0-9]&#x27;</span>, content))</span><br><span class="line">            </span><br><span class="line">            <span class="comment"># 4. 常用标点符号</span></span><br><span class="line">            <span class="comment"># 中文标点</span></span><br><span class="line">            chars.update(re.findall(r<span class="string">&#x27;[，。！？、；：&quot;&quot;&#x27;</span><span class="string">&#x27;（）《》【】…—～·｜「」『』【】]&#x27;</span>, content))</span><br><span class="line">            <span class="comment"># 英文标点</span></span><br><span class="line">            chars.update(re.findall(r<span class="string">&#x27;[.,!?;:\&#x27;</span>\&quot;()\[\]&#123;&#125;@#$%^&amp;*+=_\-\\/&lt;&gt;~`]<span class="string">&#x27;, content))</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            return chars</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">    except Exception as e:</span></span><br><span class="line"><span class="string">        print(f&quot;读取文件失败 &#123;filepath&#125;: &#123;e&#125;&quot;)</span></span><br><span class="line"><span class="string">        return set()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">def extract_chars_from_json_yaml(filepath):</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;从 JSON/YAML 文件递归提取所有字符串中的字符&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    chars = set()</span></span><br><span class="line"><span class="string">    try:</span></span><br><span class="line"><span class="string">        with open(filepath, &#x27;</span>r<span class="string">&#x27;, encoding=&#x27;</span>utf-8<span class="string">&#x27;, errors=&#x27;</span>ignore<span class="string">&#x27;) as f:</span></span><br><span class="line"><span class="string">            content = f.read()</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            # 尝试解析为 JSON 或 YAML</span></span><br><span class="line"><span class="string">            data = None</span></span><br><span class="line"><span class="string">            try:</span></span><br><span class="line"><span class="string">                data = json.loads(content)</span></span><br><span class="line"><span class="string">            except:</span></span><br><span class="line"><span class="string">                try:</span></span><br><span class="line"><span class="string">                    data = yaml.safe_load(content)</span></span><br><span class="line"><span class="string">                except:</span></span><br><span class="line"><span class="string">                    pass</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            def extract_strings(obj):</span></span><br><span class="line"><span class="string">                if isinstance(obj, str):</span></span><br><span class="line"><span class="string">                    result = set()</span></span><br><span class="line"><span class="string">                    # 汉字</span></span><br><span class="line"><span class="string">                    result.update(re.findall(r&#x27;</span>[\u4e00-\u9fa5]<span class="string">&#x27;, obj))</span></span><br><span class="line"><span class="string">                    # 英文</span></span><br><span class="line"><span class="string">                    result.update(re.findall(r&#x27;</span>[a-zA-Z]<span class="string">&#x27;, obj))</span></span><br><span class="line"><span class="string">                    # 数字</span></span><br><span class="line"><span class="string">                    result.update(re.findall(r&#x27;</span>[0-9]<span class="string">&#x27;, obj))</span></span><br><span class="line"><span class="string">                    # 标点</span></span><br><span class="line"><span class="string">                    result.update(re.findall(r&#x27;</span>[，。！？、；：<span class="string">&quot;&quot;</span><span class="string">&#x27;&#x27;</span>（）《》【】…—～·｜「」『』【】.,!?;:\&#x27;\&quot;()\[\]&#123;&#125;@#$%^&amp;*+=_\-\\/&lt;&gt;~`]<span class="string">&#x27;, obj))</span></span><br><span class="line"><span class="string">                    return result</span></span><br><span class="line"><span class="string">                elif isinstance(obj, list):</span></span><br><span class="line"><span class="string">                    result = set()</span></span><br><span class="line"><span class="string">                    for item in obj:</span></span><br><span class="line"><span class="string">                        result.update(extract_strings(item))</span></span><br><span class="line"><span class="string">                    return result</span></span><br><span class="line"><span class="string">                elif isinstance(obj, dict):</span></span><br><span class="line"><span class="string">                    result = set()</span></span><br><span class="line"><span class="string">                    for key, value in obj.items():</span></span><br><span class="line"><span class="string">                        result.update(extract_strings(key))</span></span><br><span class="line"><span class="string">                        result.update(extract_strings(value))</span></span><br><span class="line"><span class="string">                    return result</span></span><br><span class="line"><span class="string">                return set()</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            if data:</span></span><br><span class="line"><span class="string">                chars.update(extract_strings(data))</span></span><br><span class="line"><span class="string">            else:</span></span><br><span class="line"><span class="string">                # 解析失败，直接正则提取</span></span><br><span class="line"><span class="string">                chars.update(extract_chars_from_file(filepath))</span></span><br><span class="line"><span class="string">                </span></span><br><span class="line"><span class="string">    except Exception as e:</span></span><br><span class="line"><span class="string">        print(f&quot;读取失败 &#123;filepath&#125;: &#123;e&#125;&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    return chars</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">def extract_title_from_md(filepath):</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;只提取 Markdown 文件的 Front-matter title&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    try:</span></span><br><span class="line"><span class="string">        with open(filepath, &#x27;</span>r<span class="string">&#x27;, encoding=&#x27;</span>utf-8<span class="string">&#x27;, errors=&#x27;</span>ignore<span class="string">&#x27;) as f:</span></span><br><span class="line"><span class="string">            content = f.read()</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            # 匹配 Front-matter</span></span><br><span class="line"><span class="string">            fm_match = re.match(r&#x27;</span>^---\s*\n(.*?)\n---<span class="string">&#x27;, content, re.DOTALL)</span></span><br><span class="line"><span class="string">            title = &#x27;</span><span class="string">&#x27;</span></span><br><span class="line"><span class="string">            if fm_match:</span></span><br><span class="line"><span class="string">                try:</span></span><br><span class="line"><span class="string">                    fm = yaml.safe_load(fm_match.group(1))</span></span><br><span class="line"><span class="string">                    title = str(fm.get(&#x27;</span>title<span class="string">&#x27;, &#x27;</span><span class="string">&#x27;))</span></span><br><span class="line"><span class="string">                except:</span></span><br><span class="line"><span class="string">                    pass</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            # 备用：正则提取 title: xxx</span></span><br><span class="line"><span class="string">            if not title:</span></span><br><span class="line"><span class="string">                title_match = re.search(r&#x27;</span>^title:\s*(.+)$<span class="string">&#x27;, content, re.MULTILINE)</span></span><br><span class="line"><span class="string">                if title_match:</span></span><br><span class="line"><span class="string">                    title = title_match.group(1).strip().strip(&#x27;</span><span class="string">&quot;\&#x27;&#x27;)</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            # 提取所有字符</span></span><br><span class="line"><span class="string">            chars = set()</span></span><br><span class="line"><span class="string">            chars.update(re.findall(r&#x27;[\u4e00-\u9fa5]&#x27;, title))</span></span><br><span class="line"><span class="string">            chars.update(re.findall(r&#x27;[a-zA-Z]&#x27;, title))</span></span><br><span class="line"><span class="string">            chars.update(re.findall(r&#x27;[0-9]&#x27;, title))</span></span><br><span class="line"><span class="string">            chars.update(re.findall(r&#x27;[，。！？、；：&quot;</span><span class="string">&quot;&#x27;&#x27;（）《》【】…—～·｜「」『』【】.,!?;:\&#x27;\&quot;()\[\]&#123;&#125;@#$%^&amp;*+=_\-\\/&lt;&gt;~`]&#x27;, title))</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            return chars</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">    except Exception as e:</span></span><br><span class="line"><span class="string">        print(f&quot;</span>读取失败 &#123;filepath&#125;: &#123;e&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        return set()</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">def get_dynamic_fixed_chars(hexo_root):</span></span><br><span class="line"><span class="string">    &quot;</span><span class="string">&quot;&quot;</span>从配置文件动态读取固定字符<span class="string">&quot;&quot;</span><span class="string">&quot;</span></span><br><span class="line"><span class="string">    chars = set()</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 1. 从站点配置 _config.yml 读取</span></span><br><span class="line"><span class="string">    site_config = os.path.join(hexo_root, &#x27;_config.yml&#x27;)</span></span><br><span class="line"><span class="string">    if os.path.exists(site_config):</span></span><br><span class="line"><span class="string">        print(f&quot;</span>  读取站点配置: _config.yml<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        config_chars = extract_chars_from_file(site_config, skip_comments=True)</span></span><br><span class="line"><span class="string">        chars.update(config_chars)</span></span><br><span class="line"><span class="string">        print(f&quot;</span>    -&gt; &#123;len(config_chars)&#125; 字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 2. 从主题配置 _config.anzhiyu.yml 读取（过滤注释）</span></span><br><span class="line"><span class="string">    theme_config = os.path.join(hexo_root, &#x27;_config.anzhiyu.yml&#x27;)</span></span><br><span class="line"><span class="string">    if os.path.exists(theme_config):</span></span><br><span class="line"><span class="string">        print(f&quot;</span>  读取主题配置: _config.anzhiyu.yml<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        config_chars = extract_chars_from_file(theme_config, skip_comments=True)</span></span><br><span class="line"><span class="string">        chars.update(config_chars)</span></span><br><span class="line"><span class="string">        print(f&quot;</span>    -&gt; &#123;len(config_chars)&#125; 字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 3. 从主题语言文件读取</span></span><br><span class="line"><span class="string">    theme_lang_dir = os.path.join(hexo_root, &#x27;themes&#x27;, &#x27;anzhiyu&#x27;, &#x27;languages&#x27;)</span></span><br><span class="line"><span class="string">    if os.path.exists(theme_lang_dir):</span></span><br><span class="line"><span class="string">        print(f&quot;</span>  读取主题语言文件:<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        for lang_file in os.listdir(theme_lang_dir):</span></span><br><span class="line"><span class="string">            if lang_file.endswith((&#x27;.yml&#x27;, &#x27;.yaml&#x27;)):</span></span><br><span class="line"><span class="string">                filepath = os.path.join(theme_lang_dir, lang_file)</span></span><br><span class="line"><span class="string">                lang_chars = extract_chars_from_file(filepath, skip_comments=True)</span></span><br><span class="line"><span class="string">                if lang_chars:</span></span><br><span class="line"><span class="string">                    chars.update(lang_chars)</span></span><br><span class="line"><span class="string">                    print(f&quot;</span>    &#123;lang_file&#125; -&gt; &#123;len(lang_chars)&#125; 字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    return chars</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">def scan_directory_full(directory, chars_set, skip_dirs=None, depth=0):</span></span><br><span class="line"><span class="string">    &quot;</span><span class="string">&quot;&quot;</span>递归扫描目录下所有文件<span class="string">&quot;&quot;</span><span class="string">&quot;</span></span><br><span class="line"><span class="string">    if skip_dirs is None:</span></span><br><span class="line"><span class="string">        skip_dirs = [&#x27;node_modules&#x27;, &#x27;.git&#x27;, &#x27;images&#x27;, &#x27;img&#x27;, &#x27;fonts&#x27;, &#x27;css&#x27;, &#x27;js&#x27;]</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    if not os.path.exists(directory):</span></span><br><span class="line"><span class="string">        return 0, 0</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    file_count = 0</span></span><br><span class="line"><span class="string">    total_chars = 0</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    prefix = &quot;</span>  <span class="string">&quot; * depth</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    for root, dirs, files in os.walk(directory):</span></span><br><span class="line"><span class="string">        dirs[:] = [d for d in dirs if d not in skip_dirs and not d.startswith(&#x27;.&#x27;)]</span></span><br><span class="line"><span class="string">        </span></span><br><span class="line"><span class="string">        for file in files:</span></span><br><span class="line"><span class="string">            filepath = os.path.join(root, file)</span></span><br><span class="line"><span class="string">            rel_path = os.path.relpath(filepath, directory)</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            file_chars = set()</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            if file.endswith(&#x27;.md&#x27;):</span></span><br><span class="line"><span class="string">                file_chars = extract_chars_from_file(filepath)</span></span><br><span class="line"><span class="string">            elif file.endswith((&#x27;.json&#x27;, &#x27;.yml&#x27;, &#x27;.yaml&#x27;)):</span></span><br><span class="line"><span class="string">                file_chars = extract_chars_from_json_yaml(filepath)</span></span><br><span class="line"><span class="string">            elif file.endswith((&#x27;.html&#x27;, &#x27;.htm&#x27;, &#x27;.txt&#x27;)):</span></span><br><span class="line"><span class="string">                file_chars = extract_chars_from_file(filepath)</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            if file_chars:</span></span><br><span class="line"><span class="string">                chars_set.update(file_chars)</span></span><br><span class="line"><span class="string">                file_count += 1</span></span><br><span class="line"><span class="string">                total_chars += len(file_chars)</span></span><br><span class="line"><span class="string">                print(f&quot;</span>&#123;prefix&#125;  &#123;rel_path&#125; -&gt; &#123;len(file_chars)&#125; 字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    return file_count, total_chars</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">def generate_char_file(output_path, hexo_root):</span></span><br><span class="line"><span class="string">    &quot;</span><span class="string">&quot;&quot;</span>生成字符文件<span class="string">&quot;&quot;</span><span class="string">&quot;</span></span><br><span class="line"><span class="string">    print(&quot;</span>=<span class="string">&quot; * 60)</span></span><br><span class="line"><span class="string">    print(&quot;</span>Hexo 博客字体压缩工具 - 动态完整版<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(&quot;</span>=<span class="string">&quot; * 60)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    chars = set()</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 1. 文章目录：只扫描标题</span></span><br><span class="line"><span class="string">    posts_dir = os.path.join(hexo_root, &#x27;source&#x27;, &#x27;_posts&#x27;)</span></span><br><span class="line"><span class="string">    if os.path.exists(posts_dir):</span></span><br><span class="line"><span class="string">        print(f&quot;</span>\n📁 扫描文章标题(仅title): &#123;posts_dir&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        count = 0</span></span><br><span class="line"><span class="string">        for root, dirs, files in os.walk(posts_dir):</span></span><br><span class="line"><span class="string">            dirs[:] = [d for d in dirs if d not in [&#x27;node_modules&#x27;, &#x27;.git&#x27;]]</span></span><br><span class="line"><span class="string">            for file in files:</span></span><br><span class="line"><span class="string">                if file.endswith(&#x27;.md&#x27;):</span></span><br><span class="line"><span class="string">                    filepath = os.path.join(root, file)</span></span><br><span class="line"><span class="string">                    title_chars = extract_title_from_md(filepath)</span></span><br><span class="line"><span class="string">                    chars.update(title_chars)</span></span><br><span class="line"><span class="string">                    count += 1</span></span><br><span class="line"><span class="string">        print(f&quot;</span>  扫描了 &#123;count&#125; 篇文章，提取 &#123;len(chars)&#125; 个独特字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 2. 其他页面目录：全内容扫描</span></span><br><span class="line"><span class="string">    source_dir = os.path.join(hexo_root, &#x27;source&#x27;)</span></span><br><span class="line"><span class="string">    if os.path.exists(source_dir):</span></span><br><span class="line"><span class="string">        print(f&quot;</span>\n📁 扫描页面目录(全内容递归):<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        </span></span><br><span class="line"><span class="string">        for item in os.listdir(source_dir):</span></span><br><span class="line"><span class="string">            if item in [&#x27;_posts&#x27;, &#x27;images&#x27;, &#x27;img&#x27;, &#x27;fonts&#x27;, &#x27;css&#x27;, &#x27;js&#x27;]:</span></span><br><span class="line"><span class="string">                continue</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            item_path = os.path.join(source_dir, item)</span></span><br><span class="line"><span class="string">            </span></span><br><span class="line"><span class="string">            if os.path.isdir(item_path):</span></span><br><span class="line"><span class="string">                print(f&quot;</span>\n  📂 &#123;item&#125;/<span class="string">&quot;)</span></span><br><span class="line"><span class="string">                file_count, total_chars = scan_directory_full(item_path, chars, depth=1)</span></span><br><span class="line"><span class="string">                print(f&quot;</span>    合计: &#123;file_count&#125; 个文件，&#123;total_chars&#125; 字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 3. 扫描 _data 目录</span></span><br><span class="line"><span class="string">    data_dir = os.path.join(hexo_root, &#x27;source&#x27;, &#x27;_data&#x27;)</span></span><br><span class="line"><span class="string">    if os.path.exists(data_dir):</span></span><br><span class="line"><span class="string">        print(f&quot;</span>\n📁 扫描数据目录(_data):<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        file_count, total_chars = scan_directory_full(data_dir, chars, depth=1)</span></span><br><span class="line"><span class="string">        print(f&quot;</span>    合计: &#123;file_count&#125; 个文件，&#123;total_chars&#125; 字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 4. 动态读取配置文件</span></span><br><span class="line"><span class="string">    print(f&quot;</span>\n📁 动态读取配置文件:<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    fixed_chars = get_dynamic_fixed_chars(hexo_root)</span></span><br><span class="line"><span class="string">    chars.update(fixed_chars)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>  配置文件共提取: &#123;len(fixed_chars)&#125; 字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    # 5. 排序并保存</span></span><br><span class="line"><span class="string">    # 按字符类型排序：汉字 -&gt; 英文 -&gt; 数字 -&gt; 标点</span></span><br><span class="line"><span class="string">    hanzi = sorted([c for c in chars if &#x27;\u4e00&#x27; &lt;= c &lt;= &#x27;\u9fa5&#x27;])</span></span><br><span class="line"><span class="string">    english = sorted([c for c in chars if c.isalpha()])</span></span><br><span class="line"><span class="string">    digits = sorted([c for c in chars if c.isdigit()])</span></span><br><span class="line"><span class="string">    others = sorted([c for c in chars if not (&#x27;\u4e00&#x27; &lt;= c &lt;= &#x27;\u9fa5&#x27; or c.isalnum())])</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    sorted_chars = &#x27;&#x27;.join(hanzi + english + digits + others)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    with open(output_path, &#x27;w&#x27;, encoding=&#x27;utf-8&#x27;) as f:</span></span><br><span class="line"><span class="string">        f.write(sorted_chars)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    print(f&quot;</span>\n<span class="string">&quot; + &quot;</span>=<span class="string">&quot; * 60)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>✅ 共收集 &#123;len(chars)&#125; 个独特字符<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>   - 汉字: &#123;len(hanzi)&#125; 个<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>   - 英文: &#123;len(english)&#125; 个<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>   - 数字: &#123;len(digits)&#125; 个<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>   - 标点/其他: &#123;len(others)&#125; 个<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>💾 已保存到: &#123;output_path&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    preview = sorted_chars[:100]</span></span><br><span class="line"><span class="string">    print(f&quot;</span>\n📋 字符预览: &#123;preview&#125;...<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    return sorted_chars</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">def subset_font(input_font, output_font, chars_file):</span></span><br><span class="line"><span class="string">    &quot;</span><span class="string">&quot;&quot;</span>使用 fonttools 子集化字体<span class="string">&quot;&quot;</span><span class="string">&quot;</span></span><br><span class="line"><span class="string">    try:</span></span><br><span class="line"><span class="string">        from fontTools.subset import main as subset_main</span></span><br><span class="line"><span class="string">    except ImportError:</span></span><br><span class="line"><span class="string">        print(&quot;</span>\n❌ 缺少 fonttools，正在安装...<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        os.system(f&quot;</span>&#123;sys.executable&#125; -m pip install fonttools brotli zopfli<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        from fontTools.subset import main as subset_main</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    print(f&quot;</span>\n🔧 开始压缩字体...<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>   输入: &#123;input_font&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    print(f&quot;</span>   输出: &#123;output_font&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    args = [</span></span><br><span class="line"><span class="string">        input_font,</span></span><br><span class="line"><span class="string">        f&quot;</span>--text-file=&#123;chars_file&#125;<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        f&quot;</span>--output-file=&#123;output_font&#125;<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        &quot;</span>--flavor=woff2<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        &quot;</span>--desubroutinize<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        &quot;</span>--recalc-bounds<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        &quot;</span>--canonical-order<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        &quot;</span>--layout-features=*<span class="string">&quot;,</span></span><br><span class="line"><span class="string">    ]</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    ttf_output = output_font.replace(&#x27;.woff2&#x27;, &#x27;.ttf&#x27;)</span></span><br><span class="line"><span class="string">    args_ttf = [</span></span><br><span class="line"><span class="string">        input_font,</span></span><br><span class="line"><span class="string">        f&quot;</span>--text-file=&#123;chars_file&#125;<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        f&quot;</span>--output-file=&#123;ttf_output&#125;<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        &quot;</span>--desubroutinize<span class="string">&quot;,</span></span><br><span class="line"><span class="string">        &quot;</span>--recalc-bounds<span class="string">&quot;,</span></span><br><span class="line"><span class="string">    ]</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    try:</span></span><br><span class="line"><span class="string">        subset_main(args)</span></span><br><span class="line"><span class="string">        subset_main(args_ttf)</span></span><br><span class="line"><span class="string">        </span></span><br><span class="line"><span class="string">        original_size = os.path.getsize(input_font)</span></span><br><span class="line"><span class="string">        woff2_size = os.path.getsize(output_font)</span></span><br><span class="line"><span class="string">        ttf_size = os.path.getsize(ttf_output)</span></span><br><span class="line"><span class="string">        </span></span><br><span class="line"><span class="string">        print(f&quot;</span>\n✅ 压缩完成!<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        print(f&quot;</span>   原始大小: &#123;original_size/1024:.2f&#125; KB<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        print(f&quot;</span>   WOFF2 大小: &#123;woff2_size/1024:.2f&#125; KB (压缩率: &#123;woff2_size/original_size*100:.1f&#125;%)<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        print(f&quot;</span>   TTF 大小: &#123;ttf_size/1024:.2f&#125; KB (压缩率: &#123;ttf_size/original_size*100:.1f&#125;%)<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        </span></span><br><span class="line"><span class="string">        return True</span></span><br><span class="line"><span class="string">        </span></span><br><span class="line"><span class="string">    except Exception as e:</span></span><br><span class="line"><span class="string">        print(f&quot;</span>\n❌ 压缩失败: &#123;e&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        return False</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">def main():</span></span><br><span class="line"><span class="string">    &quot;</span><span class="string">&quot;&quot;</span>主函数<span class="string">&quot;&quot;</span><span class="string">&quot;</span></span><br><span class="line"><span class="string">    HEXO_ROOT = &quot;</span>/www/wwwroot/myblog<span class="string">&quot;</span></span><br><span class="line"><span class="string">    WORK_DIR = &quot;</span>/www/wwwroot/myblog/font-spider-work<span class="string">&quot;</span></span><br><span class="line"><span class="string">    INPUT_FONT = os.path.join(WORK_DIR, &quot;</span>fonts<span class="string">&quot;, &quot;</span>BailuFeiYun.ttf<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    CHARS_FILE = os.path.join(WORK_DIR, &quot;</span>chars-full.txt<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    OUTPUT_WOFF2 = os.path.join(HEXO_ROOT, &quot;</span><span class="built_in">source</span><span class="string">&quot;, &quot;</span>fonts<span class="string">&quot;, &quot;</span>BailuFeiYun.woff2<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    if not os.path.exists(INPUT_FONT):</span></span><br><span class="line"><span class="string">        print(f&quot;</span>❌ 未找到原始字体: &#123;INPUT_FONT&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        sys.exit(1)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    os.makedirs(os.path.dirname(OUTPUT_WOFF2), exist_ok=True)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    chars = generate_char_file(CHARS_FILE, HEXO_ROOT)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    if len(chars) &lt; 50:</span></span><br><span class="line"><span class="string">        print(&quot;</span>⚠️  提取字符过少，请检查路径<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        sys.exit(1)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    success = subset_font(INPUT_FONT, OUTPUT_WOFF2, CHARS_FILE)</span></span><br><span class="line"><span class="string">    </span></span><br><span class="line"><span class="string">    if success:</span></span><br><span class="line"><span class="string">        print(f&quot;</span>\n🎉 全部完成!<span class="string">&quot;)</span></span><br><span class="line"><span class="string">        print(f&quot;</span>   压缩后的字体已输出到: &#123;os.path.dirname(OUTPUT_WOFF2)&#125;<span class="string">&quot;)</span></span><br><span class="line"><span class="string">    else:</span></span><br><span class="line"><span class="string">        sys.exit(1)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">if __name__ == &quot;</span>__main__<span class="string">&quot;:</span></span><br><span class="line"><span class="string">    main()</span></span><br></pre></td></tr></table></figure><h3 id="工作流程"><a href="#工作流程" class="headerlink" title="工作流程"></a>工作流程</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">1. 扫描文章标题 ──┐</span><br><span class="line">2. 扫描页面内容 ──┤</span><br><span class="line">3. 扫描 _data 目录 ─┼──&gt; 收集所有字符 ──&gt; 去重排序 ──&gt; 生成字符文件</span><br><span class="line">4. 扫描配置文件 ──┤</span><br><span class="line">5. 扫描语言文件 ──┘</span><br><span class="line"></span><br><span class="line">6. 使用 fonttools 压缩字体</span><br><span class="line">   ├── 输入：原始 TTF 字体</span><br><span class="line">   ├── 根据字符文件裁剪</span><br><span class="line">   └── 输出：WOFF2 + TTF（子集化后）</span><br></pre></td></tr></table></figure><h3 id="输出示例"><a href="#输出示例" class="headerlink" title="输出示例"></a>输出示例</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line">============================================================</span><br><span class="line">Hexo 博客字体压缩工具 - 动态完整版</span><br><span class="line">============================================================</span><br><span class="line"></span><br><span class="line">📁 扫描文章标题(仅title): /www/wwwroot/myblog/source/_posts</span><br><span class="line">  扫描了 17 篇文章，提取 143 个独特字符</span><br><span class="line"></span><br><span class="line">📁 扫描页面目录(全内容递归):</span><br><span class="line"></span><br><span class="line">  📂 charts/</span><br><span class="line">    index.md -&gt; 67 字符</span><br><span class="line">    合计: 1 个文件，67 字符</span><br><span class="line"></span><br><span class="line">  📂 agreement/</span><br><span class="line">    index.md -&gt; 433 字符</span><br><span class="line">    合计: 1 个文件，433 字符</span><br><span class="line"></span><br><span class="line">  📂 link/</span><br><span class="line">    index.md -&gt; 126 字符</span><br><span class="line">    合计: 1 个文件，126 字符</span><br><span class="line"></span><br><span class="line">  📂 essay/</span><br><span class="line">    index.md -&gt; 29 字符</span><br><span class="line">    合计: 1 个文件，29 字符</span><br><span class="line"></span><br><span class="line">  📂 categories/</span><br><span class="line">    index.md -&gt; 28 字符</span><br><span class="line">    合计: 1 个文件，28 字符</span><br><span class="line"></span><br><span class="line">  📂 _data/</span><br><span class="line">    link.yml -&gt; 201 字符</span><br><span class="line">    bangumis.json -&gt; 231 字符</span><br><span class="line">    creativity.yml -&gt; 75 字符</span><br><span class="line">    essay.yml -&gt; 73 字符</span><br><span class="line">    about.yml -&gt; 232 字符</span><br><span class="line">    合计: 5 个文件，812 字符</span><br><span class="line"></span><br><span class="line">  📂 cdn/</span><br><span class="line">    合计: 0 个文件，0 字符</span><br><span class="line"></span><br><span class="line">  📂 about/</span><br><span class="line">    index.md -&gt; 34 字符</span><br><span class="line">    合计: 1 个文件，34 字符</span><br><span class="line"></span><br><span class="line">  📂 sitemap/</span><br><span class="line">    合计: 0 个文件，0 字符</span><br><span class="line"></span><br><span class="line">  📂 tags/</span><br><span class="line">    index.md -&gt; 28 字符</span><br><span class="line">    合计: 1 个文件，28 字符</span><br><span class="line"></span><br><span class="line">  📂 privacy/</span><br><span class="line">    index.md -&gt; 379 字符</span><br><span class="line">    合计: 1 个文件，379 字符</span><br><span class="line"></span><br><span class="line">📁 扫描数据目录(_data):</span><br><span class="line">    link.yml -&gt; 201 字符</span><br><span class="line">    bangumis.json -&gt; 231 字符</span><br><span class="line">    creativity.yml -&gt; 75 字符</span><br><span class="line">    essay.yml -&gt; 73 字符</span><br><span class="line">    about.yml -&gt; 232 字符</span><br><span class="line">    合计: 5 个文件，812 字符</span><br><span class="line"></span><br><span class="line">📁 动态读取配置文件:</span><br><span class="line">  读取站点配置: _config.yml</span><br><span class="line">    -&gt; 360 字符</span><br><span class="line">  读取主题配置: _config.anzhiyu.yml</span><br><span class="line">    -&gt; 526 字符</span><br><span class="line">  读取主题语言文件:</span><br><span class="line">    zh-TW.yml -&gt; 341 字符</span><br><span class="line">    en.yml -&gt; 67 字符</span><br><span class="line">    zh-CN.yml -&gt; 346 字符</span><br><span class="line">    default.yml -&gt; 251 字符</span><br><span class="line">  配置文件共提取: 843 字符</span><br><span class="line"></span><br><span class="line">============================================================</span><br><span class="line">✅ 共收集 1180 个独特字符</span><br><span class="line">   - 汉字: 1073 个</span><br><span class="line">   - 英文: 1125 个</span><br><span class="line">   - 数字: 10 个</span><br><span class="line">   - 标点/其他: 45 个</span><br><span class="line">💾 已保存到: /www/wwwroot/myblog/font-spider-work/chars-full.txt</span><br><span class="line"></span><br><span class="line">📋 字符预览: 一七万三上下不与专且世业东丢个中丰为主举久么义之乌乎乐也习书乾了予二于云互些交亦产享亮人亿什仅仇今介仍从他付仙代以们件价任份优伙会传伦伴伸但位低住体何作你使來例供依侧侵便保信修個們倒值假偏做停健偿備储...</span><br><span class="line"></span><br><span class="line">🔧 开始压缩字体...</span><br><span class="line">   输入: /www/wwwroot/myblog/font-spider-work/fonts/BailuFeiYun.ttf</span><br><span class="line">   输出: /www/wwwroot/myblog/source/fonts/BailuFeiYun.woff2</span><br><span class="line"></span><br><span class="line">✅ 压缩完成!</span><br><span class="line">   原始大小: 10806.62 KB</span><br><span class="line">   WOFF2 大小: 712.62 KB (压缩率: 6.6%)</span><br><span class="line">   TTF 大小: 1321.61 KB (压缩率: 12.2%)</span><br><span class="line"></span><br><span class="line">🎉 全部完成!</span><br><span class="line">   压缩后的字体已输出到: /www/wwwroot/myblog/source/fonts</span><br></pre></td></tr></table></figure><h3 id="文件位置"><a href="#文件位置" class="headerlink" title="文件位置"></a>文件位置</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">/www/wwwroot/myblog/</span><br><span class="line">├── source/fonts/           # 输出压缩后的字体</span><br><span class="line">│   ├── BailuFeiYun.woff2</span><br><span class="line">│   └── BailuFeiYun.ttf</span><br><span class="line">├── font-spider-work/       # 工作目录</span><br><span class="line">│   ├── fonts/</span><br><span class="line">│   │   └── BailuFeiYun.ttf  # 原始字体</span><br><span class="line">│   └── chars-full.txt       # 提取的字符列表</span><br><span class="line">└── compress_font.py         # 本脚本</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Hexo/">Hexo</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/Hexo/">Hexo</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/02/13/%E5%AD%97%E4%BD%93%E7%9A%84%E5%BC%95%E5%85%A5%E4%B8%8E%E5%8E%8B%E7%BC%A9/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Twikoo私有化部署</title>
      <link>https://blog.mingliangstar.com/2026/02/08/Twikoo%E7%A7%81%E6%9C%89%E5%8C%96%E9%83%A8%E7%BD%B2/</link>
      <guid>https://blog.mingliangstar.com/2026/02/08/Twikoo%E7%A7%81%E6%9C%89%E5%8C%96%E9%83%A8%E7%BD%B2/</guid>
      <pubDate>Sun, 08 Feb 2026 10:25:41 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;对于使用 Hexo</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>对于使用 Hexo 搭建的静态博客而言，一个稳定、轻量的评论系统是连接读者的重要桥梁。Twikoo 作为目前最受欢迎的开源评论方案之一，除了官方提供的云开发版本外，私有化部署能让你获得完全的数据自主权——不再受限于免费额度，无需担心云厂商政策变动，还能通过自定义二级域名和 SSL 证书实现更专业、更稳定的访问体验。<br>本文将提供一份从零开始的实操指南，手把手教你通过 Docker 完成 Twikoo 的私有化部署。无论你是习惯命令行的开发者，还是偏好图形界面的宝塔用户，都能找到适合自己的部署方式。内容涵盖域名解析、容器配置、反向代理到证书申请的全流程，特别针对 AnZhiYu 等热门 Hexo 主题给出了详细的对接配置。跟随本文操作，你将拥有一个完全属于自己、独立运行的评论服务。</p><h2 id="准备：解析二级域名"><a href="#准备：解析二级域名" class="headerlink" title="准备：解析二级域名"></a>准备：解析二级域名</h2><p>建议为 Twikoo 单独分配一个二级域名（如 <code>twikoo.yourdomain.com</code>），便于后期维护和管理。</p><ul><li><strong>记录类型</strong>：A 记录</li><li><strong>主机记录</strong>：<code>twikoo</code>（或其他你喜欢的二级域名前缀）</li><li><strong>记录值</strong>：你的服务器 IP 地址</li></ul><blockquote><p><strong>提示</strong>：解析生效需要几分钟到几小时不等，可通过 <code>ping twikoo.yourdomain.com</code> 验证是否生效。</p></blockquote><p><img src="https://images.mingliangstar.com/images/20260208/image.avif"></p><h2 id="拉起Twikoo的容器"><a href="#拉起Twikoo的容器" class="headerlink" title="拉起Twikoo的容器"></a>拉起Twikoo的容器</h2><h3 id="方案一：Docker-命令行部署（推荐）"><a href="#方案一：Docker-命令行部署（推荐）" class="headerlink" title="方案一：Docker 命令行部署（推荐）"></a>方案一：Docker 命令行部署（推荐）</h3><p>适合熟悉 Linux 命令的开发者，轻量且可控。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name twikoo -e TWIKOO_THROTTLE=1000 -p 8181:8080 -v <span class="variable">$&#123;PWD&#125;</span>/data:/app/data -d imaegoo/twikoo</span><br></pre></td></tr></table></figure><p><img src="https://images.mingliangstar.com/images/20260208/image1.avif"></p><h3 id="方案二：宝塔面板部署（可视化）"><a href="#方案二：宝塔面板部署（可视化）" class="headerlink" title="方案二：宝塔面板部署（可视化）"></a>方案二：宝塔面板部署（可视化）</h3><p>适合不熟悉命令行或已安装宝塔面板的用户。</p><p><img src="https://images.mingliangstar.com/images/20260208/image2.avif"></p><h2 id="配置反向代理"><a href="#配置反向代理" class="headerlink" title="配置反向代理"></a>配置反向代理</h2><p>直接使用 IP:端口 访问既不优雅也不安全。通过 Nginx 反向代理，可以实现：</p><ul><li>使用域名访问（如 <code>twikoo.yourdomain.com</code>）</li><li>后续支持 HTTPS（SSL 证书）</li><li>隐藏真实端口，提高安全性</li></ul><p>Nginx 配置示例,在宝塔 “网站” → “反向代理” 中添加：</p><ul><li>目标 URL：<code>http://127.0.0.1:8181</code>（即你刚才映射的本地端口）</li><li>发送域名：$host</li></ul><blockquote><p>原理：所有访问 <code>twikoo.yourdomain.com</code> 的请求，都会被 Nginx 转发到本地的 8181 端口，由 Twikoo 容器处理。</p></blockquote><p><img src="https://images.mingliangstar.com/images/20260208/image3.avif"></p><h2 id="部署ssl证书"><a href="#部署ssl证书" class="headerlink" title="部署ssl证书"></a>部署ssl证书</h2><p>为保证数据传输安全，强烈建议配置 HTTPS。宝塔中操作如下：</p><ul><li>在刚才的反向代理站点中，点击 “SSL” 选项卡</li><li>选择 “Let’s Encrypt” 免费证书，或上传自己的证书</li><li>开启 “强制 HTTPS”</li></ul><p><img src="https://images.mingliangstar.com/images/20260208/imag4.avif"></p><p>最后再浏览器访问你的Twikoo的域名，以下输出代表Twikoo部署已经完成</p><p><img src="https://images.mingliangstar.com/images/20260208/image5.avif"></p><h2 id="开启评论功能"><a href="#开启评论功能" class="headerlink" title="开启评论功能"></a>开启评论功能</h2><p>下面可以参考安知鱼主题官方文档开启评论功能</p><p><a href="https://docs.anheyu.com/advanced/#%E8%AF%84%E8%AE%BA">安知鱼主题</a></p><p><img src="https://images.mingliangstar.com/images/20260208/image6.avif"></p><p><img src="https://images.mingliangstar.com/images/20260208/image7.avif"></p><p>到这里Twikoo就部署完成了,最后记得清除缓存和重新生成静态网站</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br></pre></td></tr></table></figure><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><p>Q：为什么选择私有化部署而非云开发？<br>A：云开发有免费额度限制（如腾讯云每日读取次数限制），私有化部署只要服务器不宕机就永久可用，数据完全自主可控。<br>Q：容器重启后数据会丢失吗？<br>A：不会。-v ${PWD}&#x2F;data:&#x2F;app&#x2F;data 已将数据持久化到宿主机，只要 data 文件夹在，重新运行容器数据依然保留。<br>Q：评论通知如何配置？<br>A：访问 Twikoo 管理后台（在评论区点击登录，输入管理员密码），在”设置”中配置 SMTP 邮箱或 webhook 推送。</p><p>至此，你拥有了一个完全独立的私有化评论系统！</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Hexo/">Hexo</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Hexo/Twikoo/">Twikoo</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/Hexo/">Hexo</category>
      
      <category domain="https://blog.mingliangstar.com/tags/Twikoo/">Twikoo</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/02/08/Twikoo%E7%A7%81%E6%9C%89%E5%8C%96%E9%83%A8%E7%BD%B2/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>PostgreSQL 16.3基于pg_basebackup实现异步流复制</title>
      <link>https://blog.mingliangstar.com/2026/01/29/PostgreSQL%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E9%85%8D%E7%BD%AE/</link>
      <guid>https://blog.mingliangstar.com/2026/01/29/PostgreSQL%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E9%85%8D%E7%BD%AE/</guid>
      <pubDate>Thu, 29 Jan 2026 06:45:05 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;本文主要介绍基于pg_basebackup实现主从复制（异步流复制）&lt;/p&gt;
&lt;p&gt;PostgreSQL安装的方法可以参考这篇文章，&lt;a</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>本文主要介绍基于pg_basebackup实现主从复制（异步流复制）</p><p>PostgreSQL安装的方法可以参考这篇文章，<a href="https://blog.csdn.net/weixin_72610956/article/details/136566988">PostgreSQL安装</a></p><hr><p>关于基本的配置就不作过多的介绍了，直接开始</p><h3 id="MASTER节点"><a href="#MASTER节点" class="headerlink" title="MASTER节点"></a>MASTER节点</h3><p>首先在master节点创建一个用于复制的用户rep 设置密码 123456，并授予rolcanlogin权限</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CREATE ROLE rep WITH REPLICATION LOGIN PASSWORD &#x27;123456&#x27;;</span><br></pre></td></tr></table></figure><p>接下来需要配置pg_hba.conf文件，配置完后记得重启PG</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/2.avif"></p><p>由于我们的SLAVE节点是一个DOCKER PG的容器，下面就需要使用pg_basebackup来备份MASTER 节点的数据目录用来启动SLAVE节点，先备份</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pg_basebackup -D /opt/pg_basebackup/ -h 172.17.0.2 -p 5432 -U rep -Fp -R -X s -P -v</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/3.avif"></p><h3 id="SLAVE节点"><a href="#SLAVE节点" class="headerlink" title="SLAVE节点"></a>SLAVE节点</h3><p>接下来在DOCKER的数据目录下创建一个SLAVE的本地映射文件用于启动SLAVE节点</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/4.avif"></p><p>接下来将MASTER节点中pg_basebackup备份的数据COPY到我们准备的本地映射centos9_pg目录下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker cp centos9:/opt/pg_basebackup /var/lib/docker/centos9_pg/</span><br></pre></td></tr></table></figure><p>然后启动SLAVE节点即可</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd --name pg.slave.16.3 -e POSTGRES_PASSWORD=123456 -v /var/lib/docker/centos9_pg:/var/lib/postgresql/data  07a4ee949b9e</span><br></pre></td></tr></table></figure><p>进入容器，看到从数据目录下多了一个<code>standby.signal</code>文件，这默认是一个空文件，其实是一个标识文件。<br>是因为上面备份的时候使用了<code>-R</code>参数，所以在同步的数据里，所以会在<code>postgresql.auto.conf</code>里配置上 <code>primary_conninfo</code>信息。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/5.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/6.avif"></p><h3 id="验证主从同步"><a href="#验证主从同步" class="headerlink" title="验证主从同步"></a>验证主从同步</h3><p>在MASTER节点上可以看到流复制的监控信息，其中 state &#x3D; streaming 表示流复制状态正常</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from pg_stat_replication;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/7.avif"></p><p>下面执行DML语句进行验证（验证的数据在备份之前就可以准备好）</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/8.avif"></p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>在配置的过程中如果遇到报错一定要去看下错误日志，错误日志中会记录详细信息</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/9.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20260129/10.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/PostgreSQL/">PostgreSQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/PostgreSQL/">PostgreSQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/01/29/PostgreSQL%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E9%85%8D%E7%BD%AE/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Debian 9 (Stretch)仓库无法使用</title>
      <link>https://blog.mingliangstar.com/2026/01/27/Debian-9-Stretch-%E4%BB%93%E5%BA%93%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8/</link>
      <guid>https://blog.mingliangstar.com/2026/01/27/Debian-9-Stretch-%E4%BB%93%E5%BA%93%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8/</guid>
      <pubDate>Tue, 27 Jan 2026 07:26:42 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;blockquote&gt;
&lt;p&gt;背景：用镜像拉起的mysql5.6.44的容器，os是Debian GNU&amp;#x2F;Linux 9</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><blockquote><p>背景：用镜像拉起的mysql5.6.44的容器，os是Debian GNU&#x2F;Linux 9 (stretch)</p></blockquote><p>这个错误表明系统仍在使用 Debian 9 (Stretch)，但该版本已于 2022年6月30日 结束生命周期（EOL），官方仓库已下线。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260127/1.avif"></p><p>解决方案</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"># 进入容器</span><br><span class="line">docker exec -it &lt;container_name&gt; bash</span><br><span class="line"></span><br><span class="line"># 导入 Debian 归档密钥</span><br><span class="line">apt-key adv --keyserver keyserver.ubuntu.com --recv-keys AA8E81B4331F7F50 112695A0E562B32A 04E7233B7D453EEC EF0F382A1A7B6500 648ACFD622F3D138 0E98404D386FA1D9</span><br><span class="line"></span><br><span class="line"># 修改 apt 源为归档镜像</span><br><span class="line">cat &gt; /etc/apt/sources.list &lt;&lt; &#x27;EOF&#x27;</span><br><span class="line">deb http://archive.debian.org/debian/ stretch main contrib non-free</span><br><span class="line">deb http://archive.debian.org/debian-security stretch/updates main contrib non-free</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"># 清理并更新（忽略有效期）</span><br><span class="line">rm -rf /etc/apt/sources.list.d/mysql.list</span><br><span class="line">apt-get clean</span><br><span class="line">apt-get update -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true || true</span><br><span class="line"></span><br><span class="line"># 允许未签名安装（应急）</span><br><span class="line">apt-get install -y --allow-unauthenticated &lt;package_name&gt;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260127/2.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/01/27/Debian-9-Stretch-%E4%BB%93%E5%BA%93%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL中常见的慢查询与优化</title>
      <link>https://blog.mingliangstar.com/2026/01/16/MySQL%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84%E6%85%A2%E6%9F%A5%E8%AF%A2%E4%B8%8E%E4%BC%98%E5%8C%96/</link>
      <guid>https://blog.mingliangstar.com/2026/01/16/MySQL%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84%E6%85%A2%E6%9F%A5%E8%AF%A2%E4%B8%8E%E4%BC%98%E5%8C%96/</guid>
      <pubDate>Fri, 16 Jan 2026 14:41:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;没有将等值条件列用做组合索引前缀&quot;&gt;&lt;a href=&quot;#没有将等值条件列用做组合索引前缀&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="没有将等值条件列用做组合索引前缀"><a href="#没有将等值条件列用做组合索引前缀" class="headerlink" title="没有将等值条件列用做组合索引前缀"></a>没有将等值条件列用做组合索引前缀</h2><p>如果查询语句的谓词条件是范围条件与等值条件，存在组合索引，那么当范围条件列作为索引前缀的时候，等值条件是无法被range optimizer用来生成引擎扫描range减少扫描行数的。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260116/1.avif"></p><h2 id="索引列类型和常量类型不一致"><a href="#索引列类型和常量类型不一致" class="headerlink" title="索引列类型和常量类型不一致"></a>索引列类型和常量类型不一致</h2><p>当索引列类型和常量类型不一致的时候，可能导致索引无法使用。例如下面的例子，列类型是varchar，而常量类型是Int。在MySQL中varchar类型和int类型比较是会将varchar转换为int类型去比较，这就导致下面语句需要扫描每一行数据将id转换为int类型再做比较。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260116/2.avif"></p><h2 id="关联字段类型不一致"><a href="#关联字段类型不一致" class="headerlink" title="关联字段类型不一致"></a>关联字段类型不一致</h2><p>对于JOIN操作，如果关联字段类型不一样，比如一个是Int，一个是varchar，由于比较类型是Int，那么varchar字段的关联索引就无法用来生成REF访问，减少扫描行数。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260116/3.avif"></p><h2 id="关联字段字符集不一致"><a href="#关联字段字符集不一致" class="headerlink" title="关联字段字符集不一致"></a>关联字段字符集不一致</h2><p>对于JOIN操作，如果关联字段的字符集不一致，这也会导致索引无法被有效利用，进而导致扫描大量数据，查询执行慢。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260116/4.avif"></p><h2 id="索引列上有表达式计算"><a href="#索引列上有表达式计算" class="headerlink" title="索引列上有表达式计算"></a>索引列上有表达式计算</h2><p>当谓词条件中，索引列上有表达式计算的时候，优化器会无法分析抽取range</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260116/5.avif"></p><h2 id="range-optimizer限制"><a href="#range-optimizer限制" class="headerlink" title="range optimizer限制"></a>range optimizer限制</h2><p>索引的扫描范围分析是由range optimizer处理，一些场景会触发range optimizer的限制。例如in list或者or的条件数太多，在分析扫描范围区间的时候，会消耗大量内存，导致超过range_optimizer_max_mem_size的大小，这类语句EXPLAIN后，在warnings信息中会有提示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">***************************[ 1. row ]***************************</span><br><span class="line">Level   | Warning</span><br><span class="line">Code    | 3170</span><br><span class="line">Message | Memory capacity of 5 bytes for &#x27;range_optimizer_max_mem_size&#x27; exceeded. Range optimization was not done for this query.</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260116/6.avif"></p><blockquote><p>在 MySQL 中，<code>range_optimizer_max_mem_size</code> 是一个系统变量，用于控制查询优化器在执行查询时可以使用的最大内存大小。这个参数影响查询优化器在处理范围查询（如 <code>BETWEEN</code>、<code>IN</code> 等）时的行为，特别是当这些查询涉及多个表和大量数据时。</p><h3 id="参数作用"><a href="#参数作用" class="headerlink" title="参数作用"></a>参数作用</h3><ul><li><strong>内存使用</strong>：<code>range_optimizer_max_mem_size</code> 指定了查询优化器在处理范围查询时可以使用的最大内存量。如果查询的内存需求超过了这个限制，优化器将尝试使用其他方法来处理查询，例如将范围查询转换为全表扫描。</li></ul><h3 id="参数值"><a href="#参数值" class="headerlink" title="参数值"></a>参数值</h3><ul><li><strong>默认值</strong>：默认值通常为 1MB（1024MB），这意味着查询优化器在处理范围查询时最多可以使用 1MB 的内存。</li><li><strong>调整</strong>：你可以根据服务器的内存大小和查询的复杂性来调整这个值。增加这个值可以让查询优化器在处理更复杂的范围查询时有更多的内存可用，但也可能增加内存消耗。</li></ul></blockquote><h2 id="Range-optimizer跳过index-dive"><a href="#Range-optimizer跳过index-dive" class="headerlink" title="Range optimizer跳过index dive"></a>Range optimizer跳过index dive</h2><p>对于索引范围，range optimizer会通过index dive来估算实际扫描行数。由于这会带来实际的数据访问，有一定的代价开销，优化器会限制index dive的场景。对于in list等值条件特别多的场景，当超过eq_range_index_dive_limit的阈值，优化器就不会做index dive，而是基于NDV统计信息去估算扫描行数。如果in list中有倾斜的数据，那么行数估算就会错误。</p><blockquote><h3 id="Index-Dive"><a href="#Index-Dive" class="headerlink" title="Index Dive"></a><strong>Index Dive</strong></h3><p><strong>总结</strong>：<strong>拿着每个 IN 值或区间边界去索引根页 → 二分定位 → 读取叶子页中的 记录条数（rec_per_key）。</strong></p><p>例如：</p><p>拿着一个 IN 值 → 找到它在索引里的 边界页假设表 t 有二级索引 idx(c1)，且当前 SQL 是</p><p>SELECT * FROM t WHERE c1 IN (17, 29, 53);</p><p>优化器拿到第一个值 17。</p><p>从 索引根页（root page） 开始二分：根页里存的是“子页的最小键值+页号”。<br>例：根页条目 [10→pageA, 20→pageB, 30→pageC]<br>17 落在 10<code>~</code>20 之间 → 指向 pageA。<br>继续二分直到 叶子页。pageA 不是叶子，再二分 → 找到 叶子页 L17，叶子页里才是真正按顺序排好序的 (c1, row_id) 记录。在叶子页里 统计 17 这个键值出现了多少条，叶子页内部也是有序的，二分即可找到第一条 17。顺序往后扫，直到键值 ≠ 17，统计行数 → 得到 rec_per_key(17)&#x3D;5 条。把这个行数累加到本次 range 的总扫描行数。对 29、53 重复 1~3 步，就能算出。<br>total_rows &#x3D; rec_per_key(17) + rec_per_key(29) + rec_per_key(53)。</p><h3 id="基于NDV统计信息去估算扫描行数"><a href="#基于NDV统计信息去估算扫描行数" class="headerlink" title="基于NDV统计信息去估算扫描行数"></a>基于NDV统计信息去估算扫描行数</h3><p><strong>总结：</strong><br>“基于 NDV 统计信息去估算扫描行数” 就是“用总行数 ÷ 列的不同值个数，再乘以查询涉及的不同值个数”</p><ol><li><strong>NDV</strong></li></ol><pre><code>Number of Distinct Values——某一列里 有多少个不同的取值。  例：列 status 只有 &#39;OK&#39;,&#39;FAIL&#39;,&#39;RUNNING&#39; 3 种值 ⇒ NDV = 3。</code></pre><ol start="2"><li><strong>统计信息</strong></li></ol><pre><code>MySQL 在执行 ANALYZE TABLE 后，会把</code></pre><ol start="3"><li>表总行数 rows</li><li>该列的 NDV存进 mysql.innodb_index_stats （或 mysql.column_stats 里，8.0 直方图更细）。因此 平均每值出现的行数 &#x3D; rows &#x2F; NDV。</li><li><strong>估算扫描行数</strong></li></ol><pre><code>当优化器放弃 “index dive” 时，就直接用上面的平均值乘以 查询里要用到的不同值个数。例子：</code></pre><p>如果数据倾斜（例如 c1&#x3D;1 其实有 8 万行，其余值只有 1 行），<br>估算 100 行 vs 实际 80 004 行，就会出现 <strong>“基于 NDV 的估算失真”</strong>。</p><ul><li>表 100 万行，列 c1 NDV &#x3D; 5 万 ⇒ 平均 20 行&#x2F;值。</li><li>SQL：WHERE c1 IN (1,2,3,4,5) （5 个值）。</li><li>估算行数 &#x3D; 20 × 5 &#x3D; 100 行。</li></ul></blockquote><hr><p>内容整合于 数据库内核月报 － 2024 &#x2F; 12</p><h2 id="MySQL查询优化分析-常见慢查问题与优化方法"><a href="#MySQL查询优化分析-常见慢查问题与优化方法" class="headerlink" title="MySQL查询优化分析 - 常见慢查问题与优化方法"></a>MySQL查询优化分析 - 常见慢查问题与优化方法</h2></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/01/16/MySQL%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84%E6%85%A2%E6%9F%A5%E8%AF%A2%E4%B8%8E%E4%BC%98%E5%8C%96/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>mysql&quot;黑名单&quot;</title>
      <link>https://blog.mingliangstar.com/2026/01/13/mysql-%E9%BB%91%E5%90%8D%E5%8D%95/</link>
      <guid>https://blog.mingliangstar.com/2026/01/13/mysql-%E9%BB%91%E5%90%8D%E5%8D%95/</guid>
      <pubDate>Tue, 13 Jan 2026 09:08:00 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>目的：使用iptables禁止121.43.122.130客户端连接140.143.94.243机器上部署的mysql</p><table><thead><tr><th>部署MySQL的机器</th><th>客户端</th></tr></thead><tbody><tr><td>140.143.94.243</td><td>121.43.122.130</td></tr></tbody></table><p>安装 iptables-services（若没装）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install -y iptables-services</span><br></pre></td></tr></table></figure><p>让 systemd 接管iptables</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl start  iptables</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260113/1.avif"></p><p>在部署MySQL机器上的filter表INPUT链里加一条DROP规则</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -I INPUT -s 121.43.122.130 -p tcp --dport 3306 -j DROP</span><br></pre></td></tr></table></figure><p>查看规则是否已插入</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -nvL</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260113/2.avif"></p><p>验证</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260113/3.avif"></p><p>这种情况下端口不通</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260113/4.avif"></p><p>删除规则</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -D INPUT -s 121.43.122.130 -p tcp --dport 3306 -j DROP</span><br></pre></td></tr></table></figure><p>针对这类iptables禁用后使用wireshark分析抓包情况，可以看到tcp一直再重传</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260113/5.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/01/13/mysql-%E9%BB%91%E5%90%8D%E5%8D%95/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL中的Got an error reading communication packet</title>
      <link>https://blog.mingliangstar.com/2026/01/10/MySQL%E4%B8%AD%E7%9A%84Got-an-error-reading-communication-packet/</link>
      <guid>https://blog.mingliangstar.com/2026/01/10/MySQL%E4%B8%AD%E7%9A%84Got-an-error-reading-communication-packet/</guid>
      <pubDate>Sat, 10 Jan 2026 14:54:56 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;我们经常在MySQL的error log中可以看到这样的[Note]，从官网的介绍来说，导致下述这种情况出现的原因，有下述几种&lt;/p&gt;
&lt;!-- 这是一张图片，ocr 内容为： --&gt;
&lt;p&gt;&lt;img</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>我们经常在MySQL的error log中可以看到这样的[Note]，从官网的介绍来说，导致下述这种情况出现的原因，有下述几种</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/1.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/2.avif"></p><p><a href="https://dev.mysql.com/doc/refman/8.0/en/communication-errors.html">https://dev.mysql.com/doc/refman/8.0/en/communication-errors.html</a></p><p>另外我们要清楚，Got an error reading communication packets：是客户端异常关闭之后DB才会被动打印的日志，不是DB主动关闭的。所以首要排查方向应该是应用侧，非db侧。如果是客户端超过wait_timeout不活动被DB主动关闭的话，应该打印的日志是：Got timeout reading communication packets</p><h2 id="场景分析"><a href="#场景分析" class="headerlink" title="场景分析"></a>场景分析</h2><p>客户端使用mycli和mysql分别去连接</p><h3 id="mycli"><a href="#mycli" class="headerlink" title="mycli"></a>mycli</h3><p>可以看到使用mycli连接后Aborted_clients 增加，并且错误日志中出现</p><p>[Note] [MY-010914] [Server] Aborted connection 9 to db: ‘unconnected’ user: ‘root’ host: ‘localhost’ (Got an error reading communication packets)</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/3.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/4.avif"></p><h3 id="mysql"><a href="#mysql" class="headerlink" title="mysql"></a>mysql</h3><p>而使用mysql连接后则没有这个问题</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/5.avif"></p><p>针对mycli连接时出现的这个情况进行了抓包分析，可以看到38行有个[FIN,ACK]的Flags，查看传输层的信息发现是客户端主动关闭了连接，This frame initiates the connection closing。查看39行，可以看到应用层返回了</p><p>Error message: Got an error reading communication packets，并且在40行可以看到RST的Flags，这里可能和mycli的客户端行为有关</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/6.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/7.avif"></p><p>而使用mysql连接时查看返回的抓包情况并没有RST的Flags</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260110/8.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/01/10/MySQL%E4%B8%AD%E7%9A%84Got-an-error-reading-communication-packet/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL【bug】- spatial key</title>
      <link>https://blog.mingliangstar.com/2026/01/09/MySQL%E3%80%90bug%E3%80%91-spatial-key/</link>
      <guid>https://blog.mingliangstar.com/2026/01/09/MySQL%E3%80%90bug%E3%80%91-spatial-key/</guid>
      <pubDate>Fri, 09 Jan 2026 11:38:47 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;【bug1】&quot;&gt;&lt;a href=&quot;#【bug1】&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="【bug1】"><a href="#【bug1】" class="headerlink" title="【bug1】"></a>【bug1】</h2><p>MySQL建<strong>Spatial</strong>索引的前提条件是列定义<strong>NOT NULL</strong>，而当<strong>location</strong>列中有**’GEOMETRYCOLLECTION EMPTY ‘<strong>的值时，这里</strong>‘GEOMETRYCOLLECTION EMPTY’**变相绕过了这个限制，会导致报错。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260109/1.avif"></p><p>插入空集合 <strong>GEOMETRYCOLLECTION EMPTY，<strong>空集合</strong>占一行空间</strong>，语义上“我知道这里该有几何，但当前没有数据”。</p><p>与 NULL 的区别</p><table><thead><tr><th>场景</th><th>存储值</th><th>ST_IsEmpty</th><th>ST_AsText</th></tr></thead><tbody><tr><td>NULL</td><td>无</td><td>NULL</td><td>NULL</td></tr><tr><td>GEOMETRYCOLLECTION EMPTY</td><td>有</td><td>1</td><td>GEOMETRYCOLLECTION EMPTY</td></tr></tbody></table><p>重建表也无法进行修复</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260109/2.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE `spatial_table` (</span><br><span class="line">  `id` int NOT NULL AUTO_INCREMENT,</span><br><span class="line">  `name` varchar(255) DEFAULT NULL,</span><br><span class="line">  `location` geometry NOT NULL SRID 4326,</span><br><span class="line">  `number` varchar(20) NOT NULL DEFAULT &#x27;7425346&#x27;,</span><br><span class="line">  PRIMARY KEY (`id`),</span><br><span class="line">  UNIQUE KEY `number` (`number`),</span><br><span class="line">  SPATIAL KEY `location_index` (`location`)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">INSERT INTO spatial_table (id, name, location, number)</span><br><span class="line">VALUES</span><br><span class="line">(1, &#x27;Place A&#x27;, ST_GeomFromText(&#x27;POINT(1 1)&#x27;, 4326), &#x27;7425341&#x27;),</span><br><span class="line">(2, &#x27;Place B&#x27;, ST_GeomFromText(&#x27;LINESTRING(1 1,2 2,3 3)&#x27;, 4326), &#x27;7425342&#x27;),</span><br><span class="line">(3, &#x27;Place C&#x27;, ST_GeomFromText(&#x27;POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))&#x27;, 4326), &#x27;7425343&#x27;),</span><br><span class="line">(4, &#x27;Place D&#x27;, ST_GeomFromText(&#x27;MULTIPOINT((0 0),(20 20),(60 60))&#x27;, 4326), &#x27;7425344&#x27;),</span><br><span class="line">(5, &#x27;Place E&#x27;, ST_GeomFromText(&#x27;GEOMETRYCOLLECTION(POINT(10 10),POINT(30 30),LINESTRING(15 15,20 20))&#x27;, 4326), &#x27;7425345&#x27;),</span><br><span class="line">(6, &#x27;Place F&#x27;, ST_GeomFromText(&#x27;GEOMETRYCOLLECTION(POINT(10 10),POINT(30 30),LINESTRING(15 15,20 20))&#x27;, 4326), &#x27;7425348&#x27;),</span><br><span class="line">(7, &#x27;Beijing&#x27;, ST_GeomFromText(&#x27;POINT(39.9042 116.4074)&#x27;, 4326), &#x27;7425347&#x27;),</span><br><span class="line">(8, &#x27;&lt;null&gt;&#x27;, ST_GeomFromText(&#x27;GEOMETRYCOLLECTION EMPTY&#x27;, 4326), &#x27;7425346&#x27;);  </span><br><span class="line"></span><br><span class="line">SELECT id,name,st_astext(location),number From spatial_table;</span><br></pre></td></tr></table></figure><p><strong><font style="color:#fe2c24;">解决方法：删除这些行并重建表</font></strong></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260109/3.avif"></p><h2 id="【bug2】"><a href="#【bug2】" class="headerlink" title="【bug2】"></a>【bug2】</h2><p>先对含** SPATIAL KEY** 的表做过 <strong>ALTER TABLE → R-tree <strong>根页指针错乱，后续</strong> UPDATE&#x2F;DELETE</strong>走空间索引时找不到记录 → 报** Record in index … not found**。在<strong>MySQL Server 5.7.49</strong>、<strong>8.0.41</strong>、<strong>8.4.4</strong>和<strong>9.2.0</strong>版本中修复。</p><p>官方文档：<a href="https://bugs.mysql.com/bug.php?id=93728">https://bugs.mysql.com/bug.php?id=93728</a></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260109/4.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260109/5.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE tab (</span><br><span class="line">  c1 INT NOT NULL PRIMARY KEY,</span><br><span class="line">  c2 POINT NOT NULL SRID 4326,</span><br><span class="line">  c3 LINESTRING NOT NULL SRID 4326,</span><br><span class="line">  c4 POLYGON NOT NULL SRID 4326,</span><br><span class="line">  c5 GEOMETRY NOT NULL SRID 4326,</span><br><span class="line">  SPATIAL KEY idx2 (c2),</span><br><span class="line">  SPATIAL KEY idx3 (c3),</span><br><span class="line">  SPATIAL KEY idx4 (c4),</span><br><span class="line">  SPATIAL KEY idx5 (c5)</span><br><span class="line">) ENGINE = InnoDB;</span><br><span class="line"></span><br><span class="line">INSERT INTO tab(c1,c2,c3,c4,c5) VALUES</span><br><span class="line">(1,</span><br><span class="line"> ST_GeomFromText(&#x27;POINT(10 10)&#x27;, 4326),</span><br><span class="line"> ST_GeomFromText(&#x27;LINESTRING(5 5,20 20,30 30)&#x27;, 4326),</span><br><span class="line"> ST_GeomFromText(&#x27;POLYGON((30 30,40 40,50 50,30 50,30 40,30 30))&#x27;, 4326),</span><br><span class="line"> ST_GeomFromText(&#x27;POLYGON((30 30,40 40,50 50,30 50,30 40,30 30))&#x27;, 4326));</span><br><span class="line"></span><br><span class="line">INSERT INTO tab(c1,c2,c3,c4,c5) VALUES</span><br><span class="line">(2,</span><br><span class="line"> ST_GeomFromText(&#x27;POINT(20 20)&#x27;, 4326),</span><br><span class="line"> ST_GeomFromText(&#x27;LINESTRING(20 20,30 30,40 40)&#x27;, 4326),</span><br><span class="line"> ST_GeomFromText(&#x27;POLYGON((40 50,40 70,50 100,70 100,80 80,70 50,40 50))&#x27;, 4326),</span><br><span class="line"> ST_GeomFromText(&#x27;POLYGON((40 50,40 70,50 100,70 100,80 80,70 50,40 50))&#x27;, 4326));</span><br><span class="line"></span><br><span class="line">ALTER TABLE tab</span><br><span class="line">  ADD COLUMN new_uniq_col INT NOT NULL AUTO_INCREMENT FIRST,</span><br><span class="line">  ADD UNIQUE INDEX uniq_idx(new_uniq_col),</span><br><span class="line">  DROP PRIMARY KEY;</span><br><span class="line"></span><br><span class="line">DELETE From tab;</span><br></pre></td></tr></table></figure><p>解决方法：</p><ul><li>升级版本</li><li>重建表再重新导入数据</li></ul><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260109/6.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/01/09/MySQL%E3%80%90bug%E3%80%91-spatial-key/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>py_innodb_page_info.py表空间分析</title>
      <link>https://blog.mingliangstar.com/2026/01/04/py-innodb-page-info-py%E8%A1%A8%E7%A9%BA%E9%97%B4%E5%88%86%E6%9E%90/</link>
      <guid>https://blog.mingliangstar.com/2026/01/04/py-innodb-page-info-py%E8%A1%A8%E7%A9%BA%E9%97%B4%E5%88%86%E6%9E%90/</guid>
      <pubDate>Sun, 04 Jan 2026 09:07:59 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;由《MySQL技术内幕 InnoDB存储引擎》一书的作者姜承尧开发的</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>由《MySQL技术内幕 InnoDB存储引擎》一书的作者姜承尧开发的 <code>py_innodb_page_info.py</code> 是一款功能强大的工具，旨在深入分析MySQL表空间中的页面类型及其详细信息。该工具采用Python编写，由三个文件组成：<code>py_innodb_page_info.py</code>、<code>mylib.py</code> 和 <code>include.py</code>。为了确保工具的正常运行，这三个文件需要放置在同一个目录下。</p><p>值得注意的是，该工具需要在Python 2的环境中运行。如果在Python 3环境下使用，可能会遇到兼容性问题，导致运行出错。此外，<code>py_innodb_page_info.py</code> 工具专门设计用于解析MySQL 5.7版本的<code>.ibd</code>文件。对于MySQL 8.0及更高版本的<code>.ibd</code>文件，该工具可能无法正确解析。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/1.avif"></p><h2 id="include-py"><a href="#include-py" class="headerlink" title="include.py"></a>include.py</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">#include.py</span><br><span class="line">#encoding=utf-8</span><br><span class="line">INNODB_PAGE_SIZE = 1024 * 16 # InnoDB Page 16K</span><br><span class="line"></span><br><span class="line"># Start of the data on the page</span><br><span class="line">FIL_PAGE_DATA = 38</span><br><span class="line"></span><br><span class="line">FIL_PAGE_OFFSET = 4 # page offset inside space</span><br><span class="line">FIL_PAGE_TYPE = 24 # File page type</span><br><span class="line"></span><br><span class="line"># Types of an undo log segment */</span><br><span class="line">TRX_UNDO_INSERT = 1</span><br><span class="line">TRX_UNDO_UPDATE = 2</span><br><span class="line"></span><br><span class="line"># On a page of any file segment, data may be put starting from this offset</span><br><span class="line">FSEG_PAGE_DATA = FIL_PAGE_DATA</span><br><span class="line"></span><br><span class="line"># The offset of the undo log page header on pages of the undo log</span><br><span class="line">TRX_UNDO_PAGE_HDR = FSEG_PAGE_DATA</span><br><span class="line"></span><br><span class="line">PAGE_LEVEL = 26 #level of the node in an index tree; the leaf level is the level 0 */</span><br><span class="line"></span><br><span class="line">innodb_page_type = &#123;</span><br><span class="line">        &#x27;0000&#x27;:u&#x27;Freshly Allocated Page&#x27;,</span><br><span class="line">        &#x27;0002&#x27;:u&#x27;Undo Log Page&#x27;,</span><br><span class="line">        &#x27;0003&#x27;:u&#x27;File Segment inode&#x27;,</span><br><span class="line">        &#x27;0004&#x27;:u&#x27;Insert Buffer Free List&#x27;,</span><br><span class="line">        &#x27;0005&#x27;:u&#x27;Insert Buffer Bitmap&#x27;,</span><br><span class="line">        &#x27;0006&#x27;:u&#x27;System Page&#x27;,</span><br><span class="line">        &#x27;0007&#x27;:u&#x27;Transaction system Page&#x27;,</span><br><span class="line">        &#x27;0008&#x27;:u&#x27;File Space Header&#x27;,</span><br><span class="line">    &#x27;0009&#x27;:u&#x27;Extend Description Page&#x27;,</span><br><span class="line">    &#x27;000a&#x27;:u&#x27;Uncompressed BLOB Page&#x27;,</span><br><span class="line">    &#x27;000b&#x27;:u&#x27;1st compressed BLOB Page&#x27;,</span><br><span class="line">    &#x27;000c&#x27;:u&#x27;Subsequent compressed BLOB Page&#x27;,</span><br><span class="line">    &#x27;45bf&#x27;:u&#x27;B-tree Node&#x27;</span><br><span class="line">&#125;</span><br><span class="line">innodb_page_direction = &#123;</span><br><span class="line">        &#x27;0000&#x27;: &#x27;Unknown(0x0000)&#x27;,</span><br><span class="line">    &#x27;0001&#x27;: &#x27;Page Left&#x27;,</span><br><span class="line">    &#x27;0002&#x27;: &#x27;Page Right&#x27;,</span><br><span class="line">    &#x27;0003&#x27;: &#x27;Page Same Rec&#x27;,</span><br><span class="line">    &#x27;0004&#x27;: &#x27;Page Same Page&#x27;,</span><br><span class="line">    &#x27;0005&#x27;: &#x27;Page No Direction&#x27;,</span><br><span class="line">    &#x27;ffff&#x27;: &#x27;Unkown2(0xffff)&#x27;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="mylib-py"><a href="#mylib-py" class="headerlink" title="mylib.py"></a>mylib.py</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line">#encoding=utf-8</span><br><span class="line">import os</span><br><span class="line">import include</span><br><span class="line">from include import *</span><br><span class="line"></span><br><span class="line">VARIABLE_FIELD_COUNT = 1</span><br><span class="line">NULL_FIELD_COUNT = 0</span><br><span class="line"></span><br><span class="line">class myargv(object):</span><br><span class="line">    def __init__(self, argv):</span><br><span class="line">        self.argv = argv</span><br><span class="line">        self.parms = &#123;&#125;</span><br><span class="line">        self.tablespace = &#x27;&#x27;</span><br><span class="line"></span><br><span class="line">    # 解析输入参数</span><br><span class="line">    def parse_cmdline(self):</span><br><span class="line">        argv = self.argv</span><br><span class="line">        if len(argv) == 1:</span><br><span class="line">            print &#x27;Usage: python py_innodb_page_info.py [OPTIONS] tablespace_file&#x27;</span><br><span class="line">            print &#x27;For more options, use python py_innodb_page_info.py -h&#x27;</span><br><span class="line">            return 0</span><br><span class="line">        while argv:</span><br><span class="line">            if argv[0][0] == &#x27;-&#x27;:</span><br><span class="line">                if argv[0][1] == &#x27;h&#x27;:</span><br><span class="line">                    self.parms[argv[0]] = &#x27;&#x27;</span><br><span class="line">                    argv = argv[1:]</span><br><span class="line">                    break</span><br><span class="line">                if argv[0][1] == &#x27;v&#x27;:</span><br><span class="line">                    self.parms[argv[0]] = &#x27;&#x27;</span><br><span class="line">                    argv = argv[1:]</span><br><span class="line">                else:</span><br><span class="line">                    self.parms[argv[0]] = argv[1]</span><br><span class="line">                    argv = argv[2:]</span><br><span class="line">            else:</span><br><span class="line">                self.tablespace = argv[0]</span><br><span class="line">                argv = argv[1:]</span><br><span class="line">        if self.parms.has_key(&#x27;-h&#x27;):</span><br><span class="line">            print &#x27;Get InnoDB Page Info&#x27;</span><br><span class="line">            print &#x27;Usage: python py_innodb_page_info.py [OPTIONS] tablespace_file\n&#x27;</span><br><span class="line">            print &#x27;The following options may be given as the first argument:&#x27;</span><br><span class="line">            print &#x27;-h   help &#x27;</span><br><span class="line">            print &#x27;-o output put the result to file&#x27;</span><br><span class="line">            print &#x27;-t number thread to anayle the tablespace file&#x27;</span><br><span class="line">            print &#x27;-v   verbose mode&#x27;</span><br><span class="line">            return 0</span><br><span class="line">        return 1</span><br><span class="line"></span><br><span class="line">def mach_read_from_n(page,start_offset,length):</span><br><span class="line">    ret = page[start_offset:start_offset+length]</span><br><span class="line">    return ret.encode(&#x27;hex&#x27;)</span><br><span class="line"></span><br><span class="line"># main方法</span><br><span class="line">def get_innodb_page_type(myargv):</span><br><span class="line">        # 读取 .ibd 文件，存入 f</span><br><span class="line">    f=file(myargv.tablespace,&#x27;rb&#x27;)</span><br><span class="line">    # INNODB_PAGE_SIZE=16KB，f 一定是16KB的整数倍，一页大小是16KB</span><br><span class="line">    # 使用 f 的字节总数除以 16KB，得到的 fsize 表示页数</span><br><span class="line">    fsize = os.path.getsize(f.name)/INNODB_PAGE_SIZE</span><br><span class="line">    ret = &#123;&#125;</span><br><span class="line">    # 枚举每一页</span><br><span class="line">    for i in range(fsize):</span><br><span class="line">        # 读取16KB数据，存入page，是第i的数据</span><br><span class="line">        # page 是二进制文件</span><br><span class="line">        page = f.read(INNODB_PAGE_SIZE)</span><br><span class="line">        # page_offset 是 page[4， 8) 字符所表示的数据</span><br><span class="line">        page_offset = mach_read_from_n(page,FIL_PAGE_OFFSET,4)</span><br><span class="line">        # page_type 是 page[24, 26) 字符所表示的数据</span><br><span class="line">        page_type = mach_read_from_n(page,FIL_PAGE_TYPE,2)</span><br><span class="line">        # 如果加了参数 -v，表示输出详细数据</span><br><span class="line">        if myargv.parms.has_key(&#x27;-v&#x27;):</span><br><span class="line">                # page_type 为 45bf，表示 B-tree Node，输出它的信息</span><br><span class="line">            if page_type == &#x27;45bf&#x27;:</span><br><span class="line">                # page_level 是 page[64, 66) 字符所表示的数据</span><br><span class="line">                page_level = mach_read_from_n(page,FIL_PAGE_DATA+PAGE_LEVEL,2)</span><br><span class="line">                print &quot;page offset %s, page type &lt;%s&gt;, page level &lt;%s&gt;&quot;%(page_offset,innodb_page_type[page_type],page_level)</span><br><span class="line">            # page_type 对应 include.py 中的 innodb_page_type，输出它的信息</span><br><span class="line">            else:</span><br><span class="line">                print &quot;page offset %s, page type &lt;%s&gt;&quot;%(page_offset,innodb_page_type[page_type])</span><br><span class="line">        # 统计数据</span><br><span class="line">        if not ret.has_key(page_type):</span><br><span class="line">            ret[page_type] = 1</span><br><span class="line">        else:</span><br><span class="line">            ret[page_type] = ret[page_type] + 1</span><br><span class="line">    # 输出fsize，表示有多少页</span><br><span class="line">    print &quot;Total number of page: %d:&quot;%fsize</span><br><span class="line">    # 输出统计数据</span><br><span class="line">    for type in ret:</span><br><span class="line">        print &quot;%s: %s&quot;%(innodb_page_type[type],ret[type])</span><br></pre></td></tr></table></figure><h2 id="py-innodb-page-info-py"><a href="#py-innodb-page-info-py" class="headerlink" title="py_innodb_page_info.py"></a>py_innodb_page_info.py</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">#! /usr/bin/env python</span><br><span class="line">#encoding=utf-8</span><br><span class="line">import mylib</span><br><span class="line">from sys import argv</span><br><span class="line">from mylib import myargv</span><br><span class="line"></span><br><span class="line"># main函数</span><br><span class="line">if __name__ == &#x27;__main__&#x27;:</span><br><span class="line">        myargv = myargv(argv)</span><br><span class="line">        if myargv.parse_cmdline() == 0:</span><br><span class="line">                pass</span><br><span class="line">        else:</span><br><span class="line">                # 执行main方法</span><br><span class="line">                mylib.get_innodb_page_type(myargv)</span><br></pre></td></tr></table></figure><h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><p>先创建个example_table空表，看下example_table.ibd，可以看到总共分配了11page（Total number of page: 11），但是为啥空闲的只有6page（B-tree Node: 6），这里就不得不提到之前说到的预留空间了</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/2.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE example_table(</span><br><span class="line">    id INT AUTO_INCREMENT,</span><br><span class="line">    first_name VARCHAR(50),</span><br><span class="line">    last_name VARCHAR(50),</span><br><span class="line">    email VARCHAR(100),</span><br><span class="line">    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">    status ENUM(&#x27;active&#x27;, &#x27;inactive&#x27;) DEFAULT &#x27;active&#x27;,</span><br><span class="line">    PRIMARY KEY (id),</span><br><span class="line">    INDEX idx_last_name (last_name),</span><br><span class="line">    FULLTEXT INDEX ftx_first_name (first_name),</span><br><span class="line">    INDEX idx_status (status),</span><br><span class="line">    INDEX idx_created_at (created_at),</span><br><span class="line">    INDEX idx_first_name_last_name (first_name, last_name)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python2 py_innodb_page_info.py -v demo1/example_table.ibd</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/3.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">page offset 00000000, page type &lt;File Space Header&gt;</span><br><span class="line">page offset 00000001, page type &lt;Insert Buffer Bitmap&gt;</span><br><span class="line">page offset 00000002, page type &lt;File Segment inode&gt;</span><br><span class="line">page offset 00000003, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;  //数据页，0001表示根层，0000表示叶子层</span><br><span class="line">page offset 00000004, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 00000005, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 00000006, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 00000007, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 00000008, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 00000000, page type &lt;Freshly Allocated Page&gt;</span><br><span class="line">page offset 00000000, page type &lt;Freshly Allocated Page&gt;</span><br><span class="line">Total number of page: 11://总共分配的页数</span><br><span class="line">Freshly Allocated Page: 2//可用的数据页</span><br><span class="line">Insert Buffer Bitmap: 1//插入缓冲页</span><br><span class="line">File Space Header: 1//文件空间头</span><br><span class="line">B-tree Node: 6//数据页</span><br><span class="line">File Segment inode: 1//文件端inonde</span><br></pre></td></tr></table></figure><p>然后再使用存储过程插入1W行数据，再分析example_table.ibd</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">DELIMITER $$</span><br><span class="line"></span><br><span class="line">CREATE PROCEDURE InsertExampleData()</span><br><span class="line">BEGIN</span><br><span class="line">    DECLARE i INT DEFAULT 1;</span><br><span class="line">    DECLARE maxEmail INT DEFAULT 1000;</span><br><span class="line">    DECLARE firstName VARCHAR(50);</span><br><span class="line">    DECLARE lastName VARCHAR(50);</span><br><span class="line">    DECLARE email VARCHAR(100);</span><br><span class="line">    DECLARE status ENUM(&#x27;active&#x27;, &#x27;inactive&#x27;);</span><br><span class="line">    DECLARE timestamp DATETIME;</span><br><span class="line"></span><br><span class="line">    WHILE i &lt;= 10000 DO</span><br><span class="line">        SET firstName = CONCAT(&#x27;Name&#x27;, LPAD(i, 5, &#x27;0&#x27;));</span><br><span class="line">        SET lastName = CONCAT(&#x27;Surname&#x27;, LPAD(i, 5, &#x27;0&#x27;));</span><br><span class="line">        SET email = CONCAT(firstName, &#x27;_&#x27;, lastName, &#x27;_&#x27;, i, &#x27;@example.com&#x27;);</span><br><span class="line">        SET status = IF(i % 2 = 0, &#x27;active&#x27;, &#x27;inactive&#x27;);</span><br><span class="line">        SET timestamp = DATE_ADD(NOW(), INTERVAL FLOOR(RAND() * 365) DAY);</span><br><span class="line"></span><br><span class="line">        INSERT INTO example_table (first_name, last_name, email, created_at, status)</span><br><span class="line">        VALUES (firstName, lastName, email, timestamp, status);</span><br><span class="line"></span><br><span class="line">        SET i = i + 1;</span><br><span class="line">    END WHILE;</span><br><span class="line">END$$</span><br><span class="line"></span><br><span class="line">DELIMITER ;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CALL InsertExampleData();</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/4.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">page offset 00000000, page type &lt;File Space Header&gt;</span><br><span class="line">page offset 00000001, page type &lt;Insert Buffer Bitmap&gt;</span><br><span class="line">page offset 00000002, page type &lt;File Segment inode&gt;</span><br><span class="line">page offset 00000003, page type &lt;B-tree Node&gt;, page level &lt;0001&gt;</span><br><span class="line">page offset 00000004, page type &lt;B-tree Node&gt;, page level &lt;0001&gt;</span><br><span class="line">page offset 00000005, page type &lt;B-tree Node&gt;, page level &lt;0001&gt;</span><br><span class="line">page offset 00000006, page type &lt;B-tree Node&gt;, page level &lt;0001&gt;</span><br><span class="line">page offset 00000007, page type &lt;B-tree Node&gt;, page level &lt;0001&gt;</span><br><span class="line">page offset 00000008, page type &lt;B-tree Node&gt;, page level &lt;0001&gt;</span><br><span class="line">page offset 00000009, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 0000000a, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 0000000b, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 0000000c, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 0000000d, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 0000000e, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 0000000f, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line">page offset 00000010, page type &lt;B-tree Node&gt;, page level &lt;0000&gt;</span><br><span class="line"></span><br><span class="line">....</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">page offset 00000000, page type &lt;Freshly Allocated Page&gt;</span><br><span class="line">page offset 00000000, page type &lt;Freshly Allocated Page&gt;</span><br><span class="line">page offset 00000000, page type &lt;Freshly Allocated Page&gt;</span><br><span class="line">page offset 00000000, page type &lt;Freshly Allocated Page&gt;</span><br><span class="line">page offset 00000000, page type &lt;Freshly Allocated Page&gt;</span><br><span class="line">Total number of page: 640://总共分配的页数</span><br><span class="line">Freshly Allocated Page: 493//可用的数据页</span><br><span class="line">Insert Buffer Bitmap: 1//插入缓冲页</span><br><span class="line">File Space Header: 1//文件空间头</span><br><span class="line">B-tree Node: 144//数据页</span><br><span class="line">File Segment inode: 1//文件端inonde</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/5.avif"></p><p>这时可以看到总共分配640页（Total number of page）即10240kb，使用了144页（B-tree Node）即2304kb，可用的数据页493页（Freshly Allocated Page）即7888kb</p><p>同时去看information_schema.tables中example_table的信息，可以看到DATA_LENGTH+INDEX_LENGTH&#x3D;1589248byte+1261568byte&#x3D;2850816byte&#x3D;2784kb，DATA_FREE&#x3D;4194304byte&#x3D;4096kb，</p><p>DATA_LENGTH+INDEX_LENGTH+DATA_FREE&#x3D;6880kb 10240-6880&#x3D;3360kb</p><p>Insert Buffer Bitmap+File Space Header+File Segment inode&#x3D;48kb</p><p>那这里为什么6880kb（ DATA_LENGTH+INDEX_LENGTH+DATA_FREE）要远远小于10240kb（Total number of page），这是除了之前提到的预留空间还有碎片率吗？</p><p>ok，我们带着这个问题去分析。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from information_schema.tables where table_schema=&#x27;demo1&#x27; and table_name=&#x27;example_table&#x27;\G</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/6.avif"></p><p>这里我们计算下空间碎片率Space Debris Rate&#x3D;(70451204194304)×100≈59.53%</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">SELECT  </span><br><span class="line">  table_name,</span><br><span class="line">  table_rows,</span><br><span class="line">  ROUND(data_length / (1024 * 1024 * 1024), 2) AS data_length_gb,</span><br><span class="line">  ROUND(index_length / (1024 * 1024 * 1024), 2) AS index_length_gb,</span><br><span class="line">  data_free,</span><br><span class="line">  CASE </span><br><span class="line">    WHEN (data_length + index_length + data_free) &gt; 0 THEN </span><br><span class="line">      ROUND(data_free / (data_length + index_length + data_free) * 100, 2) </span><br><span class="line">    ELSE </span><br><span class="line">      0 </span><br><span class="line">  END AS space_debris_rate</span><br><span class="line">FROM information_schema.tables </span><br><span class="line">WHERE table_schema = &#x27;demo1&#x27; AND table_name = &#x27;example_table&#x27;;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/7.avif"></p><p>这里我们将example_table的数据全部删除然后analyze table example_table; ，再查看information_schema.tables的统计信息，然后执行optimize table demo1.example_table; ，再去分析。最后可以看到DATA_LENGTH+INDEX_LENGTH+DATA_FREE&#x3D;16384+ 81920+0&#x3D;96kb&#x3D;6page&#x3D;B-tree Node</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/8.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/9.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/10.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20260104/11.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2026/01/04/py-innodb-page-info-py%E8%A1%A8%E7%A9%BA%E9%97%B4%E5%88%86%E6%9E%90/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Error response from daemon: driver failed programming external connectivity on endpoint</title>
      <link>https://blog.mingliangstar.com/2025/12/31/Error-response-from-daemon-driver-failed-programming-external-connectivity-on-endpoint/</link>
      <guid>https://blog.mingliangstar.com/2025/12/31/Error-response-from-daemon-driver-failed-programming-external-connectivity-on-endpoint/</guid>
      <pubDate>Wed, 31 Dec 2025 03:30:19 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h1 id=&quot;error-log&quot;&gt;&lt;a href=&quot;#error-log&quot; class=&quot;headerlink&quot; title=&quot;error log&quot;&gt;&lt;/a&gt;error</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h1 id="error-log"><a href="#error-log" class="headerlink" title="error log"></a>error log</h1><p>从报错日志来看是iptables的转发规则有问题</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20251231/1.avif"></p><p>docker logs centos9查看容器日志，没看出什么异常</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20251231/2.avif"></p><p>CSDN文章参考</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20251231/3.avif"></p><p>看了上述文章之后，想起来昨天在配置k8s的时候关闭了firewalld。嗯，然后把docker服务重启，最后在启动容器果然没有报错了</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20251231/4.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/12/31/Error-response-from-daemon-driver-failed-programming-external-connectivity-on-endpoint/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>PostgreSQL YUM安装</title>
      <link>https://blog.mingliangstar.com/2025/12/12/PostgreSQL-YUM%E5%AE%89%E8%A3%85/</link>
      <guid>https://blog.mingliangstar.com/2025/12/12/PostgreSQL-YUM%E5%AE%89%E8%A3%85/</guid>
      <pubDate>Fri, 12 Dec 2025 03:34:56 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h1 id=&quot;配置环境&quot;&gt;&lt;a href=&quot;#配置环境&quot; class=&quot;headerlink&quot; title=&quot;配置环境&quot;&gt;&lt;/a&gt;配置环境&lt;/h1&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h1 id="配置环境"><a href="#配置环境" class="headerlink" title="配置环境"></a>配置环境</h1><table><thead><tr><th align="center">Linux</th><th align="center">PostgreSQL</th><th align="center">Docker</th></tr></thead><tbody><tr><td align="center">centos7</td><td align="center">15</td><td align="center">24.0.7</td></tr></tbody></table><h1 id="docker中的centos7中安装"><a href="#docker中的centos7中安装" class="headerlink" title="docker中的centos7中安装"></a>docker中的centos7中安装</h1><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/1.avif"></p><p>选择对应的版本然后在容器中的centos7中执行下面命令</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/2.avif"></p><p>但是启动容器的时候需要注意</p><ol><li>开启端口映射</li><li>开启特权模式</li><li>启动init进程</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd --name centos-postgresql -p 5433:5432 --privileged=true centos:centos7 /usr/sbin/init</span><br></pre></td></tr></table></figure><p>启动然后进入后先安装ibzstd.so.1依赖</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">yum install epel-release.noarch -y</span><br><span class="line">yum install libzstd.x86_64 -y</span><br></pre></td></tr></table></figure><h1 id="安装PosqtgreSQL"><a href="#安装PosqtgreSQL" class="headerlink" title="安装PosqtgreSQL"></a>安装PosqtgreSQL</h1><p>官网安装教程：<a href="https://www.postgresql.org/download/linux/redhat/">https://www.postgresql.org/download/linux/redhat/</a></p><p>安装完依赖后就可以按下面的顺序执行命令</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/3.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm</span><br><span class="line">yum install -y postgresql15-server</span><br><span class="line">/usr/pgsql-15/bin/postgresql-15-setup initdb</span><br><span class="line">systemctl enable postgresql-15</span><br><span class="line">systemctl start postgresql-15</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/4.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/5.avif"></p><p>执行完成后就可以切换用户登陆postgresql了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#切换用户</span><br><span class="line">su - postgres</span><br><span class="line">#登陆数据库</span><br><span class="line">psql</span><br></pre></td></tr></table></figure><p>接下来配置数据库访问控制文件，主要是配置postgresql.conf 和 pg_hba.conf 个。</p><ol><li>postgresql.conf 针对实例的配置</li><li>pg_hba.conf 针对数据库访问的控制</li></ol><p>切换到&#x2F;var&#x2F;lib&#x2F;pgsql&#x2F;15&#x2F;data目录下</p><p>注意：这里&#x2F;var&#x2F;lib&#x2F;pgsql&#x2F;15&#x2F;data的15要根据自己安装的版本来确定</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/6.avif"></p><p>配置postgresql.conf</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim postgresql.conf</span><br></pre></td></tr></table></figure><p>找到”#port”和”#listener_address”这两个参数，这两个参数是相邻的，将两行行首的”#”删除。<br>将”listen_addressee&#x3D;’localhost’”改为当前服务器的IP，如果改为</p><p>“listen_addressee&#x3D;’*’”，将监听整个网络。<br>默认的监听端口是5432，可以自行指定另外一个端口号。<br>max_connections是客户端最大的连接数， 缺省值100有点少，特别是业务系统，可以调整成1000或者更高。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/7.avif"></p><p>配置pg_hba.conf</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim pg_hba.conf</span><br></pre></td></tr></table></figure><p>将红框设置为 10.10.100.0&#x2F;24，意思是10.10.100网段的IP 连接此服务器上的PostgreSQL. 如果想允许所有IP都可以连接此服务器，则可以配置成0.0.0.0&#x2F;0，但这样是不安全的，可以把trust改为md5，表示需要密码访问，算是提供一个最低级的安全防护。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/8.avif"></p><p>配置完这俩个文件后就可以重启数据库了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl restart postgresql-15</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/9.avif"></p><p>记得关闭防火墙</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop firewalld</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/10.avif"></p><p>测试连接</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/11.avif"></p><h1 id="docker中直接安装"><a href="#docker中直接安装" class="headerlink" title="docker中直接安装"></a>docker中直接安装</h1><p>拉取postgresql镜像后直接启动容器</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#拉去镜像</span><br><span class="line">docker search postgres</span><br><span class="line">#启动容器</span><br><span class="line">docker run -itd --name postgresql -e POSTGRES_PASSWORD=数据库密码 -p 5555:5432 postgres</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/12.avif"></p><p>测试连接成功</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251212/13.avif"></p><p>注意事项：</p><ul><li>两个centos7中的防火墙记得都要放行端口或者关闭</li><li>postgresql.conf 和 pg_hba.conf文件记得配置</li></ul></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/PostgreSQL/">PostgreSQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/PostgreSQL/">PostgreSQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/12/12/PostgreSQL-YUM%E5%AE%89%E8%A3%85/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>从Miniflux 到 NextFlux：一步升级，拥抱现代化阅读体验</title>
      <link>https://blog.mingliangstar.com/2025/12/11/MiniFlux%E5%8D%87%E7%BA%A7NextFlux/</link>
      <guid>https://blog.mingliangstar.com/2025/12/11/MiniFlux%E5%8D%87%E7%BA%A7NextFlux/</guid>
      <pubDate>Thu, 11 Dec 2025 03:51:56 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>前段时间我部署了Miniflux，这是一款功能强大的极简主义RSS订阅器，它支持多平台同步、文章过滤和离线阅读等实用功能，完全满足了我的信息聚合需求；不过它的界面设计确实过于朴素，采用了最基础的列表布局和单调的配色方案，在这个视觉至上的时代里，这种毫不修饰的极简风格可能会让许多用户在初次接触时就失去耐心，随手划走转而选择那些界面更炫目、交互更花哨的阅读应用。</p><p>因此，为了弥补 Miniflux 在视觉和交互体验上的不足，我这次专门挑选了一款高颜值的第三方客户端 Nextflux。它不仅继承了 Miniflux 强大的 RSS 订阅和内容聚合功能，更通过现代化的界面设计、流畅的动画效果和直观的操作逻辑，大幅提升了用户的使用愉悦感。例如，Nextflux 支持暗黑模式与自定义主题，卡片式布局让信息浏览更加清晰高效，同时保留了 Miniflux 原有的离线阅读与全文抓取等核心能力，真正实现了功能与美感的平衡。</p><p>Nextflux 是一个基于现代化技术栈精心打造的 RSS 阅读器客户端，它专门为开源的Miniflux后端服务设计，完美融合了便捷性和功能性。该客户端采用前沿的React框架进行用户界面开发，并结合Vite这一高效构建工具，不仅确保了极速的热重载和流畅的开发体验，还优化了生产环境的打包性能，为用户提供轻量、响应迅速且高度可定制的阅读界面。无论是订阅源的智能管理、文章的分类筛选，还是跨设备的同步阅读，Nextflux都致力于提升信息获取的效率和舒适度，让用户能够专注于内容本身，而无需为技术细节分心。</p><p><img src="https://images.mingliangstar.com/images/20251211/1.avif"></p><p>Nextflux与Miniflux类似，同样采用轻量级的容器化部署方式，能够通过Docker或Podman等工具快速搭建和运行，极大简化了安装与维护流程；这种部署模式不仅确保了环境的一致性，还支持灵活扩展与版本管理，特别适合个人或小团队在云服务器、本地主机乃至树莓派等设备上高效部署，同时保持了低资源占用和高稳定性的特点。</p><p>由于之前部署了Miniflux下面就直接部署Nextflux了，当然再结尾也会附上Miniflux+Nextflux+DB的完整yml文件</p><p>使用下述命令直接拉起nextflux的容器</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd  --restart unless-stopped  --name nextflux  -p 8121:3000    electh/nextflux:latest</span><br></pre></td></tr></table></figure><p>这里需要注意下Nextflux容器的端口</p><p><img src="https://images.mingliangstar.com/images/20251211/2.avif"></p><p>拉起容器后，直接通过宿主机的IP地址加上映射的8121端口（如<code>http://192.168.1.100:8121</code>）在浏览器中访问即可；若页面加载失败，通常是由于端口映射错误导致的，此时需要检查容器日志确认实际监听的端口号，既可以通过命令行方式查看（如执行<code>docker logs 容器ID</code>命令获取详细日志），也可以在宝塔面板的”容器管理”界面中直观地查看运行日志，此外还需确认服务器防火墙是否放行了该端口，这些都是导致访问失败的常见原因。</p><p><img src="https://images.mingliangstar.com/images/20251211/3.avif"></p><p>到这里基本上就可以看到Nextflux的登录界面了，我们可以看到这里除了用户名和密码外，还有个服务地址，这个服务地址就是Miniflux的访问地址，但是有几点需要注意</p><ul><li>如果你浏览器访问Nextflux的地址使用的是ip，那么服务地址这里就需要使用 <code>http://ip:port</code>，</li><li>如果你浏览器访问Nextflux的地址使用的域名，那么服务地址这里必须使用 <code>https://域名</code></li></ul><p><img src="https://images.mingliangstar.com/images/20251211/4.avif"></p><p>下面，我们来详细分析使用IP地址访问时出现”Failed to fetch”错误的问题：当按照本文的部署方式部署Nextflux和Miniflux后，即使使用同一IP地址访问也会遇到跨域问题，这是因为浏览器严格执行同源策略，会对比前端页面来源和API请求地址的协议、域名和端口是否完全一致。具体来说，假设你通过<code>http://140.143.94.243:8121</code>访问Nextflux前端界面，而该前端尝试向<code>http://140.143.94.243:80</code>的Miniflux后端发起API请求时，虽然IP地址相同，但由于端口号不同（8121 vs 80），浏览器会判定为跨域请求，此时浏览器会先发送一个OPTIONS预检请求来检查服务器是否允许跨域访问；如果Miniflux后端没有正确配置CORS头部信息，特别是缺少关键的Access-Control-Allow-Origin响应头，或者该头部的值不包含前端来源地址，浏览器就会直接拦截后续的实际请求，导致前端控制台报出”Failed to fetch”错误。要解决这个问题，最直接的方法是在启动Miniflux容器时添加两个必要的环境变量，这些配置会让Miniflux正确处理跨域请求并返回适当的CORS头部，修改后需要重启Miniflux容器使配置生效。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">environment:</span><br><span class="line">  - CORS_ORIGINS=http://140.143.94.243:8121</span><br><span class="line">  - CORS_ALLOW_HEADERS=*</span><br></pre></td></tr></table></figure><p>这里我建议直接使用宝塔面板的可视化操作界面进行操作，这样不仅能显著提高操作容错率，还能避免因手动输入命令导致的潜在错误；关于yml配置文件，我们可以直接复用之前部署Miniflux时使用的模板文件，只需在数据库配置部分额外添加这两个关键环境变量即可，完成这些修改后，直接保存配置文件即可生效，此时我们再次通过IP地址访问服务并进行登录操作，整个过程就会变得非常顺畅，不会再出现之前遇到的连接或认证问题，这种方案既保留了原有配置的稳定性，又通过最小改动实现了新功能的支持。</p><p><img src="https://images.mingliangstar.com/images/20251211/5.avif"></p><p><img src="https://images.mingliangstar.com/images/20251211/6.avif"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">services:</span><br><span class="line">  miniflux:</span><br><span class="line">    image: miniflux/miniflux:latest</span><br><span class="line">    ports:</span><br><span class="line">      - <span class="string">&quot;8383:8080&quot;</span></span><br><span class="line">    depends_on:</span><br><span class="line">      db:</span><br><span class="line">        condition: service_healthy</span><br><span class="line">    environment:</span><br><span class="line">      - DATABASE_URL=postgres://miniflux:admin@123@db/miniflux?sslmode=<span class="built_in">disable</span></span><br><span class="line">      - RUN_MIGRATIONS=1</span><br><span class="line">      - CREATE_ADMIN=1</span><br><span class="line">      - ADMIN_USERNAME=admin</span><br><span class="line">      - ADMIN_PASSWORD=admin@123</span><br><span class="line">  - CORS_ORIGINS=http://140.143.94.243:8121   <span class="comment">#填写你的实际ip和port</span></span><br><span class="line">      - CORS_ALLOW_HEADERS=*</span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;/usr/bin/miniflux&quot;</span>, <span class="string">&quot;-healthcheck&quot;</span>, <span class="string">&quot;auto&quot;</span>]</span><br><span class="line"></span><br><span class="line">  db:</span><br><span class="line">    image: postgres:17-alpine</span><br><span class="line">    environment:</span><br><span class="line">      - POSTGRES_USER=miniflux</span><br><span class="line">      - POSTGRES_PASSWORD=admin@123</span><br><span class="line">      - POSTGRES_DB=miniflux</span><br><span class="line">    volumes:</span><br><span class="line">      - miniflux-db:/var/lib/postgresql/data</span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;pg_isready&quot;</span>, <span class="string">&quot;-U&quot;</span>, <span class="string">&quot;miniflux&quot;</span>]</span><br><span class="line">      interval: 10s</span><br><span class="line">      start_period: 30s</span><br><span class="line"></span><br><span class="line">volumes:</span><br><span class="line">  miniflux-db:</span><br></pre></td></tr></table></figure><p>最后，我们重点讲解使用域名访问和登录时需要注意的技术细节，特别是关于HTTPS协议和URL格式规范的问题。当使用HTTPS协议访问Miniflux服务时，必须确保后端服务地址同样采用HTTPS协议，否则浏览器会因混合内容安全策略而阻止请求。这里特别要强调的是URL尾斜杠的处理问题：如果你在服务地址栏输入的是类似”<code>https://miniflux.mingliang.net.cn/</code>这样带有尾斜杠的地址，而前端JavaScript代码在拼接API路径时又没有正确处理这个斜杠，就会产生<code>https://miniflux.mingliang.net.cn**//**api/me</code>这样的双斜杠路径。这种URL格式错误虽然看起来很小，但会导致严重的后果：大多数现代Web服务器（如Nginx、Apache）会将其视为无效路径，返回404 Not Found错误；而浏览器端的fetch API则会抛出”Failed to fetch”的通用错误，给调试带来困难。这个问题在单页应用(SPA)开发中尤为常见，正确的做法应该是在配置文件中统一规范基础URL格式，或者在JavaScript代码中加入路径标准化处理逻辑，确保API请求的URL始终保持正确的单斜杠格式。</p><p>如果你之前没有部署过Miniflux这个轻量级RSS阅读器的话，使用docker-compose进行一体化安装是最便捷的方式，首先你需要创建一个名为docker-compose.yml的配置文件，将以下内容完整复制进去，其中包括了Miniflux服务及其必需的PostgreSQL数据库配置，确保网络设置和端口映射（通常Miniflux默认使用8080端口）正确无误后，在当前目录下执行docker-compose up -d命令即可启动容器编排，系统会自动拉取最新镜像并完成所有依赖服务的部署，整个过程无需手动干预，非常适合快速搭建个人阅读服务。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">version: <span class="string">&#x27;3&#x27;</span></span><br><span class="line"></span><br><span class="line">services:</span><br><span class="line">  miniflux:</span><br><span class="line">    image: miniflux/miniflux:latest</span><br><span class="line">    container_name: miniflux-server</span><br><span class="line">    restart: unless-stopped</span><br><span class="line">    ports:</span><br><span class="line">      - <span class="string">&quot;8120:8080&quot;</span></span><br><span class="line">    depends_on:</span><br><span class="line">      db:</span><br><span class="line">        condition: service_healthy</span><br><span class="line">    environment:</span><br><span class="line">      - DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=<span class="built_in">disable</span></span><br><span class="line">      - RUN_MIGRATIONS=1</span><br><span class="line">      - CREATE_ADMIN=1</span><br><span class="line">      - ADMIN_USERNAME=admin</span><br><span class="line">      - ADMIN_PASSWORD=test123</span><br><span class="line">  </span><br><span class="line">  db:</span><br><span class="line">    image: postgres:17-alpine</span><br><span class="line">    container_name: miniflux-db</span><br><span class="line">    restart: unless-stopped</span><br><span class="line">    environment:</span><br><span class="line">      - POSTGRES_USER=miniflux</span><br><span class="line">      - POSTGRES_PASSWORD=secret</span><br><span class="line">      - POSTGRES_DB=miniflux</span><br><span class="line">    volumes:</span><br><span class="line">      - ./data:/var/lib/postgresql/data</span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;pg_isready&quot;</span>, <span class="string">&quot;-U&quot;</span>, <span class="string">&quot;miniflux&quot;</span>]</span><br><span class="line">      interval: 10s</span><br><span class="line">      start_period: 30s</span><br><span class="line"></span><br><span class="line">  nextflux:</span><br><span class="line">    image: electh/nextflux:latest</span><br><span class="line">    container_name: miniflux-nextflux</span><br><span class="line">    restart: unless-stopped</span><br><span class="line">    ports:</span><br><span class="line">      - <span class="string">&quot;8121:80&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><p>这种联合部署的方式Eucalyptus之前确实没有尝试过，主要参考了AWS和Azure的混合云架构设计思路，并结合了《云计算架构设计模式》一书中提到的服务网格集成方案，如果有任何配置问题或性能优化建议，欢迎各位技术同行在评论区留言讨论。另外Eucalyptus部署的Nextflux测试环境已经稳定运行两周，访问地址是<a href="https://images.mingliangstar.com/go/?url=https://nextflux.mingliang.net.cn">https://nextflux.mingliang.net.cn</a>，该平台集成了实时数据流处理和可视化分析功能，各位朋友如果需要测试体验的话可以留言说明具体，Eucalyptus会根据使用场景为大家提供免费的测试账号。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/RSS/">RSS</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/RSS/">RSS</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/12/11/MiniFlux%E5%8D%87%E7%BA%A7NextFlux/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>使用pgcli实现PostgreSQL命令自动补全功能</title>
      <link>https://blog.mingliangstar.com/2025/12/11/%E4%BD%BF%E7%94%A8pgcli%E5%AE%9E%E7%8E%B0PostgreSQL%E5%91%BD%E4%BB%A4%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8%E5%8A%9F%E8%83%BD/</link>
      <guid>https://blog.mingliangstar.com/2025/12/11/%E4%BD%BF%E7%94%A8pgcli%E5%AE%9E%E7%8E%B0PostgreSQL%E5%91%BD%E4%BB%A4%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8%E5%8A%9F%E8%83%BD/</guid>
      <pubDate>Thu, 11 Dec 2025 03:49:13 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;blockquote&gt;
&lt;p&gt;安装和配置python-3.9.0可以参考下述文章&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><blockquote><p>安装和配置python-3.9.0可以参考下述文章</p></blockquote><p><a href="https://blog.csdn.net/weixin_72610956/article/details/136936680?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522f00009fc56234d90876a4a75dcd7d976%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=f00009fc56234d90876a4a75dcd7d976&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-136936680-null-null.nonecase&utm_term=mycli&spm=1018.2226.3001.4450">使用mycli实现MySQL命令自动补全功能（Python-3.9.0）</a><!-- 这是一张图片，ocr 内容为： --><br><img src="https://images.mingliangstar.com/images/PostgreSQL/20251211/1.avif"></p><p>下面我们直接来安装pgcli</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install pgcli</span><br></pre></td></tr></table></figure><p>安装号后使用pgcli登陆的时候会发现有个报错</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251211/2.avif"></p><p>这里我们参考提示移动下这个文件的位置就好了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mv /root/.pgclirc /root/.config/pgcli/</span><br></pre></td></tr></table></figure><p>然后登陆到postgres用户来登陆我们的postgresql</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#登陆postgres用户</span><br><span class="line">su - postgres</span><br><span class="line">#登陆postgresql数据库</span><br><span class="line">pgcli</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20251211/3.avif">  </p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/PostgreSQL/">PostgreSQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/PostgreSQL/">PostgreSQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/12/11/%E4%BD%BF%E7%94%A8pgcli%E5%AE%9E%E7%8E%B0PostgreSQL%E5%91%BD%E4%BB%A4%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8%E5%8A%9F%E8%83%BD/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL性能分析工具(pperf+Flame Graphs)</title>
      <link>https://blog.mingliangstar.com/2025/12/04/MySQL%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7-pperf-Flame-Graphs/</link>
      <guid>https://blog.mingliangstar.com/2025/12/04/MySQL%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7-pperf-Flame-Graphs/</guid>
      <pubDate>Thu, 04 Dec 2025 06:21:06 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;本文将介绍如何使用perf和Flame</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>本文将介绍如何使用perf和Flame Graphs工具对MySQL进行性能分析，这两个工具能够以图形化的形式展现MySQL中的哪些函数被调用以及调用次数，对于MySQL性能分析和优化有较大的作用。</p><p>perf 用来采集性能数据，Flame Graphs 使用perf采集的数据进行图形化展示</p><p>安装perf</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install -y perf</span><br></pre></td></tr></table></figure><p>使用Linux perf工具进行系统级性能数据采集</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># 针对特定进程进行性能分析</span><br><span class="line">perf record -F 99 -p &lt;PID&gt; -g -- sleep 60</span><br><span class="line">#任务时钟</span><br><span class="line">perf record -a -g -e task-clock -p 3601 -- sleep 60</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251204/1.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251204/2.avif"></p><p>数据采集完成后，通常会生成一个二进制数据文件perf.data，通过下面的命令将采集的二进制数据进行加工，转换成易于阅读的文本文件，</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">perf script &gt; perf.script</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251204/3.avif"></p><p>安装FlameGraph</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git clone https://github.com/brendangregg/FlameGraph</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251204/4.avif"></p><p>将perf.script文件作为输入，通过Flame Graphs工具，生成svg格式的性能图形</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">../FlameGraph/stackcollapse-perf.pl perf.script | ../FlameGraph/flamegraph.pl &gt; flamegraph.svg</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251204/5.avif"></p><p>现在，可以在网络浏览器中打开 flamegraph.svg</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251204/6.avif"></p><p>使用perf+Flame Graphs方式，能够从更深层的函数调用上，以图形化的方式看到MySQL是如何执行的，以及具体某个函数执行了多少次，能够更好地看到隐藏在进程之后的具体操作，相对于文本，图形化的展示，更容易被人阅读，也更容易发现性能瓶颈以及相应的优化方向。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/12/04/MySQL%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E5%B7%A5%E5%85%B7-pperf-Flame-Graphs/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MiniFlux安全升级</title>
      <link>https://blog.mingliangstar.com/2025/11/08/MiniFlux%E5%AE%89%E5%85%A8%E5%8D%87%E7%BA%A7/</link>
      <guid>https://blog.mingliangstar.com/2025/11/08/MiniFlux%E5%AE%89%E5%85%A8%E5%8D%87%E7%BA%A7/</guid>
      <pubDate>Sat, 08 Nov 2025 08:39:45 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;在信息过载的时代，RSS 依旧是高效获取优质内容的“净土”。Miniflux 以轻量、简洁、开源的姿态，成为许多技术人自托管 RSS 的首选。然而，只在内网 IP 下阅读未免辜负了它的优雅；给 Miniflux</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>在信息过载的时代，RSS 依旧是高效获取优质内容的“净土”。Miniflux 以轻量、简洁、开源的姿态，成为许多技术人自托管 RSS 的首选。然而，只在内网 IP 下阅读未免辜负了它的优雅；给 Miniflux 配一个专属的二级域名，再披上 HTTPS 的“安全外衣”，不仅能让阅读随时随地、安全无虞，更是对自己数字领地的一次仪式感升级。接下来的篇幅，我们一起把<code>localhost:8383</code>变成<code>https://miniflux.mingliang.net.cn/</code>，让每一次订阅与更新都拥有值得收藏的新地址。</p><p>首先本篇文章中使用的是二级域名，大伙都知道域名是需要进行备案的，“而二级域名需不需要备案”取决于它的一级域名是否已经取得备案号，以及二者是否使用同一家云接入商，大致分为以下几种情况。</p><ul><li>一级域名已备案，且二级域名与一级域名在同一接入商 → 二级域名无需单独备案。</li><li>一级域名已备案，但二级域名要换到另一家国内接入商 → 先做一次“新增接入备案”，等通过后才能解析到新 IP。</li><li>一级域名没有任何备案号 → 必须先把一级域名提交首次备案，二级域名才能在中国大陆正常访问。</li><li>政府&#x2F;事业单位的<code>.gov.cn</code>等后缀二级域名 → 无论一级域名是否已备案，都要单独备案。</li></ul><p>只要网站服务器放在中国大陆，访问者能直接通过二级域名打开网页，就适用上述规则；如果服务器在境外，理论上不受中国备案系统约束，但国内 DNS&#x2F;CDN 厂商通常仍会提示“一级域名需已备案”才能开启加速或防护功能。</p><p>备案就不过多赘述了，如果不清楚的，可以参考下这篇文章：<a href="https://images.mingliangstar.com/go/?url=https://blog.csdn.net/weixin_72610956/article/details/135545236">网站ICP备案和公安备案教程</a>，下面直接进行二级域名解析教程</p><p>这里以阿里云为例，在一级域名中添加一条解析记录时，首先需要登录阿里云控制台并进入域名解析管理页面，在DNS解析设置中选择”添加记录”选项，这里的记录类型可以根据实际需求选择A类型（用于将域名指向IPv4地址），主机记录则填写你的二级域名前缀（如”www”或”blog”等），记录值需要填写对应服务器的公网IP地址（对于A记录），TTL（生存时间）通常保持默认值即可，但也可以根据业务需求进行调整，设置完成后点击确认即可完成解析记录的添加，一般情况下解析会在10分钟内生效，但受各地DNS缓存影响，全球完全生效可能需要24-48小时。</p><p><img src="https://images.mingliangstar.com/images/20251108/1.avif"></p><p>接下来进行Nginx反向代理的配置，全程使用宝塔面板的可视化界面操作，首先登录宝塔面板后，在左侧导航栏找到”网站”模块并点击进入，在菜单中选择”反向代理”选项，这时会显示当前站点的反向代理配置页面，然后点击左上角的”添加反向代理”按钮</p><p><img src="https://images.mingliangstar.com/images/20251108/2.avif"></p><p>在域名配置栏中，需要填写之前在域名控制台已解析完成的二级域名（如”test.example.com”），目标URL地址则应填写本地服务器地址<code>http://127.0.0.1</code>并加上对应的服务端口号（例如<code>:8383</code>表示该服务运行在8383端口），发送域名host保持默认设置即可（通常为自动填充的当前域名），备注栏可根据实际需求填写该条记录的相关说明（如”测试环境API服务”或”开发调试用”等描述性内容），确认所有信息无误后点击保存按钮完成配置。</p><p><img src="https://images.mingliangstar.com/images/20251108/3.avif"></p><p>最后为刚才配置的反向代理服务开启HTTPS加密连接，首先在控制面板中找到并点击刚才添加的反向代理条目右侧的设置按钮，在弹出的菜单中选择”SSL”选项，然后选择<code>Let’sL Encrypt</code>免费证书服务，系统会自动验证域名所有权并生成证书请求，验证通过后点击”申请证书”按钮，等待证书签发完成后，务必记得点击”部署”按钮将证书应用到当前反向代理配置中，这样就能为网站流量提供端到端的加密保护，有效防止数据在传输过程中被窃听或篡改，同时还能提升网站在搜索引擎中的排名。</p><p><img src="https://images.mingliangstar.com/images/20251108/4.avif"></p><p>到这里Miniflux 安全升级的全部部署工作已经圆满完成，我们不仅为Eucalyptus的个人RSS阅读器Miniflux绑定了专属域名miniflux.mingliang.net.cn，还成功配置了HTTPS加密协议，确保数据传输的安全性，现在您可以通过<a href="https://images.mingliangstar.com/go/?url=https://miniflux.mingliang.net.cn/">https://miniflux.mingliang.net.cn/</a>这个安全链接访问这个清爽简洁的RSS聚合平台，该平台采用Go语言开发，具有极低的资源占用和快速的响应速度，特别适合追求高效阅读体验的用户，如果您对这款轻量级RSS阅读器感兴趣，想要亲自体验它的强大功能，比如文章分类管理、快捷键操作、多设备同步等特性，欢迎在评论区留言，Eucalyptus会热情地为每位感兴趣的朋友创建专属测试账号，让您零门槛感受Miniflux的独特魅力。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/RSS/">RSS</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/RSS/">RSS</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/11/08/MiniFlux%E5%AE%89%E5%85%A8%E5%8D%87%E7%BA%A7/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL8.0.30中redo log的变化</title>
      <link>https://blog.mingliangstar.com/2025/10/29/MySQL8-0-%E4%B8%ADredo-log%E7%9A%84%E5%8F%98%E5%8C%96/</link>
      <guid>https://blog.mingliangstar.com/2025/10/29/MySQL8-0-%E4%B8%ADredo-log%E7%9A%84%E5%8F%98%E5%8C%96/</guid>
      <pubDate>Wed, 29 Oct 2025 14:42:21 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;MySQL8-0-30-redo-log-动态调整&quot;&gt;&lt;a href=&quot;#MySQL8-0-30-redo-log-动态调整&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="MySQL8-0-30-redo-log-动态调整"><a href="#MySQL8-0-30-redo-log-动态调整" class="headerlink" title="MySQL8.0.30 redo log 动态调整"></a>MySQL8.0.30 redo log 动态调整</h2><p>MySQL redo log记录数据记录变更，以及未数据一致性恢复提供保障。在运维MySQL 过程中，会遇到调整redo log 和redo buffer size 大小的需求，然而修改redo log 文件大小需要重启，不过 MySQL 8.0.30 版本中提供动态调整redo log 文件大小的功能。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/1.avif"></p><p><a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html">https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html</a></p><p>从 MySQL 8.0.30 开始， innodb_redo_log_capacity系统变量控制 redo log 总的大小。</p><p>因为在该版本以及之后的版本参数innodb_log_file_size 和 innodb_log_files_in_group 已经被废弃。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/2.avif"></p><p>如下图所示，8.0.30 版本对原来的循环覆盖写的结构进行了改造，不再以 redo 文件个数和单个 redo 文件的大小来进行限制，而是通过 innodb_redo_log_capacity来指定整个 redo 空间的大小。整个redo空间会被切成32个文件（固定个数），文件按照 ib_redo$SEQ 的方式进行编号，$SEQ 是一个递增的序列号。在文件管理上，所有的文件会被分成两类：</p><ul><li>normal redo 文件，命名为 ib_redo$SEQ，正常的 redo 文件，和以前一样，任意时刻只会有一个 redo 文件进行写入；</li><li>unused redo 文件，命名为 ib_redo$SEQ_tmp，未被使用的 redo 文件在被使用时，会被重命名为正常文件；</li></ul><p>后台的 log_files_governor 线程会负责处理已经写完成的文件，在满足回收条件时，会重新变成 unused redo 文件</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/3.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/4.avif"></p><p>当 innodb_redo_log_capacity 发生变化时，已经使用过的和正在使用过的 redo 文件并不会发生改变，仅需要调整 unused redo 文件。当用户修改 innodb_redo_log_capacity 时，会唤醒后台的 log_files_governor 线程，后台线程首先会重新计算当前的 redo_log_capacity，然后根据变化的类型：</p><ul><li>如果是空间放大，直接根据放大后的大小，重新生成新的 unused redo 文件；</li><li>如果是空间缩小，需要计算当前已使用的空间数能否满足目标值，如果满足，那么缩小过程和放大过程一样，直接重新生成新的 ununsed redo 文件即可；如果不能，还需要在更新 redo_log_capacity 之后，通过调整暴露给 log_writer 和 page_cleaner 线程的 lsn 信息，来加速空间回收；</li></ul><p>unused redo 文件的引入，类似于引入了缓存区的机制，因为 unused redo 文件不是正在使用的 redo 文件，所以可以直接进行重建，从而满足 innodb_redo_log_capacity 的设置。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/5.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/13.avif"></p><p>在运行时设置时，配置更改会立即发生，但可能需要一些时间才能完全实现新的限制。如果重做日志文件占用的空间小于指定值，则脏页将从缓冲池中较不积极地刷新到表空间数据文件中，最终增加重做日志文件所占用的磁盘空间。如果重做日志文件占用的空间超过指定值，则会更积极地刷新脏页，最终减少重做日志文件所占用的磁盘空间。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/6.avif"></p><p><a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-redo-log.html">https://dev.mysql.com/doc/refman/8.0/en/innodb-redo-log.html</a></p><h2 id="MySQL-8-0-17-redo-log归档"><a href="#MySQL-8-0-17-redo-log归档" class="headerlink" title="MySQL 8.0.17 redo log归档"></a>MySQL 8.0.17 redo log归档</h2><p>在需要备份重做日志以满足审计合规要求、进行数据库维护升级或迁移、以及在高负载系统中减少磁盘 I&#x2F;O 操作对性能影响的情况下特别有用。归档操作应在系统负载较低时进行，并且需要确保归档目录的安全性和正确配置。</p><p>在启用 redo log 归档之前，需要创建一个或多个目录来存储归档的 redo log，确保运行 mysqld的系统用户拥有该目录的访问权限。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p /var/lib/mysql-redo-archive/backup1</span><br><span class="line">chown -R mysql.mysql /var/lib/mysql-redo-archive</span><br><span class="line">chmod -R 700 /var/lib/mysql-redo-archive/</span><br></pre></td></tr></table></figure><p>使用 innodb_redo_log_archive_dirs 全局变量定义标记的归档路径，或者在配置文件种配置，格式为 label:directory-path，可以使用分号分隔多个条目。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set global innodb_redo_log_archive_dirs=&#x27;backup1:/var/lib/mysql-redo-archive/&#x27;;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/7.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">show variables like &#x27;innodb_redo_log_archive_dirs&#x27;;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/8.avif"></p><p>启动和停止归档，具有 innodb_redo_log_archive 权限的用户可以调用 innodb_redo_log_archive_start() 或 innodb_redo_log_archive_stop() 函数来启动或停止归档。</p><p>启动</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">do innodb_redo_log_archive_start(&#x27;backup1&#x27;, &#x27;backup1&#x27;); </span><br><span class="line">or</span><br><span class="line">select innodb_redo_log_archive_start(&#x27;backup1&#x27;, &#x27;backup1&#x27;);</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/9.avif"></p><p>停止</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">do innodb_redo_log_archive_stop();   </span><br><span class="line">or</span><br><span class="line">select innodb_redo_log_archive_stop();</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/10.avif"></p><h2 id="MySQL-8-0-16-redo-log加密"><a href="#MySQL-8-0-16-redo-log加密" class="headerlink" title="MySQL 8.0.16 redo log加密"></a>MySQL 8.0.16 redo log加密</h2><p>MySQL 8.0.16版本以后可以使用innodb_redo_log_encrypt配置选项启用了Redo日志数据加密。默认情况下，Redo日志加密是禁用的。与表空间数据一样，Redo日志数据加密是在将数据写入磁盘时进行的，而解密是在从磁盘读取重做日志数据时进行的。一旦数据读入内存，它就处于未加密形式。使用表空间加密密钥对重做日志数据进行加密和解密。</p><p>启用innodb_redo_log_encrypt时，磁盘上存在的未加密Redo日志页面将保持未加密状态，新的Redo日志页面将以加密形式写入磁盘。同样，禁用innodb_redo_log_encrypt时，磁盘上存在的已加密Redo日志页面将保持加密状态，新的Redo日志页面将以未加密形式写入磁盘。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/11.avif"></p><p><a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html">https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html</a></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SET GLOBAL default_table_encryption=ON;</span><br></pre></td></tr></table></figure><h2 id="MySQL-8-0-21-redo-log禁用"><a href="#MySQL-8-0-21-redo-log禁用" class="headerlink" title="MySQL 8.0.21 redo log禁用"></a>MySQL 8.0.21 redo log禁用</h2><p>MySQL 8.0.21版本之后可以启禁用Redo log功能。可以通过避免写入Redo和doublewrite缓冲来加快数据加载。一般初期大量灌入数据是采用。平时就不建议使用此功能，意外发生 或 服务停止可能会导致数据丢失和实例损坏。</p><p>启禁用需要有INNODB_REDO_LOG_ENABLE权限</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#启用</span><br><span class="line">ALTER INSTANCE ENABLE  INNODB REDO_LOG;</span><br><span class="line">SHOW GLOBAL STATUS LIKE &#x27;Innodb_redo_log_enabled&#x27;;</span><br><span class="line">#禁用</span><br><span class="line">ALTER INSTANCE DISABLE INNODB REDO_LOG;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251029/12.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/10/29/MySQL8-0-%E4%B8%ADredo-log%E7%9A%84%E5%8F%98%E5%8C%96/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>gh-ost菜鸟教程</title>
      <link>https://blog.mingliangstar.com/2025/10/22/gh-ost%E8%8F%9C%E9%B8%9F%E6%95%99%E7%A8%8B/</link>
      <guid>https://blog.mingliangstar.com/2025/10/22/gh-ost%E8%8F%9C%E9%B8%9F%E6%95%99%E7%A8%8B/</guid>
      <pubDate>Wed, 22 Oct 2025 09:30:41 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;code&gt;gh-ost&lt;/code&gt; 是 GitHub 开发的一款用于</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><code>gh-ost</code> 是 GitHub 开发的一款用于 MySQL 数据库的在线模式迁移解决方案，它支持无触发器的在线模式迁移。这个工具是可测试的，并提供暂停、动态控制&#x2F;重新配置、审计以及许多操作特权。<code>gh-ost</code> 旨在改变表迁移的范式，它在迁移过程中对主服务器产生的工作量很小，并且与已迁移表上的现有工作负载分离，从而减少对数据库性能的影响。</p><h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p>主要实现原理，首先建两张表，一张_gho的影子表，gh-ost会将原表数据以及增量数据都应用到这个表，最后会将这个表和原表做次表名切换，另一张是_ghc表，这个表是存放changelog的数据，包括信号标记，心跳等。其次 ，gh-ost会开两个goroutine，一个用于拷贝原表数据，一个用于apply增量的binlog到_gho表，并且两个goroutine的并行在跑的，也就是不用关心数据是先拷贝过去还是先apply binlog过去。因为这里会对insert语句做调整，首先我们拷贝的insert into会改写成insert ignore into，而binlog内insert into会改写成replace into，这样可以很好的支持两个goroutine的并行。但这样的调整能适用所有的DDL吗？答案是否定的。最后，当原表数据全部拷贝完成后，gh-ost会进入到表交换阶段，采用更加安全的原子交换。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/1.avif"></p><h3 id="过程"><a href="#过程" class="headerlink" title="过程"></a>过程</h3><ol><li>检查有没有外键和触发器。</li><li>检查表的主键信息。</li><li>检查是否主库或从库，是否开启log_slave_updates，以及binlog信息</li><li>检查gho和del结尾的临时表是否存在</li><li>创建ghc结尾的表，存数据迁移的信息，以及binlog信息等<br> <em><strong>—以上校验阶段</strong></em></li><li>初始化stream的连接,添加binlog的监听<br> <em><strong>—以下迁移阶段</strong></em></li><li>创建gho结尾的临时表，执行DDL在gho结尾的临时表上</li><li>开启事务，按照主键id把源表数据写入到gho结尾的表上，再提交，以及binlog apply。<br> <em><strong>—以下cut-over阶段</strong></em></li><li>lock源表，rename 表：rename 源表 to 源_del表，gho表 to 源表。</li><li>清理ghc表</li></ol><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>由于gh-ost是基于go1.5编译的，故安装gh-ost之前需要安装go，安装go（我的yum仓库中有go包，故直接使用yum安装，没有的话需要进行下载tar包源码安装）</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/2.avif"></p><p>验证go是否安装成功</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go env</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/3.avif"></p><p>接下来安装gh-ost，由于gh-ost的tar包再github中，下载的时候可能由于网络的原因导致下载失败，故我们使用gitee中的项目</p><p><a href="https://gitee.com/mirrors/gh-ost">https://gitee.com/mirrors/gh-ost</a></p><p>我这里直接下载的zip包，然后上传到服务器</p><p>下载到服务器上后进行解压</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">unzip gh-ost-master.zip</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/4.avif"></p><p>解压之后进入gh-ost-master目录，</p><p>然后再当前的目录下初始化一个git仓库</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git init</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/5.avif"></p><p>然后需要在build.sh中指定gh-ost版本</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/6.avif"></p><p>打开build.sh脚本设置你需要的gh-ost版本，然后保存，</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RELEASE_VERSION=v1.1.7</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/7.avif"></p><p>然后运行build.sh脚本</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/8.avif"></p><p>接下来解压适用于你操作系统的tar包，</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar xvzf gh-ost-binary-linux-amd64-20251022142618.tar.gz</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/9.avif"></p><p>最后将gh-ost二进制文件移动到&#x2F;usr&#x2F;local&#x2F;bin下，然后使用gh-ost –version验证gh-ost是否安装成功</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mv gh-ost /usr/local/bin/</span><br><span class="line">gh-ost --version</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/10.avif"></p><h2 id="实战（单节点）"><a href="#实战（单节点）" class="headerlink" title="实战（单节点）"></a>实战（单节点）</h2><p>我们创建了一个example_table表，然后使用gh-ost删除这个表中的全文索引ftx_first_name</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE example_table(</span><br><span class="line">    id INT AUTO_INCREMENT,</span><br><span class="line">    first_name VARCHAR(50),</span><br><span class="line">    last_name VARCHAR(50),</span><br><span class="line">    email VARCHAR(100),</span><br><span class="line">    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">    status ENUM(&#x27;active&#x27;, &#x27;inactive&#x27;) DEFAULT &#x27;active&#x27;,</span><br><span class="line">    PRIMARY KEY (id),</span><br><span class="line">    INDEX idx_last_name (last_name),</span><br><span class="line">    FULLTEXT INDEX ftx_first_name (first_name),</span><br><span class="line">    INDEX idx_status (status),</span><br><span class="line">    INDEX idx_created_at (created_at),</span><br><span class="line">    INDEX idx_first_name_last_name (first_name, last_name)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/11.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">gh-ost \</span><br><span class="line">--host=127.0.0.1 \</span><br><span class="line">--user=root \</span><br><span class="line">--password=123456 \</span><br><span class="line">--database=demo1 \</span><br><span class="line">--table=example_table \</span><br><span class="line">--alter=&quot;DROP INDEX ftx_first_name&quot; \</span><br><span class="line">--execute \</span><br><span class="line">--allow-on-master</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/12.avif"></p><p>可以看到example_table中的全文索引ftx_first_name已经删除</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/13.avif"></p><p>通过解析binlog我们可以看到首先gh-ost创建了存放changelog的<code>demo1</code>.<code>_example_table_ghc</code>表，然后创建了影子表<code>demo1</code>.<code>_example_table_gho</code></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/14.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">create /* gh-ost */ table `demo1`.`_example_table_ghc` (</span><br><span class="line">                        id bigint unsigned auto_increment,</span><br><span class="line">                        last_update timestamp not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,</span><br><span class="line">                        hint varchar(64) charset ascii not null,</span><br><span class="line">                        value varchar(4096) charset ascii not null,</span><br><span class="line">                        primary key(id),</span><br><span class="line">                        unique key hint_uidx(hint)</span><br><span class="line">                ) auto_increment=256 comment=&#x27;gh-ost changelog&#x27;</span><br><span class="line">/*!*/;</span><br></pre></td></tr></table></figure><p>随后在影子表<code>demo1</code>.<code>_example_table_gho</code>执行了ddl，并设置了AUTO_INCREMENT</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/15.avif"></p><p>binlog中继续往下看，在end_log_pos 18708，又创建了<code>demo1</code>.<code>_example_table_del</code></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/16.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">create /* gh-ost */ table `demo1`.`_example_table_del` (</span><br><span class="line">                        id int auto_increment primary key</span><br><span class="line">                ) engine=InnoDB comment=&#x27;ghost-cut-over-sentry&#x27;</span><br><span class="line">/*!*/;</span><br></pre></td></tr></table></figure><p>在end_log_pos 24355，删除了<code>_example_table_del</code></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/17.avif"></p><p>在end_log_pos 25086，使用rename了</p><p>将<code>demo1</code>.<code>example_table</code> 重命名为<code>demo1</code>.<code>_example_table_del</code></p><p>将<code>demo1</code>.<code>_example_table_gho</code>重命名为<code>demo1</code>.<code>example_table</code></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/18.avif"></p><p>最后删除了 <code>_example_table_ghc</code>和 <code>_example_table_ghk</code></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251022/19.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/10/22/gh-ost%E8%8F%9C%E9%B8%9F%E6%95%99%E7%A8%8B/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL中的数据类型占用空间和范围</title>
      <link>https://blog.mingliangstar.com/2025/10/14/MySQL%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8D%A0%E7%94%A8%E7%A9%BA%E9%97%B4%E5%92%8C%E8%8C%83%E5%9B%B4/</link>
      <guid>https://blog.mingliangstar.com/2025/10/14/MySQL%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8D%A0%E7%94%A8%E7%A9%BA%E9%97%B4%E5%92%8C%E8%8C%83%E5%9B%B4/</guid>
      <pubDate>Tue, 14 Oct 2025 03:29:53 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;数据类型&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;th&gt;占用空间&lt;/th&gt;
&lt;th&gt;最大值~最小值 (SIGNED)&lt;/th&gt;
&lt;th&gt;最大值~最小值</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><table><thead><tr><th>数据类型</th><th>描述</th><th>占用空间</th><th>最大值~最小值 (SIGNED)</th><th>最大值~最小值 (UNSIGNED)</th></tr></thead><tbody><tr><td>TINYINT</td><td>微整数</td><td>1 byte</td><td>-128 ~ 127</td><td>0 ~ 255</td></tr><tr><td>SMALLINT</td><td>小整数</td><td>2 bytes</td><td>-32768 ~ 32767</td><td>0 ~ 65535</td></tr><tr><td>MEDIUMINT</td><td>中等整数</td><td>3 bytes</td><td>-8388608 ~ 8388607</td><td>0 ~ 16777215</td></tr><tr><td><strong><font style="color:#fe2c24;">INT</font></strong> 或 INTEGER</td><td>整数</td><td>4 bytes</td><td>-2147483648 ~ 2147483647</td><td>0 ~ 4294967295</td></tr><tr><td><strong><font style="color:#fe2c24;">BIGINT</font></strong></td><td>大整数</td><td>8 bytes</td><td>-9223372036854775808 ~ 9223372036854775807</td><td>0 ~ 18446744073709551615</td></tr><tr><td>FLOAT</td><td>单精度浮点数</td><td>4 bytes</td><td>-3.40282347E+38 ~ 3.40282347E+38</td><td>0 ~ 3.40282347E+38</td></tr><tr><td>DOUBLE</td><td>双精度浮点数</td><td>8 bytes</td><td>-1.7976931348623157E+308 ~ 1.7976931348623157E+308</td><td>0 ~ 1.7976931348623157E+308</td></tr><tr><td>DECIMAL(M,D)</td><td>精确小数，M为总位数，D为小数位</td><td>M+2字节</td><td>取决于M和D</td><td>取决于M和D</td></tr><tr><td>DATE</td><td>日期</td><td>3 bytes</td><td>0000-01-01 ~ 9999-12-31</td><td>0000-01-01 ~ 9999-12-31</td></tr><tr><td>TIME</td><td>时间</td><td>3 bytes</td><td>-838:59:59 ~ 838:59:59</td><td>00:00:00 ~ 838:59:59</td></tr><tr><td>DATETIME</td><td>日期时间</td><td>5 bytes</td><td>0000-01-01 00:00:00 ~ 9999-12-31 23:59:59</td><td>0000-01-01 00:00:00 ~ 9999-12-31 23:59:59</td></tr><tr><td>TIMESTAMP</td><td>时间戳</td><td>4 bytes</td><td>1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC</td><td>1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC</td></tr><tr><td>YEAR</td><td>年份</td><td>1 byte</td><td>1901 ~ 2155</td><td>1901 ~ 2155</td></tr><tr><td><strong><font style="color:#fe2c24;">CHAR(M)</font></strong></td><td>固定长度字符串</td><td>M bytes</td><td>空字符串 ~ M字符字符串</td><td>空字符串 ~ M字符字符串</td></tr><tr><td><strong><font style="color:#fe2c24;">VARCHAR(M)</font></strong></td><td>可变长度字符串</td><td><font style="background-color:#ffd900;">长度 + 1 byte</font></td><td>空字符串 ~ M字符字符串</td><td>空字符串 ~ M字符字符串</td></tr><tr><td>TINYTEXT</td><td>小文本</td><td>长度 + 1 byte</td><td>空字符串 ~ 255字符字符串</td><td>空字符串 ~ 255字符字符串</td></tr><tr><td>TEXT</td><td>文本</td><td>长度 + 2 bytes</td><td>空字符串 ~ 65,535字符字符串</td><td>空字符串 ~ 65,535字符字符串</td></tr><tr><td>MEDIUMTEXT</td><td>中等文本</td><td>长度 + 3 bytes</td><td>空字符串 ~ 16,777,215字符字符串</td><td>空字符串 ~ 16,777,215字符字符串</td></tr><tr><td>LONGTEXT</td><td>大文本</td><td>长度 + 4 bytes</td><td>空字符串 ~ 4,294,967,295字符字符串</td><td>空字符串 ~ 4,294,967,295字符字符串</td></tr><tr><td>BINARY(M)</td><td>固定长度二进制字符串</td><td>M bytes</td><td>空字符串 ~ M字节字符串</td><td>空字符串 ~ M字节字符串</td></tr><tr><td>VARBINARY(M)</td><td>可变长度二进制字符串</td><td>长度 + 1 byte</td><td>空字符串 ~ M字节字符串</td><td>空字符串 ~ M字节字符串</td></tr><tr><td>TINYBLOB</td><td>小BLOB</td><td>长度 + 1 byte</td><td>空二进制字符串 ~ 255字节</td><td>空二进制字符串 ~ 255字节</td></tr><tr><td>BLOB</td><td>BLOB</td><td>长度 + 2 bytes</td><td>空二进制字符串 ~ 65,535字节</td><td>空二进制字符串 ~ 65,535字节</td></tr><tr><td>MEDIUMBLOB</td><td>中等BLOB</td><td>长度 + 3 bytes</td><td>空二进制字符串 ~ 16,777,215字节</td><td>空二进制字符串 ~ 16,777,215字节</td></tr><tr><td>LONGBLOB</td><td>大BLOB</td><td>长度 + 4 bytes</td><td>空二进制字符串 ~ 4,294,967,295字节</td><td>空二进制字符串 ~ 4,294,967,295字节</td></tr><tr><td>ENUM(‘value1’,…)</td><td>枚举，预定义字符串列表中选择</td><td>1~2 bytes</td><td>取决于枚举值</td><td>取决于枚举值</td></tr><tr><td>SET(‘value1’,…)</td><td>集合，预定义字符串列表中选择</td><td>1~8 bytes</td><td>取决于集合值</td><td>取决于集合值</td></tr><tr><td>BIT(M)</td><td>位字段</td><td>M bits</td><td>0 ~ 2^M - 1</td><td>0 ~ 2^M - 1</td></tr><tr><td><font style="background-color:#ffd900;">GEOMETRY</font></td><td>空间几何数据类型</td><td>可变</td><td>取决于数据大小</td><td>取决于数据大小</td></tr><tr><td><font style="background-color:#ffd900;">POINT</font></td><td>点类型</td><td>可变</td><td>取决于数据大小</td><td>取决于数据大小</td></tr><tr><td><font style="background-color:#ffd900;">LINESTRING</font></td><td>线字符串类型</td><td>可变</td><td>取决于数据大小</td><td>取决于数据大小</td></tr><tr><td><font style="background-color:#ffd900;">POLYGON</font></td><td>多边形类型</td><td>可变</td><td>取决于数据大小</td><td>取决于数据大小</td></tr><tr><td>JSON</td><td>JSON数据类型</td><td>可变</td><td>取决于JSON数据大小</td><td>取决于JSON数据大小</td></tr></tbody></table></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/10/14/MySQL%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8D%A0%E7%94%A8%E7%A9%BA%E9%97%B4%E5%92%8C%E8%8C%83%E5%9B%B4/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL中的空间碎片率计算分析</title>
      <link>https://blog.mingliangstar.com/2025/10/11/MySQL%E4%B8%AD%E7%9A%84%E7%A9%BA%E9%97%B4%E7%A2%8E%E7%89%87%E7%8E%87%E8%AE%A1%E7%AE%97%E5%88%86%E6%9E%90/</link>
      <guid>https://blog.mingliangstar.com/2025/10/11/MySQL%E4%B8%AD%E7%9A%84%E7%A9%BA%E9%97%B4%E7%A2%8E%E7%89%87%E7%8E%87%E8%AE%A1%E7%AE%97%E5%88%86%E6%9E%90/</guid>
      <pubDate>Sat, 11 Oct 2025 06:12:41 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;空间碎片的类型&quot;&gt;&lt;a href=&quot;#空间碎片的类型&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="空间碎片的类型"><a href="#空间碎片的类型" class="headerlink" title="空间碎片的类型"></a><strong>空间碎片的类型</strong></h2><p>MySQL 中的空间碎片主要分为两种类型：<strong>数据碎片</strong>和<strong>索引碎片</strong>。</p><h2 id="数据碎片"><a href="#数据碎片" class="headerlink" title="数据碎片"></a>数据碎片</h2><p>数据碎片是指表中的数据页（或数据块）中未被充分利用的空间。数据页是 MySQL 存储数据的基本单位，通常大小为 16 KB（对于 InnoDB 存储引擎）。</p><ul><li><code>INSERT</code>** 操作**：插入数据时，如果插入的数据量较小，可能会导致数据页没有被完全填满，从而产生未使用的空间。</li><li><code>DELETE</code>** 操作**：删除数据时，被删除的数据行所占用的空间会变成未使用的空间。如果这些空间没有被后续的 <code>INSERT</code> 操作重新利用，就会形成碎片。</li><li><code>UPDATE</code>** 操作**：如果更新操作导致数据行的大小发生变化（例如，从较短的字符串更新为较长的字符串），可能会导致数据行被移动到新的数据页，从而产生碎片。</li></ul><h2 id="索引碎片"><a href="#索引碎片" class="headerlink" title="索引碎片"></a>索引碎片</h2><p>索引碎片是指索引中的索引页（或索引块）中未被充分利用的空间。索引页是 MySQL 存储索引信息的基本单位，通常大小为 16 KB（对于 InnoDB 存储引擎）。</p><ul><li><code>INSERT</code>** 操作**：插入数据时，如果插入的数据行导致索引页分裂，可能会产生未使用的空间。</li><li><code>DELETE</code>** 操作**：删除数据时，被删除的数据行所占用的索引空间会变成未使用的空间。如果这些空间没有被后续的 <code>INSERT</code> 操作重新利用，就会形成碎片。</li><li><code>UPDATE</code>** 操作**：如果更新操作导致索引键值的变化，可能会导致索引页的重新组织，从而产生碎片。</li></ul><h2 id="碎片的危害"><a href="#碎片的危害" class="headerlink" title="碎片的危害"></a>碎片的危害</h2><ul><li><strong>增加磁盘 I&#x2F;O 操作</strong>：当存在存储碎片时，数据在磁盘上的存储位置变得分散。例如，一个查询原本只需要读取一个连续的数据块就能获取所需信息，但由于碎片的存在，数据可能分布在多个不连续的磁盘位置。这就导致数据库在执行查询操作时，需要多次进行磁盘 I&#x2F;O 操作来读取分散的数据。对于频繁查询的数据库系统，大量的额外磁盘 I&#x2F;O 会显著降低系统的整体性能。</li><li><strong>降低存储效率</strong>：在 MySQL 中，缓冲池（如 InnoDB 缓冲池）用于缓存数据页和索引页，以减少磁盘 I&#x2F;O。但是，碎片会使数据页和索引页在缓冲池中难以高效地缓存。由于碎片导致数据页不完整或部分空闲，缓冲池可能无法充分利用其空间来缓存完整的、经常使用的数据页。</li><li><strong>造成磁盘空间浪费</strong>：存储碎片使得磁盘空间无法得到有效利用。这些碎片空间单个可能较小，但随着时间的推移和操作的积累，它们会占用大量的磁盘空间。例如，在一个数据库表空间中，由于数据的删除和更新操作产生了许多小碎片，这些碎片空间加起来可能占据了相当大的磁盘容量，但却无法被有效地用于存储新的数据。</li></ul><h2 id="空间碎片率计算公式"><a href="#空间碎片率计算公式" class="headerlink" title="空间碎片率计算公式"></a>空间碎片率计算公式</h2><h3 id="8-0"><a href="#8-0" class="headerlink" title="8.0"></a>8.0</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span>  </span><br><span class="line">  TABLE_NAME,</span><br><span class="line">  TABLE_ROWS,</span><br><span class="line">  ROUND(DATA_LENGTH <span class="operator">/</span> (<span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span>), <span class="number">2</span>) <span class="keyword">AS</span> DATA_LENGTH_GB,</span><br><span class="line">  ROUND(INDEX_LENGTH <span class="operator">/</span> (<span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span>), <span class="number">2</span>) <span class="keyword">AS</span> INDEX_LENGTH_GB,</span><br><span class="line">  DATA_FREE,</span><br><span class="line">  <span class="keyword">CASE</span> </span><br><span class="line">    <span class="keyword">WHEN</span> (DATA_LENGTH <span class="operator">+</span> INDEX_LENGTH <span class="operator">+</span> DATA_FREE) <span class="operator">&gt;</span> <span class="number">0</span> <span class="keyword">THEN</span> </span><br><span class="line">      ROUND(DATA_FREE <span class="operator">/</span> (DATA_LENGTH <span class="operator">+</span> INDEX_LENGTH <span class="operator">+</span> DATA_FREE) <span class="operator">*</span> <span class="number">100</span>, <span class="number">2</span>) </span><br><span class="line">    <span class="keyword">ELSE</span> </span><br><span class="line">      <span class="number">0</span> </span><br><span class="line">  <span class="keyword">END</span> <span class="keyword">AS</span> Space_debris_rate,</span><br><span class="line">  (<span class="keyword">SELECT</span> ROUND(FILE_SIZE <span class="operator">/</span> (<span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span>), <span class="number">2</span>) </span><br><span class="line">   <span class="keyword">FROM</span> information_schema.innodb_tablespaces </span><br><span class="line">   <span class="keyword">WHERE</span> name <span class="operator">=</span> <span class="string">&#x27;demo1/example_table&#x27;</span>) <span class="keyword">AS</span> FILE_SIZE_GB</span><br><span class="line"><span class="keyword">FROM</span> information_schema.tables </span><br><span class="line"><span class="keyword">WHERE</span> table_schema <span class="operator">=</span> <span class="string">&#x27;demo1&#x27;</span> <span class="keyword">AND</span> table_name <span class="operator">=</span> <span class="string">&#x27;example_table&#x27;</span>;</span><br></pre></td></tr></table></figure><h3 id="5-7"><a href="#5-7" class="headerlink" title="5.7"></a>5.7</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span>  </span><br><span class="line">  table_name,</span><br><span class="line">  table_rows,</span><br><span class="line">  ROUND(data_length <span class="operator">/</span> (<span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span>), <span class="number">2</span>) <span class="keyword">AS</span> data_length_gb,</span><br><span class="line">  ROUND(index_length <span class="operator">/</span> (<span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span> <span class="operator">*</span> <span class="number">1024</span>), <span class="number">2</span>) <span class="keyword">AS</span> index_length_gb,</span><br><span class="line">  data_free,</span><br><span class="line">  <span class="keyword">CASE</span> </span><br><span class="line">    <span class="keyword">WHEN</span> (data_length <span class="operator">+</span> index_length <span class="operator">+</span> data_free) <span class="operator">&gt;</span> <span class="number">0</span> <span class="keyword">THEN</span> </span><br><span class="line">      ROUND(data_free <span class="operator">/</span> (data_length <span class="operator">+</span> index_length <span class="operator">+</span> data_free) <span class="operator">*</span> <span class="number">100</span>, <span class="number">2</span>) </span><br><span class="line">    <span class="keyword">ELSE</span> </span><br><span class="line">      <span class="number">0</span> </span><br><span class="line">  <span class="keyword">END</span> <span class="keyword">AS</span> space_debris_rate</span><br><span class="line"><span class="keyword">FROM</span> information_schema.tables </span><br><span class="line"><span class="keyword">WHERE</span> table_schema <span class="operator">=</span> <span class="string">&#x27;demo1&#x27;</span> <span class="keyword">AND</span> table_name <span class="operator">=</span> <span class="string">&#x27;example_table&#x27;</span>;</span><br></pre></td></tr></table></figure><h2 id="单个节点空间碎片率分析"><a href="#单个节点空间碎片率分析" class="headerlink" title="单个节点空间碎片率分析"></a>单个节点空间碎片率分析</h2><p>创建example_table，然后使用存储过程插入2千万行数据</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/1.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE example_table(</span><br><span class="line">    id INT AUTO_INCREMENT,</span><br><span class="line">    first_name VARCHAR(50),</span><br><span class="line">    last_name VARCHAR(50),</span><br><span class="line">    email VARCHAR(100),</span><br><span class="line">    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">    status ENUM(&#x27;active&#x27;, &#x27;inactive&#x27;) DEFAULT &#x27;active&#x27;,</span><br><span class="line">    PRIMARY KEY (id),</span><br><span class="line">    INDEX idx_last_name (last_name),</span><br><span class="line">    FULLTEXT INDEX ftx_first_name (first_name),</span><br><span class="line">    INDEX idx_status (status),</span><br><span class="line">    INDEX idx_created_at (created_at),</span><br><span class="line">    INDEX idx_first_name_last_name (first_name, last_name)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/2.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">DELIMITER //</span><br><span class="line"></span><br><span class="line">CREATE PROCEDURE InsertTwentyMillionRows()</span><br><span class="line">BEGIN</span><br><span class="line">    DECLARE v_max INT DEFAULT 20000000; -- 总行数</span><br><span class="line">    DECLARE v_batch_size INT DEFAULT 1000; -- 每次插入的行数：1000</span><br><span class="line">    DECLARE v_count INT DEFAULT 0; -- 当前插入的行数</span><br><span class="line"></span><br><span class="line">    START TRANSACTION;</span><br><span class="line"></span><br><span class="line">    -- 循环直到达到目标行数</span><br><span class="line">    WHILE v_count &lt; v_max DO</span><br><span class="line">        -- 插入1000行数据</span><br><span class="line">        INSERT INTO example_table (first_name, last_name, email, status)</span><br><span class="line">        SELECT</span><br><span class="line">            CONCAT(&#x27;FirstName&#x27;, LPAD((v_count * v_batch_size) + num, 7, &#x27;0&#x27;)) AS first_name,</span><br><span class="line">            CONCAT(&#x27;LastName&#x27;, LPAD((v_count * v_batch_size) + num, 7, &#x27;0&#x27;)) AS last_name,</span><br><span class="line">            CONCAT(&#x27;user&#x27;, LPAD((v_count * v_batch_size) + num, 7, &#x27;0&#x27;), &#x27;@example.com&#x27;) AS email,</span><br><span class="line">            CASE WHEN ((v_count * v_batch_size) + num) % 2 = 0 THEN &#x27;active&#x27; ELSE &#x27;inactive&#x27; END AS status</span><br><span class="line">        FROM (</span><br><span class="line">            SELECT a.num + (b.num * 10) AS num</span><br><span class="line">            FROM (</span><br><span class="line">                SELECT 0 AS num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9</span><br><span class="line">            ) a</span><br><span class="line">            CROSS JOIN (</span><br><span class="line">                SELECT 0 AS num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9</span><br><span class="line">            ) b</span><br><span class="line">        ) AS subquery;</span><br><span class="line"></span><br><span class="line">        -- 更新当前插入的行数</span><br><span class="line">        SET v_count = v_count + v_batch_size;</span><br><span class="line"></span><br><span class="line">        -- 每插入100000行数据，提交一次事务，避免事务过大导致性能问题</span><br><span class="line">        IF v_count % 100000 = 0 THEN</span><br><span class="line">            COMMIT;</span><br><span class="line">            START TRANSACTION;</span><br><span class="line">        END IF;</span><br><span class="line">    END WHILE;</span><br><span class="line"></span><br><span class="line">    COMMIT;</span><br><span class="line">END //</span><br><span class="line"></span><br><span class="line">DELIMITER ;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/3.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CALL InsertTwentyMillionRows();</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/4.avif"></p><p>查看information_schema.tables表中的信息</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/5.avif"></p><p>delete删除表中的所有数据，并使用上述sql查看碎片率</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/6.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/18.avif"></p><p>再次查看information_schema.tables表中的统计信息，没有变化，使用analyze更新统计信息</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/7.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/8.avif"></p><p>再次查看information_schema.tables表中的统计信息，发现已更新，这时在次使用上述sql查看碎片率，发现碎片率变到99.98%</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/9.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/10.avif"></p><p>最后使用optimize重建表后发现碎片率归0</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/11.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/12.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/13.avif"></p><p>这里有时执行optimize后data_free并不会完全归零，这是因为InnoDB 存储引擎在表空间中预留了一部分空间，用于未来的插入操作。这是为了提高插入性能，避免频繁的页分裂。即使表空间被重新组织，InnoDB 也会保留这部分预留空间，因此 data_free 不会完全归零。当然除了预留空间外，还可能包括未使用的页、表空间的最小单位、并发操作以及存储引擎的限制。</p><p>表空间和页的概念</p><ul><li><strong>表空间（Tablespace）</strong>：InnoDB 使用表空间来存储数据和索引。表空间是由一个或多个文件组成的，这些文件可以是单个文件（如 <code>ibdata1</code>）或多文件表空间（如 <code>.ibd</code> 文件）。表空间是 InnoDB 存储数据和索引的基本单位。</li><li><strong>页（Page）</strong>：页是表空间中存储数据和索引的基本单位，通常大小为 16 KB。每个页可以存储多行数据或索引条目。InnoDB 通过页来管理数据和索引的存储。</li></ul><p>预留空间的目的</p><p>InnoDB 在表空间中预留一部分空间的主要目的是为了优化插入操作和减少碎片化。以下是具体原因：</p><p>提高插入性能</p><ul><li><strong>预留空间</strong>：当表中插入新数据时，InnoDB 会尝试将新数据插入到预留空间中。预留空间的存在减少了频繁分配新页的需要，从而提高了插入操作的效率。</li><li><strong>减少页分裂</strong>：如果没有预留空间，插入操作可能会导致页分裂。页分裂是指一个页满了之后，InnoDB 会将页中的数据分成两部分，分别存储在两个新的页中。页分裂会增加碎片化，降低读写性能。预留空间可以减少页分裂的发生。</li></ul><p>减少碎片化</p><ul><li><strong>减少未使用空间</strong>：预留空间可以减少表空间中的未使用空间（<code>DATA_FREE</code>）。通过预留一部分空间，InnoDB 可以更有效地利用表空间，减少碎片化的产生。</li><li><strong>优化存储管理</strong>：预留空间有助于优化表空间的存储管理，减少表空间的碎片化，提高存储效率。</li></ul><h2 id="主从节点空间碎片率分析"><a href="#主从节点空间碎片率分析" class="headerlink" title="主从节点空间碎片率分析"></a>主从节点空间碎片率分析</h2><p>使用上述相同的方式插入2千万行数据，可以发现主节点和只读节点的空间碎片率和物理文件存在差异</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/14.avif"></p><p>在主节点执行analyze更新统计信息</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/15.avif"></p><p>这时碎片率有所上升，但是主和只读还是不完全相等</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/16.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20251011/17.avif"></p><h3 id="主库和只读实例的碎片率出现较大差异的原因分析"><a href="#主库和只读实例的碎片率出现较大差异的原因分析" class="headerlink" title="主库和只读实例的碎片率出现较大差异的原因分析"></a>主库和只读实例的碎片率出现较大差异的原因分析</h3><h4 id="复制原理与多线程复制"><a href="#复制原理与多线程复制" class="headerlink" title="复制原理与多线程复制"></a>复制原理与多线程复制</h4><ul><li>逻辑复制原理：MySQL 的逻辑复制是基于二进制日志（binlog）的。主库将数据变更操作记录到 binlog 中，从库通过 I&#x2F;O 线程读取主库的 binlog，并将其存储到本地的中继日志（relay log）中。然后，从库的 SQL 线程会读取 relay log 并应用这些变更。</li><li>多线程复制：为了提高复制效率，MySQL 支持多线程复制。在多线程复制中，从库可以使用多个 SQL 线程并行地应用 relay log 中的事件。这可以显著提高复制的性能，但也会引入一些复杂性。</li></ul><h4 id="多线程复制中的顺序问题"><a href="#多线程复制中的顺序问题" class="headerlink" title="多线程复制中的顺序问题"></a>多线程复制中的顺序问题</h4><ul><li>事务依赖性：在单线程复制中，SQL 线程会严格按照 binlog 中的顺序应用事件，确保数据的一致性。但在多线程复制中，多个 SQL 线程可能会并行地应用 relay log 中的事件。如果这些事件之间存在依赖关系（例如，一个 <code>INSERT</code> 操作依赖于之前的某个 <code>DELETE</code> 操作），并行应用可能会导致顺序发生变化。</li><li>分组提交：MySQL 的多线程复制支持分组提交（Group Commit），即将多个事件分组后并行提交。虽然 MySQL 会尽量保证分组内的事件顺序，但不同分组之间的事件顺序可能会发生变化。</li></ul><p>碎片率差异的原因</p><ul><li><code>INSERT</code> 和 <code>DELETE</code> 操作顺序变化：如果只读实例的 <code>INSERT</code> 和 <code>DELETE</code> 操作顺序与主库不同，可能会导致数据分布和索引结构的变化。例如，主库中先执行了一个 <code>DELETE</code> 操作，然后执行了一个 <code>INSERT</code> 操作，而只读实例中这两个操作的顺序相反，这可能会导致只读实例中的数据碎片率增加。</li><li>索引维护差异：<code>INSERT</code> 和 <code>DELETE</code> 操作会影响索引的维护。如果操作顺序不同，索引的分裂和合并操作也会不同，从而导致索引碎片率的差异。</li><li>并发写入和删除：在多线程复制中，多个线程可能会同时对同一个表进行写入和删除操作。如果这些操作的顺序不一致，可能会导致数据页的碎片化。例如，一个线程在某个数据页中插入了大量数据，而另一个线程在同一个数据页中删除了部分数据，这可能会导致数据页的碎片化。</li></ul></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/10/11/MySQL%E4%B8%AD%E7%9A%84%E7%A9%BA%E9%97%B4%E7%A2%8E%E7%89%87%E7%8E%87%E8%AE%A1%E7%AE%97%E5%88%86%E6%9E%90/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Miniflux – RSS 订阅</title>
      <link>https://blog.mingliangstar.com/2025/10/07/Miniflux-%E2%80%93-RSS-%E8%AE%A2%E9%98%85/</link>
      <guid>https://blog.mingliangstar.com/2025/10/07/Miniflux-%E2%80%93-RSS-%E8%AE%A2%E9%98%85/</guid>
      <pubDate>Tue, 07 Oct 2025 12:12:24 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;什么是Miniflux&quot;&gt;&lt;a href=&quot;#什么是Miniflux&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="什么是Miniflux"><a href="#什么是Miniflux" class="headerlink" title="什么是Miniflux"></a>什么是Miniflux</h2><p>Miniflux 是一个用 Go 写的极简开源 RSS 阅读器，单二进制 +内建 Web UI，五分钟就能容器化跑起来；它默认 Fever API、内存占用极低，界面干净无广告，适合只想安静看文章、不想折腾样式插件的极简党。</p><h3 id="核心功能与特点"><a href="#核心功能与特点" class="headerlink" title="核心功能与特点"></a>核心功能与特点</h3><ul><li>极简设计 ：功能精简，专注于核心阅读体验。</li><li>高性能 ：基于 Go 语言开发，单二进制文件，无依赖。</li><li>轻量且快速 ：资源占用低，响应迅速。</li><li>现代技术栈 ：使用现代 JavaScript（ES6 和 Fetch API），无复杂框架。</li><li>单一数据库支持 ：仅支持 PostgreSQL，确保数据一致性和性能。</li><li>易于安装 ：提供 Docker 镜像，一键部署。</li></ul><h3 id="适用场景"><a href="#适用场景" class="headerlink" title="适用场景"></a>适用场景</h3><ul><li>极简主义爱好者：追求简洁、高效的新闻阅读体验。</li><li>开发者：通过 API 集成到其他应用中。</li><li>低资源环境：在树莓派等低性能设备上运行。</li></ul><h3 id="官方地址"><a href="#官方地址" class="headerlink" title="官方地址"></a>官方地址</h3><ul><li>官方网站：<a href="https://images.mingliangstar.com/go/?url=https://miniflux.app/">https://miniflux.app</a></li><li>GitHub 仓库：<a href="https://github.com/miniflux/v2">https://github.com/miniflux/v2</a></li></ul><h2 id="前提条件"><a href="#前提条件" class="headerlink" title="前提条件"></a>前提条件</h2><p>在开始部署之前，请确保你的系统已经安装了 Docker 和 Docker Compose。如果尚未安装，请参考Eucalyptus写的<a href="https://images.mingliangstar.com/go/?url=https://blog.csdn.net/weixin_72610956/article/details/131507884">Centos7下安装Docker-CSDN博客</a> ，</p><h2 id="创建-Docker-Compose-配置文件"><a href="#创建-Docker-Compose-配置文件" class="headerlink" title="创建 Docker Compose 配置文件"></a>创建 Docker Compose 配置文件</h2><h3 id="命令行部署"><a href="#命令行部署" class="headerlink" title="命令行部署"></a>命令行部署</h3><p>首先登录你部署Miniflux的服务器，然后创建个docker-compose.yml文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">services:</span><br><span class="line">  miniflux:</span><br><span class="line">    image: miniflux/miniflux:latest</span><br><span class="line">    ports:</span><br><span class="line">      - <span class="string">&quot;80:8080&quot;</span></span><br><span class="line">    depends_on:</span><br><span class="line">      db:</span><br><span class="line">        condition: service_healthy</span><br><span class="line">    environment:</span><br><span class="line">      - DATABASE_URL=postgres://miniflux:admin@123@db/miniflux?sslmode=<span class="built_in">disable</span></span><br><span class="line">      - RUN_MIGRATIONS=1</span><br><span class="line">      - CREATE_ADMIN=1</span><br><span class="line">      - ADMIN_USERNAME=admin</span><br><span class="line">      - ADMIN_PASSWORD=admin@123</span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;/usr/bin/miniflux&quot;</span>, <span class="string">&quot;-healthcheck&quot;</span>, <span class="string">&quot;auto&quot;</span>]</span><br><span class="line"></span><br><span class="line">  db:</span><br><span class="line">    image: postgres:17-alpine</span><br><span class="line">    environment:</span><br><span class="line">      - POSTGRES_USER=miniflux          <span class="comment"># 与 DATABASE_URL 用户一致</span></span><br><span class="line">      - POSTGRES_PASSWORD=admin@123</span><br><span class="line">      - POSTGRES_DB=miniflux</span><br><span class="line">    volumes:</span><br><span class="line">      - miniflux-db:/var/lib/postgresql/data   <span class="comment"># 官方默认路径</span></span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;pg_isready&quot;</span>, <span class="string">&quot;-U&quot;</span>, <span class="string">&quot;miniflux&quot;</span>]  <span class="comment"># 用户一致</span></span><br><span class="line">      interval: 10s</span><br><span class="line">      start_period: 30s</span><br><span class="line"></span><br><span class="line">volumes:</span><br><span class="line">  miniflux-db:</span><br></pre></td></tr></table></figure><p>接下来再当前目录下直接执行下述命令即可</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure><p><img src="https://images.mingliangstar.com/images/20251007/1.avif"></p><h3 id="宝塔可视化部署"><a href="#宝塔可视化部署" class="headerlink" title="宝塔可视化部署"></a>宝塔可视化部署</h3><p>当然也可完全使用宝塔可视化部署，在宝塔中的docker容器编排这里部署</p><p><img src="https://images.mingliangstar.com/images/20251007/2.avif"></p><p><img src="https://images.mingliangstar.com/images/20251007/3.avif"></p><p>compose内容</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">version: <span class="string">&quot;3.9&quot;</span></span><br><span class="line"></span><br><span class="line">services:</span><br><span class="line">  miniflux:</span><br><span class="line">    image: miniflux/miniflux:latest</span><br><span class="line">    ports:</span><br><span class="line">      - <span class="string">&quot;<span class="variable">$&#123;MINIFLUX_PORT&#125;</span>:8080&quot;</span>          <span class="comment"># ← 变量</span></span><br><span class="line">    depends_on:</span><br><span class="line">      db:</span><br><span class="line">        condition: service_healthy</span><br><span class="line">    environment:</span><br><span class="line">      - DATABASE_URL=postgres://<span class="variable">$&#123;DB_USER&#125;</span>:<span class="variable">$&#123;DB_PASS&#125;</span>@db/<span class="variable">$&#123;DB_NAME&#125;</span>?sslmode=<span class="built_in">disable</span></span><br><span class="line">      - RUN_MIGRATIONS=1</span><br><span class="line">      - CREATE_ADMIN=1</span><br><span class="line">      - ADMIN_USERNAME=<span class="variable">$&#123;ADMIN_USER&#125;</span></span><br><span class="line">      - ADMIN_PASSWORD=<span class="variable">$&#123;ADMIN_PASS&#125;</span></span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;/usr/bin/miniflux&quot;</span>, <span class="string">&quot;-healthcheck&quot;</span>, <span class="string">&quot;auto&quot;</span>]</span><br><span class="line"></span><br><span class="line">  db:</span><br><span class="line">    image: postgres:17-alpine</span><br><span class="line">    environment:</span><br><span class="line">      - POSTGRES_USER=<span class="variable">$&#123;DB_USER&#125;</span></span><br><span class="line">      - POSTGRES_PASSWORD=<span class="variable">$&#123;DB_PASS&#125;</span></span><br><span class="line">      - POSTGRES_DB=<span class="variable">$&#123;DB_NAME&#125;</span></span><br><span class="line">    volumes:</span><br><span class="line">      - miniflux-db:/var/lib/postgresql/data</span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;pg_isready&quot;</span>, <span class="string">&quot;-U&quot;</span>, <span class="string">&quot;<span class="variable">$&#123;DB_USER&#125;</span>&quot;</span>]</span><br><span class="line">      interval: 10s</span><br><span class="line">      start_period: 30s</span><br><span class="line"></span><br><span class="line">volumes:</span><br><span class="line">  miniflux-db:</span><br></pre></td></tr></table></figure><p>.env内容</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Miniflux 外部端口</span></span><br><span class="line">MINIFLUX_PORT=80</span><br><span class="line"></span><br><span class="line"><span class="comment"># 数据库三要素</span></span><br><span class="line">DB_USER=miniflux</span><br><span class="line">DB_PASS=admin@123</span><br><span class="line">DB_NAME=miniflux</span><br><span class="line"></span><br><span class="line"><span class="comment"># 管理员账号</span></span><br><span class="line">ADMIN_USER=admin</span><br><span class="line">ADMIN_PASS=admin@123</span><br></pre></td></tr></table></figure><h3 id="Miniflux订阅RSS"><a href="#Miniflux订阅RSS" class="headerlink" title="Miniflux订阅RSS"></a>Miniflux订阅RSS</h3><p>到这里Miniflux已经部署完成了，接下来在浏览器访问<code>http://&lt;IP&gt;:80</code>即可，ip使用你部署Miniflux服务器的公网ip，Miniflux的用户是admin，密码是admin@123，pg的用户名是miniflux，密码是admin@123</p><p>输入Miniflux密码进行登录</p><p><img src="https://images.mingliangstar.com/images/20251007/4.avif"></p><p>刚进去的是英文界面，可以在set设置简体中文</p><p><img src="https://images.mingliangstar.com/images/20251007/5.avif"></p><p>然后添加订阅源，输入你要订阅BLOG的RSS地址例如：<code>https://mingliang.net.cn/feed/</code></p><p><img src="https://images.mingliangstar.com/images/20251007/6.avif"></p><p>然后就可以看到BLOG的文章内容了</p><p><img src="https://images.mingliangstar.com/images/20251007/7.avif"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>到这里Miniflux就完成了部署并且订阅了Blog的RSS，整个过程仅需几分钟就能搭建起一个轻量高效的RSS阅读平台，你可以通过网页端随时随地获取最新内容更新，无需担心广告干扰或算法推荐；如果你不方便自行部署的话，可以_<strong>留言申请Eucalyptus</strong>_部署的Miniflux服务的用户名进行体验，我们提供免费的测试账号供你试用一周，期间你可以完整体验Miniflux的所有功能，包括多设备同步、快捷键操作、文章收藏等特色功能，感受这款开源RSS阅读器的简洁与高效。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/RSS/">RSS</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/RSS/">RSS</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/10/07/Miniflux-%E2%80%93-RSS-%E8%AE%A2%E9%98%85/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>PostgreSQL编译安装教程</title>
      <link>https://blog.mingliangstar.com/2025/09/29/PostgreSQL%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</link>
      <guid>https://blog.mingliangstar.com/2025/09/29/PostgreSQL%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</guid>
      <pubDate>Mon, 29 Sep 2025 03:14:05 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h1 id=&quot;系统环境&quot;&gt;&lt;a href=&quot;#系统环境&quot; class=&quot;headerlink&quot; title=&quot;系统环境&quot;&gt;&lt;/a&gt;系统环境&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;操作系统：CentOS</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h1 id="系统环境"><a href="#系统环境" class="headerlink" title="系统环境"></a>系统环境</h1><ul><li>操作系统：CentOS 7.6.1810</li><li>PostgreSQL版本： 16.0</li></ul><h1 id="下载压缩包"><a href="#下载压缩包" class="headerlink" title="下载压缩包"></a>下载压缩包</h1><p>官网地址：<a href="https://www.postgresql.org/ftp/source/">PostgreSQL: File Browser</a></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/1.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/2.avif"></p><h2 id="下载压缩包-1"><a href="#下载压缩包-1" class="headerlink" title="下载压缩包"></a>下载压缩包</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://ftp.postgresql.org/pub/source/v16.0/postgresql-16.0.tar.gz</span><br></pre></td></tr></table></figure><h2 id="解压压缩包"><a href="#解压压缩包" class="headerlink" title="解压压缩包"></a>解压压缩包</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -xzvf  postgresql-16.0.tar.gz</span><br></pre></td></tr></table></figure><h2 id="查看解压文件"><a href="#查看解压文件" class="headerlink" title="查看解压文件"></a>查看解压文件</h2><p>解压之后会看到下面的文件</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/3.avif"></p><h1 id="编译安装"><a href="#编译安装" class="headerlink" title="编译安装"></a>编译安装</h1><h2 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h2><p>进入postgresql-16.0目录，编译configure文件</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/4.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./configure --prefix=/usr/local/pgsql</span><br></pre></td></tr></table></figure><p>参数：–prefix&#x3D;&#x2F;usr&#x2F;local&#x2F;pgsql<br>表示编译好的文件放到目录”&#x2F;usr&#x2F;local&#x2F;pgsql”里，这个目录不用用户自己创建，编译过程会自动创建。</p><p>注意事项：</p><p>PostgreSQL编译过程会用到一些依赖的库，如果你的操作系统比较旧，编译过程可能会出现错误，告诉你要安装缺少的依赖库。</p><p>看到.&#x2F;config.status说明编译完成，可以看见config.status文件</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/5.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/6.avif"></p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make &amp;&amp; make install</span><br></pre></td></tr></table></figure><p>完成以后，在”–prefix&#x3D;&#x2F;usr&#x2F;local&#x2F;pgsql”参数对应的”&#x2F;usr&#x2F;local&#x2F;pgsql”的目录就是我们所有PostgreSQL存放的文件，这里的这个data和log文件现在是没有的。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/7.avif"></p><h1 id="用户权限和环境变量设置"><a href="#用户权限和环境变量设置" class="headerlink" title="用户权限和环境变量设置"></a>用户权限和环境变量设置</h1><p>编译安装成功后，接下来要做的就是创建一个普通用户，因为默认Linux超级用户（root）不能启动PostgreSQL，所以需要创建一个普通用户来操作数据库。</p><h2 id="创建用户"><a href="#创建用户" class="headerlink" title="创建用户"></a>创建用户</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">#创建用户组postgres</span><br><span class="line">groupadd postgres</span><br><span class="line">#创建用户postgres并设置groups、gid和家目录</span><br><span class="line">useradd -g postgres -G postgres -d /home/postgresql postgres </span><br><span class="line">#设置用户密码</span><br><span class="line">passwd postgres</span><br></pre></td></tr></table></figure><h2 id="创建数据目录和日志目录"><a href="#创建数据目录和日志目录" class="headerlink" title="创建数据目录和日志目录"></a>创建数据目录和日志目录</h2><p>注意当前路径是在&#x2F;usr&#x2F;local&#x2F;pgsql下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir data log</span><br></pre></td></tr></table></figure><h2 id="设置权限"><a href="#设置权限" class="headerlink" title="设置权限"></a>设置权限</h2><p>接下来需要设置权限，将&#x2F;usr&#x2F;local&#x2F;pgsql (我们安装PostgreSQL数据库的目录) 目录全部赋权给postgres用户</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chown -R postgres.postgres /usr/local/pgsql/</span><br></pre></td></tr></table></figure><h2 id="设置环境变量"><a href="#设置环境变量" class="headerlink" title="设置环境变量"></a>设置环境变量</h2><p>为了方便起见设置一下相关的环境变量，此处是要设置postgres用户的环境变量，所以首先要把Linux的登陆用户由root切换到以postgres用户登陆。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">su - postgres</span><br></pre></td></tr></table></figure><p>因为我们创建Linux用户”postgres”是指定了用户的目为”&#x2F;home&#x2F;postgresql”，所以登陆后显示的目录是：&#x2F;home&#x2F;postgresql</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/8.avif"></p><p>要创建环境变量，实际上就是对文件.bash_profile的修改，所以我们首先要找到这个文件，这个文件就在”&#x2F;home&#x2F;postgresql”里，由于这个文件是隐藏文件所以要加-a参数</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ll -a</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/9.avif"></p><p>编辑.bash_profile文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim .bash_profile</span><br></pre></td></tr></table></figure><p>添加下面的内容</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/10.avif"></p><p>使配置的环境变量生效</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source /home/postgresql/.bash_profile</span><br></pre></td></tr></table></figure><p>检查是否生效</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -V</span><br></pre></td></tr></table></figure><p>看到安装PostgreSQL的版本号则代表生效</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/11.avif"></p><h1 id="初始化数据库"><a href="#初始化数据库" class="headerlink" title="初始化数据库"></a>初始化数据库</h1><p>新安装的PostgreSQL数据库系统，要先初始化基本的基础数据库，然后我们才能在上面创建我们自己的数据库。初始化数据库的指令是”initdb”，这个指令位于”&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;bin&#x2F;“</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/12.avif"></p><p>我们可以用指令”initdb –help”看看这个文件的帮助信息。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/13.avif"></p><p>如上图，可以看到在使用”initdb”进行初始化的时，可以指定参数进行一些初始化工作，例如指定pgdata（postgresql数据库目录）、指定encoding（编码）、指定数据库超级用户的用户名和密码等等。注意，如果pgdata目录没有指定，则会默认使用环境变量中的PGDATA指定的目录作为数据库存放的目录，由于之前我们刚刚设置了”PGDATA&#x3D;&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;data”环境变量，所以此处我们也就无需再额外指定，直接执行初始化命令即可。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">initdb</span><br></pre></td></tr></table></figure><p>若是执行initdb看到下面报错，说明现在登陆的不是postgres用户，需要切换到postgres用户来执行initdb命令</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/14.avif"></p><p>看到下面信息就代表成功</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/15.avif"></p><p>同时在”&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;data]”的目录可以看到生成的数据和配置文件等。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/16.avif"></p><ol><li>base目录是表空间目录</li><li>global目录是相关全局变量的目录</li><li>pg_hba.conf是访问控制配置，127.0.0.1改为信任的客户端ip网段使其可以远程访问</li><li>postgresql.conf是PostgreSQL主配置文件，”listen_address&#x3D;localhost”改为”*”使其监听整个网络，方便起见我这里将pg_hba.conf的ip地址修改为0.0.0.0&#x2F;0，而加密方式改为md5，就表示需要密码访问，算是提供一个最低级的安全防护</li></ol><h1 id="数据库访问控制配置文件"><a href="#数据库访问控制配置文件" class="headerlink" title="数据库访问控制配置文件"></a>数据库访问控制配置文件</h1><p>主要是配置postgresql.conf 和 pg_hba.conf 个。</p><ol><li>postgresql.conf 针对实例的配置</li><li>pg_hba.conf 针对数据库访问的控制</li></ol><h2 id="postgresql-conf"><a href="#postgresql-conf" class="headerlink" title="postgresql.conf"></a>postgresql.conf</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim postgresql.conf</span><br></pre></td></tr></table></figure><p>找到”#port”和”#listener_address”这两个参数，这两个参数是相邻的，将两行行首的”#”删除。<br>将”listen_addressee&#x3D;’localhost’”改为当前服务器的IP，如果改为</p><p>“listen_addressee&#x3D;’*’”，将监听整个网络。<br>默认的监听端口是5432，可以自行指定另外一个端口号。<br>max_connections是客户端最大的连接数， 缺省值100有点少，特别是业务系统，可以调整成1000或者更高。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/17.avif"></p><h2 id="pg-hba-conf"><a href="#pg-hba-conf" class="headerlink" title="pg_hba.conf"></a>pg_hba.conf</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim pg_hba.conf</span><br></pre></td></tr></table></figure><p>将红框设置为 10.10.100.0&#x2F;24，意思是10.10.100网段的IP 连接此服务器上的PostgreSQL. 如果想允许所有IP都可以连接此服务器，则可以配置成0.0.0.0&#x2F;0，但这样是不安全的，可以把trust改为md5，表示需要密码访问，算是提供一个最低级的安全防护。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/18.avif"></p><h1 id="PostgreSQL启动与关闭"><a href="#PostgreSQL启动与关闭" class="headerlink" title="PostgreSQL启动与关闭"></a>PostgreSQL启动与关闭</h1><h2 id="手动"><a href="#手动" class="headerlink" title="手动"></a>手动</h2><p>启动与关闭数据库是执行pg_ctl命令，在执行时，需要指定数据库路径和日志文件路径，格式如下。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pg_ctl -D &lt;数据存放路径&gt; -l &lt;日志文件路径&gt; [ stop | start ]</span><br></pre></td></tr></table></figure><p>如果已经指定了环境变量PGDATA，”数据存放路径”参数可以省略。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pg_ctl -D /usr/local/pgsql/data -l /usr/local/pgsql/log/pg_server.log start</span><br></pre></td></tr></table></figure><h2 id="自动"><a href="#自动" class="headerlink" title="自动"></a>自动</h2><p>此步骤需要root用户操作，如果你是用PostgreSQL的用户postgres登陆的话，要用exit指令退出，回到root登陆才能操作。<br>PostgreSQL解压后的安装包目录中提供了数据库启动与关闭的脚本，此脚本不但可以帮助我们简化操作，而且可以用作开机启动的脚本和service&#x2F;systemctl 控制服务的脚本。目录里”linux”文件就是我们要找的文件。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/19.avif"></p><p>如果找不到linux文件可以执行下面命令查看</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find / -name macos</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/20.avif"></p><p>把文件”linux”拷贝到目录”etc&#x2F;init.d&#x2F;“下，并改名为postgresql。<br>把脚本文件”postgresql”加入到开机启动的程序列表。<br>赋予”postgresql”文件有执行的权限。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cp /opt/postgresql/postgresql-16.0/contrib/start-scripts/linux /etc/init.d/postgresql</span><br><span class="line">chkconfig --add postgresql或者systemctl enable postgresql</span><br><span class="line">chmod 755 /etc/init.d/postgresql</span><br></pre></td></tr></table></figure><p>主要设置文件”postgresql”的四个变量的值。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/init.d/postgresql</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/21.avif"></p><p>prefix 是软件的安装路径<br>PGDATA 是数据存放路径<br>PGUSER 是启动PostgreSQL服务器的用户<br>PGLOG 是日志文件</p><p>以后可以开机启动和通过service命令控制启动和关闭了。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service postgresql start/stop</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/22.avif"></p><h1 id="客户端测试连接"><a href="#客户端测试连接" class="headerlink" title="客户端测试连接"></a>客户端测试连接</h1><p>可以通过PostgreSQL自带的客户端工具程序psql来进行连接，这个psql指令文件位于&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;bin目录下，因为我们做了变量环境设置，所以可以在任何目录下直接输入psql连接PostgreSQL服务器。温馨提示：用客户端程序psql连接数据库前，要把当前Linux登陆用户从root切换到postgres用户，这个是我们创建的PostgreSQL的超级用户。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">su - postgres</span><br><span class="line">psql</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/23.avif"></p><p>可以看到，已经连接上了数据库服务器。</p><h2 id="设置用户postgres密码"><a href="#设置用户postgres密码" class="headerlink" title="设置用户postgres密码"></a>设置用户postgres密码</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">postgres=# \password</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/24.avif"></p><p>命令”\l”是显示数据库。更多的SQL操作命令可以参考PostgreSQL的官方文档。退出pgsql客户端命令是”\q”或者exit</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/25.avif"></p><h1 id="DBeaver连接测试"><a href="#DBeaver连接测试" class="headerlink" title="DBeaver连接测试"></a>DBeaver连接测试</h1><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/26.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/PostgreSQL/20250929/27.avif"></p><p>测试连接成功</p><p>PostgreSQL安装到此完毕。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/PostgreSQL/">PostgreSQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/PostgreSQL/">PostgreSQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/09/29/PostgreSQL%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL抛出的Public Key Retrieval is not allowed</title>
      <link>https://blog.mingliangstar.com/2025/09/10/MySQL%E6%8A%9B%E5%87%BA%E7%9A%84Public-Key-Retrieval-is-not-allowed/</link>
      <guid>https://blog.mingliangstar.com/2025/09/10/MySQL%E6%8A%9B%E5%87%BA%E7%9A%84Public-Key-Retrieval-is-not-allowed/</guid>
      <pubDate>Wed, 10 Sep 2025 06:37:45 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;有时候在连接实例的时候会遇到这样的报错&lt;strong&gt;Public Key Retrieval is not allowed&lt;/strong&gt;&lt;/p&gt;
&lt;!-- 这是一张图片，ocr 内容为：</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>有时候在连接实例的时候会遇到这样的报错<strong>Public Key Retrieval is not allowed</strong></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250910/1.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250910/2.avif"></p><h2 id="问题分析"><a href="#问题分析" class="headerlink" title="问题分析"></a>问题分析</h2><p>这是因为账号使用了caching_sha2_password 密码插件</p><p>而caching_sha2_password 插件为了加快认证过程，在服务端维护了一个<strong>密码哈希缓存</strong>。当客户端发起连接时：</p><ul><li><em><strong>如果用户的密码哈希已经被缓存，服务端可以直接验证，无需客户端发送明文密码进行验证。</strong></em></li><li><em><strong>如果缓存中没有该用户的密码哈希，则客户端需要发送明文密码进行认证。</strong></em></li></ul><p>在发送明文密码时，出于安全考虑，MySQL 要求：</p><ul><li>要么客户端和服务端之间建立 SSL 加密连接。</li><li>要么客户端允许通过服务端公钥加密明文密码。</li></ul><p>如果两者都不满足，就会抛出 Public Key Retrieval is not allowed 错误。</p><p>以下三种情况会导致缓存中没有用户的密码哈希</p><ul><li>发生重启</li><li>发生HA</li><li>有操作flush privileges</li></ul><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250910/3.avif"></p><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><p>1、客户端的话可以设置驱动中的allowPublicKeyRetrieval&#x3D;true</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250910/4.avif"></p><p>2、JDBC的话可以在连接字符串中添加allowPublicKeyRetrieval&#x3D;true参数，以允许公钥检索。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jdbc:mysql://localhost:3306/?allowPublicKeyRetrieval=true</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250910/5.avif"></p><p>3、将账号的密码插件改为mysql_native_password</p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>设置allowPublicKeyRetrieval&#x3D;true的方法会自动从 MySQL 服务端获取 RSA 公钥，但这种方法有一定的安全风险，可能会受到中间人攻击。攻击者可以伪造 RSA 公钥，窃取用户密码。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/09/10/MySQL%E6%8A%9B%E5%87%BA%E7%9A%84Public-Key-Retrieval-is-not-allowed/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Wordpress登录页面DIY</title>
      <link>https://blog.mingliangstar.com/2025/09/01/%E7%99%BB%E5%BD%95%E9%A1%B5%E9%9D%A2DIY/</link>
      <guid>https://blog.mingliangstar.com/2025/09/01/%E7%99%BB%E5%BD%95%E9%A1%B5%E9%9D%A2DIY/</guid>
      <pubDate>Mon, 01 Sep 2025 12:37:45 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>由于部分WordPress主题在默认配置下没有对后台登录界面进行定制化开发，用户只能使用系统自带的原生登录页面，这种页面往往设计简陋、缺乏品牌特色，与网站整体风格格格不入，影响了用户体验和品牌形象；为此，我通过深入研究WordPress的login_head和login_footer钩子，对原生登录页面进行了全面的二次开发，不仅替换了默认的WordPress logo为网站品牌标识，还重新设计了登录表单的布局和配色方案，增加了背景图片和CSS3动画效果，同时优化了移动端的响应式布局，使登录页面与网站主题风格完美统一，大大提升了后台管理的专业性和视觉体验。</p><blockquote><p>源码下载地址：<a href="https://images.mingliangstar.com/go/?url=https://gitcode.com/weixin_72610956/Blog/tree/login">https://gitcode.com/weixin_72610956&#x2F;Blog&#x2F;tree&#x2F;login</a></p></blockquote><p><img src="https://images.mingliangstar.com/images/20250901/1.avif"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#下述了两个代码文件均放置到主题目录下的自建self-innovate文件中</span></span><br><span class="line">login-style.php</span><br><span class="line">login-style.css</span><br></pre></td></tr></table></figure><p>核心代码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">/**</span><br><span class="line"> * 登录页美化（Logo 完全禁用点击）</span><br><span class="line"> */</span><br><span class="line">add_action( &#x27;login_enqueue_scripts&#x27;, function () &#123;</span><br><span class="line">    wp_enqueue_style( &#x27;my-login&#x27;, get_theme_file_uri( &#x27;/self-innovate/login-style.css&#x27; ), [], &#x27;1.0.0&#x27; );</span><br><span class="line">&#125; );</span><br><span class="line"></span><br><span class="line">/* 完全移除 &lt;a&gt; 的 href，避免刷新 */</span><br><span class="line">add_filter( &#x27;login_headerurl&#x27;, function () &#123;</span><br><span class="line">    return &#x27;javascript:void(0);&#x27;;   // 真正无动作</span><br><span class="line">&#125; );</span><br><span class="line"></span><br><span class="line">/* 悬停文字留空，防止提示 */</span><br><span class="line">add_filter( &#x27;login_headertext&#x27;, &#x27;__return_empty_string&#x27; );</span><br></pre></td></tr></table></figure><p>下述是css代码，需替换css中body.login和login::before的background:url(”)路径</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line">/* 1. 背景与斜遮罩 */</span><br><span class="line">body.login&#123;</span><br><span class="line">  height:100vh;</span><br><span class="line">  margin:0;</span><br><span class="line">  display:flex;</span><br><span class="line">  align-items:center;</span><br><span class="line">  justify-content:center;</span><br><span class="line">  background:url(<span class="string">&#x27;https://mingliang.net.cn/wp-content/uploads/2025/05/16-scaled.jpg&#x27;</span>) center/cover no-repeat;</span><br><span class="line">  position:relative;</span><br><span class="line">&#125;</span><br><span class="line">body.login::before&#123;</span><br><span class="line">  content:<span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  position:absolute;</span><br><span class="line">  inset:0;</span><br><span class="line">  background:linear-gradient(-75deg, transparent 0% 50%, rgba(255,255,255,.6) 50% 100%);</span><br><span class="line">  z-index:1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* 2. 登录框整体定位与 Logo */</span><br><span class="line"><span class="comment">#login&#123;</span></span><br><span class="line">  position:relative;</span><br><span class="line">  z-index:2;</span><br><span class="line">  width:340px;</span><br><span class="line">  padding:40px 40px 40px; /* 40px+140px空间已含在顶部padding */</span><br><span class="line">  padding-top:140px;      /* 给Logo留空间 */</span><br><span class="line">  margin-left:150px;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">#login::before&#123;           /* Logo伪元素 */</span></span><br><span class="line">  content:<span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  position:absolute;</span><br><span class="line">  top:20px;</span><br><span class="line">  left:50%;</span><br><span class="line">  transform:translateX(-50%);</span><br><span class="line">  width:160px;</span><br><span class="line">  aspect-ratio:1;</span><br><span class="line">  background:url(<span class="string">&#x27;https://images.mingliangstar.com/logo/logo1.avif?imageslim&#x27;</span>) center/contain no-repeat;</span><br><span class="line">  pointer-events:none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* 3. 表单 */</span><br><span class="line">body.login form#loginform&#123;</span><br><span class="line">  margin:24px 0 !important;</span><br><span class="line">  padding:26px 24px !important;</span><br><span class="line">  box-shadow:0 1px 3px rgba(0,0,0,.04) !important;</span><br><span class="line">  background:transparent !important;</span><br><span class="line">  border:none !important;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* 4. 文字Logo */</span><br><span class="line">.login h1 a&#123;</span><br><span class="line">  background:none !important;</span><br><span class="line">  text-indent:0;</span><br><span class="line">  width:auto;</span><br><span class="line">  height:auto;</span><br><span class="line">  font:700 24px/1.2 sans-serif;</span><br><span class="line">  color:#333;</span><br><span class="line">  margin-bottom:24px;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* 5. 输入框 */</span><br><span class="line">.login form .input&#123;</span><br><span class="line">  border:1px solid <span class="comment">#e1e5e9;</span></span><br><span class="line">  border-radius:8px;</span><br><span class="line">  padding:12px 16px;</span><br><span class="line">  font-size:15px;</span><br><span class="line">  transition:border-color .3s, box-shadow .3s;</span><br><span class="line">&#125;</span><br><span class="line">.login form .input:focus&#123;</span><br><span class="line">  border-color:#667eea;</span><br><span class="line">  box-shadow:0 0 0 2px rgba(102,126,234,.25);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* 6. 按钮 */</span><br><span class="line">.wp-core-ui .button-primary&#123;</span><br><span class="line">  width:100%;</span><br><span class="line">  border:none;</span><br><span class="line">  border-radius:30px;</span><br><span class="line">  padding:12px 0;</span><br><span class="line">  font:600 16px/1 sans-serif;</span><br><span class="line">  background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);</span><br><span class="line">  transition:transform .3s;</span><br><span class="line">&#125;</span><br><span class="line">.wp-core-ui .button-primary:hover&#123;</span><br><span class="line">  transform:translateY(-2px);</span><br><span class="line">  box-shadow:0 6px 20px rgba(102,126,234,.45);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/* 7. 隐藏语言切换 */</span><br><span class="line"><span class="comment">#language-switcher&#123;display:none !important;&#125;</span></span><br></pre></td></tr></table></figure><p>最后需再functions.php中调用该模块</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">require_once get_theme_file_path( <span class="string">&#x27;/self-innovate/login-style.php&#x27;</span> );</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/">Wordpress</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/09/01/%E7%99%BB%E5%BD%95%E9%A1%B5%E9%9D%A2DIY/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>20250831主题友链页面自研</title>
      <link>https://blog.mingliangstar.com/2025/08/31/Meteor%E4%B8%BB%E9%A2%98%E5%8F%8B%E9%93%BE%E9%A1%B5%E9%9D%A2%E8%87%AA%E7%A0%94/</link>
      <guid>https://blog.mingliangstar.com/2025/08/31/Meteor%E4%B8%BB%E9%A2%98%E5%8F%8B%E9%93%BE%E9%A1%B5%E9%9D%A2%E8%87%AA%E7%A0%94/</guid>
      <pubDate>Sun, 31 Aug 2025 13:47:25 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>20250831主题虽然设计简约现代，但由于缺乏原生的友情链接管理功能，许多博主只能将友情链接勉强添加在网站底部，这不仅影响页面美观，也不便于访客查找和互动；为了解决这一痛点，本博主对主题进行了深度二次开发，专门打造了一个独立的友情链接页面，该页面不仅实现了友链分类展示、图文混排等基本功能，更创新性地开发了前端提交表单，允许其他站长直接在线提交申请，同时配套开发了完善的后台审核系统，管理员可以便捷地查看申请信息、审核状态，并一键通过或拒绝，整个流程实现了自动化闭环管理，大大提升了友链交换的效率和用户体验。</p><blockquote><p>源码下载地址：<a href="https://images.mingliangstar.com/go/?url=https://gitcode.com/weixin_72610956/Blog/tree/link">https://gitcode.com/weixin_72610956&#x2F;Blog&#x2F;tree&#x2F;link</a></p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">default-avatar.jpg</span><br><span class="line">page-links.css</span><br><span class="line">page-links.js</span><br><span class="line">pending-links.php</span><br></pre></td></tr></table></figure><p>以下是核心代码部分，这段代码实现了系统的关键功能，</p><p>并且这里对友链头像有三个判断的逻辑</p><ul><li>有头像 → 正常显示；</li><li>无头像 → 立即显示默认头像；</li><li>有头像但 3 秒仍未加载完成 → 自动替换成默认头像。</li></ul><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Template Name: 友情链接</span></span><br><span class="line"><span class="comment"> * Description:  极简友链模板（样式/脚本已分离，含评论）</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">get_header</span>(); </span><br><span class="line"><span class="meta">?&gt;</span></span><br><span class="line"></span><br><span class="line">&lt;div <span class="class"><span class="keyword">class</span>=&quot;<span class="title">hero</span>-<span class="title">title</span>&quot;&gt;</span></span><br><span class="line"><span class="class">  &lt;?<span class="title">php</span> <span class="title">the_title</span>( &#x27;&lt;<span class="title">h1</span>&gt;&#x27;, &#x27;&lt;/<span class="title">h1</span>&gt;&#x27; ); ?&gt;</span></span><br><span class="line"><span class="class">  &lt;<span class="title">p</span> <span class="title">class</span>=&quot;<span class="title">hero</span>-<span class="title">sub</span>&quot;&gt;欢迎交换友链 · 携手点亮彼此的星空&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line"><span class="class">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">&lt;!-- 载入独立样式 --&gt;</span></span><br><span class="line"><span class="class">&lt;<span class="title">link</span> <span class="title">rel</span>=&quot;<span class="title">stylesheet</span>&quot; <span class="title">href</span>=&quot;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">get_template_directory_uri</span>(); ?&gt;/<span class="title">self</span>-<span class="title">innovate</span>/<span class="title">page</span>-<span class="title">links</span>.<span class="title">css</span>&quot;&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">&lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">page</span>-<span class="title">links</span>&quot;&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">  &lt;!-- 搜索框 --&gt;</span></span><br><span class="line"><span class="class">  &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">link</span>-<span class="title">search</span>&quot;&gt;</span></span><br><span class="line"><span class="class">    &lt;<span class="title">input</span> <span class="title">type</span>=&quot;<span class="title">text</span>&quot; <span class="title">id</span>=&quot;<span class="title">link</span>-<span class="title">search</span>&quot; <span class="title">placeholder</span>=&quot;搜索站点名称或描述…&quot;&gt;</span></span><br><span class="line"><span class="class">  &lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">  &lt;!-- 友链列表 --&gt;</span></span><br><span class="line"><span class="class">  &lt;?<span class="title">php</span></span></span><br><span class="line"><span class="class">  $<span class="title">cats</span> = <span class="title">get_terms</span>( &#x27;<span class="title">link_category</span>&#x27;, <span class="title">array</span>( &#x27;<span class="title">hide_empty</span>&#x27; =&gt; 0 ) );</span></span><br><span class="line"><span class="class">  <span class="title">foreach</span> ( $<span class="title">cats</span> <span class="title">as</span> $<span class="title">cat</span> ) :</span></span><br><span class="line"><span class="class">    $<span class="title">bookmarks</span> = <span class="title">get_bookmarks</span>( <span class="title">array</span>(</span></span><br><span class="line"><span class="class">      &#x27;<span class="title">category</span>&#x27; =&gt; $<span class="title">cat</span>-&gt;<span class="title">term_id</span>,</span></span><br><span class="line"><span class="class">      &#x27;<span class="title">orderby</span>&#x27;  =&gt; &#x27;<span class="title">rating</span>&#x27;,</span></span><br><span class="line"><span class="class">      &#x27;<span class="title">order</span>&#x27;    =&gt; &#x27;<span class="title">DESC</span>&#x27;</span></span><br><span class="line"><span class="class">    ) );</span></span><br><span class="line"><span class="class">    <span class="title">if</span> ( <span class="title">empty</span>( $<span class="title">bookmarks</span> ) ) <span class="title">continue</span>;</span></span><br><span class="line"><span class="class">  ?&gt;</span></span><br><span class="line"><span class="class">    &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">link</span>-<span class="title">cat</span>&quot;&gt;</span></span><br><span class="line"><span class="class">      &lt;<span class="title">h2</span>&gt;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_html</span>( $<span class="title">cat</span>-&gt;<span class="title">name</span> ); ?&gt;&lt;/<span class="title">h2</span>&gt;</span></span><br><span class="line"><span class="class">      &lt;?<span class="title">php</span> <span class="title">if</span> ( ! <span class="title">empty</span>( $<span class="title">cat</span>-&gt;<span class="title">description</span> ) ) : ?&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">p</span> <span class="title">class</span>=&quot;<span class="title">link</span>-<span class="title">cat</span>-<span class="title">desc</span>&quot;&gt;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_html</span>( $<span class="title">cat</span>-&gt;<span class="title">description</span> ); ?&gt;&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line"><span class="class">      &lt;?<span class="title">php</span> <span class="title">endif</span>; ?&gt;</span></span><br><span class="line"><span class="class">      &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">links</span>&quot;&gt;</span></span><br><span class="line"><span class="class">      &lt;?<span class="title">php</span> <span class="title">foreach</span> ( $<span class="title">bookmarks</span> <span class="title">as</span> $<span class="title">link</span> ) : ?&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">a</span> <span class="title">class</span>=&quot;<span class="title">link</span>-<span class="title">card</span>&quot; <span class="title">href</span>=&quot;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_url</span>( $<span class="title">link</span>-&gt;<span class="title">link_url</span> ); ?&gt;&quot; <span class="title">target</span>=&quot;<span class="title">_blank</span>&quot; <span class="title">rel</span>=&quot;<span class="title">noopener</span>&quot;&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">img</span></span></span><br><span class="line"><span class="class">          <span class="title">src</span>=&quot;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_url</span>( $<span class="title">link</span>-&gt;<span class="title">link_image</span> ?: &#x27;&#x27; ); ?&gt;&quot;</span></span><br><span class="line"><span class="class">          <span class="title">data</span>-<span class="title">default</span>=&quot;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_url</span>( <span class="title">get_template_directory_uri</span>() . &#x27;/<span class="title">self</span>-<span class="title">innovate</span>/<span class="title">default</span>-<span class="title">avatar</span>.<span class="title">jpg</span>&#x27; ); ?&gt;&quot;</span></span><br><span class="line"><span class="class">          <span class="title">alt</span>=&quot;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_attr</span>( $<span class="title">link</span>-&gt;<span class="title">link_name</span> ); ?&gt;&quot;</span></span><br><span class="line"><span class="class">          <span class="title">onerror</span>=&quot;<span class="title">this</span>.<span class="title">src</span>=<span class="title">this</span>.<span class="title">dataset</span>.<span class="title">default</span>&quot;</span></span><br><span class="line"><span class="class">          <span class="title">onload</span>=&quot;<span class="title">clearTimeout</span>(<span class="title">this</span>.<span class="title">t</span>)&quot;</span></span><br><span class="line"><span class="class">          <span class="title">ontimeout</span>=&quot;<span class="title">this</span>.<span class="title">src</span>=<span class="title">this</span>.<span class="title">dataset</span>.<span class="title">default</span>&quot;</span></span><br><span class="line"><span class="class">      /&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">script</span>&gt;</span></span><br><span class="line"><span class="class">          (<span class="title">function</span>(<span class="title">img</span>)</span>&#123;</span><br><span class="line">            img.t = <span class="title function_ invoke__">setTimeout</span>(function()&#123; img.src = img.dataset.<span class="keyword">default</span>; &#125;, <span class="number">3000</span>);</span><br><span class="line">          &#125;)(document.currentScript.previousElementSibling);</span><br><span class="line">        &lt;/script&gt;</span><br><span class="line">          &lt;div <span class="class"><span class="keyword">class</span>=&quot;<span class="title">info</span>&quot;&gt;</span></span><br><span class="line"><span class="class">            &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">name</span>&quot;&gt;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_html</span>( $<span class="title">link</span>-&gt;<span class="title">link_name</span> ); ?&gt;&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">            &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">desc</span>&quot;&gt;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">esc_html</span>( $<span class="title">link</span>-&gt;<span class="title">link_description</span> ); ?&gt;&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">          &lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;/<span class="title">a</span>&gt;</span></span><br><span class="line"><span class="class">      &lt;?<span class="title">php</span> <span class="title">endforeach</span>; ?&gt;</span></span><br><span class="line"><span class="class">      &lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">    &lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">  &lt;?<span class="title">php</span> <span class="title">endforeach</span>; ?&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">    &lt;!-- 后台内容显示 --&gt;</span></span><br><span class="line"><span class="class">  &lt;?<span class="title">php</span> <span class="title">if</span> ( <span class="title">get_the_content</span>() ) : ?&gt;</span></span><br><span class="line"><span class="class">    &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">link</span>-<span class="title">intro</span>&quot; <span class="title">style</span>=&quot;<span class="title">margin</span>-<span class="title">bottom</span>:30<span class="title">px</span>;&quot;&gt;&lt;?<span class="title">php</span> <span class="title">the_content</span>(); ?&gt;&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">  &lt;?<span class="title">php</span> <span class="title">endif</span>; ?&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">  </span></span><br><span class="line"><span class="class">  &lt;!-- 友链申请弹窗 --&gt;</span></span><br><span class="line"><span class="class">  &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">btn</span>-<span class="title">center</span>&quot;&gt;</span></span><br><span class="line"><span class="class">    &lt;<span class="title">button</span> <span class="title">id</span>=&quot;<span class="title">open</span>-<span class="title">link</span>-<span class="title">modal</span>&quot; <span class="title">class</span>=&quot;<span class="title">btn</span>-<span class="title">hero</span>&quot;&gt;</span></span><br><span class="line"><span class="class">      &lt;<span class="title">span</span>&gt;申请交换友链&lt;/<span class="title">span</span>&gt;</span></span><br><span class="line"><span class="class">    &lt;/<span class="title">button</span>&gt;</span></span><br><span class="line"><span class="class">  &lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">  &lt;!-- ===== 评论区 ===== --&gt;</span></span><br><span class="line"><span class="class">    &lt;?<span class="title">php</span></span></span><br><span class="line"><span class="class">    // <span class="title">while</span> ( <span class="title">have_posts</span>() ) : <span class="title">the_post</span>();</span></span><br><span class="line"><span class="class">        <span class="title">if</span> ( <span class="title">comments_open</span>() || <span class="title">get_comments_number</span>() ) : ?&gt;</span></span><br><span class="line"><span class="class">            &lt;<span class="title">section</span> <span class="title">class</span>=&quot;<span class="title">link</span>-<span class="title">comments</span>&quot;&gt;</span></span><br><span class="line"><span class="class">                &lt;<span class="title">h2</span> <span class="title">class</span>=&quot;<span class="title">comments</span>-<span class="title">title</span>&quot;&gt;&lt;/<span class="title">h2</span>&gt;</span></span><br><span class="line"><span class="class">                &lt;?<span class="title">php</span> <span class="title">comments_template</span>(); ?&gt;</span></span><br><span class="line"><span class="class">            &lt;/<span class="title">section</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;?<span class="title">php</span></span></span><br><span class="line"><span class="class">        <span class="title">endif</span>;</span></span><br><span class="line"><span class="class">    // <span class="title">endwhile</span>;</span></span><br><span class="line"><span class="class">    ?&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">  &lt;!-- 弹窗 --&gt;</span></span><br><span class="line"><span class="class">  &lt;<span class="title">div</span> <span class="title">id</span>=&quot;<span class="title">link</span>-<span class="title">modal</span>-<span class="title">overlay</span>&quot; <span class="title">class</span>=&quot;<span class="title">modal</span>-<span class="title">fade</span>&quot;&gt;</span></span><br><span class="line"><span class="class">    &lt;<span class="title">div</span> <span class="title">class</span>=&quot;<span class="title">modal</span>-<span class="title">dialog</span>&quot;&gt;</span></span><br><span class="line"><span class="class">      &lt;<span class="title">button</span> <span class="title">class</span>=&quot;<span class="title">modal</span>-<span class="title">close</span>&quot; <span class="title">aria</span>-<span class="title">label</span>=&quot;关闭&quot;&gt;×&lt;/<span class="title">button</span>&gt;</span></span><br><span class="line"><span class="class">      &lt;<span class="title">h3</span> <span class="title">class</span>=&quot;<span class="title">modal</span>-<span class="title">title</span>&quot;&gt;申请交换友链&lt;/<span class="title">h3</span>&gt;</span></span><br><span class="line"><span class="class">      &lt;<span class="title">form</span> <span class="title">id</span>=&quot;<span class="title">link</span>-<span class="title">form</span>&quot; <span class="title">class</span>=&quot;<span class="title">modal</span>-<span class="title">form</span>&quot;&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">input</span> <span class="title">type</span>=&quot;<span class="title">text</span>&quot;   <span class="title">name</span>=&quot;<span class="title">link_name</span>&quot;        <span class="title">placeholder</span>=&quot;网站名称 *&quot; <span class="title">required</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">input</span> <span class="title">type</span>=&quot;<span class="title">url</span>&quot;    <span class="title">name</span>=&quot;<span class="title">link_url</span>&quot;         <span class="title">placeholder</span>=&quot;网站地址 *&quot; <span class="title">required</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">input</span> <span class="title">type</span>=&quot;<span class="title">email</span>&quot;  <span class="title">name</span>=&quot;<span class="title">link_owner_email</span>&quot; <span class="title">placeholder</span>=&quot;站长邮箱 *&quot; <span class="title">required</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">input</span> <span class="title">type</span>=&quot;<span class="title">url</span>&quot;    <span class="title">name</span>=&quot;<span class="title">link_image</span>&quot;       <span class="title">placeholder</span>=&quot;头像 / <span class="title">Logo</span> *&quot; <span class="title">required</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">textarea</span> <span class="title">name</span>=&quot;<span class="title">link_description</span>&quot; <span class="title">rows</span>=&quot;3&quot; <span class="title">placeholder</span>=&quot;一句话描述 *&quot; <span class="title">required</span>&gt;&lt;/<span class="title">textarea</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">button</span> <span class="title">type</span>=&quot;<span class="title">submit</span>&quot; <span class="title">class</span>=&quot;<span class="title">btn</span>-<span class="title">submit</span>&quot;&gt;提交申请&lt;/<span class="title">button</span>&gt;</span></span><br><span class="line"><span class="class">        &lt;<span class="title">p</span> <span class="title">id</span>=&quot;<span class="title">form</span>-<span class="title">msg</span>&quot; <span class="title">class</span>=&quot;<span class="title">form</span>-<span class="title">msg</span>&quot;&gt;&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line"><span class="class">      &lt;/<span class="title">form</span>&gt;</span></span><br><span class="line"><span class="class">    &lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">  &lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">&lt;!-- 载入独立脚本 --&gt;</span></span><br><span class="line"><span class="class">&lt;<span class="title">script</span>&gt;</span></span><br><span class="line"><span class="class">  <span class="title">var</span> <span class="title">ajax_comment_obj</span> = &lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">wp_json_encode</span>(<span class="title">array</span>(&#x27;<span class="title">ajax_url</span>&#x27; =&gt; <span class="title">admin_url</span>(&#x27;<span class="title">admin</span>-<span class="title">ajax</span>.<span class="title">php</span>&#x27;))); ?&gt;;</span></span><br><span class="line"><span class="class">&lt;/<span class="title">script</span>&gt;</span></span><br><span class="line"><span class="class">&lt;<span class="title">script</span> <span class="title">src</span>=&quot;&lt;?<span class="title">php</span> <span class="title">echo</span> <span class="title">get_template_directory_uri</span>(); ?&gt;/<span class="title">self</span>-<span class="title">innovate</span>/<span class="title">page</span>-<span class="title">links</span>.<span class="title">js</span>&quot; <span class="title">defer</span>&gt;&lt;/<span class="title">script</span>&gt;</span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class">&lt;?<span class="title">php</span> <span class="title">get_footer</span>(); ?&gt;</span></span><br></pre></td></tr></table></figure><p>下面是核心代码的css样式</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *  * page-links.css</span></span><br><span class="line"><span class="comment"> *   * 版本：1.0.0</span></span><br><span class="line"><span class="comment"> *    * 描述：友情链接页面专用样式</span></span><br><span class="line"><span class="comment"> *     * 作者：Eucalyptus</span></span><br><span class="line"><span class="comment"> *      * 创建日期：2025-08-30</span></span><br><span class="line"><span class="comment"> *       * 修改记录：</span></span><br><span class="line"><span class="comment"> *        *   - 2025-08-30：首版，含友链卡片、搜索、弹窗</span></span><br><span class="line"><span class="comment"> *         */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========= 1. 页面通用 ========= */</span></span><br><span class="line"><span class="selector-class">.page-links</span>&#123;</span><br><span class="line">  <span class="attribute">max-width</span>:<span class="number">960px</span>;</span><br><span class="line">  <span class="attribute">margin</span>:<span class="number">0</span> auto;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">40px</span> <span class="number">20px</span>;</span><br><span class="line">  <span class="attribute">font-family</span>:-apple-system,BlinkMacSystemFont,<span class="string">&quot;Segoe UI&quot;</span>,Roboto,<span class="string">&quot;Helvetica Neue&quot;</span>,Arial,<span class="string">&quot;Noto Sans&quot;</span>,sans-serif;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ============ 顶部标题（跟随深浅 + 移动端适配） ============ */</span></span><br><span class="line"><span class="comment">/* 友情链接横幅 */</span></span><br><span class="line"><span class="selector-class">.hero-title</span>&#123;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">3.5rem</span> <span class="number">1.5rem</span> <span class="number">2.5rem</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">0</span> <span class="number">0</span> <span class="number">1.5rem</span> <span class="number">1.5rem</span>;</span><br><span class="line">  <span class="attribute">text-align</span>:center;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.hero-title</span> <span class="selector-tag">h1</span>&#123;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">2.2rem</span>;</span><br><span class="line">  <span class="attribute">font-weight</span>:<span class="number">700</span>;</span><br><span class="line">  <span class="attribute">letter-spacing</span>:.<span class="number">5px</span>;</span><br><span class="line">  <span class="attribute">position</span>:relative;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.hero-title</span> <span class="selector-tag">h1</span><span class="selector-pseudo">::after</span>&#123;</span><br><span class="line">  <span class="attribute">content</span>:<span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  <span class="attribute">display</span>:block;</span><br><span class="line">  <span class="attribute">width</span>:<span class="number">60px</span>;</span><br><span class="line">  <span class="attribute">height</span>:<span class="number">3px</span>;</span><br><span class="line">  <span class="attribute">background</span>:<span class="number">#667eea</span>;</span><br><span class="line">  <span class="attribute">margin</span>:<span class="number">8px</span> auto <span class="number">0</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">2px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.hero-sub</span>&#123;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">1rem</span>;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#666</span>;</span><br><span class="line">  <span class="attribute">margin-top</span>:.<span class="number">75rem</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========= 玻璃态卡片 3.0 ========= */</span></span><br><span class="line"><span class="selector-class">.links</span>&#123;</span><br><span class="line">  <span class="attribute">display</span>:grid;</span><br><span class="line">  <span class="attribute">grid-template-columns</span>:<span class="built_in">repeat</span>(<span class="number">3</span>, <span class="number">1</span>fr); <span class="comment">/* 固定 3 列 */</span></span><br><span class="line">  <span class="attribute">gap</span>:<span class="number">24px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.link-card</span>&#123;</span><br><span class="line">  <span class="attribute">position</span>:relative;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">20px</span>;</span><br><span class="line">  <span class="attribute">background</span>:transparent;                <span class="comment">/* 跟随深浅 */</span></span><br><span class="line">  <span class="attribute">border</span>:<span class="number">1px</span> solid <span class="built_in">rgba</span>(<span class="built_in">var</span>(--color-border,<span class="number">0</span> <span class="number">0</span> <span class="number">0</span>),.<span class="number">1</span>);</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">20px</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">8px</span> <span class="number">32px</span> <span class="built_in">rgba</span>(<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,.<span class="number">08</span>);  <span class="comment">/* 深浅通用阴影 */</span></span><br><span class="line">  <span class="attribute">transition</span>:.<span class="number">4s</span> <span class="built_in">cubic-bezier</span>(.<span class="number">175</span>,.<span class="number">885</span>,.<span class="number">32</span>,<span class="number">1.275</span>);</span><br><span class="line">  <span class="attribute">overflow</span>:hidden;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-pseudo">:root</span>&#123;</span><br><span class="line">  <span class="attr">--color-border</span>: <span class="number">0</span> <span class="number">0</span> <span class="number">0</span>;       <span class="comment">/* 深色模式 */</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;light&quot;</span>]</span>&#123;</span><br><span class="line">  <span class="attr">--color-border</span>: <span class="number">255</span> <span class="number">255</span> <span class="number">255</span>; <span class="comment">/* 浅色模式 */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.link-card</span><span class="selector-pseudo">::before</span>&#123;                               <span class="comment">/* 光泽渐变 */</span></span><br><span class="line">  <span class="attribute">content</span>:<span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  <span class="attribute">position</span>:absolute;</span><br><span class="line">  <span class="attribute">inset</span>:<span class="number">0</span>;</span><br><span class="line">  <span class="attribute">background</span>:<span class="built_in">linear-gradient</span>(<span class="number">135deg</span>,transparent <span class="number">40%</span>,<span class="built_in">rgba</span>(<span class="number">255</span>,<span class="number">255</span>,<span class="number">255</span>,.<span class="number">3</span>));</span><br><span class="line">  <span class="attribute">pointer-events</span>:none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.link-card</span><span class="selector-pseudo">:hover</span>&#123;</span><br><span class="line">  <span class="attribute">transform</span>:<span class="built_in">translateY</span>(-<span class="number">6px</span>) <span class="built_in">scale</span>(<span class="number">1.02</span>);</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">12px</span> <span class="number">48px</span> <span class="built_in">rgba</span>(<span class="number">102</span>,<span class="number">126</span>,<span class="number">234</span>,.<span class="number">25</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 头像 */</span></span><br><span class="line"><span class="selector-class">.link-card</span> <span class="selector-tag">img</span>&#123;</span><br><span class="line">  <span class="attribute">width</span>:<span class="number">64px</span>;</span><br><span class="line">  <span class="attribute">height</span>:<span class="number">64px</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">50%</span>;</span><br><span class="line">  <span class="attribute">border</span>:<span class="number">2px</span> solid <span class="number">#fff</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">4px</span> <span class="number">12px</span> <span class="built_in">rgba</span>(<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,.<span class="number">08</span>);</span><br><span class="line">  <span class="attribute">object-fit</span>:cover;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 文字区 */</span></span><br><span class="line"><span class="selector-class">.link-card</span> <span class="selector-class">.info</span>&#123;</span><br><span class="line">  <span class="attribute">margin-left</span>:<span class="number">16px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.link-card</span> <span class="selector-class">.name</span>&#123;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">18px</span>;</span><br><span class="line">  <span class="attribute">font-weight</span>:<span class="number">700</span>;</span><br><span class="line">  <span class="attribute">letter-spacing</span>:.<span class="number">5px</span>;</span><br><span class="line">  <span class="attribute">margin-bottom</span>:<span class="number">6px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.link-card</span> <span class="selector-class">.desc</span>&#123;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">14px</span>;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#555</span>;</span><br><span class="line">  <span class="attribute">line-height</span>:<span class="number">1.5</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 右上角角标（纯 CSS） */</span></span><br><span class="line"><span class="selector-class">.link-card</span>&#123;</span><br><span class="line">  <span class="attribute">position</span>: relative;           <span class="comment">/* 为伪元素定位 */</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.link-card</span><span class="selector-pseudo">::after</span>&#123;</span><br><span class="line">  <span class="attribute">content</span>: <span class="string">&quot;友链&quot;</span>;              <span class="comment">/* 角标文字 */</span></span><br><span class="line">  <span class="attribute">position</span>: absolute;</span><br><span class="line">  <span class="attribute">top</span>: <span class="number">8px</span>;</span><br><span class="line">  <span class="attribute">right</span>: <span class="number">8px</span>;</span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">2px</span> <span class="number">6px</span>;</span><br><span class="line">  <span class="attribute">font-size</span>: <span class="number">11px</span>;</span><br><span class="line">  <span class="attribute">font-weight</span>: <span class="number">600</span>;</span><br><span class="line">  <span class="attribute">color</span>: <span class="number">#fff</span>;</span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">linear-gradient</span>(<span class="number">135deg</span>,<span class="number">#ea66d4</span>,<span class="number">#ac5196</span>);</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">4px</span>;</span><br><span class="line">  <span class="attribute">opacity</span>: <span class="number">0</span>;</span><br><span class="line">  <span class="attribute">transition</span>: opacity .<span class="number">3s</span>;</span><br><span class="line">  <span class="attribute">pointer-events</span>: none;         <span class="comment">/* 不影响点击 */</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.link-card</span><span class="selector-pseudo">:hover</span><span class="selector-pseudo">::after</span>&#123;</span><br><span class="line">  <span class="attribute">opacity</span>: <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ===== 分类标题 3.0 ===== */</span></span><br><span class="line"><span class="selector-class">.link-cat</span>&#123;</span><br><span class="line">  <span class="attribute">position</span>:relative;</span><br><span class="line">  <span class="attribute">margin-bottom</span>:<span class="number">40px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.link-cat</span> <span class="selector-tag">h2</span>&#123;</span><br><span class="line">  <span class="attribute">display</span>:inline-flex;</span><br><span class="line">  <span class="attribute">align-items</span>:center;</span><br><span class="line">  <span class="attribute">gap</span>:<span class="number">8px</span>;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">8px</span> <span class="number">18px</span>;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">20px</span>;</span><br><span class="line">  <span class="attribute">margin-bottom</span>: <span class="number">15px</span>;</span><br><span class="line">  <span class="attribute">font-weight</span>:<span class="number">700</span>;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#fff</span>;</span><br><span class="line">  <span class="attribute">background</span>:<span class="built_in">linear-gradient</span>(<span class="number">135deg</span>,<span class="number">#667eea</span>,<span class="number">#764ba2</span>);</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">20px</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">4px</span> <span class="number">12px</span> <span class="built_in">rgba</span>(<span class="number">102</span>,<span class="number">126</span>,<span class="number">234</span>,.<span class="number">25</span>);</span><br><span class="line">  <span class="attribute">letter-spacing</span>:.<span class="number">5px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 分类描述 */</span></span><br><span class="line"><span class="selector-class">.link-cat-desc</span>&#123;</span><br><span class="line">  <span class="attribute">margin</span>: -<span class="number">8px</span> <span class="number">0</span> <span class="number">24px</span> <span class="number">18px</span>;   <span class="comment">/* 负值贴紧标题，左侧与标题文字对齐 */</span></span><br><span class="line">  <span class="attribute">font-size</span>: <span class="number">0.9rem</span>;</span><br><span class="line">  <span class="attribute">color</span>: <span class="number">#555</span>;</span><br><span class="line">  <span class="attribute">letter-spacing</span>: .<span class="number">4px</span>;</span><br><span class="line">  <span class="attribute">line-height</span>: <span class="number">1.5</span>;</span><br><span class="line">  <span class="attribute">max-width</span>: <span class="number">540px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========= 移动端适配 ========= */</span></span><br><span class="line"><span class="keyword">@media</span> (<span class="attribute">max-width</span>: <span class="number">768px</span>) &#123;</span><br><span class="line">  <span class="selector-class">.links</span> &#123;</span><br><span class="line">    <span class="attribute">grid-template-columns</span>: <span class="number">1</span>fr; <span class="comment">/* 1 列 */</span></span><br><span class="line">    <span class="attribute">gap</span>: <span class="number">20px</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="selector-class">.link-card</span> &#123;</span><br><span class="line">    <span class="attribute">padding</span>: <span class="number">16px</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="selector-class">.link-card</span> <span class="selector-tag">img</span> &#123;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">48px</span>;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">48px</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="selector-class">.link-card</span> <span class="selector-class">.name</span> &#123;</span><br><span class="line">    <span class="attribute">font-size</span>: <span class="number">16px</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="selector-class">.link-card</span> <span class="selector-class">.desc</span> &#123;</span><br><span class="line">    <span class="attribute">font-size</span>: <span class="number">13px</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/* ========= 4. 搜索框 ========= */</span></span><br><span class="line"><span class="selector-class">.link-search</span>&#123;</span><br><span class="line">  <span class="attribute">display</span>:flex;</span><br><span class="line">  <span class="attribute">margin-bottom</span>:<span class="number">40px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.link-search</span> <span class="selector-tag">input</span>&#123;</span><br><span class="line">  <span class="attribute">width</span>:<span class="number">100%</span>;</span><br><span class="line">  <span class="attribute">max-width</span>:<span class="number">320px</span>;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">12px</span> <span class="number">40px</span> <span class="number">12px</span> <span class="number">16px</span>;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">15px</span>;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#333</span>;</span><br><span class="line">  <span class="attribute">background</span>:<span class="number">#fff</span>;</span><br><span class="line">  <span class="attribute">border</span>:<span class="number">2px</span> solid transparent;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">30px</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">4px</span> <span class="number">12px</span> <span class="built_in">rgba</span>(<span class="number">102</span>,<span class="number">126</span>,<span class="number">234</span>,.<span class="number">15</span>);</span><br><span class="line">  <span class="attribute">transition</span>:border-color .<span class="number">3s</span>, box-shadow .<span class="number">3s</span>;</span><br><span class="line">  <span class="attribute">outline</span>:none;</span><br><span class="line">  <span class="attribute">background-image</span>:<span class="built_in">url</span>(<span class="string">&#x27;data:image/svg+xml;utf8,&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;%23667eea&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;circle cx=&quot;11&quot; cy=&quot;11&quot; r=&quot;8&quot;&gt;&lt;/circle&gt;&lt;line x1=&quot;21&quot; y1=&quot;21&quot; x2=&quot;16.65&quot; y2=&quot;16.65&quot;&gt;&lt;/line&gt;&lt;/svg&gt;&#x27;</span>);</span><br><span class="line">  <span class="attribute">background-repeat</span>:no-repeat;</span><br><span class="line">  <span class="attribute">background-position</span><span class="selector-pseudo">:right</span> <span class="number">14px</span> center;</span><br><span class="line">  <span class="attribute">background-size</span>:<span class="number">20px</span> <span class="number">20px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 悬浮/聚焦高亮 */</span></span><br><span class="line"><span class="selector-class">.link-search</span> <span class="selector-tag">input</span><span class="selector-pseudo">:focus</span>&#123;</span><br><span class="line">  <span class="attribute">border-color</span>:<span class="number">#667eea</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">4px</span> <span class="built_in">rgba</span>(<span class="number">102</span>,<span class="number">126</span>,<span class="number">234</span>,.<span class="number">25</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* placeholder 样式 */</span></span><br><span class="line"><span class="selector-class">.link-search</span> <span class="selector-tag">input</span><span class="selector-pseudo">::placeholder</span>&#123;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#7f8c8d</span>;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">14px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========= 5. 按钮 &amp; 弹窗 ========= */</span></span><br><span class="line"><span class="comment">/* 5.1 触发按钮居中容器 */</span></span><br><span class="line"><span class="selector-class">.btn-center</span>&#123;</span><br><span class="line">  <span class="attribute">display</span>:flex;</span><br><span class="line">  <span class="attribute">justify-content</span>:center;</span><br><span class="line">  <span class="attribute">margin</span>:<span class="number">30px</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5.2 主按钮样式 */</span></span><br><span class="line"><span class="selector-class">.btn-hero</span>&#123;</span><br><span class="line">  <span class="attribute">position</span>:relative;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">12px</span> <span class="number">32px</span>;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">16px</span>;</span><br><span class="line">  <span class="attribute">font-weight</span>:<span class="number">600</span>;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#fff</span>;</span><br><span class="line">  <span class="attribute">background</span>:<span class="built_in">linear-gradient</span>(<span class="number">135deg</span>,<span class="number">#667eea</span> <span class="number">0%</span>, <span class="number">#764ba2</span> <span class="number">100%</span>);</span><br><span class="line">  <span class="attribute">border</span>:none;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">30px</span>;</span><br><span class="line">  <span class="attribute">cursor</span>:pointer;</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">6px</span> <span class="number">20px</span> <span class="built_in">rgba</span>(<span class="number">102</span>,<span class="number">126</span>,<span class="number">234</span>,.<span class="number">4</span>);</span><br><span class="line">  <span class="attribute">transition</span>:all .<span class="number">3s</span>;</span><br><span class="line">  <span class="attribute">overflow</span>:hidden;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.btn-hero</span><span class="selector-pseudo">:hover</span>&#123;</span><br><span class="line">  <span class="attribute">transform</span>:<span class="built_in">translateY</span>(-<span class="number">3px</span>) <span class="built_in">scale</span>(<span class="number">1.03</span>);</span><br><span class="line">  <span class="attribute">box-shadow</span>:<span class="number">0</span> <span class="number">10px</span> <span class="number">30px</span> <span class="built_in">rgba</span>(<span class="number">102</span>,<span class="number">126</span>,<span class="number">234</span>,.<span class="number">55</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5.3 弹窗遮罩 */</span></span><br><span class="line"><span class="selector-class">.modal-fade</span>&#123;</span><br><span class="line">  <span class="attribute">position</span>:fixed;</span><br><span class="line">  <span class="attribute">inset</span>:<span class="number">0</span>;</span><br><span class="line">  <span class="attribute">display</span>:flex;</span><br><span class="line">  <span class="attribute">align-items</span>:center;</span><br><span class="line">  <span class="attribute">justify-content</span>:center;</span><br><span class="line">  <span class="attribute">background</span>:<span class="built_in">rgba</span>(<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,.<span class="number">55</span>);</span><br><span class="line">  <span class="attribute">backdrop-filter</span>:<span class="built_in">blur</span>(<span class="number">4px</span>);</span><br><span class="line">  <span class="attribute">opacity</span>:<span class="number">0</span>;</span><br><span class="line">  <span class="attribute">visibility</span>:hidden;</span><br><span class="line">  <span class="attribute">transition</span>:.<span class="number">35s</span>;</span><br><span class="line">  <span class="attribute">z-index</span>:<span class="number">9999</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.modal-fade</span><span class="selector-class">.show</span>&#123;</span><br><span class="line">  <span class="attribute">opacity</span>:<span class="number">1</span>;</span><br><span class="line">  <span class="attribute">visibility</span>:visible;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5.4 弹窗主体 */</span></span><br><span class="line"><span class="selector-class">.modal-dialog</span>&#123;</span><br><span class="line">  <span class="attribute">width</span>:<span class="number">92%</span>;</span><br><span class="line">  <span class="attribute">max-width</span>:<span class="number">420px</span>;</span><br><span class="line">  <span class="attribute">background</span>:<span class="number">#fff</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">16px</span>;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">32px</span> <span class="number">36px</span> <span class="number">36px</span>;</span><br><span class="line">  <span class="attribute">position</span>:relative;</span><br><span class="line">  <span class="attribute">transform</span>:<span class="built_in">translateY</span>(-<span class="number">30px</span>) <span class="built_in">scale</span>(.<span class="number">95</span>);</span><br><span class="line">  <span class="attribute">transition</span>:transform .<span class="number">35s</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.modal-fade</span><span class="selector-class">.show</span> <span class="selector-class">.modal-dialog</span>&#123;</span><br><span class="line">  <span class="attribute">transform</span>:none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5.5 关闭按钮 */</span></span><br><span class="line"><span class="selector-class">.modal-close</span>&#123;</span><br><span class="line">  <span class="attribute">position</span>:absolute;</span><br><span class="line">  <span class="attribute">top</span>:<span class="number">14px</span>;</span><br><span class="line">  <span class="attribute">right</span>:<span class="number">18px</span>;</span><br><span class="line">  <span class="attribute">font-size</span>:<span class="number">26px</span>;</span><br><span class="line">  <span class="attribute">background</span>:none;</span><br><span class="line">  <span class="attribute">border</span>:none;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#999</span>;</span><br><span class="line">  <span class="attribute">cursor</span>:pointer;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 5.6 表单元素 */</span></span><br><span class="line"><span class="selector-class">.modal-form</span>&#123;</span><br><span class="line">  <span class="attribute">display</span>:flex;</span><br><span class="line">  <span class="attribute">flex-direction</span>:column;</span><br><span class="line">  <span class="attribute">gap</span>:<span class="number">14px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.modal-form</span> <span class="selector-tag">input</span>,</span><br><span class="line"><span class="selector-class">.modal-form</span> <span class="selector-tag">textarea</span>&#123;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">12px</span> <span class="number">14px</span>;</span><br><span class="line">  <span class="attribute">border</span>:<span class="number">1px</span> solid <span class="number">#e1e5e9</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">8px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.btn-submit</span>&#123;</span><br><span class="line">  <span class="attribute">margin-top</span>:<span class="number">8px</span>;</span><br><span class="line">  <span class="attribute">padding</span>:<span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">color</span>:<span class="number">#fff</span>;</span><br><span class="line">  <span class="attribute">border</span>:none;</span><br><span class="line">  <span class="attribute">border-radius</span>:<span class="number">30px</span>;</span><br><span class="line">  <span class="attribute">background</span>:<span class="built_in">linear-gradient</span>(<span class="number">135deg</span>,<span class="number">#667eea</span> <span class="number">0%</span>,<span class="number">#764ba2</span> <span class="number">100%</span>);</span><br><span class="line">  <span class="attribute">cursor</span>:pointer;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 移动端补丁，溢出锁死 */</span></span><br><span class="line"><span class="selector-class">.page-links</span>&#123;</span><br><span class="line">  <span class="attribute">overflow-x</span>: hidden;   <span class="comment">/* 关键：禁止横向滚动 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>以下是JavaScript代码，主要用来实现前端友链页面的实时搜索功能、友链提交弹窗（使用模态框组件展示表单，包含必填字段验证和样式反馈）以及后端提交申请内容到后端的功能</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* ========= 实时搜索 ========= */</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;link-search&#x27;</span>).<span class="title function_">addEventListener</span>(<span class="string">&#x27;input&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> kw = <span class="variable language_">this</span>.<span class="property">value</span>.<span class="title function_">toLowerCase</span>();</span><br><span class="line">  <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.link-card&#x27;</span>).<span class="title function_">forEach</span>(<span class="function"><span class="params">card</span> =&gt;</span> &#123;</span><br><span class="line">    card.<span class="property">style</span>.<span class="property">display</span> = card.<span class="property">textContent</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(kw) ? <span class="string">&#x27;flex&#x27;</span> : <span class="string">&#x27;none&#x27;</span>;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========= 弹窗控制 ========= */</span></span><br><span class="line"><span class="keyword">const</span> overlay = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;link-modal-overlay&#x27;</span>);</span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;open-link-modal&#x27;</span>).<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, <span class="function">() =&gt;</span> overlay.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;show&#x27;</span>));</span><br><span class="line">overlay.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, <span class="function"><span class="params">e</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> (e.<span class="property">target</span> === overlay || e.<span class="property">target</span>.<span class="property">classList</span>.<span class="title function_">contains</span>(<span class="string">&#x27;modal-close&#x27;</span>)) overlay.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&#x27;show&#x27;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========= Ajax 提交友链 ========= */</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;link-form&#x27;</span>).<span class="title function_">addEventListener</span>(<span class="string">&#x27;submit&#x27;</span>, <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">  e.<span class="title function_">preventDefault</span>();</span><br><span class="line">  <span class="keyword">const</span> data = <span class="keyword">new</span> <span class="title class_">FormData</span>(<span class="variable language_">this</span>);</span><br><span class="line">  data.<span class="title function_">append</span>(<span class="string">&#x27;action&#x27;</span>, <span class="string">&#x27;submit_link_apply&#x27;</span>);</span><br><span class="line">  <span class="title function_">fetch</span>(ajax_comment_obj.<span class="property">ajax_url</span>, &#123; <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>, <span class="attr">body</span>: data &#125;)</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">r</span> =&gt;</span> r.<span class="title function_">json</span>())</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;form-msg&#x27;</span>).<span class="property">textContent</span> = res.<span class="property">data</span>;</span><br><span class="line">      <span class="keyword">if</span> (res.<span class="property">success</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">reset</span>();</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> overlay.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&#x27;show&#x27;</span>), <span class="number">1500</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>最后是后端处理前端请求并为link_manager新增待审核列的代码，审核逻辑基于链接是否在前端隐藏， 关闭私密功能即可前端展示</p><p><img src="https://images.mingliangstar.com/images/20250831/1.avif"></p><p><img src="https://images.mingliangstar.com/images/20250831/2.avif"></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 待审核友链提示</span></span><br><span class="line"><span class="comment"> * 包含：后台列表新增“待审核”列 + 红色气泡菜单提示 + Ajax 接收</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* --------------------------------------------------</span></span><br><span class="line"><span class="comment"> * 1. 后台列表新增“待审核”列，纯文本，系统默认样式</span></span><br><span class="line"><span class="comment"> * -------------------------------------------------- */</span></span><br><span class="line"><span class="comment">/* 新增“待审核”列（键名 review） */</span></span><br><span class="line"><span class="title function_ invoke__">add_filter</span>( <span class="string">&#x27;manage_link-manager_columns&#x27;</span>, function ( <span class="variable">$cols</span> ) &#123;</span><br><span class="line">    <span class="variable">$cols</span>[<span class="string">&#x27;review&#x27;</span>] = <span class="string">&#x27;待审核&#x27;</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable">$cols</span>;</span><br><span class="line">&#125; );</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 单元格输出红色气泡 */</span></span><br><span class="line"><span class="title function_ invoke__">add_action</span>( <span class="string">&#x27;manage_link_custom_column&#x27;</span>, function ( <span class="variable">$col</span>, <span class="variable">$link_id</span> ) &#123;</span><br><span class="line">    <span class="keyword">if</span> ( <span class="variable">$col</span> === <span class="string">&#x27;review&#x27;</span> ) &#123;</span><br><span class="line">        <span class="keyword">echo</span> <span class="title function_ invoke__">get_bookmark_field</span>( <span class="string">&#x27;link_visible&#x27;</span>, <span class="variable">$link_id</span> ) === <span class="string">&#x27;N&#x27;</span></span><br><span class="line">            ? <span class="string">&#x27;&lt;span style=&quot;display:inline-block;background:#e60026;color:#fff;font-size:11px;padding:2px 6px;border-radius:10px;margin-left:4px;&quot;&gt;待审&lt;/span&gt;&#x27;</span></span><br><span class="line">            : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;, <span class="number">10</span>, <span class="number">2</span> );</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* --------------------------------------------------</span></span><br><span class="line"><span class="comment"> * 2. 后台“链接”菜单右上角红色数字气泡</span></span><br><span class="line"><span class="comment"> * -------------------------------------------------- */</span></span><br><span class="line"><span class="title function_ invoke__">add_action</span>( <span class="string">&#x27;admin_menu&#x27;</span>, function () &#123;</span><br><span class="line">    <span class="variable">$count</span> = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">foreach</span> ( <span class="title function_ invoke__">get_bookmarks</span>( [ <span class="string">&#x27;hide_invisible&#x27;</span> =&gt; <span class="number">0</span> ] ) <span class="keyword">as</span> <span class="variable">$link</span> ) &#123;</span><br><span class="line">        <span class="keyword">if</span> ( <span class="variable">$link</span>-&gt;link_visible === <span class="string">&#x27;N&#x27;</span> ) <span class="variable">$count</span>++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ( <span class="variable">$count</span> ) &#123;</span><br><span class="line">        <span class="keyword">global</span> <span class="variable">$menu</span>;</span><br><span class="line">        <span class="keyword">foreach</span> ( <span class="variable">$menu</span> <span class="keyword">as</span> &amp;<span class="variable">$item</span> ) &#123;</span><br><span class="line">            <span class="keyword">if</span> ( <span class="variable">$item</span>[<span class="number">2</span>] === <span class="string">&#x27;link-manager.php&#x27;</span> ) &#123;</span><br><span class="line">                <span class="variable">$item</span>[<span class="number">0</span>] .= <span class="string">&#x27; &lt;span class=&quot;awaiting-mod&quot;&gt;&lt;span class=&quot;pending-count&quot;&gt;&#x27;</span> . <span class="variable">$count</span> . <span class="string">&#x27;&lt;/span&gt;&lt;/span&gt;&#x27;</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125; );</span><br><span class="line"></span><br><span class="line"><span class="comment">/* --------------------------------------------------</span></span><br><span class="line"><span class="comment"> * 3. Ajax 接收端（无邮件）</span></span><br><span class="line"><span class="comment"> * -------------------------------------------------- */</span></span><br><span class="line"><span class="title function_ invoke__">add_action</span>( <span class="string">&#x27;wp_ajax_nopriv_submit_link_apply&#x27;</span>, <span class="string">&#x27;handle_link_apply&#x27;</span> );</span><br><span class="line"><span class="title function_ invoke__">add_action</span>( <span class="string">&#x27;wp_ajax_submit_link_apply&#x27;</span>,        <span class="string">&#x27;handle_link_apply&#x27;</span> );</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">handle_link_apply</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="variable">$name</span>  = <span class="title function_ invoke__">sanitize_text_field</span>( <span class="variable">$_POST</span>[<span class="string">&#x27;link_name&#x27;</span>] ?? <span class="string">&#x27;&#x27;</span> );</span><br><span class="line">    <span class="variable">$url</span>   = <span class="title function_ invoke__">esc_url_raw</span>        ( <span class="variable">$_POST</span>[<span class="string">&#x27;link_url&#x27;</span>]  ?? <span class="string">&#x27;&#x27;</span> );</span><br><span class="line">    <span class="variable">$email</span> = <span class="title function_ invoke__">sanitize_email</span>      ( <span class="variable">$_POST</span>[<span class="string">&#x27;link_owner_email&#x27;</span>] ?? <span class="string">&#x27;&#x27;</span> );</span><br><span class="line">    <span class="variable">$desc</span>  = <span class="title function_ invoke__">sanitize_text_field</span>( <span class="variable">$_POST</span>[<span class="string">&#x27;link_description&#x27;</span>] ?? <span class="string">&#x27;&#x27;</span> );</span><br><span class="line">    <span class="variable">$img</span>   = <span class="title function_ invoke__">esc_url_raw</span>        ( <span class="variable">$_POST</span>[<span class="string">&#x27;link_image&#x27;</span>]       ?? <span class="string">&#x27;&#x27;</span> );</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> ( <span class="keyword">empty</span>( <span class="variable">$name</span> ) || <span class="keyword">empty</span>( <span class="variable">$url</span> ) || ! <span class="title function_ invoke__">is_email</span>( <span class="variable">$email</span> ) ) &#123;</span><br><span class="line">        <span class="title function_ invoke__">wp_send_json_error</span>( <span class="string">&#x27;请完整填写必填项&#x27;</span> );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_ invoke__">wp_insert_link</span>( [</span><br><span class="line">        <span class="string">&#x27;link_name&#x27;</span>        =&gt; <span class="variable">$name</span>,</span><br><span class="line">        <span class="string">&#x27;link_url&#x27;</span>         =&gt; <span class="variable">$url</span>,</span><br><span class="line">        <span class="string">&#x27;link_description&#x27;</span> =&gt; <span class="variable">$desc</span>,</span><br><span class="line">        <span class="string">&#x27;link_image&#x27;</span>       =&gt; <span class="variable">$img</span>,</span><br><span class="line">        <span class="string">&#x27;link_owner_email&#x27;</span> =&gt; <span class="variable">$email</span>,</span><br><span class="line">        <span class="string">&#x27;link_visible&#x27;</span>     =&gt; <span class="string">&#x27;N&#x27;</span>,</span><br><span class="line">    ] );</span><br><span class="line"></span><br><span class="line">    <span class="title function_ invoke__">wp_send_json_success</span>( <span class="string">&#x27;已收到申请，审核后显示，感谢！&#x27;</span> );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上传代码至20250831主题目录完成部署，最后在functions.php中启用link_manager并调用pending-links.php处理后台任务。</p><p>WordPress的functions.php文件中添加指定代码可实现特定功能，需注意代码正确性和备份以防出错。</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 开启后台链接 */</span></span><br><span class="line"><span class="title function_ invoke__">add_filter</span>( <span class="string">&#x27;pre_option_link_manager_enabled&#x27;</span>, <span class="string">&#x27;__return_true&#x27;</span> );</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 后台新增友链提示功能 */</span></span><br><span class="line"><span class="keyword">require_once</span> <span class="title function_ invoke__">get_theme_file_path</span>( <span class="string">&#x27;/self-innovate/pending-links.php&#x27;</span> );</span><br></pre></td></tr></table></figure><blockquote><p>展示地址：<a href="https://images.mingliangstar.com/%e5%8f%8b%e9%93%be/">https://images.mingliangstar.com/%e5%8f%8b%e9%93%be/</a></p></blockquote></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/Meteor/">Meteor</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/Meteor/">Meteor</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/08/31/Meteor%E4%B8%BB%E9%A2%98%E5%8F%8B%E9%93%BE%E9%A1%B5%E9%9D%A2%E8%87%AA%E7%A0%94/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL8.0.14 双密码机制</title>
      <link>https://blog.mingliangstar.com/2025/08/06/MySQL8-0-14-%E5%8F%8C%E5%AF%86%E7%A0%81%E6%9C%BA%E5%88%B6/</link>
      <guid>https://blog.mingliangstar.com/2025/08/06/MySQL8-0-14-%E5%8F%8C%E5%AF%86%E7%A0%81%E6%9C%BA%E5%88%B6/</guid>
      <pubDate>Wed, 06 Aug 2025 05:59:03 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;MySQL 8.0</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>MySQL 8.0 引入了双密码策略，这是一种增强安全性的机制。双密码策略允许为每个用户设置两个密码：主密码和次级密码。主密码用于日常操作数据库，而次级密码则用于紧急情况下的访问，有效防止了密码泄露和未授权访问。</p><p>双密码机制使得大规模数据库密码轮换变得更平滑，而无需任何的停机时间。在 MySQL 8.0.14 版本之前，更换密码通常会遇到服务不可用时间的问题。而从_** MySQL 8.0.14**_ 起，开始支持了双密码策略。在密码更换时，可以保留旧密码依旧可用。</p><p>在更改密码时，首先通过 <code>RETAIN CURRENT PASSWORD</code> 子句设置新的主密码，并保留当前密码作为辅助密码。此时，客户端可以继续使用旧密码（辅助密码）连接数据库，同时新密码（主密码）也已经生效。当新密码已经在所有服务器上同步，且所有应用程序也更新为使用新密码时，可以使用 <code>DISCARD OLD PASSWORD</code> 子句来丢弃辅助密码（原密码），使得数据库仅接受主密码（新密码）。</p><p>这种机制特别适用于复杂的系统，尤其是涉及大量 MySQL 实例、复制、多个应用程序连接以及频繁的密码更新时，能够保持服务不中断，从而实现更流畅的密码更改流程。</p><h2 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">#创建&#x27;demo7&#x27;@&#x27;%&#x27;用户设置密码123456</span><br><span class="line">create user &#x27;demo7&#x27;@&#x27;%&#x27; identified by &#x27;123456&#x27;;</span><br><span class="line">#更新&#x27;demo7&#x27;@&#x27;%&#x27;的密码为1234567并保留旧密码123456</span><br><span class="line">ALTER USER &#x27;demo7&#x27;@&#x27;%&#x27; IDENTIFIED BY &#x27;1234567&#x27; RETAIN CURRENT PASSWORD;</span><br><span class="line">#丢弃旧密码</span><br><span class="line">alter user &#x27;demo7&#x27;@&#x27;%&#x27;  DISCARD OLD PASSWORD;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250806/1.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250806/2.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250806/3.avif"></p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p><em><strong>MySQL 8.0.14</strong></em> 起，开始支持了双密码策略，之前并不支持</p><p>8.0.13</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250806/4.avif"></p><p>8.0.14</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250806/5.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/08/06/MySQL8-0-14-%E5%8F%8C%E5%AF%86%E7%A0%81%E6%9C%BA%E5%88%B6/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Centos7下安装Docker</title>
      <link>https://blog.mingliangstar.com/2025/07/31/Centos7%E4%B8%8B%E5%AE%89%E8%A3%85Docker/</link>
      <guid>https://blog.mingliangstar.com/2025/07/31/Centos7%E4%B8%8B%E5%AE%89%E8%A3%85Docker/</guid>
      <pubDate>Thu, 31 Jul 2025 06:38:22 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;百科说：Docker</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>百科说：Docker 是一个开源的应用容器引擎，让开发者可以打包他们的应用以及依赖包到一个可移植的容器中，然后发布到任何流行的Linux机器上，也可以实现虚拟化，容器是完全使用沙箱机制，相互之间不会有任何接口。</p><p>看起来有点雾，用过虚拟机的应该对虚拟化技术有点印象，不知道也没关系，就把它当成轻量级的虚拟机吧（虽然一个是完全虚拟化，一个是操作系统层虚拟化）</p><p>百科又说：Docker 使用客户端-服务器 (C&#x2F;S) 架构模式 使用远程API来管理和创建Docker容器。Docker 容器（Container）通过 Docker 镜像（Image）来创建，二者之间的关系类似于面向对象编程中的对象与类</p><p>那Docker由什么组成呢， 包括三个基本概念:</p><ul><li>仓库（Repository）  </li><li>镜像（Image）  </li><li>容器(Container）<br>打个比方：你如果想玩英雄联盟中骚气的亚索，你首先得有这个英雄（Docker的镜像），然后你得花金币去英雄商店（Docker的仓库）买，接着进游戏就会看到一个半蹲的发型飘逸的剑客（Docker的容器），所以：</li></ul><p>其中Registry是Docker用于存放镜像文件的仓库，Docker 仓库的概念跟Git 类似（就像商店存放所有的英雄，只是更改英雄的权限在某些非程序员手里）。</p><p>所谓镜像就是构建容器的源代码，是一个只读的模板，由一层一层的文件系统组成的，类似于虚拟机的镜像（英雄也是只读的，有自己的技能被动，你也不能进行操作）。</p><p>那么容器就是由Docker镜像创建的运行实例，类似于虚拟机，容器之间是相互隔离的，包含特定的应用及其所需的依赖文件（好比每个英雄都是隔离的，都有自己的皮肤，技能以及走的路线)。</p><p>注：Docker Hub是Docker公司提供的一个注册服务器（Register）来保存多个仓库，每个仓库又可以包含多个具备不同tag的镜像。</p><h2 id="安装-Docker"><a href="#安装-Docker" class="headerlink" title="安装 Docker"></a>安装 Docker</h2><p>1.开启linux内核流量转发</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">cat &gt; /etc/sysctl.d/docker.conf &lt;&lt;EOF</span><br><span class="line">net.bridge.bridge-nf-call-ip6tables = 1</span><br><span class="line">net.bridge.bridge-nf-call-iptables = 1</span><br><span class="line">net.ipv4.conf.default.rp_filter = 0</span><br><span class="line">net.ipv4.conf.all.rp_filter = 0</span><br><span class="line">net.ipv4.ip_forward=1</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">modprobe br_netfilter</span><br><span class="line"></span><br><span class="line">sysctl -p /etc/sysctl.d/docker.conf</span><br></pre></td></tr></table></figure><p>2.布置yum仓库，阿里云自带仓库2.阿里云提供的docker专属repo仓库</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</span><br><span class="line">curl /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo</span><br></pre></td></tr></table></figure><p>3.更新yum缓存</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum clean all &amp;&amp; yum makecache</span><br></pre></td></tr></table></figure><p>4.查看源中可用的版本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum list docker-ce –showduplicates | sort -r</span><br></pre></td></tr></table></figure><p>5.安装docker-ce</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#这里的版本可以随意选择</span><br><span class="line">yum install -y docker-ce-20.16.7 -y</span><br></pre></td></tr></table></figure><p>6.配置docker加速器</p><p>使用docker首要操作就是获取镜像文件，默认下载是从Docker Hub下载，网速较慢，国内很多云服务商都提供了加速器服务，阿里云加速器，Daocloud加速器， 灵雀云加速器。</p><p>先创建一个目录存储加速器</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p /etc/docker</span><br></pre></td></tr></table></figure><p>配置加速器文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/docker/daemon.json</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">        &quot;registry-mirrors&quot;: [</span><br><span class="line">        &quot;https://ghcr.geekery.cn&quot;,</span><br><span class="line">        &quot;https://hub.geekery.cn&quot;,</span><br><span class="line">        &quot;https://docker.m.daocloud.io&quot;,</span><br><span class="line">        &quot;https://docker.rainbond.cc&quot;,</span><br><span class="line">        &quot;https://docker.ckyl.me&quot;,</span><br><span class="line">        &quot;https://docker.1panelproxy.com&quot;,</span><br><span class="line">        &quot;https://2a6bf1988cb6428c877f723ec7530dbc.mirror.swr.myhuaweicloud.com&quot;,</span><br><span class="line">        &quot;https://docker.m.daocloud.io&quot;,</span><br><span class="line">        &quot;https://hub-mirror.c.163.com&quot;,</span><br><span class="line">        &quot;https://mirror.baidubce.com&quot;,</span><br><span class="line">        &quot;https://your_preferred_mirror&quot;,</span><br><span class="line">        &quot;https://dockerhub.icu&quot;,</span><br><span class="line">        &quot;https://docker.registry.cyou&quot;,</span><br><span class="line">        &quot;https://docker-cf.registry.cyou&quot;,</span><br><span class="line">        &quot;https://dockercf.jsdelivr.fyi&quot;,</span><br><span class="line">        &quot;https://docker.jsdelivr.fyi&quot;,</span><br><span class="line">        &quot;https://dockertest.jsdelivr.fyi&quot;,</span><br><span class="line">        &quot;https://mirror.aliyuncs.com&quot;,</span><br><span class="line">        &quot;https://dockerproxy.com&quot;,</span><br><span class="line">        &quot;https://mirror.baidubce.com&quot;,</span><br><span class="line">        &quot;https://docker.nju.edu.cn&quot;,</span><br><span class="line">        &quot;https://docker.mirrors.sjtug.sjtu.edu.cn&quot;,</span><br><span class="line">        &quot;https://docker.mirrors.ustc.edu.cn&quot;,</span><br><span class="line">        &quot;https://mirror.iscas.ac.cn&quot;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>7.启动docker</p><p>使刚才配置的加速器生效</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl daemon-reload</span><br></pre></td></tr></table></figure><p>设置开机自启动</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl enable docker</span><br></pre></td></tr></table></figure><p>启动</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl start docke</span><br></pre></td></tr></table></figure><p>8.检验docker是否安装并成功启动</p><p>查看进程</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -ef | grep docker</span><br></pre></td></tr></table></figure><p>查看详细信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker version</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/07/31/Centos7%E4%B8%8B%E5%AE%89%E8%A3%85Docker/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL Innodb Cluster配置</title>
      <link>https://blog.mingliangstar.com/2025/07/22/MySQL-Innodb-Cluster%E9%85%8D%E7%BD%AE/</link>
      <guid>https://blog.mingliangstar.com/2025/07/22/MySQL-Innodb-Cluster%E9%85%8D%E7%BD%AE/</guid>
      <pubDate>Tue, 22 Jul 2025 07:24:26 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;本篇文章中MySQL服务采用&lt;a</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="配置规划"><a href="#配置规划" class="headerlink" title="配置规划"></a>配置规划</h2><p>本篇文章中MySQL服务采用<a href="https://blog.csdn.net/weixin_72610956/article/details/149334380?spm=1001.2014.3001.5502">编译安装</a>，</p><table><thead><tr><th align="left"><font style="color:#3d464d;">ip</font><font style="color:#3d464d;">地址</font></th><th align="left"><font style="color:#3d464d;">主机名</font></th><th align="left"><font style="color:#3d464d;">角色</font></th><th align="left"><font style="color:#3d464d;">安装软件</font></th></tr></thead><tbody><tr><td align="left"><font style="color:#3d464d;">192.168.3.2</font></td><td align="left"><font style="color:#3d464d;">348aeb8077a8</font></td><td align="left"><font style="color:#3d464d;">主（初始化）</font></td><td align="left"><font style="color:#3d464d;">Mysql8.0.30</font><br/><font style="color:#3d464d;"></font><font style="color:#3d464d;">mysql-shell</font><br/><font style="color:#3d464d;"></font><font style="color:#3d464d;">mysql-route</font></td></tr><tr><td align="left"><font style="color:#3d464d;">192.168.3.2</font></td><td align="left"><font style="color:#3d464d;">7ff037fcf001</font></td><td align="left"><font style="color:#3d464d;">备（初始化）</font></td><td align="left"><font style="color:#3d464d;">Mysql8.0.30</font><br/><font style="color:#3d464d;"></font><font style="color:#3d464d;">mysql-shell</font><br/><font style="color:#3d464d;"></font><font style="color:#3d464d;">mysql-route</font></td></tr><tr><td align="left"><font style="color:#3d464d;">192.168.3.4</font></td><td align="left"><font style="color:#3d464d;">fc7b8078d23b</font></td><td align="left"><font style="color:#3d464d;">备（初始化）</font></td><td align="left"><font style="color:#3d464d;">Mysql8.0.30</font><br/><font style="color:#3d464d;"></font><font style="color:#3d464d;">mysql-shell</font><br/><font style="color:#3d464d;"></font><font style="color:#3d464d;">mysql-route</font></td></tr></tbody></table><h2 id="三台主机分别创建‘mingliang‘-’-’-用户并授权"><a href="#三台主机分别创建‘mingliang‘-’-’-用户并授权" class="headerlink" title="三台主机分别创建‘mingliang‘@’%’ 用户并授权"></a>三台主机分别创建‘mingliang‘@’%’ 用户并授权</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">create user &#x27;mingliang&#x27;@&#x27;%&#x27; identified with mysql_native_password by &#x27;123456&#x27;;</span><br><span class="line">grant all on *.* to  &#x27;mingliang&#x27;@&#x27;%&#x27; with grant option;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/1.avif"></p><h2 id="安装mysql-shell（三台机器必须全部安装）"><a href="#安装mysql-shell（三台机器必须全部安装）" class="headerlink" title="安装mysql shell（三台机器必须全部安装）"></a>安装mysql shell（三台机器必须全部安装）</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">tar -xzvf mysql-shell-8.0.30-linux-glibc2.12-x86-64bit.tar.gz</span><br><span class="line">mv mysql-shell-8.0.30-linux-glibc2.12-x86-64bit /usr/local/mysqlsh</span><br><span class="line">chown mysql8:mysql8 -R /usr/local/mysqlsh</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/2.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/3.avif"></p><h3 id="在mysql8用户中配置环境变量"><a href="#在mysql8用户中配置环境变量" class="headerlink" title="在mysql8用户中配置环境变量"></a>在mysql8用户中配置环境变量</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">su - mysql8</span><br><span class="line">vim .bash_profile  /添加下述内容</span><br><span class="line"></span><br><span class="line">export PATH=$MYSQL_HOME/bin:/usr/local/mysqlsh/bin:$PATH</span><br><span class="line"></span><br><span class="line">#使文件生效</span><br><span class="line">source .bash_profile</span><br></pre></td></tr></table></figure><h3 id="使用mysql-shell登录测试"><a href="#使用mysql-shell登录测试" class="headerlink" title="使用mysql shell登录测试"></a>使用mysql shell登录测试</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqlsh --mysqlx -h 192.168.3.2 -P 33060 -umingliang -p</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/4.avif"></p><blockquote><p>这里登录测试的时候出现了一个这样的错误</p><p><font style="color:#DF2A3F;">MySQL Error 2027: Requested session assumes MySQL X Protocol but ‘192.168.3.2:3306’ seems to speak the classic MySQL protocol (Unexpected response received from server, msg-id:10)</font></p><p>这个是因为上面连接的时候X协议的端口没有指定正确，可以使用mysql -u root -p -e “select @@mysqlx_port”查看X协议端口，然后连接的时候指定正确的端口就可以成功登录了</p><p>参考文档：<a href="https://stackoverflow.org.cn/questions/64326446">https://stackoverflow.org.cn/questions/64326446</a></p></blockquote><h2 id="安装mysql-router（三台主机必须全部安装）"><a href="#安装mysql-router（三台主机必须全部安装）" class="headerlink" title="安装mysql router（三台主机必须全部安装）"></a>安装mysql router（三台主机必须全部安装）</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">tar -xvf mysql-router-8.0.30-linux-glibc2.12-x86_64.tar.xz</span><br><span class="line"></span><br><span class="line">#没有xz的话需要安装下</span><br><span class="line">yum install -y xz</span><br><span class="line"></span><br><span class="line">mv mysql-router-8.0.30-linux-glibc2.12-x86_64 /usr/local/mysqlrouter</span><br><span class="line">chown mysql8:mysql8 /usr/local/mysqlrouter</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/5.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/6.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/7.avif"></p><h3 id="在MySQL8用户中配置环境变量"><a href="#在MySQL8用户中配置环境变量" class="headerlink" title="在MySQL8用户中配置环境变量"></a>在MySQL8用户中配置环境变量</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">su - mysql8</span><br><span class="line">vim .bash_profile  /添加下述内容</span><br><span class="line"></span><br><span class="line">export PATH=$MYSQL_HOME/bin:/usr/local/mysqlsh/bin:/usr/local/mysqlrouter/bin:$PATH</span><br><span class="line"></span><br><span class="line">#使文件生效</span><br><span class="line">source .bash_profile</span><br></pre></td></tr></table></figure><h2 id="通过MySQLShell搭建MGR，下面步骤每个节点都执行"><a href="#通过MySQLShell搭建MGR，下面步骤每个节点都执行" class="headerlink" title="通过MySQLShell搭建MGR，下面步骤每个节点都执行"></a><font style="color:#3d464d;background-color:#FFFFFF;">通过MySQLShell搭建MGR，下面步骤每个节点都执行</font></h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">#192.168.3.2 root@348aeb8077a8  master</span><br><span class="line">su - mysql8</span><br><span class="line">mysqlsh --mysqlx -h 192.168.3.2 -P33060 -umingliang -p</span><br><span class="line">  dba.configureInstance();</span><br><span class="line">  dba.configureInstance();</span><br><span class="line"></span><br><span class="line">#192.168.3.3 root@7ff037fcf001  slave1</span><br><span class="line">su - mysql8</span><br><span class="line">mysqlsh --mysqlx -h 192.168.3.3 -P33060 -umingliang -p</span><br><span class="line">  dba.configureInstance();</span><br><span class="line">  dba.configureInstance();</span><br><span class="line"></span><br><span class="line">#192.168.3.4 root@fc7b8078d23b  slave2</span><br><span class="line">su - mysql8</span><br><span class="line">mysqlsh --mysqlx -h 192.168.3.4 -P33060 -umingliang -p</span><br><span class="line">  dba.configureInstance();</span><br><span class="line">  dba.configureInstance();</span><br><span class="line">  </span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/8.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/9.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/10.avif"></p><h3 id="创建集群实例（在master执行即可）"><a href="#创建集群实例（在master执行即可）" class="headerlink" title="创建集群实例（在master执行即可）"></a>创建集群实例（在master执行即可）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">#默认为单主模式，第一个加入为写节点</span><br><span class="line">#---第一个节点创建集群实例(192.168.3.2)</span><br><span class="line"></span><br><span class="line">  var cluster = dba.createCluster(&#x27;DemoCluster&#x27;)</span><br><span class="line"></span><br><span class="line">#添加其他节点192.168.3.3和192.168.3.3，此时会进行数据库克隆，</span><br><span class="line">#把节点1的数据库复制到其它数据库，同时进行同步。</span><br><span class="line"></span><br><span class="line">  var cluster=dba.getCluster()</span><br><span class="line">  cluster.addInstance(&#x27;mingliang@192.168.3.3:3306&#x27;)</span><br><span class="line">  cluster.addInstance(&#x27;mingliang@192.168.3.4:3306&#x27;)</span><br><span class="line"></span><br><span class="line">#查看集群状态</span><br><span class="line">  var cluster=dba.getCluster()</span><br><span class="line">  cluster.status();</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/11.avif"></p><blockquote><p>这里由于3个节点的UUID相同导致，添加集群节点的没有添加进去</p><p><font style="color:#DF2A3F;">Cluster.addInstance: Cannot add an instance with the same server UUID (1d6dd7c2-5ff7-11f0-bb22-0242c0a80302) of an active member of the cluster ‘348aeb8077a8:3306’. Please change the UUID of the instance to add, all members must have a unique server UUID. (RuntimeError)</font></p><p>更新uuid后，master节点执行了克隆恢复，但是发现一直处于* Waiting for server restart… 状态，直至超时，去slave查看error.log发现发生了crash，导致启动失败</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/12.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/13.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/14.avif"></p><p>最后重新配置了一次，在添加节点恢复的时候选择了增量恢复后，成功添加</p><p>#添加slave1</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/15.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/16.avif"></p><p>#添加slave2</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/17.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/18.avif"></p></blockquote><h2 id="配置MySQLRouter路由"><a href="#配置MySQLRouter路由" class="headerlink" title="配置MySQLRouter路由"></a><font style="color:#3d464d;background-color:#FFFFFF;">配置MySQLRouter路由</font></h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">#创建路由文件</span><br><span class="line">su - mysql8</span><br><span class="line">mkdir myroyter</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#路由初始化</span><br><span class="line">#master</span><br><span class="line">mysqlrouter --bootstrap mingliang@172.0.0.1:3306 --directory /home/mysql8/myrouter --conf-use-sockets  --user mysql8</span><br><span class="line"></span><br><span class="line">#启动路由</span><br><span class="line">.myrouter/star.sh</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/19.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/20.avif"></p><h2 id="测试配置"><a href="#测试配置" class="headerlink" title="测试配置"></a>测试配置</h2><h3 id="连接测试"><a href="#连接测试" class="headerlink" title="连接测试"></a>连接测试</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql -u mingliang -p -P6446</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/21.avif"></p><h3 id="数据同步测试"><a href="#数据同步测试" class="headerlink" title="数据同步测试"></a>数据同步测试</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">create database demo1;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/22.avif"></p><h3 id="故障测试"><a href="#故障测试" class="headerlink" title="故障测试"></a>故障测试</h3><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/23.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/24.avif"></p><h3 id="主备切换"><a href="#主备切换" class="headerlink" title="主备切换"></a>主备切换</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cluster.setPrimaryInstance(&#x27;192.168.3.2:3306&#x27;)</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/25.avif"></p><h3 id="关闭集群"><a href="#关闭集群" class="headerlink" title="关闭集群"></a>关闭集群</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">#先关闭2个从节点，然后在关闭主节点</span><br><span class="line"></span><br><span class="line">#Mgr无需单独关闭，单主备库都关闭时，其进程自动关闭</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/26.avif"></p><h3 id="重启集群"><a href="#重启集群" class="headerlink" title="重启集群"></a>重启集群</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#先启动2个从节点，然后再启动主节点</span><br><span class="line"></span><br><span class="line">#启动mgr</span><br><span class="line">  dba.rebootClusterFromCompleteOutage()</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250722/27.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/07/22/MySQL-Innodb-Cluster%E9%85%8D%E7%BD%AE/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>MySQL Innodb Cluster介绍</title>
      <link>https://blog.mingliangstar.com/2025/07/14/MySQL-Innodb-Cluster%E4%BB%8B%E7%BB%8D/</link>
      <guid>https://blog.mingliangstar.com/2025/07/14/MySQL-Innodb-Cluster%E4%BB%8B%E7%BB%8D/</guid>
      <pubDate>Mon, 14 Jul 2025 08:52:52 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;MySQL InnoDB Cluster 是 MySQL 官方提供的高可用性解决方案，它结合了 MySQL Shell、MySQL Server 和 Group Replication</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>MySQL InnoDB Cluster 是 MySQL 官方提供的高可用性解决方案，它结合了 MySQL Shell、MySQL Server 和 Group Replication 技术，使您能够部署和管理完整的集成高可用性解决方案。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250714/1.avif"></p><p><a href="https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-introduction.html">https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-introduction.html</a></p><p>以下是对 MySQL InnoDB Cluster 的详细介绍：</p><h3 id="核心组件"><a href="#核心组件" class="headerlink" title="核心组件"></a>核心组件</h3><ol><li><strong>MySQL Shell</strong>：MySQL Shell 是一个现代化的命令行客户端，提供对 MySQL Server 的强大交互式访问，支持 JavaScript 和 Python 两种编程语言接口。在 InnoDB Cluster 环境中，MySQL Shell 充当了管理和监控集群的控制台工具，内置了 AdminAPI，用于简化群的创建、配置、扩展、维护等操作。</li><li><strong>MySQL Router</strong>：MySQL Router 是轻量级的服务代理，用于透明地路由客户端请求到正确的 MySQL 服务器实例。根据集的部署信息，MySQL Router 能自动生成合适的配置，确保客户端应用无需关心后端服务器的细节，即可无缝连接到群中的主节点（在单主模式下）或读写节点（在多主模式下），并根据集状态自动调整路由策略。</li><li><strong>MySQL Server 和 Group Replication</strong>：使一组 MySQL 实例能够提供高可用性。InnoDB Cluster 提供了一种替代的、易于使用的编程方式来使用组复制。</li></ol><h3 id="核心原理与优势"><a href="#核心原理与优势" class="headerlink" title="核心原理与优势"></a>核心原理与优势</h3><p>InnoDB Cluster 基于 MySQL Group Replication 构建，提供自动成员管理、容错、自动故障转移等功能。InnoDB Cluster 通常以单主模式运行，有一个主实例（读写）和多个辅助实例（只读）。高级用户还可以利用多主模式，其中所有实例都是主实例。您甚至可以在 InnoDB Cluster 在线时更改集的拓扑结构，以确保尽可能高的可用性。</p><h3 id="与经典主从复制的比较"><a href="#与经典主从复制的比较" class="headerlink" title="与经典主从复制的比较"></a>与经典主从复制的比较</h3><p>经典的主从复制是 MySQL 原生的复制功能，采用异步方式。主服务器执行更改数据的事务后，会产生 binlog，之后 binlog 会被发送到从服务器变成 relay log。与此同时，主服务器会对提交返回。从服务器接收到 relay log 后，会通过一个 applier 的线程对 日志 里面的内容进行施放，使产生的数据更改写入从服务器，之后产生自己的 binlog，进行提交。</p><p>与经典的主从复制相比，InnoDB Cluster 基于组复制，提供了更高的可用性。在 InnoDB Cluster 中，每个 MySQL 服务器实例都是组复制的成员，数据在集群内的同步更加可靠。此外，InnoDB Cluster 还提供了自动故障转移功能，能够在某个实例出现故障时自动将任务转移到其他实例上，避免了手动介入和业务中断。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>InnoDB Cluster 作为一种新兴的数据库解决方案，通过提供自动故障转移、易于管理的 API 和路由等功能，为企业提供了高可用性的数据库服务。在实际应用中，通过合理的配置和管理，InnoDB Cluster 能够确保业务的连续性和数据的可靠性。随着技术的发展和业务的不断扩展，InnoDB Cluster 将成为越来越多企业的首选数据库解决方案。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/MySQL/">MySQL</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/MySQL/">MySQL</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/07/14/MySQL-Innodb-Cluster%E4%BB%8B%E7%BB%8D/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>WPCode添加代码启用后网站报错怎么处理</title>
      <link>https://blog.mingliangstar.com/2025/05/31/WPcode%E6%8A%A5%E9%94%99%E5%A4%84%E7%90%86/</link>
      <guid>https://blog.mingliangstar.com/2025/05/31/WPcode%E6%8A%A5%E9%94%99%E5%A4%84%E7%90%86/</guid>
      <pubDate>Sat, 31 May 2025 13:25:07 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;有时候我们使用WPCode插件添加的代码可能会出现问题，或者与其他代码产生冲突，这就可能导致网站出现报错的情况。&lt;/p&gt;
&lt;!-- 这是一张图片，ocr 内容为： --&gt;
&lt;p&gt;&lt;img</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>有时候我们使用WPCode插件添加的代码可能会出现问题，或者与其他代码产生冲突，这就可能导致网站出现报错的情况。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250531/1.avif"></p><p>这种时候通常可以采取两种不同的应对方式：</p><h2 id="一、修改文件"><a href="#一、修改文件" class="headerlink" title="一、修改文件"></a>一、修改文件</h2><p>如果在添加代码后网站出现报错，可以尝试通过登录后台服务器或者使用FTP删除或重命名 WPCode 插件的文件夹，这个文件夹的名称通常是 “insert-headers-and-footers”，操作前建议先备份相关数据，以确保网站的安全。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#重命名</span></span><br><span class="line"> <span class="built_in">mv</span> insert-headers-and-footers insert-headers-and-footers-mv</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250531/2.avif"></p><p>其实不建议使用这种方法，如果你是把代码添加到了functions.php文件中，可以直接编辑并删除。但这种情况涉及的是插件，使用的是WPCode插件，一旦你重新启用它，之前添加的代码又会被载入并保持开启状态，这样一来，你网站上的报错问题还会再次出现。</p><h2 id="二、进入WPCode插件的安全模式"><a href="#二、进入WPCode插件的安全模式" class="headerlink" title="二、进入WPCode插件的安全模式"></a>二、进入WPCode插件的安全模式</h2><p>在网站域名后面加上 <code>/wp-admin/?wpcode-safe-mode=1</code> 即可进入安全模式，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://mingliang.net.cn//wp-admin/?wpcode-safe-mode=1</span><br></pre></td></tr></table></figure><p>进入安全模式后可以看到网站将不再执行 WPCode 插件所添加的任何代码。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250531/4.avif"></p><p>这时你可以在后台的WPCode插件中找到刚刚添加并导致错误的代码片段，直接删除或禁用，以恢复正常运行。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250531/3.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/%E6%8F%92%E4%BB%B6/">插件</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8F%92%E4%BB%B6/">插件</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/05/31/WPcode%E6%8A%A5%E9%94%99%E5%A4%84%E7%90%86/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>WordPress通过简码插入bilibili视频</title>
      <link>https://blog.mingliangstar.com/2025/03/25/BILIBILI%E7%AE%80%E7%A0%81/</link>
      <guid>https://blog.mingliangstar.com/2025/03/25/BILIBILI%E7%AE%80%E7%A0%81/</guid>
      <pubDate>Tue, 25 Mar 2025 15:24:09 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;一、前言&quot;&gt;&lt;a href=&quot;#一、前言&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><p>B站是国内非常受欢迎的视频分享平台，上面不仅内容丰富，而且很多视频制作精良、趣味十足。很多人，比如我，就喜欢将B站的视频通过 iframe 嵌入到自己的网页中，但这段代码又长又复杂，字符长度大约有230个，每次使用都很麻烦。为了让大家更方便地在 WordPress 网站中插入B站视频，我准备了一个简单实用的短代码教程，轻松几步就能搞定。</p><h2 id="二、代码"><a href="#二、代码" class="headerlink" title="二、代码"></a>二、代码</h2><p>将以下代码复制到网站主题的 functions.php 文件末尾即可完成添加。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 添加插入Bilibili视频的短代码</span><br><span class="line"> *</span><br><span class="line"> * @param array <span class="variable">$atts</span> 短代码属性数组</span><br><span class="line"> * @param string|null <span class="variable">$content</span> 短代码内容（未使用）</span><br><span class="line"> * @<span class="built_in">return</span> string 返回生成的HTML代码</span><br><span class="line"> */</span><br><span class="line"><span class="keyword">function</span> vbilibili_shortcode( <span class="variable">$atts</span>, <span class="variable">$content</span> = null ) &#123;</span><br><span class="line">    // 默认参数值</span><br><span class="line">    <span class="variable">$defaults</span> = array(</span><br><span class="line">        <span class="string">&#x27;av&#x27;</span> =&gt; <span class="string">&#x27;&#x27;</span>,    // Bilibili视频的AV号</span><br><span class="line">        <span class="string">&#x27;bv&#x27;</span> =&gt; <span class="string">&#x27;&#x27;</span>,    // Bilibili视频的BV号</span><br><span class="line">        <span class="string">&#x27;w&#x27;</span>  =&gt; <span class="string">&#x27;100%&#x27;</span>, // 默认宽度为100%</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    // 解析短代码中的参数</span><br><span class="line">    <span class="variable">$atts</span> = shortcode_atts( <span class="variable">$defaults</span>, <span class="variable">$atts</span> );</span><br><span class="line">    </span><br><span class="line">    // 如果参数 av 和 bv 都为空，则返回错误信息</span><br><span class="line">    <span class="keyword">if</span> ( empty( <span class="variable">$atts</span>[<span class="string">&#x27;av&#x27;</span>] ) &amp;&amp; empty( <span class="variable">$atts</span>[<span class="string">&#x27;bv&#x27;</span>] ) ) &#123;</span><br><span class="line">        <span class="built_in">return</span> <span class="string">&#x27;&lt;p&gt;av 和 bv 不可为空&lt;/p&gt;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 如果参数 av 和 bv 同时存在，则返回错误信息</span><br><span class="line">    <span class="keyword">if</span> ( ! empty( <span class="variable">$atts</span>[<span class="string">&#x27;av&#x27;</span>] ) &amp;&amp; ! empty( <span class="variable">$atts</span>[<span class="string">&#x27;bv&#x27;</span>] ) ) &#123;</span><br><span class="line">        <span class="built_in">return</span> <span class="string">&#x27;&lt;p&gt;av 和 bv 不可同时存在&lt;/p&gt;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 根据参数 av 或 bv 构建 iframe 的 URL</span><br><span class="line">    <span class="keyword">if</span> ( ! empty( <span class="variable">$atts</span>[<span class="string">&#x27;av&#x27;</span>] ) ) &#123;</span><br><span class="line">        <span class="variable">$iframe_url</span> = <span class="string">&#x27;https://player.bilibili.com/player.html?aid=&#x27;</span> . esc_attr( <span class="variable">$atts</span>[<span class="string">&#x27;av&#x27;</span>] ) . <span class="string">&#x27;&amp;high_quality=1&#x27;</span>;</span><br><span class="line">    &#125; elseif ( ! empty( <span class="variable">$atts</span>[<span class="string">&#x27;bv&#x27;</span>] ) ) &#123;</span><br><span class="line">        <span class="variable">$iframe_url</span> = <span class="string">&#x27;https://player.bilibili.com/player.html?bvid=&#x27;</span> . esc_attr( <span class="variable">$atts</span>[<span class="string">&#x27;bv&#x27;</span>] ) . <span class="string">&#x27;&amp;high_quality=1&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 构建 iframe 的 HTML 代码，并直接应用内联样式</span><br><span class="line">    <span class="variable">$iframe</span> = <span class="string">&#x27;&lt;div style=&quot;position:relative; padding-bottom:56.25%; height:0; overflow:hidden; margin:0 auto;&quot;&gt;&lt;iframe src=&quot;&#x27;</span> . <span class="variable">$iframe_url</span> . <span class="string">&#x27;&quot; style=&quot;position:absolute; top:0; left:0; width:100%; height:100%;&quot; frameborder=&quot;no&quot; scrolling=&quot;no&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    // 返回 iframe 的 HTML 代码</span><br><span class="line">    <span class="built_in">return</span> <span class="variable">$iframe</span>;</span><br><span class="line">&#125;</span><br><span class="line">add_shortcode( <span class="string">&#x27;vbilibili&#x27;</span>, <span class="string">&#x27;vbilibili_shortcode&#x27;</span> );</span><br></pre></td></tr></table></figure><p>将内容嵌入到<code>&lt;iframe&gt;</code>中，并通过设置相关属性来限制<code>&lt;iframe&gt;</code> 内的页面无法在新窗口或新标签页中打开，从而防止跳转到 B 站。可以通过在 <code>&lt;iframe&gt;</code> 标签中添加 sandbox 属性，结合 allow 属性精确控制权限，确保用户在当前页面内浏览，不被引导至其他网站。这种方式有助于提升用户体验的连续性，同时防止意外跳转带来的干扰。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sandbox=<span class="string">&quot;allow-top-navigation allow-same-origin allow-forms allow-scripts&quot;</span></span><br></pre></td></tr></table></figure><h2 id="三、WPCode"><a href="#三、WPCode" class="headerlink" title="三、WPCode"></a>三、WPCode</h2><p>如果你使用的是一个经常更新的主题，每次更新后都需要将代码添加到 functions.php 文件中，这显然十分麻烦。为了解决这个问题，你可以使用 WPCode 插件，在不修改主题文件的情况下，轻松实现自定义代码片段的添加和管理。</p><h3 id="3-1、WPCode介绍"><a href="#3-1、WPCode介绍" class="headerlink" title="3.1、WPCode介绍"></a>3.1、WPCode介绍</h3><p>WPCode 是一款流行的WordPress插件，它允许用户在不修改主题文件的情况下，向WordPress网站添加自定义代码片段。这款插件非常适合需要在网站中添加额外功能的站长，例如，添加Google分析或百度统计的代码，或者插入自定义CSS、JavaScript等。</p><p>WPCode插件还提供了一个代码片段库，您可以在这个库里面找到经过验证的PHP代码片段，例如：禁用REST API、禁用 XML-RPC、禁用注释、允许 SVG 文件上传、禁用 Gutenberg、添加经典编辑器等，而无需为每个请求安装单独的插件。使用这个插件，还可以控制代码的激活状态，如果需要在调试情况下先不适用某个功能，可以先不激活，而不是直接删除。</p><p>总之非常方便，如果您的网站也是WordPress网站，那么站长建议您可以安装下这个插件试一试。</p><h3 id="3-2、自定义代码到WPCode"><a href="#3-2、自定义代码到WPCode" class="headerlink" title="3.2、自定义代码到WPCode"></a>3.2、自定义代码到WPCode</h3><p><img src="https://images.mingliangstar.com/images/20250325/1.avif"></p><p><img src="https://images.mingliangstar.com/images/20250325/2.avif"></p><p><img src="https://images.mingliangstar.com/images/20250325/2.avif"></p><h3 id="3-3、使用简码"><a href="#3-3、使用简码" class="headerlink" title="3.3、使用简码"></a>3.3、使用简码</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[vbilibili 参数名=<span class="string">&quot;参数值&quot;</span>][/vbilibili]</span><br></pre></td></tr></table></figure><p>参数：</p><table><thead><tr><th>参数名</th><th>可选值</th><th>默认值</th><th>解释</th><th>是否必须</th></tr></thead><tbody><tr><td>av</td><td>–</td><td>–</td><td>Bilibili 视频的 AV 号</td><td>是</td></tr><tr><td>bv</td><td>–</td><td>–</td><td>Bilibili 视频的 BV 号</td><td>是</td></tr></tbody></table><p>示例：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[vbilibili bv=BV1SoZ5YVEJg][/vbilibili]</span><br></pre></td></tr></table></figure><div style="position: relative; width: 100%; height: 0; padding-bottom: 56.25%;">  <iframe     src="https://player.bilibili.com/player.html?bvid=BV1SoZ5YVEJg&page=1&high_quality=1&as_wide=1&allowfullscreen=true&autoplay=0"     style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"     frameborder="0"     scrolling="no"     allowfullscreen>  </iframe></div><p>注意：  </p><ul><li>Bilibili 视频的 AV 号或 BV 号是必须的，但只要输入 AV 号或 BV 号的其中一个即可。  </li><li>Bilibili 视频的 AV 号不要带上 av</li></ul></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/%E7%AE%80%E7%A0%81/">简码</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E7%AE%80%E7%A0%81/">简码</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/03/25/BILIBILI%E7%AE%80%E7%A0%81/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Wordpress登录页面插件</title>
      <link>https://blog.mingliangstar.com/2025/01/03/%E7%99%BB%E5%BD%95%E9%A1%B5%E9%9D%A2%E6%8F%92%E4%BB%B6/</link>
      <guid>https://blog.mingliangstar.com/2025/01/03/%E7%99%BB%E5%BD%95%E9%A1%B5%E9%9D%A2%E6%8F%92%E4%BB%B6/</guid>
      <pubDate>Fri, 03 Jan 2025 03:36:28 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;code&gt;20250103 | wp-login</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><p><code>20250103 | wp-login Custom Login Page Customizer</code> 是一款WordPress插件，它提供了丰富的自定义字段来改变WordPress登录页面的布局。使用该插件，您可以完全修改登录页面的外观和感觉，包括登录错误消息、忘记密码错误消息、注册错误消息、忘记密码提示消息等。20250103 插件使用 Customizer API 构建，允许您实时预览登录页面的更改。该插件非常易于使用，不需要任何编码技能，只需为登录表单的每个元素设置选项，就可以在几秒钟内创建一个新的自定义登录页面。</p><p>20250103 提供了免费和专业版插件，专业版提供了更多的功能，如Google字体、Google reCaptcha、选择主题等。如果您希望为您的WordPress网站添加一个外观酷炫的登录页面，20250103 是一个必备的插件。</p><h2 id="二、20250103功能"><a href="#二、20250103功能" class="headerlink" title="二、20250103功能"></a>二、20250103功能</h2><p>Logo：可以更改登录Logo {image，width，height，padding，URL and Title}。<br>背景：您可以自定义背景图像或颜色。设置其位置、大小和可重复属性。<br>登录表单：即使你可以自定义登录表单{图像或颜色，宽度，高度，填充和边框}。自定义输入文本字段{宽度，边距，文本颜色，标签颜色和背景颜色}。<br>忘记形式：美丽的插件在这里你可以改变背景或颜色的忘记形式。<br>按钮：您可以设置按钮所见即所得的颜色。<br>错误消息：插件的主要功能.您可以更改错误日志消息，因为您希望在20250103→ Error Messages中向用户显示。<br>欢迎消息：与错误日志消息相同，您可以通过20250103→ Welcome Messages自定义欢迎消息。<br>表单页脚：登录按钮后，这里是表单页脚.您可以自定义页脚{文本、显示、文本装饰、文本颜色、文本悬停颜色和文本大小}。在此部分中，您还可以自定义页脚文本。</p><p>定制后使WordPress登录页面移动的友好<br>这个插件也是响应式的。这意味着，当您自定义登录页面，它会在移动的上看起来不错，即它是响应式的.</p><h2 id="三、演示"><a href="#三、演示" class="headerlink" title="三、演示"></a>三、演示</h2><p>使用reCAPTCHA和Google Fonts需要购买20250103Pro版，而系统中其他所有工具和服务均可免费使用。无论是进行基础的表单验证、网站数据分析，还是应用多样化的字体样式，平台都为用户提供了全面支持，让在线项目的创建和管理更加高效便捷。</p><p>20250103默认主题</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250103/1.avif"></p><p>20250103ProPro主题</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20250103/2.avif"></p><h2 id="四、20250103Pro百度网盘下载"><a href="#四、20250103Pro百度网盘下载" class="headerlink" title="四、20250103Pro百度网盘下载"></a>四、20250103Pro百度网盘下载</h2><p>为了确保功能完整使用，建议将20250103与其付费升级版本20250103Pro一并安装，这样可以充分发挥其全部潜力并提升用户体验。</p><blockquote><p>百度网盘地址：<a href="https://pan.baidu.com/s/1gm3aBamBy7o9_7bRZ_WcZg?pwd=xqqn">https://pan.baidu.com/s/1gm3aBamBy7o9_7bRZ_WcZg?pwd&#x3D;xqqn</a><br>提取码：xqqn</p></blockquote></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8F%92%E4%BB%B6/">插件</category>
      
      
      <comments>https://blog.mingliangstar.com/2025/01/03/%E7%99%BB%E5%BD%95%E9%A1%B5%E9%9D%A2%E6%8F%92%E4%BB%B6/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>轻博客的粒子浪漫</title>
      <link>https://blog.mingliangstar.com/2024/12/13/%E8%BD%BB%E5%8D%9A%E5%AE%A2%E7%9A%84%E7%B2%92%E5%AD%90%E6%B5%AA%E6%BC%AB/</link>
      <guid>https://blog.mingliangstar.com/2024/12/13/%E8%BD%BB%E5%8D%9A%E5%AE%A2%E7%9A%84%E7%B2%92%E5%AD%90%E6%B5%AA%E6%BC%AB/</guid>
      <pubDate>Fri, 13 Dec 2024 02:50:50 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;一、鼠标点击烟花特效&quot;&gt;&lt;a href=&quot;#一、鼠标点击烟花特效&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、鼠标点击烟花特效"><a href="#一、鼠标点击烟花特效" class="headerlink" title="一、鼠标点击烟花特效"></a>一、鼠标点击烟花特效</h2><blockquote><p>鸣谢：<a href="https://juejin.cn/post/7106018120036253710#heading-2">https://juejin.cn/post/7106018120036253710#heading-2</a></p></blockquote><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">function</span> <span class="title function_">clickEffect</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> balls = [];</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> longPressed = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> longPress;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> multiplier = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> width, height;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> origin;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> normal;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">let</span> ctx;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> colours = [<span class="string">&quot;#F73859&quot;</span>, <span class="string">&quot;#14FFEC&quot;</span>, <span class="string">&quot;#00E0FF&quot;</span>, <span class="string">&quot;#FF99FE&quot;</span>, <span class="string">&quot;#FAF15D&quot;</span>];</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> canvas = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;canvas&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">  <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(canvas);</span></span><br><span class="line"><span class="language-javascript">  canvas.<span class="title function_">setAttribute</span>(<span class="string">&quot;style&quot;</span>, <span class="string">&quot;width: 100%; height: 100%; top: 0; left: 0; z-index: 99999; position: fixed; pointer-events: none;&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> pointer = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;span&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">  pointer.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&quot;pointer&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">  <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(pointer);</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">if</span> (canvas.<span class="property">getContext</span> &amp;&amp; <span class="variable language_">window</span>.<span class="property">addEventListener</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    ctx = canvas.<span class="title function_">getContext</span>(<span class="string">&quot;2d&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">updateSize</span>();</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;resize&#x27;</span>, updateSize, <span class="literal">false</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">loop</span>();</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&quot;mousedown&quot;</span>, <span class="keyword">function</span>(<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="title function_">pushBalls</span>(<span class="title function_">randBetween</span>(<span class="number">10</span>, <span class="number">20</span>), e.<span class="property">clientX</span>, e.<span class="property">clientY</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&quot;is-pressed&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">      longPress = <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&quot;is-longpress&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        longPressed = <span class="literal">true</span>;</span></span><br><span class="line"><span class="language-javascript">      &#125;, <span class="number">500</span>);</span></span><br><span class="line"><span class="language-javascript">    &#125;, <span class="literal">false</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&quot;mouseup&quot;</span>, <span class="keyword">function</span>(<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="built_in">clearInterval</span>(longPress);</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">if</span> (longPressed == <span class="literal">true</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&quot;is-longpress&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">pushBalls</span>(<span class="title function_">randBetween</span>(<span class="number">50</span> + <span class="title class_">Math</span>.<span class="title function_">ceil</span>(multiplier), <span class="number">100</span> + <span class="title class_">Math</span>.<span class="title function_">ceil</span>(multiplier)), e.<span class="property">clientX</span>, e.<span class="property">clientY</span>);</span></span><br><span class="line"><span class="language-javascript">        longPressed = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&quot;is-pressed&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">    &#125;, <span class="literal">false</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&quot;mousemove&quot;</span>, <span class="keyword">function</span>(<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">let</span> x = e.<span class="property">clientX</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">let</span> y = e.<span class="property">clientY</span>;</span></span><br><span class="line"><span class="language-javascript">      pointer.<span class="property">style</span>.<span class="property">top</span> = y + <span class="string">&quot;px&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">      pointer.<span class="property">style</span>.<span class="property">left</span> = x + <span class="string">&quot;px&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    &#125;, <span class="literal">false</span>);</span></span><br><span class="line"><span class="language-javascript">  &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;canvas or addEventListener is unsupported!&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">updateSize</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    canvas.<span class="property">width</span> = <span class="variable language_">window</span>.<span class="property">innerWidth</span> * <span class="number">2</span>;</span></span><br><span class="line"><span class="language-javascript">    canvas.<span class="property">height</span> = <span class="variable language_">window</span>.<span class="property">innerHeight</span> * <span class="number">2</span>;</span></span><br><span class="line"><span class="language-javascript">    canvas.<span class="property">style</span>.<span class="property">width</span> = <span class="variable language_">window</span>.<span class="property">innerWidth</span> + <span class="string">&#x27;px&#x27;</span>;</span></span><br><span class="line"><span class="language-javascript">    canvas.<span class="property">style</span>.<span class="property">height</span> = <span class="variable language_">window</span>.<span class="property">innerHeight</span> + <span class="string">&#x27;px&#x27;</span>;</span></span><br><span class="line"><span class="language-javascript">    ctx.<span class="title function_">scale</span>(<span class="number">2</span>, <span class="number">2</span>);</span></span><br><span class="line"><span class="language-javascript">    width = (canvas.<span class="property">width</span> = <span class="variable language_">window</span>.<span class="property">innerWidth</span>);</span></span><br><span class="line"><span class="language-javascript">    height = (canvas.<span class="property">height</span> = <span class="variable language_">window</span>.<span class="property">innerHeight</span>);</span></span><br><span class="line"><span class="language-javascript">    origin = &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">x</span>: width / <span class="number">2</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">y</span>: height / <span class="number">2</span></span></span><br><span class="line"><span class="language-javascript">    &#125;;</span></span><br><span class="line"><span class="language-javascript">    normal = &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">x</span>: width / <span class="number">2</span>,</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">y</span>: height / <span class="number">2</span></span></span><br><span class="line"><span class="language-javascript">    &#125;;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">class</span> <span class="title class_">Ball</span> &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">constructor</span>(<span class="params">x = origin.x, y = origin.y</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">x</span> = x;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">y</span> = y;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">angle</span> = <span class="title class_">Math</span>.<span class="property">PI</span> * <span class="number">2</span> * <span class="title class_">Math</span>.<span class="title function_">random</span>();</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">if</span> (longPressed == <span class="literal">true</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">this</span>.<span class="property">multiplier</span> = <span class="title function_">randBetween</span>(<span class="number">14</span> + multiplier, <span class="number">15</span> + multiplier);</span></span><br><span class="line"><span class="language-javascript">      &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">this</span>.<span class="property">multiplier</span> = <span class="title function_">randBetween</span>(<span class="number">6</span>, <span class="number">12</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">vx</span> = (<span class="variable language_">this</span>.<span class="property">multiplier</span> + <span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">0.5</span>) * <span class="title class_">Math</span>.<span class="title function_">cos</span>(<span class="variable language_">this</span>.<span class="property">angle</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">vy</span> = (<span class="variable language_">this</span>.<span class="property">multiplier</span> + <span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">0.5</span>) * <span class="title class_">Math</span>.<span class="title function_">sin</span>(<span class="variable language_">this</span>.<span class="property">angle</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">r</span> = <span class="title function_">randBetween</span>(<span class="number">8</span>, <span class="number">12</span>) + <span class="number">3</span> * <span class="title class_">Math</span>.<span class="title function_">random</span>();</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">color</span> = colours[<span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * colours.<span class="property">length</span>)];</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">update</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">x</span> += <span class="variable language_">this</span>.<span class="property">vx</span> - normal.<span class="property">x</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">y</span> += <span class="variable language_">this</span>.<span class="property">vy</span> - normal.<span class="property">y</span>;</span></span><br><span class="line"><span class="language-javascript">      normal.<span class="property">x</span> = -<span class="number">2</span> / <span class="variable language_">window</span>.<span class="property">innerWidth</span> * <span class="title class_">Math</span>.<span class="title function_">sin</span>(<span class="variable language_">this</span>.<span class="property">angle</span>);</span></span><br><span class="line"><span class="language-javascript">      normal.<span class="property">y</span> = -<span class="number">2</span> / <span class="variable language_">window</span>.<span class="property">innerHeight</span> * <span class="title class_">Math</span>.<span class="title function_">cos</span>(<span class="variable language_">this</span>.<span class="property">angle</span>);</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">r</span> -= <span class="number">0.3</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">vx</span> *= <span class="number">0.9</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="variable language_">this</span>.<span class="property">vy</span> *= <span class="number">0.9</span>;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">pushBalls</span>(<span class="params">count = <span class="number">1</span>, x = origin.x, y = origin.y</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; count; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">      balls.<span class="title function_">push</span>(<span class="keyword">new</span> <span class="title class_">Ball</span>(x, y));</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">randBetween</span>(<span class="params">min, max</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * max) + min;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">loop</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    ctx.<span class="property">fillStyle</span> = <span class="string">&quot;rgba(255, 255, 255, 0)&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">    ctx.<span class="title function_">clearRect</span>(<span class="number">0</span>, <span class="number">0</span>, canvas.<span class="property">width</span>, canvas.<span class="property">height</span>);</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; balls.<span class="property">length</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">let</span> b = balls[i];</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">if</span> (b.<span class="property">r</span> &lt; <span class="number">0</span>) <span class="keyword">continue</span>;</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="property">fillStyle</span> = b.<span class="property">color</span>;</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="title function_">beginPath</span>();</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="title function_">arc</span>(b.<span class="property">x</span>, b.<span class="property">y</span>, b.<span class="property">r</span>, <span class="number">0</span>, <span class="title class_">Math</span>.<span class="property">PI</span> * <span class="number">2</span>, <span class="literal">false</span>);</span></span><br><span class="line"><span class="language-javascript">      ctx.<span class="title function_">fill</span>();</span></span><br><span class="line"><span class="language-javascript">      b.<span class="title function_">update</span>();</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">if</span> (longPressed == <span class="literal">true</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      multiplier += <span class="number">0.2</span>;</span></span><br><span class="line"><span class="language-javascript">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!longPressed &amp;&amp; multiplier &gt;= <span class="number">0</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      multiplier -= <span class="number">0.4</span>;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">removeBall</span>();</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">requestAnimationFrame</span>(loop);</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">removeBall</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; balls.<span class="property">length</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">let</span> b = balls[i];</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">if</span> (b.<span class="property">x</span> + b.<span class="property">r</span> &lt; <span class="number">0</span> || b.<span class="property">x</span> - b.<span class="property">r</span> &gt; width || b.<span class="property">y</span> + b.<span class="property">r</span> &lt; <span class="number">0</span> || b.<span class="property">y</span> - b.<span class="property">r</span> &gt; height || b.<span class="property">r</span> &lt; <span class="number">0</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        balls.<span class="title function_">splice</span>(i, <span class="number">1</span>);</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript">&#125;</span></span><br><span class="line"><span class="language-javascript"><span class="title function_">clickEffect</span>();<span class="comment">//调用特效函数</span></span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="二、鼠标点击爱心特效"><a href="#二、鼠标点击爱心特效" class="headerlink" title="二、鼠标点击爱心特效"></a>二、鼠标点击爱心特效</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 网页鼠标点击特效（爱心） --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">         ! <span class="keyword">function</span> (<span class="params">e, t, a</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">r</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">for</span> (<span class="keyword">var</span> e = <span class="number">0</span>; e &lt; s.<span class="property">length</span>; e++) s[e].<span class="property">alpha</span> &lt;= <span class="number">0</span> ? (t.<span class="property">body</span>.<span class="title function_">removeChild</span>(s[e].<span class="property">el</span>), s.<span class="title function_">splice</span>(e, <span class="number">1</span>)) : (s[</span></span><br><span class="line"><span class="language-javascript">                        e].<span class="property">y</span>--, s[e].<span class="property">scale</span> += <span class="number">.004</span>, s[e].<span class="property">alpha</span> -= <span class="number">.013</span>, s[e].<span class="property">el</span>.<span class="property">style</span>.<span class="property">cssText</span> = <span class="string">&quot;left:&quot;</span> + s[e].<span class="property">x</span> +</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;px;top:&quot;</span> + s[e].<span class="property">y</span> + <span class="string">&quot;px;opacity:&quot;</span> + s[e].<span class="property">alpha</span> + <span class="string">&quot;;transform:scale(&quot;</span> + s[e].<span class="property">scale</span> + <span class="string">&quot;,&quot;</span> + s[e]</span></span><br><span class="line"><span class="language-javascript">                    .<span class="property">scale</span> + <span class="string">&quot;) rotate(45deg);background:&quot;</span> + s[e].<span class="property">color</span> + <span class="string">&quot;;z-index:99999&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">requestAnimationFrame</span>(r)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">n</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> t = <span class="string">&quot;function&quot;</span> == <span class="keyword">typeof</span> e.<span class="property">onclick</span> &amp;&amp; e.<span class="property">onclick</span>;</span></span><br><span class="line"><span class="language-javascript">                e.<span class="property">onclick</span> = <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    t &amp;&amp; <span class="title function_">t</span>(), <span class="title function_">o</span>(e)</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">o</span>(<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> a = t.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                a.<span class="property">className</span> = <span class="string">&quot;heart&quot;</span>, s.<span class="title function_">push</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">el</span>: a,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">x</span>: e.<span class="property">clientX</span> - <span class="number">5</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">y</span>: e.<span class="property">clientY</span> - <span class="number">5</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">scale</span>: <span class="number">1</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">alpha</span>: <span class="number">1</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">color</span>: <span class="title function_">c</span>()</span></span><br><span class="line"><span class="language-javascript">                &#125;), t.<span class="property">body</span>.<span class="title function_">appendChild</span>(a)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">i</span>(<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> a = t.<span class="title function_">createElement</span>(<span class="string">&quot;style&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                a.<span class="property">type</span> = <span class="string">&quot;text/css&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">try</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                    a.<span class="title function_">appendChild</span>(t.<span class="title function_">createTextNode</span>(e))</span></span><br><span class="line"><span class="language-javascript">                &#125; <span class="keyword">catch</span> (t) &#123;</span></span><br><span class="line"><span class="language-javascript">                    a.<span class="property">styleSheet</span>.<span class="property">cssText</span> = e</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">                t.<span class="title function_">getElementsByTagName</span>(<span class="string">&quot;head&quot;</span>)[<span class="number">0</span>].<span class="title function_">appendChild</span>(a)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">c</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span> <span class="string">&quot;rgb(&quot;</span> + ~~(<span class="number">255</span> * <span class="title class_">Math</span>.<span class="title function_">random</span>()) + <span class="string">&quot;,&quot;</span> + ~~(<span class="number">255</span> * <span class="title class_">Math</span>.<span class="title function_">random</span>()) + <span class="string">&quot;,&quot;</span> + ~~(<span class="number">255</span> * <span class="title class_">Math</span></span></span><br><span class="line"><span class="language-javascript">                    .<span class="title function_">random</span>()) + <span class="string">&quot;)&quot;</span></span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> s = [];</span></span><br><span class="line"><span class="language-javascript">            e.<span class="property">requestAnimationFrame</span> = e.<span class="property">requestAnimationFrame</span> || e.<span class="property">webkitRequestAnimationFrame</span> || e</span></span><br><span class="line"><span class="language-javascript">                .<span class="property">mozRequestAnimationFrame</span> || e.<span class="property">oRequestAnimationFrame</span> || e.<span class="property">msRequestAnimationFrame</span> || <span class="keyword">function</span> (<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="built_in">setTimeout</span>(e, <span class="number">1e3</span> / <span class="number">60</span>)</span></span><br><span class="line"><span class="language-javascript">                &#125;, <span class="title function_">i</span>(</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;.heart&#123;width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);&#125;.heart:after,.heart:before&#123;content: &#x27;&#x27;;width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;&#125;.heart:after&#123;top: -5px;&#125;.heart:before&#123;left: -5px;&#125;&quot;</span></span></span><br><span class="line"><span class="language-javascript">                ), <span class="title function_">n</span>(), <span class="title function_">r</span>()</span></span><br><span class="line"><span class="language-javascript">        &#125;(<span class="variable language_">window</span>, <span class="variable language_">document</span>);</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="三、鼠标点击文字特效"><a href="#三、鼠标点击文字特效" class="headerlink" title="三、鼠标点击文字特效"></a>三、鼠标点击文字特效</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> a_idx = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">window</span>.<span class="property">onclick</span> = <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> a = <span class="keyword">new</span> <span class="title class_">Array</span>(<span class="string">&quot;❤富强❤&quot;</span>, <span class="string">&quot;❤民主❤&quot;</span>, <span class="string">&quot;❤文明❤&quot;</span>, <span class="string">&quot;❤和谐❤&quot;</span>, <span class="string">&quot;❤自由❤&quot;</span>, <span class="string">&quot;❤平等❤&quot;</span>, <span class="string">&quot;❤公正❤&quot;</span>, <span class="string">&quot;❤法治❤&quot;</span>, <span class="string">&quot;❤爱国❤&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;❤敬业❤&quot;</span>, <span class="string">&quot;❤诚信❤&quot;</span>, <span class="string">&quot;❤友善❤&quot;</span>);</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> heart = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;b&quot;</span>); <span class="comment">//创建b元素</span></span></span><br><span class="line"><span class="language-javascript">                heart.<span class="property">onselectstart</span> = <span class="keyword">new</span> <span class="title class_">Function</span>(<span class="string">&#x27;event.returnValue=false&#x27;</span>); <span class="comment">//防止拖动</span></span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(heart).<span class="property">innerHTML</span> = a[a_idx]; <span class="comment">//将b元素添加到页面上</span></span></span><br><span class="line"><span class="language-javascript">                a_idx = (a_idx + <span class="number">1</span>) % a.<span class="property">length</span>;</span></span><br><span class="line"><span class="language-javascript">                heart.<span class="property">style</span>.<span class="property">cssText</span> = <span class="string">&quot;position: fixed;left:-100%;&quot;</span>; <span class="comment">//给p元素设置样式</span></span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> f = <span class="number">16</span>, <span class="comment">// 字体大小</span></span></span><br><span class="line"><span class="language-javascript">                    x = event.<span class="property">clientX</span> - f / <span class="number">2</span>, <span class="comment">// 横坐标</span></span></span><br><span class="line"><span class="language-javascript">                    y = event.<span class="property">clientY</span> - f, <span class="comment">// 纵坐标</span></span></span><br><span class="line"><span class="language-javascript">                    c = <span class="title function_">randomColor</span>(), <span class="comment">// 随机颜色</span></span></span><br><span class="line"><span class="language-javascript">                    a = <span class="number">1</span>, <span class="comment">// 透明度</span></span></span><br><span class="line"><span class="language-javascript">                    s = <span class="number">1.2</span>; <span class="comment">// 放大缩小</span></span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> timer = <span class="built_in">setInterval</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123; <span class="comment">//添加定时器</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">if</span> (a &lt;= <span class="number">0</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">removeChild</span>(heart);</span></span><br><span class="line"><span class="language-javascript">                        <span class="built_in">clearInterval</span>(timer);</span></span><br><span class="line"><span class="language-javascript">                    &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                        heart.<span class="property">style</span>.<span class="property">cssText</span> = <span class="string">&quot;font-size:16px;cursor: default;position: fixed;color:&quot;</span> +</span></span><br><span class="line"><span class="language-javascript">                            c + <span class="string">&quot;;left:&quot;</span> + x + <span class="string">&quot;px;top:&quot;</span> + y + <span class="string">&quot;px;opacity:&quot;</span> + a + <span class="string">&quot;;transform:scale(&quot;</span> +</span></span><br><span class="line"><span class="language-javascript">                            s + <span class="string">&quot;);&quot;</span>;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">                        y--;</span></span><br><span class="line"><span class="language-javascript">                        a -= <span class="number">0.016</span>;</span></span><br><span class="line"><span class="language-javascript">                        s += <span class="number">0.002</span>;</span></span><br><span class="line"><span class="language-javascript">                    &#125;</span></span><br><span class="line"><span class="language-javascript">                &#125;, <span class="number">15</span>)</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 随机颜色</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">randomColor</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span> <span class="string">&quot;rgb(&quot;</span> + (~~(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">255</span>)) + <span class="string">&quot;,&quot;</span> + (~~(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">255</span>)) + <span class="string">&quot;,&quot;</span> + (~~(<span class="title class_">Math</span></span></span><br><span class="line"><span class="language-javascript">                .<span class="title function_">random</span>() * <span class="number">255</span>)) + <span class="string">&quot;)&quot;</span>;</span></span><br><span class="line"><span class="language-javascript"> </span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;());</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="四、鼠标星星拖尾特效"><a href="#四、鼠标星星拖尾特效" class="headerlink" title="四、鼠标星星拖尾特效"></a>四、鼠标星星拖尾特效</h2><blockquote><p>鸣谢：<a href="https://images.mingliangstar.com/go/?url=https://blog.csdn.net/weixin_44461275/article/details/131402453">https://blog.csdn.net/weixin_44461275&#x2F;article&#x2F;details&#x2F;131402453</a></p></blockquote><h3 id="JS"><a href="#JS" class="headerlink" title="JS"></a>JS</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">drawStar</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">//定义数组，arr存放每个小星星的信息，colour为颜色数组，存几个好看的颜色</span></span><br><span class="line">  <span class="keyword">var</span> arr = [];</span><br><span class="line">  <span class="keyword">var</span> colours = [<span class="string">&quot;#ffff00&quot;</span>, <span class="string">&quot;#66ffff&quot;</span>, <span class="string">&quot;#3399ff&quot;</span>, <span class="string">&quot;#99ff00&quot;</span>, <span class="string">&quot;#ff9900&quot;</span>];</span><br><span class="line">  <span class="keyword">var</span> timeoutList = []; <span class="comment">// 计时器列表-用于后续清理计时器</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// 创建画布</span></span><br><span class="line">  <span class="keyword">const</span> canvas = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;canvas&#x27;</span>)</span><br><span class="line">  <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(canvas)</span><br><span class="line">  <span class="keyword">var</span> ctx = canvas.<span class="title function_">getContext</span>(<span class="string">&quot;2d&quot;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 让画布自适应窗口大小，这个复制即可</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">resizeCanvas</span>(<span class="params"></span>) &#123;</span><br><span class="line">    canvas.<span class="property">width</span> = <span class="variable language_">window</span>.<span class="property">innerWidth</span>;</span><br><span class="line">    canvas.<span class="property">height</span> = <span class="variable language_">window</span>.<span class="property">innerHeight</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title function_">resizeCanvas</span>();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 给画布css样式，固定定位，且阻止用户的鼠标事件</span></span><br><span class="line">  canvas.<span class="property">style</span>.<span class="property">cssText</span> = <span class="string">`</span></span><br><span class="line"><span class="string">    position: fixed;</span></span><br><span class="line"><span class="string">    z-index: 1000;</span></span><br><span class="line"><span class="string">    top: 0;</span></span><br><span class="line"><span class="string">    left: 0;</span></span><br><span class="line"><span class="string">    pointer-events: none;</span></span><br><span class="line"><span class="string">  `</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 封装绘制一个五角星函数</span></span><br><span class="line">  <span class="comment">// x是圆心横坐标，y是圆心纵坐标，其实就是鼠标位置（x ，y）</span></span><br><span class="line">  <span class="comment">// r是里面小圆半径 ，l是大圆半径</span></span><br><span class="line">  <span class="comment">// rot是初始旋转角度</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">star</span>(<span class="params">x, y, r, l, rot</span>) &#123;</span><br><span class="line">    ctx.<span class="title function_">beginPath</span>();</span><br><span class="line">    <span class="comment">// 循环5次，因为5个点</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">      <span class="comment">//先绘制小圆上一个点</span></span><br><span class="line">      ctx.<span class="title function_">lineTo</span>(</span><br><span class="line">        <span class="title class_">Math</span>.<span class="title function_">cos</span>(((<span class="number">18</span> + i * <span class="number">72</span> - rot) * <span class="title class_">Math</span>.<span class="property">PI</span>) / <span class="number">180</span>) * r + x,</span><br><span class="line">        -<span class="title class_">Math</span>.<span class="title function_">sin</span>(((<span class="number">18</span> + i * <span class="number">72</span> - rot) * <span class="title class_">Math</span>.<span class="property">PI</span>) / <span class="number">180</span>) * r + y</span><br><span class="line">      );</span><br><span class="line">      <span class="comment">//连线到大圆上一个点</span></span><br><span class="line">      ctx.<span class="title function_">lineTo</span>(</span><br><span class="line">        <span class="title class_">Math</span>.<span class="title function_">cos</span>(((<span class="number">54</span> + i * <span class="number">72</span> - rot) * <span class="title class_">Math</span>.<span class="property">PI</span>) / <span class="number">180</span>) * l + x,</span><br><span class="line">        -<span class="title class_">Math</span>.<span class="title function_">sin</span>(((<span class="number">54</span> + i * <span class="number">72</span> - rot) * <span class="title class_">Math</span>.<span class="property">PI</span>) / <span class="number">180</span>) * l + y</span><br><span class="line">      );</span><br><span class="line">    &#125;</span><br><span class="line">    ctx.<span class="title function_">closePath</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 绘制一堆星星</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">draw</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">//循环数组</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="keyword">let</span> temp = arr[i];</span><br><span class="line">      <span class="comment">//调用绘制一个星星函数</span></span><br><span class="line">      <span class="title function_">star</span>(temp.<span class="property">x</span>, temp.<span class="property">y</span>, temp.<span class="property">r</span>, temp.<span class="property">r</span> * <span class="number">3</span>, temp.<span class="property">rot</span>);</span><br><span class="line">      <span class="comment">//星星颜色</span></span><br><span class="line">      ctx.<span class="property">fillStyle</span> = temp.<span class="property">color</span>;</span><br><span class="line">      <span class="comment">//星星边框颜色</span></span><br><span class="line">      ctx.<span class="property">strokeStyle</span> = temp.<span class="property">color</span>;</span><br><span class="line">      <span class="comment">//线宽度</span></span><br><span class="line">      ctx.<span class="property">lineWidth</span> = <span class="number">0.1</span>;</span><br><span class="line">      <span class="comment">//角有弧度</span></span><br><span class="line">      ctx.<span class="property">lineJoin</span> = <span class="string">&quot;round&quot;</span>;</span><br><span class="line">      <span class="comment">// 填充</span></span><br><span class="line">      ctx.<span class="title function_">fill</span>();</span><br><span class="line">      <span class="comment">// 绘制路径</span></span><br><span class="line">      ctx.<span class="title function_">stroke</span>();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//更新动画</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">update</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">//循环数组</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="comment">// x坐标+dx移动距离</span></span><br><span class="line">      arr[i].<span class="property">x</span> += arr[i].<span class="property">dx</span>;</span><br><span class="line">      <span class="comment">// y坐标+dy移动距离</span></span><br><span class="line">      arr[i].<span class="property">y</span> += arr[i].<span class="property">dy</span>;</span><br><span class="line">      <span class="comment">// 加上旋转角度</span></span><br><span class="line">      arr[i].<span class="property">rot</span> += arr[i].<span class="property">td</span>;</span><br><span class="line">      <span class="comment">// 半径慢慢减小</span></span><br><span class="line">      arr[i].<span class="property">r</span> -= <span class="number">0.015</span>;</span><br><span class="line">      <span class="comment">// 当半径小于0时</span></span><br><span class="line">      <span class="keyword">if</span> (arr[i].<span class="property">r</span> &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">//删除该星星</span></span><br><span class="line">        arr.<span class="title function_">splice</span>(i, <span class="number">1</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 添加当前位置星星数据</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">addStarts</span>(<span class="params">e</span>) &#123;</span><br><span class="line">    <span class="comment">// 每移动触发一次事件给arr数组添加一个星星</span></span><br><span class="line">    arr.<span class="title function_">push</span>(&#123;</span><br><span class="line">      <span class="comment">// x是初始横坐标</span></span><br><span class="line">      <span class="attr">x</span>: e.<span class="property">clientX</span>,</span><br><span class="line">      <span class="comment">//y是初始纵坐标</span></span><br><span class="line">      <span class="attr">y</span>: e.<span class="property">clientY</span>,</span><br><span class="line">      <span class="comment">//r是星星里面那个小圆半径，哪来的小圆等会说</span></span><br><span class="line">      <span class="attr">r</span>: <span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">0.5</span> + <span class="number">1.5</span>,</span><br><span class="line">      <span class="comment">//运动时旋转的角度</span></span><br><span class="line">      <span class="attr">td</span>: <span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">4</span> - <span class="number">2</span>,</span><br><span class="line">      <span class="comment">// X轴移动距离</span></span><br><span class="line">      <span class="attr">dx</span>: <span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">2</span> - <span class="number">1</span>,</span><br><span class="line">      <span class="comment">// y轴移动距离</span></span><br><span class="line">      <span class="attr">dy</span>: <span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">1</span> + <span class="number">1</span>,</span><br><span class="line">      <span class="comment">// 初始的旋转角度</span></span><br><span class="line">      <span class="attr">rot</span>: <span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">90</span> + <span class="number">90</span>,</span><br><span class="line">      <span class="comment">// 颜色</span></span><br><span class="line">      <span class="attr">color</span>: colours[<span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * colours.<span class="property">length</span>)],</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 监听屏幕变化事件</span></span><br><span class="line">  <span class="variable language_">window</span>.<span class="property">onresize</span> = resizeCanvas;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 监听鼠标移动事件</span></span><br><span class="line">  <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&quot;mousemove&quot;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 添加星星数据</span></span><br><span class="line">    <span class="title function_">addStarts</span>(e);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//设置100毫秒内效果</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index &lt; <span class="number">200</span>; index++) &#123;</span><br><span class="line">      <span class="keyword">if</span> (index === <span class="number">0</span> &amp;&amp; timeoutList.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> timeoutName <span class="keyword">of</span> timeoutList) &#123;</span><br><span class="line">          <span class="built_in">clearTimeout</span>(timeoutName)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      timeoutList[index] = <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">//清屏</span></span><br><span class="line">        ctx.<span class="title function_">clearRect</span>(<span class="number">0</span>, <span class="number">0</span>, canvas.<span class="property">width</span>, canvas.<span class="property">height</span>);</span><br><span class="line">        <span class="comment">//绘制</span></span><br><span class="line">        <span class="title function_">draw</span>();</span><br><span class="line">        <span class="comment">//更新</span></span><br><span class="line">        <span class="title function_">update</span>();</span><br><span class="line">      &#125;, index * <span class="number">20</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title function_">drawStar</span>()</span><br></pre></td></tr></table></figure><h3 id="HTML"><a href="#HTML" class="headerlink" title="HTML"></a>HTML</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    </span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;js-cursor-container&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        (<span class="keyword">function</span> <span class="title function_">fairyDustCursor</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> possibleColors = [<span class="string">&quot;#D61C59&quot;</span>, <span class="string">&quot;#E7D84B&quot;</span>, <span class="string">&quot;#1B8798&quot;</span>]</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> width = <span class="variable language_">window</span>.<span class="property">innerWidth</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> height = <span class="variable language_">window</span>.<span class="property">innerHeight</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> cursor = &#123; <span class="attr">x</span>: width / <span class="number">2</span>, <span class="attr">y</span>: width / <span class="number">2</span> &#125;;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">var</span> particles = [];</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">init</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">bindEvents</span>();</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">loop</span>();</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// Bind events that are needed</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">bindEvents</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;mousemove&#x27;</span>, onMouseMove);</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;resize&#x27;</span>, onWindowResize);</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">onWindowResize</span>(<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                width = <span class="variable language_">window</span>.<span class="property">innerWidth</span>;</span></span><br><span class="line"><span class="language-javascript">                height = <span class="variable language_">window</span>.<span class="property">innerHeight</span>;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">onMouseMove</span>(<span class="params">e</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                cursor.<span class="property">x</span> = e.<span class="property">clientX</span>;</span></span><br><span class="line"><span class="language-javascript">                cursor.<span class="property">y</span> = e.<span class="property">clientY</span>;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">addParticle</span>(cursor.<span class="property">x</span>, cursor.<span class="property">y</span>, possibleColors[<span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * possibleColors.<span class="property">length</span>)]);</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">addParticle</span>(<span class="params">x, y, color</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> particle = <span class="keyword">new</span> <span class="title class_">Particle</span>();</span></span><br><span class="line"><span class="language-javascript">                particle.<span class="title function_">init</span>(x, y, color);</span></span><br><span class="line"><span class="language-javascript">                particles.<span class="title function_">push</span>(particle);</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">updateParticles</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// Updated</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; particles.<span class="property">length</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">                    particles[i].<span class="title function_">update</span>();</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// Remove dead particles</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">for</span> (<span class="keyword">var</span> i = particles.<span class="property">length</span> - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i-) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">if</span> (particles[i].<span class="property">lifeSpan</span> &lt; <span class="number">0</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                        particles[i].<span class="title function_">die</span>();</span></span><br><span class="line"><span class="language-javascript">                        particles.<span class="title function_">splice</span>(i, <span class="number">1</span>);</span></span><br><span class="line"><span class="language-javascript">                    &#125;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">loop</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">requestAnimationFrame</span>(loop);</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">updateParticles</span>();</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="comment">/**</span></span></span><br><span class="line"><span class="comment"><span class="language-javascript">             * Particles</span></span></span><br><span class="line"><span class="comment"><span class="language-javascript">             */</span></span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">Particle</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">character</span> = <span class="string">&quot;*&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">lifeSpan</span> = <span class="number">120</span>; <span class="comment">//ms</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">initialStyles</span> = &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;position&quot;</span>: <span class="string">&quot;fixed&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;display&quot;</span>: <span class="string">&quot;inline-block&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;top&quot;</span>: <span class="string">&quot;0px&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;left&quot;</span>: <span class="string">&quot;0px&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;pointerEvents&quot;</span>: <span class="string">&quot;none&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;touch-action&quot;</span>: <span class="string">&quot;none&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;z-index&quot;</span>: <span class="string">&quot;10000000&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;fontSize&quot;</span>: <span class="string">&quot;25px&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="string">&quot;will-change&quot;</span>: <span class="string">&quot;transform&quot;</span></span></span><br><span class="line"><span class="language-javascript">                &#125;;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// Init, and set properties</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">init</span> = <span class="keyword">function</span> (<span class="params">x, y, color</span>) &#123;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">velocity</span> = &#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="attr">x</span>: (<span class="title class_">Math</span>.<span class="title function_">random</span>() &lt; <span class="number">0.5</span> ? -<span class="number">1</span> : <span class="number">1</span>) * (<span class="title class_">Math</span>.<span class="title function_">random</span>() / <span class="number">2</span>),</span></span><br><span class="line"><span class="language-javascript">                        <span class="attr">y</span>: <span class="number">1</span></span></span><br><span class="line"><span class="language-javascript">                    &#125;;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">position</span> = &#123; <span class="attr">x</span>: x + <span class="number">10</span>, <span class="attr">y</span>: y + <span class="number">10</span> &#125;;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">initialStyles</span>.<span class="property">color</span> = color;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">element</span> = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;span&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">element</span>.<span class="property">innerHTML</span> = <span class="variable language_">this</span>.<span class="property">character</span>;</span></span><br><span class="line"><span class="language-javascript">                    <span class="title function_">applyProperties</span>(<span class="variable language_">this</span>.<span class="property">element</span>, <span class="variable language_">this</span>.<span class="property">initialStyles</span>);</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="title function_">update</span>();</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;.js-cursor-container&#x27;</span>).<span class="title function_">appendChild</span>(<span class="variable language_">this</span>.<span class="property">element</span>);</span></span><br><span class="line"><span class="language-javascript">                &#125;;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">update</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">position</span>.<span class="property">x</span> += <span class="variable language_">this</span>.<span class="property">velocity</span>.<span class="property">x</span>;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">position</span>.<span class="property">y</span> += <span class="variable language_">this</span>.<span class="property">velocity</span>.<span class="property">y</span>;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">lifeSpan</span>-;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">element</span>.<span class="property">style</span>.<span class="property">transform</span> = <span class="string">&quot;translate3d(&quot;</span> + <span class="variable language_">this</span>.<span class="property">position</span>.<span class="property">x</span> + <span class="string">&quot;px,&quot;</span> + <span class="variable language_">this</span>.<span class="property">position</span>.<span class="property">y</span> + <span class="string">&quot;px, 0) scale(&quot;</span> + (<span class="variable language_">this</span>.<span class="property">lifeSpan</span> / <span class="number">120</span>) + <span class="string">&quot;)&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">die</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">element</span>.<span class="property">parentNode</span>.<span class="title function_">removeChild</span>(<span class="variable language_">this</span>.<span class="property">element</span>);</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="comment">/**</span></span></span><br><span class="line"><span class="comment"><span class="language-javascript">             * Utils</span></span></span><br><span class="line"><span class="comment"><span class="language-javascript">             */</span></span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// Applies css `properties` to an element.</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">function</span> <span class="title function_">applyProperties</span>(<span class="params">target, properties</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> properties) &#123;</span></span><br><span class="line"><span class="language-javascript">                    target.<span class="property">style</span>[key] = properties[key];</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (!(<span class="string">&#x27;ontouchstart&#x27;</span> <span class="keyword">in</span> <span class="variable language_">window</span> || navigator.<span class="property">msMaxTouchPoints</span>)) <span class="title function_">init</span>();</span></span><br><span class="line"><span class="language-javascript">        &#125;)();    </span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/">Wordpress</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/12/13/%E8%BD%BB%E5%8D%9A%E5%AE%A2%E7%9A%84%E7%B2%92%E5%AD%90%E6%B5%AA%E6%BC%AB/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>解决容器启动后无法编辑文件的问题</title>
      <link>https://blog.mingliangstar.com/2024/09/07/%E8%A7%A3%E5%86%B3%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E5%90%8E%E6%97%A0%E6%B3%95%E7%BC%96%E8%BE%91%E6%96%87%E4%BB%B6%E7%9A%84%E9%97%AE%E9%A2%98/</link>
      <guid>https://blog.mingliangstar.com/2024/09/07/%E8%A7%A3%E5%86%B3%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E5%90%8E%E6%97%A0%E6%B3%95%E7%BC%96%E8%BE%91%E6%96%87%E4%BB%B6%E7%9A%84%E9%97%AE%E9%A2%98/</guid>
      <pubDate>Sat, 07 Sep 2024 14:09:25 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;前段时间拉取了个MySQL的容器节点，但是拉起之后发现居然编辑不了MySQL的配置文件，这是我的启动命令&lt;/p&gt;
&lt;figure class=&quot;highlight</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>前段时间拉取了个MySQL的容器节点，但是拉起之后发现居然编辑不了MySQL的配置文件，这是我的启动命令</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd -p 3310:3306  -e MYSQL_ROOT_PASSWORD=12345678 --name slave2  f5f171121fa3 bash</span><br></pre></td></tr></table></figure><hr><p><strong><font style="color:#ff9900;">下面总结下解决方法：</font></strong></p><ol><li>编辑docker file直接从根本上解决问题（还没试过）</li><li>安装需要命令的rpm包（不推荐，依赖特别多）</li><li>将需要编辑的文件在宿主机上编辑，然后再传到容器中（不推荐，特麻烦）</li><li>直接宿主机的挂载目录中编辑对应的容器文件（还行，比较容易）</li><li>我还有个想法，俗话所一切皆文件，直接将需要命令的相关文件从宿主机copy到容器中即可（还没试过）</li></ol><hr><p>当然上面的方法比较另辟迄今，当我们遇到没有一个命令时首先想到的应该是安装，但是有的小伙伴也可能又和我遇到了同样的问题，比如，一顿操作猛如虎….</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240907/1.avif"></p><p>首先启动一个容器后看下启动容器的os信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /etc/os-release</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240907/2.avif"></p><p>可以看到这个MySQL是oracle封装的你使用其他os命令肯定不行，但是我们可能对oracle linux server的命令不是很熟悉，那么该怎么办呢，下面介绍一个比yum,dnf还要轻量级的软件包管理器—microdnf</p><blockquote><p><code>microdnf</code> 是一个轻量级的包管理器，它是 DNF 的一个分支，专为使用在容器环境和嵌入式系统中而设计。由于容器和嵌入式系统通常有资源限制，包括有限的磁盘空间和内存，<code>microdnf</code> 被优化以减少其内存占用和执行速度。</p><p>以下是 <code>microdnf</code> 的一些关键特点：</p><ul><li><strong>轻量化</strong>：<code>microdnf</code> 旨在减少内存和磁盘的使用，使其适合在资源受限的环境中运行。</li><li><strong>兼容性</strong>：它与 DNF 高度兼容，支持大部分 DNF 命令和功能，但去掉了一些在容器中不必要的功能。</li><li><strong>简单性</strong>：<code>microdnf</code> 提供了一个简单的方法来安装、更新和删除软件包。</li><li><strong>依赖管理</strong>：尽管是轻量级，<code>microdnf</code> 仍然处理依赖关系，确保安装的软件包所依赖的包也得到安装。</li><li><strong>配置文件</strong>：<code>microdnf</code> 使用 <code>/etc/microdnf.conf</code> 或 <code>/etc/dnf/microdnf.conf</code> 作为其主要配置文件。</li><li><strong>仓库管理</strong>：它支持配置软件仓库（repositories），允许用户添加、移除或修改仓库的配置。</li><li><strong>包管理操作</strong>：<code>microdnf</code> 支持基本的包管理操作，如安装、更新、查询和删除软件包。</li><li><strong>静默操作</strong>：它支持静默模式，可以在不提示用户输入的情况下自动执行操作。</li><li><strong>安全性</strong>：<code>microdnf</code> 可以配置为自动更新安全相关的包，帮助维护容器的安全性。</li><li><strong>使用场景</strong>：它适用于容器化应用、嵌入式系统和任何需要轻量级包管理器的场景。</li><li><strong>与 DNF 的区别</strong>：<code>microdnf</code> 没有 DNF 的所有特性，比如管理插件、复杂的仓库元数据处理等。</li></ul><p><strong>命令示例</strong>：<br>_   - 安装包：<code>microdnf install &lt;package_name&gt;</code><br>__- 更新包：<code>microdnf update &lt;package_name&gt;</code><br>__- 查询包：<code>microdnf info &lt;package_name&gt;</code><br>__- 删除包：<code>microdnf remove &lt;package_name&gt;</code><br>_<em>- 列出已安装包：<code>microdnf list --installed</code></em></p><p><code>microdnf</code> 是一个实用的工具，尤其适用于需要轻量级包管理的场合。然而，它可能不适合那些需要 DNF 所有高级功能的环境。在使用 <code>microdnf</code> 时，您应该根据您的具体需求和环境来评估其适用性。</p></blockquote><p>用microdnf安装vim</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">microdnf -y install vim</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240907/3.avif"></p><p><strong><font style="color:#fe2c24;">学识浅薄，疏漏难免，祈望高贤不吝赐教。</font></strong></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/09/07/%E8%A7%A3%E5%86%B3%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E5%90%8E%E6%97%A0%E6%B3%95%E7%BC%96%E8%BE%91%E6%96%87%E4%BB%B6%E7%9A%84%E9%97%AE%E9%A2%98/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>搭建与配置私有Docker镜像仓库实战指南</title>
      <link>https://blog.mingliangstar.com/2024/09/04/%E6%90%AD%E5%BB%BA%E4%B8%8E%E9%85%8D%E7%BD%AE%E7%A7%81%E6%9C%89Docker%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97/</link>
      <guid>https://blog.mingliangstar.com/2024/09/04/%E6%90%AD%E5%BB%BA%E4%B8%8E%E9%85%8D%E7%BD%AE%E7%A7%81%E6%9C%89Docker%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97/</guid>
      <pubDate>Wed, 04 Sep 2024 08:46:46 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a><strong>前言</strong></h2><p>在当今快速迭代的软件开发环境中，Docker已成为容器化应用部署的事实标准，极大地提升了应用的可移植性、一致性和开发效率。随着企业级应用对容器技术依赖的日益加深，私有Docker镜像仓库的重要性愈发凸显。它不仅关乎于镜像的安全存储与高效分发，更是实现团队间高效协作与持续集成&#x2F;持续部署（CI&#x2F;CD）流程的关键一环。</p><p>然而，对于许多开发者和IT管理人员而言，搭建并配置一个稳定、高效且安全的私有Docker镜像仓库仍是一项挑战。从环境准备到服务部署，从访问控制到镜像备份，每一步都需谨慎规划与实施，以确保满足企业的特定需求和合规要求。</p><p>《搭建与配置私有Docker镜像仓库实战指南》正是为解决这一需求而生。本文旨在通过详实的步骤说明与实战案例，引导读者从零开始，深入理解私有Docker镜像仓库的核心概念，掌握Harbor、Nexus等主流私有仓库软件的安装、配置与管理技巧。我们不仅会探讨基本的部署策略，还会涉及高级功能如镜像签名、复制策略、性能优化及安全实践，确保您的私有仓库能够稳健运行，为团队带来最大化的效益。</p><p>无论您是刚刚接触容器技术的新手，还是寻求提升现有基础设施效能的资深工程师，本指南都将为您提供宝贵的参考与启示。让我们一同开启构建高效、安全私有Docker镜像仓库的旅程，为您的DevOps实践增添强大动力。</p><hr><p><strong><font style="color:#ff9900;">关于镜像加速器的配置在之前的文章中已经介绍过了</font></strong></p><p><a href="https://blog.mingliangstar.com/2025/07/31/Centos7%E4%B8%8B%E5%AE%89%E8%A3%85Docker/">centos7下安装docker</a></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240906/1.avif"></p><p><strong><font style="color:#ff9900;">当然阿里云官方文档中的这个加速器好像没有什么diao用</font></strong>，<a href="https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors">容器镜像服务 (aliyun.com)</a></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240906/2.avif"></p><p><strong><font style="color:#ff9900;">推荐配置：</font></strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">   &quot;registry-mirrors&quot;: [</span><br><span class="line"> </span><br><span class="line">  &quot;https://docker.m.daocloud.io&quot;,</span><br><span class="line">        &quot;https://dockerproxy.com&quot;,</span><br><span class="line">        &quot;https://docker.mirrors.ustc.edu.cn&quot;,</span><br><span class="line">        &quot;https://docker.nju.edu.cn&quot;</span><br><span class="line"> </span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong><font style="color:#ff9900;">最后记得重启容器哦 </font></strong></p><hr><p><strong><font style="color:#ff9900;">关于镜像仓库配置首先你要知道</font></strong></p><p>在Linux中安装Docker后，默认配置的镜像仓库是Docker Hub。Docker Hub是一个公开的注册服务器，其中包含了大量的官方镜像以及用户贡献的镜像。当你在Docker中运行如<code>docker pull ubuntu</code>这样的命令时，如果没有指定其他仓库地址，Docker会默认从Docker Hub下载镜像。</p><p><strong><font style="color:#ff9900;">其次如果你没有配置镜像仓库，那么如果需要去指定的镜像仓库拉去或推送镜像，则每次推送或拉取镜像时都需要认证，就像阿里云中的介绍，是比较麻烦，</font></strong><a href="https://cr.console.aliyun.com/repository/cn-hangzhou/pikaqiu-hub/pikaqiu/details">https://cr.console.aliyun.com/repository/cn-hangzhou/pikaqiu-hub/pikaqiu/details</a></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240906/3.avif"></p><p><strong><font style="color:#ff9900;">为了避免每次推送或拉取镜像时都需要认证，可以配置镜像仓库凭据</font></strong></p><p>首先介绍两个文件</p><p><strong><font style="color:#ff9900;">&#x2F;root&#x2F;.docker&#x2F;config.json</font></strong></p><p><em><code>/root/.docker/config.json</code> 是一个位于Linux系统根用户目录<code>.docker</code>隐藏文件夹中的JSON格式配置文件。它主要用于存储Docker客户端的认证信息，比如 Docker Hub 或其他私有 registry 的用户名、密码（经过加密处理）以及访问令牌等认证凭据。此外，该文件还可以包含Docker CLI的默认配置，比如proxies设置。当用户通过Docker命令行与Docker daemon交互，进行镜像拉取、推送等操作时，Docker客户端会自动引用此文件中的认证信息，以实现权限验证和管理。</em></p><p><strong><font style="color:#ff9900;">&#x2F;etc&#x2F;docker&#x2F;daemon.json</font></strong></p><p><code>_daemon.json_</code><em>是Docker守护进程的配置文件，它允许系统管理员自定义Docker守护程序的行为。此文件通常位于</em><code>_/etc/docker/_</code><em>目录下。通过修改</em><code>_daemon.json_</code><em>，可以调整Docker守护进程的多种设置，包括网络配置、日志记录、存储驱动等。</em></p><hr><p><strong><font style="color:#ff9900;">下面是</font></strong><code>**&lt;font style=&quot;color:#ff9900;&quot;&gt;daemon.json文件的简单配置&lt;/font&gt;**</code></p><p><code>&lt;font style=&quot;color:#0d0016;&quot;&gt;推荐文章：&lt;/font&gt;</code><a href="https://blog.csdn.net/ygq13572549874/article/details/139885519">Docker配置文件daemon.json介绍及优化-CSDN博客</a></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  &quot;debug&quot;: true,                   // 启用 Docker 守护进程的调试日志</span><br><span class="line">  &quot;registry-mirrors&quot;: [           // 设置 Docker 镜像仓库的镜像源，加速拉取镜像</span><br><span class="line">    &quot;https://your.mirror.address&quot;</span><br><span class="line">  ],</span><br><span class="line">  &quot;live-restore&quot;: true,            // 当 Docker 守护进程重启时，保持正在运行的容器不被停止</span><br><span class="line">  &quot;insecure-registries&quot;: [        // 添加不受信任的私有 Docker 注册表</span><br><span class="line">    &quot;myinsecueregistry:5000&quot;</span><br><span class="line">  ],</span><br><span class="line">  &quot;max-concurrent-downloads&quot;: 5,   // 最大并发下载数量</span><br><span class="line">  &quot;iptables&quot;: false,               // 禁用 Docker 自动管理 iptables 规则</span><br><span class="line">  &quot;log-driver&quot;: &quot;json-file&quot;,       // 设置日志驱动，默认为 json-file，也可以是 syslog、journald 等</span><br><span class="line">  &quot;log-opts&quot;: &#123;                    // 日志驱动的额外选项</span><br><span class="line">    &quot;max-size&quot;: &quot;100m&quot;,</span><br><span class="line">    &quot;max-file&quot;: &quot;3&quot;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><p><strong><font style="color:#ff9900;">下面是&#x2F;root&#x2F;.docker&#x2F;config.json文件的简单（</font></strong><code>**&lt;font style=&quot;color:#ff9900;&quot;&gt;镜像仓库）配置&lt;/font&gt;**</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">        &quot;auths&quot;: &#123;</span><br><span class="line">                &quot;registry.cn-hangzhou.aliyuncs.com&quot;: &#123;</span><br><span class="line">                        &quot;auth&quot;: &quot;加密后的密码&quot;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240906/4.avif"></p><hr><p><strong><font style="color:#ff9900;">最后修改配置后记得重启容器</font></strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl daemon-reload</span><br><span class="line">sudo systemctl restart docker</span><br></pre></td></tr></table></figure><hr><p><strong><font style="color:#fe2c24;">学识浅薄，疏漏难免，祈望高贤不吝赐教。</font></strong></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/09/04/%E6%90%AD%E5%BB%BA%E4%B8%8E%E9%85%8D%E7%BD%AE%E7%A7%81%E6%9C%89Docker%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Docker的网络模式详解与应用</title>
      <link>https://blog.mingliangstar.com/2024/09/03/Docker%E7%9A%84%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3%E4%B8%8E%E5%BA%94%E7%94%A8/</link>
      <guid>https://blog.mingliangstar.com/2024/09/03/Docker%E7%9A%84%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3%E4%B8%8E%E5%BA%94%E7%94%A8/</guid>
      <pubDate>Tue, 03 Sep 2024 09:34:01 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>Docker作为一个革命性的技术平台，极大地简化了应用程序的部署、管理和扩展过程，其中容器网络是其核心组件之一，对于充分挖掘Docker潜力至关重要。虽然不少开发者和IT专业人员可能已经接触或应用过Docker，但深入理解其网络机制仍然是提升容器化技能的关键步骤。本文旨在提供一个全面而深入的指南，帮助您不仅了解Docker网络的基础，还能掌握其高级特性和最佳实践。</p><hr><h1 id="Docker内置网络"><a href="#Docker内置网络" class="headerlink" title="Docker内置网络"></a>Docker内置网络</h1><p>当我们完成docker engine的安装以后，docker会在每一个engine上面生成一个3种网络，他们是：<code>bridge</code>, <code>none</code>还有<code>host</code>。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/1.avif"></p><hr><h2 id="bridge"><a href="#bridge" class="headerlink" title="bridge"></a>bridge</h2><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><p>当Docker进程启动时，会在主机上创建一个名为docker0的虚拟网桥，此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似，这样主机上的所有容器就通过交换机连在了一个二层网络中。</p><p>如下图所示，当Docker1需要访问外网时，请求先到达Docker0虚拟网卡，然后在到达物理网卡，请求就发送出去了。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/2.avif"></p><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><p>客户端执行”docker run”命令创建并启动容器。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/3.avif"></p><p>查看容器信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker inspect nginx</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/4.avif"></p><ul><li>Docker引擎创建一对虚拟接囗veth pair;并把它们分别放到宿主机和新容器的网络命名空间中。</li><li>Docker引擎将宿主机上的veth接囗连接到宿主机的docker0网桥上，并且给它分配一个以 “veth” 开头的名字，如 veth8ead84e@if117。</li><li>Docker引擎将容器上的veth接囗改名为 “eth0” ，并且该接囗只有在容器内网络命名空间中是可见的。</li><li>Docker引擎从宿主机的dockerO网桥上分配一个空闲的ip地址给容器内的eth0，例如<code>172 .17.0.2</code>。并将容器内eth0的路由网关设置为 docker0 的内部IP地址，例如<code>172 .17.0.1</code>。完成以上的这些步骤后，容器就可以使用其内部的虚拟接囗”eth0”来连接到其他的容器和访问外部的网络了。</li></ul><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/5.avif"></p><p>由于上面启动nginx容器的时候使用的是默认的bridge网络，并且也没有添加端口映射，所以iptables不会做DNAT规则</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/6.avif"></p><p>如果启动容器的时候做了端口映射，则iptables会做DNAT规则，实现端口转发功能，可以使用iptables -t nat -nL查看</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/7.avif"></p><h3 id="工作原理"><a href="#工作原理" class="headerlink" title="工作原理"></a>工作原理</h3><p>在 <strong>Docker</strong> 中启动容器时，如果没有指定网络模式，它默认连接到 <strong>Docker</strong> 主机上的一个桥接网络。这个桥接网络起初是空的，当容器连接到它时，<strong>Docker</strong> 会为每个容器分配一个 <strong>IP</strong> 地址和一个网络接口，并将这个接口连接到虚拟桥接上。</p><p><strong>Docker</strong> 的桥接网络通常使用 <strong>NAT</strong>（网络地址转换）来连接到物理网络，使得容器能够通过宿主机的 <strong>IP</strong> 地址访问外部网络。</p><h3 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h3><ul><li><strong>隔离容器网络环境</strong>：当你希望运行的每个容器都有独立的网络堆栈时，Bridge网络非常有用。每个使用Bridge网络的容器都会获得自己的IP地址，并且容器之间的网络通信需要通过端口映射来进行，这提供了基本的网络隔离。</li><li><strong>快速部署和测试</strong>：在开发和测试环境中，Bridge网络可以让开发者快速搭建一个与外部网络隔离的环境来部署和测试应用，而不会影响到主机或其他网络环境。</li><li><strong>服务发现</strong>：虽然基础的Bridge网络不直接支持服务发现，但通过结合DNS解析（如使用docker-compose或Kubernetes中的服务发现机制）可以在一定程度上实现容器间的服务发现和通信。</li><li><strong>端口映射</strong>：当需要从宿主机或其他网络访问容器内的服务时，可以使用Bridge网络并通过端口映射功能将容器的内部端口映射到宿主机的一个端口上，便于外部访问。</li><li><strong>多主机通信需求不高场景</strong>：对于一些简单的多容器应用，如果不需要跨主机的容器网络通信，或者可以通过其他手段（如使用外部负载均衡器）来实现跨主机通信，使用Bridge网络就足够了。</li><li><strong>轻量级解决方案</strong>：相比于更复杂的网络解决方案如overlay网络（用于跨多个Docker主机的容器通信）或macvlan网络，Bridge网络更简单、轻量，适合对网络需求不复杂的场景。</li></ul><hr><h2 id="host"><a href="#host" class="headerlink" title="host"></a>host</h2><h3 id="基本概念-1"><a href="#基本概念-1" class="headerlink" title="基本概念"></a>基本概念</h3><p>host 模式 ： 使用 –net&#x3D;host 指定</p><p>相当于VMware 中的桥接模式，与宿主机在同一个网络中，但是没有独立IP地址</p><p>Docker 使用了Linux 的Namespace 技术来进行资源隔离，如PID Namespace隔离进程，Mount Namespace隔离文件系统，Network Namespace 隔离网络等。一个Network Namespace 提供了一份独立的网络环境，包括网卡，路由，iptable 规则等都与其他Network Namespace 隔离。一个Docker 容器一般会分配一个独立的Network Namespace</p><p>但是如果启动容器的时候使用host 模式，那么这个容器将不会获得一个独立的Network Namespace ，而是和宿主机共用一个Network Namespace 。容器将不会虚拟出自己的网卡，配置自己的IP等，而是使用宿主机的IP和端口范围.此时容器不再拥有隔离的、独立的网络栈。不拥有所有端口资源</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/8.avif"></p><h3 id="案例-1"><a href="#案例-1" class="headerlink" title="案例"></a>案例</h3><p>我们拉起一个host网络的centos容器，查看容器信息，如下图所示，并没有发现IP信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd --net=host --name centos7  eeb6ee3f44bd</span><br><span class="line">docker inspect centos7</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/9.avif"></p><p>我们可以进入容器内部去查看下网络信息，通过下图发现，host网络模式下的容器的IP和宿主机IP一致</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">//进入容器</span><br><span class="line">docker exec -it centos7 bash</span><br><span class="line">//安装网络工具</span><br><span class="line">yum install net-tools -y</span><br><span class="line">//查看IP</span><br><span class="line">ifconfig</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/10.avif"></p><h3 id="工作原理-1"><a href="#工作原理-1" class="headerlink" title="工作原理"></a>工作原理</h3><p>主机网络模式下，容器将不会获得独立的 <strong>IP</strong> 地址。容器的网络堆栈将直接映射到宿主机上，容器内的网络服务可以直接绑定到宿主机的 <strong>IP</strong> 地址和端口上。这种模式通常用于需要进行大量网络操作或需要提供高性能网络服务的场景。</p><h3 id="使用场景-1"><a href="#使用场景-1" class="headerlink" title="使用场景"></a>使用场景</h3><ul><li><strong>性能敏感型应用</strong>：当容器化应用需要最大化网络性能时，使用主机网络是一个好选择。因为它消除了网络虚拟化带来的额外开销。</li><li><strong>端口冲突</strong>：在主机网络模式下，容器可以直接使用宿主机的端口，避免了端口映射可能带来的端口冲突问题。</li><li><strong>网络监控和管理</strong>：对于需要进行网络监控和管理的工具，主机网络模式能够提供更广泛的网络可视性和控制能力。</li></ul><hr><h2 id="none"><a href="#none" class="headerlink" title="none"></a>none</h2><h3 id="基本概念-2"><a href="#基本概念-2" class="headerlink" title="基本概念"></a>基本概念</h3><p>使用none模式，Docker容器拥有自己的Network Namespace，但是，并不为Docker容器进行任何网络配置。也就是说，这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/11.avif"></p><h3 id="案例-2"><a href="#案例-2" class="headerlink" title="案例"></a>案例</h3><p>启动一个none网络的centos7的容器，查容器信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd --name centos7 --net=none eeb6ee3f44bd</span><br><span class="line">docker inspect centos7</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/13.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/14.avif"></p><p>进入容器查看网络信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">//进入容器</span><br><span class="line">docker exec -it centos7 bash</span><br><span class="line">//安装网络工具</span><br><span class="line">yum install net-tools -y</span><br><span class="line">//查看IP</span><br><span class="line">ifconfig</span><br></pre></td></tr></table></figure><h3 id="！！！大佬救命"><a href="#！！！大佬救命" class="headerlink" title="！！！大佬救命"></a><strong>！！！大佬救命</strong></h3><blockquote><p>这里可能处于none网络的原因，导致上面安装网络工具的时候失败</p><p>&#x2F;&#x2F;安装网络工具</p><p>yum install net-tools -y</p><p>执行日志：</p><p>Loaded plugins: fastestmirror, ovl<br>Loading mirror speeds from cached hostfile<br><a href="http://mirrors.cloud.aliyuncs.com/centos/7/os/x86_64/repodata/repomd.xml">http://mirrors.cloud.aliyuncs.com/centos/7/os/x86_64&#x2F;repodata&#x2F;repomd.xml</a>: [Errno 14] curl#6 - “Could not resolve host: mirrors.cloud.aliyuncs.com; Unknown error”<br>Trying other mirror.</p><p>One of the configured repositories failed (CentOS-7),<br>and yum doesn’t have enough cached data to continue. At this point the only<br>safe thing yum can do is fail. There are a few ways to work “fix” this:</p><ol><li><p>Contact the upstream for the repository and get them to fix the problem.</p></li><li><p>Reconfigure the baseurl&#x2F;etc. for the repository, to point to a working</p></li></ol><p>upstream. This is most often useful if you are using a newer</p><p>distribution release than is supported by the repository (and the</p><p>packages for the previous distribution release still work).</p><ol start="3"><li>Run the command with the repository temporarily disabled</li></ol><p>yum –disablerepo&#x3D;base …</p><ol start="4"><li>Disable the repository permanently, so yum won’t use it by default. Yum</li></ol><p>will then just ignore the repository until you permanently enable it</p><p>again or use –enablerepo for temporary usage:</p><p>yum-config-manager –disable base</p><p>or</p><p>subscription-manager repos –disable&#x3D;base</p><ol start="5"><li>Configure the failing repository to be skipped, if it is unavailable.</li></ol><p>Note that yum will try to contact the repo. when it runs most commands,</p><p>so will have to try and fail each time (and thus. yum will be be much</p><p>slower). If it is a very temporary problem though, this is often a nice</p><p>compromise:</p><p>yum-config-manager –save –setopt&#x3D;base.skip_if_unavailable&#x3D;true</p><p>failure: repodata&#x2F;repomd.xml from base: [Errno 256] No more mirrors to try.<br><a href="http://mirrors.cloud.aliyuncs.com/centos/7/os/x86_64/repodata/repomd.xml">http://mirrors.cloud.aliyuncs.com/centos/7/os/x86_64&#x2F;repodata&#x2F;repomd.xml</a>: [Errno 14] curl#6 - “Could not resolve host: mirrors.cloud.aliyuncs.com; Unknown error”</p></blockquote><hr><h2 id="container"><a href="#container" class="headerlink" title="container"></a>container</h2><h3 id="基本概念-3"><a href="#基本概念-3" class="headerlink" title="基本概念"></a>基本概念</h3><p>这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace，而不是和宿主机共享。新创建的容器不会创建自己的网卡，配置自己的 IP，而是和一个指定的容器共享 IP、端口范围等。同样，两个容器除了网络方面，其他的如文件系统、进程列表等还是隔离的。因此，在这种模式下，容器之间可以通过 localhost 或者 127.0.0.1 进行相互间的访问，从而提高了传输的效率。</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/15.avif"></p><h3 id="案例-3"><a href="#案例-3" class="headerlink" title="案例"></a>案例</h3><p>首先创建个基础容器</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd --name centos7.A eeb6ee3f44bd</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/16.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/17.avif"></p><p>然后基于刚才的容器创建新的容器</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd --net=container:04dcd560b6ce --name centos7.B eeb6ee3f44bd</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/19.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/20.avif"></p><p>对比上面创建的两个容器centos7.A和centos7.B发现使用了相同的网络命名空间，这是因为在创建容器B时使用了container模式，使得容器B不再创建自己的网络命名空间，而直接使用容器A的网络命名空间。</p><hr><h1 id="自定义网络"><a href="#自定义网络" class="headerlink" title="自定义网络"></a>自定义网络</h1><p>上面介绍的3种自带的网络模式有各自的局限性，因此，docker推荐大家自定义网络。通过自定义网络，我们可以实现“服务发现”与“DNS解析”。</p><p>docker 允许我们创建3种类型的自定义网络，<code>bridge</code>，<code>overlay</code>，<code>MACVLAN</code></p><ol><li><code>bridge</code>：Bridge模式是Docker默认的网络模式，当Docker进程启动时，会在主机上创建一个名为docker0的虚拟网桥，用来连接宿主机和容器，此主机上的Docker容器都会连接到这个虚拟网桥上</li><li><code>overlay</code>：当有多个docker主机时，跨主机的container通信</li><li><code>macvlan</code>：每个container都有一个虚拟的MAC地址</li></ol><hr><h2 id="bridge-1"><a href="#bridge-1" class="headerlink" title="bridge"></a>bridge</h2><h3 id="基本概念-4"><a href="#基本概念-4" class="headerlink" title="基本概念"></a>基本概念</h3><p>虽然Docker提供的默认bridge网络能满足很多基本需求，但在某些场景下，你可能需要创建自定义的bridge网络以实现更灵活的网络配置，比如指定子网、IP范围、网桥名称等。</p><p>自定义bridge网络为Docker容器提供了更灵活和可控的网络配置方式，它不仅能够帮助用户更好地组织和隔离容器网络，还支持更复杂的网络架构设计，满足不同应用场景的需求。通过精细的网络配置，可以有效地提升容器化应用的部署效率和管理便利性。</p><h3 id="案例-4"><a href="#案例-4" class="headerlink" title="案例"></a>案例</h3><p>首先创建一个网络（这里创建的时候没有指定子网网段）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network create -d bridge test_bridge</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/21.avif"></p><p>看下内置网络bridge和我们创建的test_bridge网络有什么区别</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker inspect test_bridge</span><br><span class="line">docker inspect bridge</span><br></pre></td></tr></table></figure><p>自定义test_bridge网络</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/22.avif"></p><p>内置网络bridge</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/23.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/24.avif"></p><p>基于自定义网络test_bridge创建一个容器</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -itd --name centos7.test --net=test_bridge eeb6ee3f44b</span><br></pre></td></tr></table></figure><p>进入容器查看网络信息，会发现分配的ip在172.18.0.0&#x2F;16网段中</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/25.avif"></p><h3 id="Docker网络允许您将容器附加到任意数量的网络"><a href="#Docker网络允许您将容器附加到任意数量的网络" class="headerlink" title="Docker网络允许您将容器附加到任意数量的网络"></a>Docker网络允许您将容器附加到任意数量的网络</h3><p>将我们之前创建的centos7.A容器加入到test_bridge网络中，先看下centos7.A容器最初的网络信息</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/26.avif"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network connect test_bridge centos7.A</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/27.avif"></p><p>断开centos7.A容器和test_bridge网络的连接</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network disconnect test_bridge centos7.A</span><br></pre></td></tr></table></figure><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240903/28.avif"></p><h3 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">docker network create --driver bridge --subnet=172.18.0.0/16 my-bridge-network</span><br><span class="line"></span><br><span class="line">--driver bridge 指定了网络类型为bridge。</span><br><span class="line">--subnet=172.18.0.0/16 指定了网络的子网和CIDR，你可以根据需要选择合适的子网。</span><br><span class="line">my-bridge-network 是自定义网络的名称。</span><br></pre></td></tr></table></figure><hr><h2 id="overlay"><a href="#overlay" class="headerlink" title="overlay"></a>overlay</h2><h3 id="基本概念-5"><a href="#基本概念-5" class="headerlink" title="基本概念"></a>基本概念</h3><p>覆盖网络（Overlay Network）是 Docker 的一个高级网络类型，主要用于 Docker Swarm 集群环境中。它允许不同 Docker 主机上的容器相互通信，无论它们的物理位置如何。覆盖网络通过在宿主机之间创建一个虚拟网络层，来连接分布在不同节点上的容器。</p><h3 id="工作原理-2"><a href="#工作原理-2" class="headerlink" title="工作原理"></a>工作原理</h3><p>覆盖网络使用网络驱动（如 VXLAN）在宿主机之间建立一个虚拟网络。这个网络工作在现有的物理网络之上，容器之间的通信会被封装并通过这个虚拟网络传输。当数据包到达目的地后，它会被解封装并传递给目标容器。这种方式使得容器间能够透明地通信，就像它们在同一个网络中一样。</p><h3 id="使用场景-2"><a href="#使用场景-2" class="headerlink" title="使用场景"></a>使用场景</h3><ul><li><strong>多主机容器部署</strong>：当你需要在多个 <strong>Docker</strong> 主机上部署容器，并且这些容器需要相互通信时，覆盖网络是理想的选择。</li><li><strong>Docker Swarm 集群</strong>：在 <strong>Docker Swarm</strong> 环境中，覆盖网络允许不同节点上的服务实例之间进行通信，非常适合微服务架构。</li><li><strong>跨主机负载均衡</strong>：覆盖网络支持跨多个宿主机的负载均衡，使得服务可以更加灵活地扩展和管理。</li></ul><h3 id="使用方法-1"><a href="#使用方法-1" class="headerlink" title="使用方法"></a>使用方法</h3><p>要在 <strong>Docker Swarm</strong> 环境中创建一个覆盖网络，首先确保你的 <strong>Docker</strong> 环境已经初始化为 <strong>Swarm</strong> 模式，然后使用以下命令创建覆盖网络：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network create -d overlay my_overlay_network</span><br></pre></td></tr></table></figure><p>创建了覆盖网络后，你可以在部署服务时指定使用这个网络：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker service create --name my_service --network my_overlay_network my_image</span><br></pre></td></tr></table></figure><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li><strong>网络性能</strong>：由于覆盖网络中存在数据封装和解封装的过程，可能会对网络性能造成一定影响。</li><li><strong>安全性</strong>：<strong>Docker</strong> 提供了网络加密选项来保护覆盖网络中的数据传输。</li><li><strong>网络管理</strong>：管理覆盖网络可能需要对 <strong>Docker Swarm</strong> 集群的管理和网络原理有一定的了解。</li></ul><hr><h2 id="macvlan"><a href="#macvlan" class="headerlink" title="macvlan"></a>macvlan</h2><h3 id="基本概念-6"><a href="#基本概念-6" class="headerlink" title="基本概念"></a>基本概念</h3><p>Macvlan 网络是 Docker 提供的另一种网络类型，允许容器直接连接到物理网络。每个使用 Macvlan 网络的容器都会被分配一个独立的 MAC 地址，使其在网络上表现得就像是一个物理设备一样。这种网络类型适用于需要容器直接参与物理网络的场景，例如，当容器需要有自己的 IP 地址、或需要绕过 Docker 网络堆栈的复杂性时。</p><h3 id="工作原理-3"><a href="#工作原理-3" class="headerlink" title="工作原理"></a>工作原理</h3><p>Macvlan 网络通过创建一个或多个虚拟网络接口（Macvlan 接口）来工作，这些接口附加到宿主机的物理网络接口上。每个接口都有自己的 MAC 地址，容器通过这些虚拟接口与外部网络进行通信。这样，容器可以直接出现在物理网络上，而不是通过 Docker 主机的网络堆栈。</p><h3 id="使用场景-3"><a href="#使用场景-3" class="headerlink" title="使用场景"></a>使用场景</h3><ul><li><strong>需要直接网络访问</strong>：对于需要绕过 <strong>NAT</strong>、或需要与外部网络中的其他设备直接通信的容器，<strong>Macvlan</strong> 网络是一个理想的选择。</li><li><strong>遗留系统集成</strong>：在一些遗留系统或需要直接网络访问的环境中，<strong>Macvlan</strong> 网络可以帮助容器更好地集成进这些环境中。</li><li><strong>网络性能</strong>：由于容器直接连接到物理网络，<strong>Macvlan</strong> 可以提供更好的网络性能，减少虚拟化带来的开销。</li></ul><h3 id="使用方法-2"><a href="#使用方法-2" class="headerlink" title="使用方法"></a>使用方法</h3><p>创建 <strong>Macvlan</strong> 网络的基本步骤如下：</p><ul><li><strong>创建 Macvlan 网络</strong>：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 my_macvlan_net</span><br></pre></td></tr></table></figure><p>这个命令会在宿主机的 <code>eth0</code> 网络接口上创建一个新的 <strong>Macvlan</strong> 网络，设置了子网和网关。</p><ul><li><strong>运行容器并连接到 Macvlan 网络</strong>：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --network my_macvlan_net --name my_container my_image</span><br></pre></td></tr></table></figure><p>这个命令启动一个容器，并将其连接到刚刚创建的 <strong>Macvlan</strong> 网络。</p><h3 id="注意事项-1"><a href="#注意事项-1" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li><strong>网络隔离</strong>：使用 <strong>Macvlan</strong> 网络时，容器的网络隔离级别较低，容器直接暴露在物理网络上</li><li><strong>路由和防火墙配置</strong>：可能需要在网络设备或宿主机上进行额外的路由和防火墙配置，以确保网络通信的正确性和安全性。</li><li><strong>宿主机通信</strong>：默认情况下，使用 <strong>Macvlan</strong> 的容器可能无法与其宿主机进行直接通信。这可能需要额外的网络配置来解决。</li></ul><hr><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>Docker 网络是容器化技术中不可或缺的一部分，它不仅提供了容器之间以及容器与外部世界之间通信的能力，还支持了高度的网络隔离和安全性。通过不同的网络类型和配置，Docker 能够满足各种应用场景的需求，从简单的单机部署到复杂的多主机、跨主机的集群环境。</p><p>briadge网络作为默认的网络类型，适用于大多数标准部署场景，提供了容器与外部网络的连接以及容器之间的隔离。host网络模式提供了最高的网络性能，适用于性能敏感型应用。overlay网络支持跨主机的容器通信，是在 Docker Swarm 集群中运行分布式应用的理想选择。Macvlan 网络则允许容器直接连接到物理网络，适用于需要直接网络访问或遗留系统集成的场景。</p><p>每种网络类型都有其适用场景和注意事项。选择合适的网络类型和配置，可以帮助开发者和运维人员构建高效、安全且易于管理的容器化应用。同时，Docker 的网络配置和管理工具也提供了灵活性和便利性，使得网络管理变得更加简单。</p><p>Docker 网络提供了强大而灵活的网络功能，支持各种应用部署和运行模式。通过合理选择和配置网络类型，可以最大化地发挥 Docker 容器的潜力，构建出高性能、安全且易于管理的容器化应用。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/09/03/Docker%E7%9A%84%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3%E4%B8%8E%E5%BA%94%E7%94%A8/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>WordPress纯代码实现圆角彩色背景标签云</title>
      <link>https://blog.mingliangstar.com/2024/08/20/%E6%A0%87%E7%AD%BE%E4%BA%91/</link>
      <guid>https://blog.mingliangstar.com/2024/08/20/%E6%A0%87%E7%AD%BE%E4%BA%91/</guid>
      <pubDate>Tue, 20 Aug 2024 14:17:35 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;**标签云</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><p>**标签云 **对我们的文章画龙点睛，如果让我们的标签云随机产生彩色效果，更是增加了不是个性化，我们现在抛弃插件，自己动手从网上学习DIY自己的彩色标签云。</p><h2 id="二、代码部署"><a href="#二、代码部署" class="headerlink" title="二、代码部署"></a>二、代码部署</h2><p>代码需放入主题目录下的tag-color-cloud.php文件中</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line">/**</span><br><span class="line"> * 彩色圆角标签云</span><br><span class="line"> */</span><br><span class="line"><span class="keyword">if</span> ( ! defined( <span class="string">&#x27;ABSPATH&#x27;</span> ) ) &#123; <span class="built_in">exit</span>; &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> colorCloud( <span class="variable">$text</span> ) &#123;</span><br><span class="line">    <span class="built_in">return</span> preg_replace_callback(</span><br><span class="line">        <span class="string">&#x27;|&lt;a (.+?)&gt;|i&#x27;</span>,</span><br><span class="line">        <span class="keyword">function</span> ( <span class="variable">$m</span> ) &#123;</span><br><span class="line">            <span class="variable">$colors</span> = array( <span class="string">&#x27;F99&#x27;</span>, <span class="string">&#x27;C9C&#x27;</span>, <span class="string">&#x27;F96&#x27;</span>, <span class="string">&#x27;6CC&#x27;</span>, <span class="string">&#x27;6C9&#x27;</span>, <span class="string">&#x27;37A7FF&#x27;</span>, <span class="string">&#x27;B0D686&#x27;</span>, <span class="string">&#x27;E6CC6E&#x27;</span> );</span><br><span class="line">            <span class="variable">$color</span>  = <span class="variable">$colors</span>[ array_rand( <span class="variable">$colors</span> ) ];</span><br><span class="line"></span><br><span class="line">            // 去掉原有的 style 属性（若有）</span><br><span class="line">            <span class="variable">$attrs</span> = preg_replace( <span class="string">&#x27;/style=([&quot;\&#x27;</span>])(.*?)\1/i<span class="string">&#x27;, &#x27;</span><span class="string">&#x27;, $m[1] );</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">            // 追加新样式</span></span><br><span class="line"><span class="string">            $style  = &quot;display:inline-block;color:#fff;padding:1px 5px;margin:0 5px 5px 0;&quot;;</span></span><br><span class="line"><span class="string">            $style .= &quot;background-color:#&#123;$color&#125;;border-radius:3px;&quot;;</span></span><br><span class="line"><span class="string">            $style .= &quot;transition:background-color .4s linear;&quot;;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">            return &#x27;</span>&lt;a <span class="string">&#x27; . $attrs . &#x27;</span> style=<span class="string">&quot;&#x27; . <span class="variable">$style</span> . &#x27;&quot;</span>&gt;<span class="string">&#x27;;</span></span><br><span class="line"><span class="string">        &#125;,</span></span><br><span class="line"><span class="string">        $text</span></span><br><span class="line"><span class="string">    );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">add_filter( &#x27;</span>wp_tag_cloud<span class="string">&#x27;, &#x27;</span>colorCloud<span class="string">&#x27;, 10 );</span></span><br></pre></td></tr></table></figure><p>最后在functions.php中调用即可</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/* 彩色圆角标签云 */</span><br><span class="line">require_once get_template_directory() . <span class="string">&#x27;/self-innovate/tag-color-cloud.php&#x27;</span>;</span><br></pre></td></tr></table></figure></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/categories/Wordpress/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/Wordpress/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/%E6%A0%87%E7%AD%BE%E4%BA%91/">标签云</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%A0%87%E7%AD%BE%E4%BA%91/">标签云</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/08/20/%E6%A0%87%E7%AD%BE%E4%BA%91/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>快速迁移网站</title>
      <link>https://blog.mingliangstar.com/2024/07/22/%E5%BF%AB%E9%80%9F%E8%BF%81%E7%A7%BB%E7%BD%91%E7%AB%99/</link>
      <guid>https://blog.mingliangstar.com/2024/07/22/%E5%BF%AB%E9%80%9F%E8%BF%81%E7%A7%BB%E7%BD%91%E7%AB%99/</guid>
      <pubDate>Mon, 22 Jul 2024 12:34:22 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;一、前言&quot;&gt;&lt;a href=&quot;#一、前言&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><p>从建站开始到现在也有一年了，也看着服务器马上就要到期了。现在有俩个选择可以解决这个问题，其一是在现有的服务器上选择续费，但是成本很高，由于笔者的网站在建站的这一年之内也没有什么收入，所以很难拿出这么一大笔的费用，那么只能选择其二了，那就是购买一台新的服务器，毕竟在有活动的时候够买，相对来说还是很便宜的，但是如果购买新的服务器的话，也会面临一定的问题比如如何将网站从旧的服务器迁移到新的服务器。</p><p>先总结一下迁移的思路吧：</p><ul><li>首先要给新的服务器安装上和旧服务器一样的宝塔环境，包括php版本、mysql版本，这样能避免网站数据出错。</li><li>网站数据一定要提前备份，防止出现其他问题可以方便恢复。</li><li>然后在发送数据服务器上安装一键迁移工具，填写接收数据服务器信息，包括秘钥，就可以开始自动迁移了。</li></ul><h2 id="二、安装迁移工具"><a href="#二、安装迁移工具" class="headerlink" title="二、安装迁移工具"></a>二、安装迁移工具</h2><p>直接在宝塔面板的软件商店搜索<code>一键迁移</code>，即可找到宝塔一键迁移API版本，点击安装即可。</p><p><img src="https://images.mingliangstar.com/images/20240722/1.avif"></p><h2 id="三、配置API"><a href="#三、配置API" class="headerlink" title="三、配置API"></a>三、配置API</h2><p>接收数据服务器上，点击面板设置，开启API，获得接口秘钥，并将发送数据端IP加入接收数据服务器API的IP白名单，最后点击保存即可。</p><p><img src="https://images.mingliangstar.com/images/20240722/2.avif"></p><h2 id="四、开启迁移"><a href="#四、开启迁移" class="headerlink" title="四、开启迁移"></a>四、开启迁移</h2><p>发送数据服务器上，找到我们刚刚下载的宝塔一键迁移API版本，填写面板地址和API秘钥。<br>注意：面板地址和API秘钥都是接收数据服务器、接收数据服务器、接收数据服务器上的，千万别填错了。<br>面板地址包含 协议 + 主机IP地址 + 面板端口<br>例如：<a href="http://192.168.0.1:8888/">http://192.168.0.1:8888</a></p><p><img src="https://images.mingliangstar.com/images/20240722/3.avif"></p><p><img src="https://images.mingliangstar.com/images/20240722/4.avif"></p><p><img src="https://images.mingliangstar.com/images/20240722/5.avif"></p><p><img src="https://images.mingliangstar.com/images/20240722/6.avif"></p><p><img src="https://images.mingliangstar.com/images/20240722/7.avif"></p><h2 id="五、解析测试"><a href="#五、解析测试" class="headerlink" title="五、解析测试"></a>五、解析测试</h2><p>迁移完成后，网站文件和数据库就都已经到新的网站了，这个时候域名再重新解析到新的网站就可以正常访问了。</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/%E5%AE%9D%E5%A1%94/">宝塔</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E5%AE%9D%E5%A1%94/">宝塔</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/07/22/%E5%BF%AB%E9%80%9F%E8%BF%81%E7%A7%BB%E7%BD%91%E7%AB%99/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>DOCKER容器拉起后如何添加新的端口映射</title>
      <link>https://blog.mingliangstar.com/2024/07/18/DOCKER%E5%AE%B9%E5%99%A8%E6%8B%89%E8%B5%B7%E5%90%8E%E5%A6%82%E4%BD%95%E6%B7%BB%E5%8A%A0%E6%96%B0%E7%9A%84%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84/</link>
      <guid>https://blog.mingliangstar.com/2024/07/18/DOCKER%E5%AE%B9%E5%99%A8%E6%8B%89%E8%B5%B7%E5%90%8E%E5%A6%82%E4%BD%95%E6%B7%BB%E5%8A%A0%E6%96%B0%E7%9A%84%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84/</guid>
      <pubDate>Thu, 18 Jul 2024 07:08:57 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;前段时间在用docker部署服务的时候发现，容器已经启动，但是需要新的端口映射（&lt;strong&gt;&lt;font</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>前段时间在用docker部署服务的时候发现，容器已经启动，但是需要新的端口映射（<strong><font style="color:#fe2c24;">即容器在启动的时候只进行了部分的端口映射</font></strong>），经过查询资料后发现现在网上有2种方法，<strong><font style="color:#ff9900;">一中是修改json文件</font></strong>。<strong><font style="color:#a2e043;">另一种是将已经运行的容器打包成一个新的镜像，然后基于打包后的镜像来在启动容器的时候开启全部的端口映射</font></strong>。但是经过我的测试发现第一种修改json文件的方式好像会重置容器。</p><h1 id="方法一"><a href="#方法一" class="headerlink" title="方法一"></a><strong>方法一</strong></h1><p><strong><font style="color:#ff9900;">停止docker服务</font></strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop docker</span><br></pre></td></tr></table></figure><p>修改json文件，一般要修改的文件在&#x2F;var&#x2F;lib&#x2F;docker&#x2F;containers&#x2F;下，找到要修改的容器然后进入目录即可看到<strong>hostconfig.json</strong>和<strong>config.v2.json</strong></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240718/1.avif"></p><ul><li>**config.v2.json：**Docker容器的配置文件之一，包含了容器的配置信息，如环境变量、端口映射、卷挂载点等。版本2表示这是Docker引入新配置格式后的文件。</li><li>**hostconfig.json：**另一个重要的Docker容器配置文件，包含了容器的主机配置信息，比如网络模式、资源限制(如CPU份额和内存限制)、重启策略等。</li></ul><p><strong><font style="color:#ff9900;">按照格式添加端口即可</font></strong></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240718/2.avif"></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240718/3.avif"></p><p><strong><font style="color:#ff9900;">启动docker服务</font></strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stat docker</span><br></pre></td></tr></table></figure><p><strong><font style="color:#fe2c24;">经过这种方式修改后确实会添加新的端口映射，但是容器也好像会被重置 。</font><strong><strong><font style="color:#ff9900;">除了这个问题因为这种方式还涉及到了docker的启停，若是容器过多的话会影响到别的业</font></strong></strong><font style="color:#0d0016;">（不推荐）</font></strong></p><h1 id="方法二"><a href="#方法二" class="headerlink" title="方法二"></a>方法二</h1><p>将容器打包成镜像，然后基于打包后的镜像来在启动容器的时候开启全部的端口映射即可</p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240718/4.avif"></p><hr><p><strong><font style="color:#ff9900;">若是还有别的方法或者文章中有错误的话请指出！！！</font></strong></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/07/18/DOCKER%E5%AE%B9%E5%99%A8%E6%8B%89%E8%B5%B7%E5%90%8E%E5%A6%82%E4%BD%95%E6%B7%BB%E5%8A%A0%E6%96%B0%E7%9A%84%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Docker attach V/S Docker exec</title>
      <link>https://blog.mingliangstar.com/2024/07/18/Docker-attach-V-S-Docker-exec/</link>
      <guid>https://blog.mingliangstar.com/2024/07/18/Docker-attach-V-S-Docker-exec/</guid>
      <pubDate>Thu, 18 Jul 2024 07:08:27 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;p&gt;docker exec和docker attach都是进入容器的命令但是它么两个有一些区别你们知道吗？&lt;/p&gt;
&lt;h1 id=&quot;docker-attach-语法&quot;&gt;&lt;a</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><p>docker exec和docker attach都是进入容器的命令但是它么两个有一些区别你们知道吗？</p><h1 id="docker-attach-语法"><a href="#docker-attach-语法" class="headerlink" title="docker attach 语法"></a>docker attach 语法</h1><p><font style="color:#ff9900;">attach是</font><a href="https://so.csdn.net/so/search?q=Docker&spm=1001.2101.3001.7020"><font style="color:#ff9900;">Docker</font></a><font style="color:#ff9900;">自带的命令，命令的语法为：</font></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker attach 容器ID</span><br></pre></td></tr></table></figure><h1 id="docker-exec-语法"><a href="#docker-exec-语法" class="headerlink" title="docker exec 语法"></a>docker exec 语法</h1><p><font style="color:#ff9900;">从Docker的1.3版本起，Docker提供了更加方便的工具exec命令，可以在运行容器内直接执行任意命令。命令语法为：</font></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec -it 容器ID bash</span><br></pre></td></tr></table></figure><h1 id="两者区别"><a href="#两者区别" class="headerlink" title="两者区别"></a>两者区别</h1><ul><li>当多个窗口同是attach到同一个容器的时候，所有窗口都会同步显示；当某个窗口因命令阻塞时，其他窗口也无法执行操作。</li><li>可以使用 docker exec -it 容器id &#x2F;bin&#x2F;bash 进入容器并开启一个新的bash终端。 使用exit或者Ctrl+d退出容器终端时，不会导致容器的停止。</li><li>使用 docker attach 容器id 进入正在执行容器，不会启动新的终端， 使用exit或者Ctrl+d退出容器时，会导致容器的停止，但是使用Ctrl+p+q退出后容器不会停止。</li></ul></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/07/18/Docker-attach-V-S-Docker-exec/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Docker生命周期和原理</title>
      <link>https://blog.mingliangstar.com/2024/06/18/Docker%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%92%8C%E5%8E%9F%E7%90%86/</link>
      <guid>https://blog.mingliangstar.com/2024/06/18/Docker%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%92%8C%E5%8E%9F%E7%90%86/</guid>
      <pubDate>Tue, 18 Jun 2024 07:08:41 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h1 id=&quot;1-Docker生命周期&quot;&gt;&lt;a href=&quot;#1-Docker生命周期&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h1 id="1-Docker生命周期"><a href="#1-Docker生命周期" class="headerlink" title="1.Docker生命周期"></a>1.Docker生命周期</h1><h2 id="废话少说直接看图"><a href="#废话少说直接看图" class="headerlink" title="废话少说直接看图"></a><em><font style="color:#fe2c24;">废话少说直接看图</font></em></h2><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240618/1.avif"></p><h1 id="2-Docker原理"><a href="#2-Docker原理" class="headerlink" title="2.Docker原理"></a>2.Docker原理</h1><h2 id="作为大神或者准架构师-架构师，一定要了解一下docker的底层原理-。"><a href="#作为大神或者准架构师-架构师，一定要了解一下docker的底层原理-。" class="headerlink" title="作为大神或者准架构师&#x2F;架构师，一定要了解一下docker的底层原理__。"></a><em><font style="color:#fe2c24;">作为大神或者准架构师&#x2F;架构师，一定要了解一下docker的底层原理</font>__<strong>。</strong></em></h2><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240618/2.avif"></p><h2 id="所有对容器的修改动作，都只会发生在容器层里，只有容器层是可写的，其余镜像层都是只读的"><a href="#所有对容器的修改动作，都只会发生在容器层里，只有容器层是可写的，其余镜像层都是只读的" class="headerlink" title="所有对容器的修改动作，都只会发生在容器层里，只有容器层是可写的，其余镜像层都是只读的"></a><em><font style="color:#fe2c24;">所有对容器的修改动作，都只会发生在容器层里，只有容器层是可写的，其余镜像层都是只读的</font></em></h2><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/Docker/20240618/3.avif"></p><h2 id=""><a href="#" class="headerlink" title=""></a><!-- 这是一张图片，ocr 内容为： --></h2><p><img src="https://images.mingliangstar.com/images/Docker/20240618/4.avif"></p><h1 id="3-总结"><a href="#3-总结" class="headerlink" title="3. 总结"></a><strong><font style="color:#0d0016;">3. 总结</font></strong></h1><h2 id="一句话Docker是分层的"><a href="#一句话Docker是分层的" class="headerlink" title="一句话Docker是分层的"></a><em><strong><font style="color:#fe2c24;">一句话Docker是分层的</font></strong></em></h2></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/Docker/">Docker</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Docker/">Docker</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/06/18/Docker%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%92%8C%E5%8E%9F%E7%90%86/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>WordPress中Gravatar头像无法访问</title>
      <link>https://blog.mingliangstar.com/2024/05/27/Cravatar%E5%A4%B4%E5%83%8F%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AE/</link>
      <guid>https://blog.mingliangstar.com/2024/05/27/Cravatar%E5%A4%B4%E5%83%8F%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AE/</guid>
      <pubDate>Mon, 27 May 2024 14:44:01 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&gt;&lt;h2 id=&quot;一、前言&quot;&gt;&lt;a href=&quot;#一、前言&quot; class=&quot;headerlink&quot;</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><p>一般情况下，WordPress默认都是使用Gravatar头像，如果用户没有注册过Gravatar头像，那就使用网站设置的默认头像，这样用户体验不是很好；再则，如果直接调用远程Gravatar头像，还会影响网站的加载速度(WordPress缓存Gravatar头像到本地，提高加载速度)。所以，作为一个开放注册的WordPress网站而言，在用户资料页面添加自定义用户头像功能是极为重要的。</p><p>Gravatar有时候无法访问导致头像显示不出来，只能使用默认的头像，要解决这个问题我这有三种方法：</p><ul><li>使用Simple Local Avatars插件</li><li>代码配置、</li><li>使用国内的Gravatar为 WordPress 集成</li></ul><p>总体来说插件是最简单稳定的，下面会分别介绍这三种方法，大家可以自行选择</p><h2 id="二、插件"><a href="#二、插件" class="headerlink" title="二、插件"></a>二、插件</h2><p>站长可以在 <a href="https://images.mingliangstar.com/go/?url=https://mingliang.net.cn/"><em><strong>WordPress</strong></em></a>后台直接搜索插件<code>_**Simple Local Avatars**_</code>进行在线安装，启用之后可以在<code>仪表盘</code>&gt;&gt; <code>用户</code> &gt;&gt; <code>我的个人资料</code>进行头像设置，同理管理员也可以修改其他用户头像。</p><p><img src="https://images.mingliangstar.com/images/20240527/1.avif"></p><p><img src="https://images.mingliangstar.com/images/20240527/2.avif"></p><h2 id="三、代码配置"><a href="#三、代码配置" class="headerlink" title="三、代码配置"></a>三、代码配置</h2><p>Simple Local Avatars 是英文的，只有一个主文件 simple-local-avatars.php，你也可以将这个功能直接集成到你的主题中，只需将该插件的 simple-local-avatars.php 放到正在使用的主题的根目录，然后在 functions.php文件中使用下面的代码引入该文件即可：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">require_once(TEMPLATEPATH . <span class="string">&#x27;/simple-local-avatars.php&#x27;</span>);</span><br></pre></td></tr></table></figure><p>通过以上的两种方式，你的网站已经具备了自定义用户头像功能。那么，如何调用自定义头像？很简单，可以调用get_simple_local_avatar 或 get_avatar 函数即可，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;?php <span class="built_in">echo</span> get_avatar(get_the_author_meta(<span class="string">&#x27;ID&#x27;</span>)); ?&gt;</span><br></pre></td></tr></table></figure><blockquote><p>如果你已设置了Gravatar头像，也上传了自定义头像，优先显示自定义头像</p></blockquote><p>simple-local-avatars.php 完整代码：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br></pre></td><td class="code"><pre><span class="line">&lt;?php</span><br><span class="line"> </span><br><span class="line">/**</span><br><span class="line"> </span><br><span class="line">Plugin Name: Simple Local Avatars</span><br><span class="line"> </span><br><span class="line">Plugin URI: http://get10up.com/plugins/simple-local-avatars-wordpress/</span><br><span class="line"> </span><br><span class="line">Description: Adds an avatar upload field to user profiles <span class="keyword">if</span> the current user has media permissions. Generates requested sizes on demand just like Gravatar! Simple and lightweight.</span><br><span class="line"> </span><br><span class="line">Version: 1.3.1</span><br><span class="line"> </span><br><span class="line">Author: Jake Goldman (10up LLC), Oomph Inc</span><br><span class="line"> </span><br><span class="line">Author URI: http://get10up.com</span><br><span class="line"> </span><br><span class="line">Plugin: Copyright 2011 Jake Goldman (email : jake@get10up.com)</span><br><span class="line"> </span><br><span class="line">This program is free software; you can redistribute it and/or modify</span><br><span class="line"> </span><br><span class="line">it under the terms of the GNU General Public License as published by</span><br><span class="line"> </span><br><span class="line">the Free Software Foundation; either version 2 of the License, or</span><br><span class="line"> </span><br><span class="line">(at your option) any later version.</span><br><span class="line"> </span><br><span class="line">This program is distributed <span class="keyword">in</span> the hope that it will be useful,</span><br><span class="line"> </span><br><span class="line">but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span class="line"> </span><br><span class="line">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span class="line"> </span><br><span class="line">GNU General Public License <span class="keyword">for</span> more details.</span><br><span class="line"> </span><br><span class="line">You should have received a copy of the GNU General Public License</span><br><span class="line"> </span><br><span class="line">along with this program; <span class="keyword">if</span> not, write to the Free Software</span><br><span class="line"> </span><br><span class="line">Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</span><br><span class="line"> </span><br><span class="line">NOTE: Previous versions may have accidentally and incorrectly attributed the</span><br><span class="line"> </span><br><span class="line">copyright to employers of Mr. Goldman. While credit is given to all contributors</span><br><span class="line"> </span><br><span class="line">to the current version, including Mr. Goldman<span class="string">&#x27;s employers, the copyright belongs</span></span><br><span class="line"><span class="string">- and has always belonged - to Mr. Goldman, personally.</span></span><br><span class="line"><span class="string">*/</span></span><br><span class="line"><span class="string">/**</span></span><br><span class="line"><span class="string">* add field to user profiles</span></span><br><span class="line"><span class="string">*/</span></span><br><span class="line"><span class="string">class Simple_Local_Avatars &#123;</span></span><br><span class="line"><span class="string">private $user_id_being_edited;</span></span><br><span class="line"><span class="string">public function __construct() &#123;</span></span><br><span class="line"><span class="string">add_filter( &#x27;</span>get_avatar<span class="string">&#x27;, array( $this, &#x27;</span>get_avatar<span class="string">&#x27; ), 10, 5 );</span></span><br><span class="line"><span class="string">add_action( &#x27;</span>admin_init<span class="string">&#x27;, array( $this, &#x27;</span>admin_init<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">add_action( &#x27;</span>show_user_profile<span class="string">&#x27;, array( $this, &#x27;</span>edit_user_profile<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">add_action( &#x27;</span>edit_user_profile<span class="string">&#x27;, array( $this, &#x27;</span>edit_user_profile<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">add_action( &#x27;</span>personal_options_update<span class="string">&#x27;, array( $this, &#x27;</span>edit_user_profile_update<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">add_action( &#x27;</span>edit_user_profile_update<span class="string">&#x27;, array( $this, &#x27;</span>edit_user_profile_update<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">add_filter( &#x27;</span>avatar_defaults<span class="string">&#x27;, array( $this, &#x27;</span>avatar_defaults<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">public function get_avatar( $avatar = &#x27;</span><span class="string">&#x27;, $id_or_email, $size = 96, $default = &#x27;</span><span class="string">&#x27;, $alt = false ) &#123;</span></span><br><span class="line"><span class="string">if ( is_numeric($id_or_email) )</span></span><br><span class="line"><span class="string">$user_id = (int) $id_or_email;</span></span><br><span class="line"><span class="string">elseif ( is_string( $id_or_email ) &amp;&amp; ( $user = get_user_by( &#x27;</span>email<span class="string">&#x27;, $id_or_email ) ) )</span></span><br><span class="line"><span class="string">$user_id = $user-&gt;ID;</span></span><br><span class="line"><span class="string">elseif ( is_object( $id_or_email ) &amp;&amp; ! empty( $id_or_email-&gt;user_id ) )</span></span><br><span class="line"><span class="string">$user_id = (int) $id_or_email-&gt;user_id;</span></span><br><span class="line"><span class="string">if ( empty( $user_id ) )</span></span><br><span class="line"><span class="string">return $avatar;</span></span><br><span class="line"><span class="string">$local_avatars = get_user_meta( $user_id, &#x27;</span>simple_local_avatar<span class="string">&#x27;, true );</span></span><br><span class="line"><span class="string">if ( empty( $local_avatars ) || empty( $local_avatars[&#x27;</span>full<span class="string">&#x27;] ) )</span></span><br><span class="line"><span class="string">return $avatar;</span></span><br><span class="line"><span class="string">$size = (int) $size;</span></span><br><span class="line"><span class="string">if ( empty( $alt ) )</span></span><br><span class="line"><span class="string">$alt = get_the_author_meta( &#x27;</span>display_name<span class="string">&#x27;, $user_id );</span></span><br><span class="line"><span class="string">// generate a new size</span></span><br><span class="line"><span class="string">if ( empty( $local_avatars[$size] ) ) &#123;</span></span><br><span class="line"><span class="string">$upload_path = wp_upload_dir();</span></span><br><span class="line"><span class="string">$avatar_full_path = str_replace( $upload_path[&#x27;</span>baseurl<span class="string">&#x27;], $upload_path[&#x27;</span>basedir<span class="string">&#x27;], $local_avatars[&#x27;</span>full<span class="string">&#x27;] );</span></span><br><span class="line"><span class="string">$image_sized = image_resize( $avatar_full_path, $size, $size, true );</span></span><br><span class="line"><span class="string">// deal with original being &gt;= to original image (or lack of sizing ability)</span></span><br><span class="line"><span class="string">$local_avatars[$size] = is_wp_error($image_sized) ? $local_avatars[$size] = $local_avatars[&#x27;</span>full<span class="string">&#x27;] : str_replace( $upload_path[&#x27;</span>basedir<span class="string">&#x27;], $upload_path[&#x27;</span>baseurl<span class="string">&#x27;], $image_sized );</span></span><br><span class="line"><span class="string">// save updated avatar sizes</span></span><br><span class="line"><span class="string">update_user_meta( $user_id, &#x27;</span>simple_local_avatar<span class="string">&#x27;, $local_avatars );</span></span><br><span class="line"><span class="string">&#125; elseif ( substr( $local_avatars[$size], 0, 4 ) != &#x27;</span>http<span class="string">&#x27; ) &#123;</span></span><br><span class="line"><span class="string">$local_avatars[$size] = home_url( $local_avatars[$size] );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">$author_class = is_author( $user_id ) ? &#x27;</span> current-author<span class="string">&#x27; : &#x27;</span><span class="string">&#x27; ;</span></span><br><span class="line"><span class="string">$avatar = &quot;&lt;img alt=&#x27;</span><span class="string">&quot; . esc_attr( <span class="variable">$alt</span> ) . &quot;</span><span class="string">&#x27; src=&#x27;</span><span class="string">&quot; . <span class="variable">$local_avatars</span>[<span class="variable">$size</span>] . &quot;</span><span class="string">&#x27; class=&#x27;</span>avatar avatar-&#123;<span class="variable">$size</span>&#125;&#123;<span class="variable">$author_class</span>&#125; photo<span class="string">&#x27; height=&#x27;</span>&#123;<span class="variable">$size</span>&#125;<span class="string">&#x27; width=&#x27;</span>&#123;<span class="variable">$size</span>&#125;<span class="string">&#x27; /&gt;&quot;;</span></span><br><span class="line"><span class="string">return apply_filters( &#x27;</span>simple_local_avatar<span class="string">&#x27;, $avatar );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">public function admin_init() &#123;</span></span><br><span class="line"><span class="string">load_plugin_textdomain( &#x27;</span>simple-local-avatars<span class="string">&#x27;, false, dirname( plugin_basename( __FILE__ ) ) . &#x27;</span>/localization/<span class="string">&#x27; );</span></span><br><span class="line"><span class="string">register_setting( &#x27;</span>discussion<span class="string">&#x27;, &#x27;</span>simple_local_avatars_caps<span class="string">&#x27;, array( $this, &#x27;</span>sanitize_options<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">add_settings_field( &#x27;</span>simple-local-avatars-caps<span class="string">&#x27;, __(&#x27;</span>Local Avatar Permissions<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;), array( $this, &#x27;</span>avatar_settings_field<span class="string">&#x27; ), &#x27;</span>discussion<span class="string">&#x27;, &#x27;</span>avatars<span class="string">&#x27; );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">public function sanitize_options( $input ) &#123;</span></span><br><span class="line"><span class="string">$new_input[&#x27;</span>simple_local_avatars_caps<span class="string">&#x27;] = empty( $input[&#x27;</span>simple_local_avatars_caps<span class="string">&#x27;] ) ? 0 : 1;</span></span><br><span class="line"><span class="string">return $new_input;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">public function avatar_settings_field( $args ) &#123;</span></span><br><span class="line"><span class="string">$options = get_option(&#x27;</span>simple_local_avatars_caps<span class="string">&#x27;);</span></span><br><span class="line"><span class="string">echo &#x27;</span></span><br><span class="line"> </span><br><span class="line">&lt;label <span class="keyword">for</span>=<span class="string">&quot;simple_local_avatars_caps&quot;</span>&gt;</span><br><span class="line"> </span><br><span class="line">&lt;input <span class="built_in">type</span>=<span class="string">&quot;checkbox&quot;</span> name=<span class="string">&quot;simple_local_avatars_caps&quot;</span> <span class="built_in">id</span>=<span class="string">&quot;simple_local_avatars_caps&quot;</span> value=<span class="string">&quot;1&quot;</span> <span class="string">&#x27; . @checked( $options[&#x27;</span>simple_local_avatars_caps<span class="string">&#x27;], 1, false ) . &#x27;</span> /&gt;</span><br><span class="line"> </span><br><span class="line"><span class="string">&#x27; . __(&#x27;</span>Only allow <span class="built_in">users</span> with file upload capabilities to upload <span class="built_in">local</span> avatars (Authors and above)<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;) . &#x27;</span></span><br><span class="line"> </span><br><span class="line">&lt;/label&gt;</span><br><span class="line"> </span><br><span class="line"><span class="string">&#x27;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">public function edit_user_profile( $profileuser ) &#123;</span></span><br><span class="line"><span class="string">?&gt;</span></span><br><span class="line"><span class="string">&lt;h3&gt;&lt;?php _e( &#x27;</span>Avatar<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27; ); ?&gt;&lt;/h3&gt;</span></span><br><span class="line"><span class="string">&lt;table class=&quot;form-table&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;tr&gt;</span></span><br><span class="line"><span class="string">&lt;th&gt;&lt;label for=&quot;simple-local-avatar&quot;&gt;&lt;?php _e(&#x27;</span>Upload Avatar<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;); ?&gt;&lt;/label&gt;&lt;/th&gt;</span></span><br><span class="line"><span class="string">&lt;td style=&quot;width: 50px;&quot; valign=&quot;top&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;?php echo get_avatar( $profileuser-&gt;ID ); ?&gt;</span></span><br><span class="line"><span class="string">&lt;/td&gt;</span></span><br><span class="line"><span class="string">&lt;td&gt;</span></span><br><span class="line"><span class="string">&lt;?php</span></span><br><span class="line"><span class="string">$options = get_option(&#x27;</span>simple_local_avatars_caps<span class="string">&#x27;);</span></span><br><span class="line"><span class="string">if ( empty($options[&#x27;</span>simple_local_avatars_caps<span class="string">&#x27;]) || current_user_can(&#x27;</span>upload_files<span class="string">&#x27;) ) &#123;</span></span><br><span class="line"><span class="string">do_action( &#x27;</span>simple_local_avatar_notices<span class="string">&#x27; );</span></span><br><span class="line"><span class="string">wp_nonce_field( &#x27;</span>simple_local_avatar_nonce<span class="string">&#x27;, &#x27;</span>_simple_local_avatar_nonce<span class="string">&#x27;, false );</span></span><br><span class="line"><span class="string">?&gt;</span></span><br><span class="line"><span class="string">&lt;input type=&quot;file&quot; name=&quot;simple-local-avatar&quot; id=&quot;simple-local-avatar&quot; /&gt;&lt;br /&gt;</span></span><br><span class="line"><span class="string">&lt;?php</span></span><br><span class="line"><span class="string">if ( empty( $profileuser-&gt;simple_local_avatar ) )</span></span><br><span class="line"><span class="string">echo &#x27;</span>&lt;span class=<span class="string">&quot;description&quot;</span>&gt;<span class="string">&#x27; . __(&#x27;</span>No <span class="built_in">local</span> avatar is <span class="built_in">set</span>. Use the upload field to add a <span class="built_in">local</span> avatar.<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;) . &#x27;</span>&lt;/span&gt;<span class="string">&#x27;;</span></span><br><span class="line"><span class="string">else</span></span><br><span class="line"><span class="string">echo &#x27;</span></span><br><span class="line"> </span><br><span class="line">&lt;input <span class="built_in">type</span>=<span class="string">&quot;checkbox&quot;</span> name=<span class="string">&quot;simple-local-avatar-erase&quot;</span> value=<span class="string">&quot;1&quot;</span> /&gt; <span class="string">&#x27; . __(&#x27;</span>Delete <span class="built_in">local</span> avatar<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;) . &#x27;</span>&lt;br /&gt;</span><br><span class="line"> </span><br><span class="line">&lt;span class=<span class="string">&quot;description&quot;</span>&gt;<span class="string">&#x27; . __(&#x27;</span>Replace the <span class="built_in">local</span> avatar by uploading a new avatar, or erase the <span class="built_in">local</span> avatar (falling back to a gravatar) by checking the delete option.<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;) . &#x27;</span>&lt;/span&gt;</span><br><span class="line"> </span><br><span class="line"><span class="string">&#x27;;</span></span><br><span class="line"><span class="string">&#125; else &#123;</span></span><br><span class="line"><span class="string">if ( empty( $profileuser-&gt;simple_local_avatar ) )</span></span><br><span class="line"><span class="string">echo &#x27;</span>&lt;span class=<span class="string">&quot;description&quot;</span>&gt;<span class="string">&#x27; . __(&#x27;</span>No <span class="built_in">local</span> avatar is <span class="built_in">set</span>. Set up your avatar at Gravatar.com.<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;) . &#x27;</span>&lt;/span&gt;<span class="string">&#x27;;</span></span><br><span class="line"><span class="string">else</span></span><br><span class="line"><span class="string">echo &#x27;</span>&lt;span class=<span class="string">&quot;description&quot;</span>&gt;<span class="string">&#x27; . __(&#x27;</span>You <span class="keyword">do</span> not have media management permissions. To change your <span class="built_in">local</span> avatar, contact the blog administrator.<span class="string">&#x27;,&#x27;</span>simple-local-avatars<span class="string">&#x27;) . &#x27;</span>&lt;/span&gt;<span class="string">&#x27;;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">?&gt;</span></span><br><span class="line"><span class="string">&lt;/td&gt;</span></span><br><span class="line"><span class="string">&lt;/tr&gt;</span></span><br><span class="line"><span class="string">&lt;/table&gt;</span></span><br><span class="line"><span class="string">&lt;script type=&quot;text/javascript&quot;&gt;var form = document.getElementById(&#x27;</span>your-profile<span class="string">&#x27;);form.encoding = &#x27;</span>multipart/form-data<span class="string">&#x27;;form.setAttribute(&#x27;</span>enctype<span class="string">&#x27;, &#x27;</span>multipart/form-data<span class="string">&#x27;);&lt;/script&gt;</span></span><br><span class="line"><span class="string">&lt;?php</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">public function edit_user_profile_update( $user_id ) &#123;</span></span><br><span class="line"><span class="string">if ( ! isset( $_POST[&#x27;</span>_simple_local_avatar_nonce<span class="string">&#x27;] ) || ! wp_verify_nonce( $_POST[&#x27;</span>_simple_local_avatar_nonce<span class="string">&#x27;], &#x27;</span>simple_local_avatar_nonce<span class="string">&#x27; ) ) //security</span></span><br><span class="line"><span class="string">return;</span></span><br><span class="line"><span class="string">if ( ! empty( $_FILES[&#x27;</span>simple-local-avatar<span class="string">&#x27;][&#x27;</span>name<span class="string">&#x27;] ) ) &#123;</span></span><br><span class="line"><span class="string">$mimes = array(</span></span><br><span class="line"><span class="string">&#x27;</span>jpg|jpeg|jpe<span class="string">&#x27; =&gt; &#x27;</span>image/jpeg<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">&#x27;</span>gif<span class="string">&#x27; =&gt; &#x27;</span>image/gif<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">&#x27;</span>avif<span class="string">&#x27; =&gt; &#x27;</span>image/avif<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">&#x27;</span>bmp<span class="string">&#x27; =&gt; &#x27;</span>image/bmp<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">&#x27;</span>tif|tiff<span class="string">&#x27; =&gt; &#x27;</span>image/tiff<span class="string">&#x27;</span></span><br><span class="line"><span class="string">);</span></span><br><span class="line"><span class="string">// front end (theme my profile etc) support</span></span><br><span class="line"><span class="string">if ( ! function_exists( &#x27;</span>wp_handle_upload<span class="string">&#x27; ) )</span></span><br><span class="line"><span class="string">require_once( ABSPATH . &#x27;</span>wp-admin/includes/file.php<span class="string">&#x27; );</span></span><br><span class="line"><span class="string">$this-&gt;avatar_delete( $user_id ); // delete old images if successful</span></span><br><span class="line"><span class="string">// need to be more secure since low privelege users can upload</span></span><br><span class="line"><span class="string">if ( strstr( $_FILES[&#x27;</span>simple-local-avatar<span class="string">&#x27;][&#x27;</span>name<span class="string">&#x27;], &#x27;</span>.php<span class="string">&#x27; ) )</span></span><br><span class="line"><span class="string">wp_die(&#x27;</span>For security reasons, the extension <span class="string">&quot;.php&quot;</span> cannot be <span class="keyword">in</span> your file name.<span class="string">&#x27;);</span></span><br><span class="line"><span class="string">$this-&gt;user_id_being_edited = $user_id; // make user_id known to unique_filename_callback function</span></span><br><span class="line"><span class="string">$avatar = wp_handle_upload( $_FILES[&#x27;</span>simple-local-avatar<span class="string">&#x27;], array( &#x27;</span>mimes<span class="string">&#x27; =&gt; $mimes, &#x27;</span>test_form<span class="string">&#x27; =&gt; false, &#x27;</span>unique_filename_callback<span class="string">&#x27; =&gt; array( $this, &#x27;</span>unique_filename_callback<span class="string">&#x27; ) ) );</span></span><br><span class="line"><span class="string">if ( empty($avatar[&#x27;</span>file<span class="string">&#x27;]) ) &#123; // handle failures</span></span><br><span class="line"><span class="string">switch ( $avatar[&#x27;</span>error<span class="string">&#x27;] ) &#123;</span></span><br><span class="line"><span class="string">case &#x27;</span>File <span class="built_in">type</span> does not meet security guidelines. Try another.<span class="string">&#x27; :</span></span><br><span class="line"><span class="string">add_action( &#x27;</span>user_profile_update_errors<span class="string">&#x27;, create_function(&#x27;</span><span class="variable">$a</span><span class="string">&#x27;,&#x27;</span><span class="variable">$a</span>-&gt;add(<span class="string">&quot;avatar_error&quot;</span>,__(<span class="string">&quot;Please upload a valid image file for the avatar.&quot;</span>,<span class="string">&quot;simple-local-avatars&quot;</span>));<span class="string">&#x27;) );</span></span><br><span class="line"><span class="string">break;</span></span><br><span class="line"><span class="string">default :</span></span><br><span class="line"><span class="string">add_action( &#x27;</span>user_profile_update_errors<span class="string">&#x27;, create_function(&#x27;</span><span class="variable">$a</span><span class="string">&#x27;,&#x27;</span><span class="variable">$a</span>-&gt;add(<span class="string">&quot;avatar_error&quot;</span>,<span class="string">&quot;&lt;strong&gt;&quot;</span>.__(<span class="string">&quot;There was an error uploading the avatar:&quot;</span>,<span class="string">&quot;simple-local-avatars&quot;</span>).<span class="string">&quot;&lt;/strong&gt; &#x27; . esc_attr( <span class="variable">$avatar</span>[&#x27;error&#x27;] ) . &#x27;&quot;</span>);<span class="string">&#x27;) );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">return;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">update_user_meta( $user_id, &#x27;</span>simple_local_avatar<span class="string">&#x27;, array( &#x27;</span>full<span class="string">&#x27; =&gt; $avatar[&#x27;</span>url<span class="string">&#x27;] ) ); // save user information (overwriting old)</span></span><br><span class="line"><span class="string">&#125; elseif ( ! empty( $_POST[&#x27;</span>simple-local-avatar-erase<span class="string">&#x27;] ) ) &#123;</span></span><br><span class="line"><span class="string">$this-&gt;avatar_delete( $user_id );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">/**</span></span><br><span class="line"><span class="string">* remove the custom get_avatar hook for the default avatar list output on options-discussion.php</span></span><br><span class="line"><span class="string">*/</span></span><br><span class="line"><span class="string">public function avatar_defaults( $avatar_defaults ) &#123;</span></span><br><span class="line"><span class="string">remove_action( &#x27;</span>get_avatar<span class="string">&#x27;, array( $this, &#x27;</span>get_avatar<span class="string">&#x27; ) );</span></span><br><span class="line"><span class="string">return $avatar_defaults;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">/**</span></span><br><span class="line"><span class="string">* delete avatars based on user_id</span></span><br><span class="line"><span class="string">*/</span></span><br><span class="line"><span class="string">public function avatar_delete( $user_id ) &#123;</span></span><br><span class="line"><span class="string">$old_avatars = get_user_meta( $user_id, &#x27;</span>simple_local_avatar<span class="string">&#x27;, true );</span></span><br><span class="line"><span class="string">$upload_path = wp_upload_dir();</span></span><br><span class="line"><span class="string">if ( is_array($old_avatars) ) &#123;</span></span><br><span class="line"><span class="string">foreach ($old_avatars as $old_avatar ) &#123;</span></span><br><span class="line"><span class="string">$old_avatar_path = str_replace( $upload_path[&#x27;</span>baseurl<span class="string">&#x27;], $upload_path[&#x27;</span>basedir<span class="string">&#x27;], $old_avatar );</span></span><br><span class="line"><span class="string">@unlink( $old_avatar_path );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">delete_user_meta( $user_id, &#x27;</span>simple_local_avatar<span class="string">&#x27; );</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">public function unique_filename_callback( $dir, $name, $ext ) &#123;</span></span><br><span class="line"><span class="string">$user = get_user_by( &#x27;</span><span class="built_in">id</span><span class="string">&#x27;, (int) $this-&gt;user_id_being_edited );</span></span><br><span class="line"><span class="string">$name = $base_name = sanitize_file_name( $user-&gt;display_name . &#x27;</span>_avatar<span class="string">&#x27; );</span></span><br><span class="line"><span class="string">$number = 1;</span></span><br><span class="line"><span class="string">while ( file_exists( $dir . &quot;/$name$ext&quot; ) ) &#123;</span></span><br><span class="line"><span class="string">$name = $base_name . &#x27;</span>_<span class="string">&#x27; . $number;</span></span><br><span class="line"><span class="string">$number++;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">return $name . $ext;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">$simple_local_avatars = new Simple_Local_Avatars;</span></span><br><span class="line"><span class="string">/**</span></span><br><span class="line"><span class="string">* more efficient to call simple local avatar directly in theme and avoid gravatar setup</span></span><br><span class="line"><span class="string">*</span></span><br><span class="line"><span class="string">* @param int|string|object $id_or_email A user ID, email address, or comment object</span></span><br><span class="line"><span class="string">* @param int $size Size of the avatar image</span></span><br><span class="line"><span class="string">* @param string $default URL to a default image to use if no avatar is available</span></span><br><span class="line"><span class="string">* @param string $alt Alternate text to use in image tag. Defaults to blank</span></span><br><span class="line"><span class="string">* @return string &lt;img&gt; tag for the user&#x27;</span>s avatar</span><br><span class="line"> </span><br><span class="line">*/</span><br><span class="line"> </span><br><span class="line"><span class="keyword">function</span> get_simple_local_avatar( <span class="variable">$id_or_email</span>, <span class="variable">$size</span> = <span class="string">&#x27;96&#x27;</span>, <span class="variable">$default</span> = <span class="string">&#x27;&#x27;</span>, <span class="variable">$alt</span> = <span class="literal">false</span> ) &#123;</span><br><span class="line"> </span><br><span class="line">global <span class="variable">$simple_local_avatars</span>;</span><br><span class="line"> </span><br><span class="line"><span class="variable">$avatar</span> = <span class="variable">$simple_local_avatars</span>-&gt;get_avatar( <span class="string">&#x27;&#x27;</span>, <span class="variable">$id_or_email</span>, <span class="variable">$size</span>, <span class="variable">$default</span>, <span class="variable">$alt</span> );</span><br><span class="line"> </span><br><span class="line"><span class="keyword">if</span> ( empty ( <span class="variable">$avatar</span> ) )</span><br><span class="line"> </span><br><span class="line"><span class="variable">$avatar</span> = get_avatar( <span class="variable">$id_or_email</span>, <span class="variable">$size</span>, <span class="variable">$default</span>, <span class="variable">$alt</span> );</span><br><span class="line"> </span><br><span class="line"><span class="built_in">return</span> <span class="variable">$avatar</span>;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">/**</span><br><span class="line"> </span><br><span class="line">* on uninstallation, remove the custom field from the <span class="built_in">users</span> and delete the <span class="built_in">local</span> avatars</span><br><span class="line"> </span><br><span class="line">*/</span><br><span class="line"> </span><br><span class="line">register_uninstall_hook( __FILE__, <span class="string">&#x27;simple_local_avatars_uninstall&#x27;</span> );</span><br><span class="line"> </span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">simple_local_avatars_uninstall</span></span>() &#123;</span><br><span class="line"> </span><br><span class="line"><span class="variable">$simple_local_avatars</span> = new Simple_Local_Avatars;</span><br><span class="line"> </span><br><span class="line"><span class="variable">$users</span> = get_users_of_blog();</span><br><span class="line"> </span><br><span class="line">foreach ( <span class="variable">$users</span> as <span class="variable">$user</span> )</span><br><span class="line"> </span><br><span class="line"><span class="variable">$simple_local_avatars</span>-&gt;avatar_delete( <span class="variable">$user</span>-&gt;user_id );</span><br><span class="line"> </span><br><span class="line">delete_option(<span class="string">&#x27;simple_local_avatars_caps&#x27;</span>);</span><br><span class="line"> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="四、-Gravatar-集成"><a href="#四、-Gravatar-集成" class="headerlink" title="四、_Gravatar_集成"></a>四、_<strong>Gravatar</strong>_集成</h2><p>1 、注意，以下主题因为使用自有的头像方案，完全屏蔽了 Gravatar，所以也不支持 Gravatar： 7b2 日主题 子比主题 2 、对于此类主题、插件仍需适配 Gravatar？请到支持论坛中开贴↗获取帮助。 3 、如果您是普通用户不想要改代码，快速使用请安装文派头像 （WPAvatar）↗插件。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">您可以很方便的为 WordPress 集成 Gravatar 头像服务，只需要将以下代码加入您的插件或主题的 functions.php 里即可：</span><br></pre></td></tr></table></figure><blockquote><p>Gravatar 官网文档：<code>https://cravatar.com/developer/for-wordpress</code></p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> ( ! function_exists( <span class="string">&#x27;get_cravatar_url&#x27;</span> ) ) &#123;</span><br><span class="line">    /**</span><br><span class="line">     * 替换 Gravatar 头像为 Gravatar 头像</span><br><span class="line">     *</span><br><span class="line">     * Gravatar 是 Gravatar 在中国的完美替代方案，您可以在 https://cravatar.com 更新您的头像</span><br><span class="line">     */</span><br><span class="line">    <span class="keyword">function</span> get_cravatar_url( <span class="variable">$url</span> ) &#123;</span><br><span class="line">        <span class="variable">$sources</span> = array(</span><br><span class="line">            <span class="string">&#x27;www.gravatar.com&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;0.gravatar.com&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;1.gravatar.com&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;2.gravatar.com&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;secure.gravatar.com&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;cn.gravatar.com&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;gravatar.com&#x27;</span>,</span><br><span class="line">        );</span><br><span class="line">        <span class="built_in">return</span> str_replace( <span class="variable">$sources</span>, <span class="string">&#x27;cravatar.cn&#x27;</span>, <span class="variable">$url</span> );</span><br><span class="line">    &#125;</span><br><span class="line">    add_filter( <span class="string">&#x27;um_user_avatar_url_filter&#x27;</span>, <span class="string">&#x27;get_cravatar_url&#x27;</span>, 1 );</span><br><span class="line">    add_filter( <span class="string">&#x27;bp_gravatar_url&#x27;</span>, <span class="string">&#x27;get_cravatar_url&#x27;</span>, 1 );</span><br><span class="line">    add_filter( <span class="string">&#x27;get_avatar_url&#x27;</span>, <span class="string">&#x27;get_cravatar_url&#x27;</span>, 1 );</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> ( ! function_exists( <span class="string">&#x27;set_defaults_for_cravatar&#x27;</span> ) ) &#123;</span><br><span class="line">    /**</span><br><span class="line">     * 替换 WordPress 讨论设置中的默认头像</span><br><span class="line">     */</span><br><span class="line">    <span class="keyword">function</span> set_defaults_for_cravatar( <span class="variable">$avatar_defaults</span> ) &#123;</span><br><span class="line">        <span class="variable">$avatar_defaults</span>[<span class="string">&#x27;gravatar_default&#x27;</span>] = <span class="string">&#x27;Gravatar 标志&#x27;</span>;</span><br><span class="line">        <span class="built_in">return</span> <span class="variable">$avatar_defaults</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    add_filter( <span class="string">&#x27;avatar_defaults&#x27;</span>, <span class="string">&#x27;set_defaults_for_cravatar&#x27;</span>, 1 );</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> ( ! function_exists( <span class="string">&#x27;set_user_profile_picture_for_cravatar&#x27;</span> ) ) &#123;</span><br><span class="line">    /**</span><br><span class="line">     * 替换个人资料卡中的头像上传地址</span><br><span class="line">     */</span><br><span class="line">    <span class="keyword">function</span> <span class="function"><span class="title">set_user_profile_picture_for_cravatar</span></span>() &#123;</span><br><span class="line">        <span class="built_in">return</span> <span class="string">&#x27;&lt;a href=&quot;https://cravatar.com&quot; target=&quot;_blank&quot;&gt; 您可以在 Gravatar 修改您的资料图片&lt;/a&gt;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    add_filter( <span class="string">&#x27;user_profile_picture_description&#x27;</span>, <span class="string">&#x27;set_user_profile_picture_for_cravatar&#x27;</span>, 1 );</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>您可以在 <em><strong>Gravatar</strong></em> 修改您的资料图片：<a href="https://images.mingliangstar.com/go/?url=https://cn.cravatar.com/avatars">https://cn.cravatar.com/avatars</a></p><!-- 这是一张图片，ocr 内容为： --><p><img src="https://images.mingliangstar.com/images/20240527/3.avif"></p><p>至此三种配置方法已经完成，希望能帮助到您</p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Gravatar/">Gravatar</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Gravatar/Wordpress/">Wordpress</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/Gravatar/">Gravatar</category>
      
      
      <comments>https://blog.mingliangstar.com/2024/05/27/Cravatar%E5%A4%B4%E5%83%8F%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AE/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>人机验证解决VAPTCHA</title>
      <link>https://blog.mingliangstar.com/2023/12/14/%E4%BA%BA%E6%9C%BA%E9%AA%8C%E8%AF%81%E8%A7%A3%E5%86%B3VAPTCHA/</link>
      <guid>https://blog.mingliangstar.com/2023/12/14/%E4%BA%BA%E6%9C%BA%E9%AA%8C%E8%AF%81%E8%A7%A3%E5%86%B3VAPTCHA/</guid>
      <pubDate>Thu, 14 Dec 2023 12:51:49 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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;CAPTCHA 是“Completely Automated</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、引言"><a href="#一、引言" class="headerlink" title="一、引言"></a>一、引言</h2><p>CAPTCHA 是“Completely Automated Public Turing Test* to Tell Humans Apart（全自动区分计算机和人类的图灵测试）”的首字母缩写。它是指各种认证方法，这些方法利用一个对于人类来说很简单但对机器来说很难的挑战来测试用户，以验证用户是否为人类。 CAPTCHA 可防止诈骗者和垃圾邮件发送者使用机器人填写用于恶意目的的 Web 表单。</p><p>传统 CAPTCHA 要求用户阅读并正确重新输入无法通过光学字符识别 (OCR) 技术解释的失真文本。 最新的 CAPTCHA 技术使用 AI 驱动的行为和风险分析，根据活动模式（而不是单个离散任务）对人类用户进行认证。</p><p>许多网站都要求用户在登录到帐户档案、提交注册表、发表评论或执行黑客可能使用机器人执行的某些其他操作之前回答 CAPTCHA 问题。 回答这种问题，即表明用户是人类，并被允许在网站上继续执行活动。</p><p>注意事项：</p><ul><li>如果你使用的主题后台有CAPTCHA的API调用接口，您直接调用即可  </li><li>如果你使用的主题后台没有CAPTCHA的API调用接口，则您需要自己部署代码然后调用CAPTCHA的API接口实现人机验证</li></ul><h2 id="二、主题有自带"><a href="#二、主题有自带" class="headerlink" title="二、主题有自带"></a>二、主题有自带</h2><h3 id="2-1、注册"><a href="#2-1、注册" class="headerlink" title="2.1、注册"></a>2.1、注册</h3><p>CAPTCHA官网：<a href="https://images.mingliangstar.com/go/?url=https://www.vaptcha.com/">https://www.vaptcha.com/</a></p><h3 id="2-2、创建验证单元"><a href="#2-2、创建验证单元" class="headerlink" title="2.2、创建验证单元"></a>2.2、创建验证单元</h3><p>完成注册后，您将能够在管理界面中生成CAPTCHA的验证ID（VID）和密钥（KEY）。随后，只需在后台的主题设置中进行相应的配置即可启用CAPTCHA功能。</p><p><img src="https://images.mingliangstar.com/images/20231214/1.avif"></p><p><img src="https://images.mingliangstar.com/images/20231214/2.avif"></p><h3 id="2-3、后台设置"><a href="#2-3、后台设置" class="headerlink" title="2.3、后台设置"></a>2.3、后台设置</h3><p><img src="https://images.mingliangstar.com/images/20231214/3.avif"></p><h2 id="三、主题没有自带"><a href="#三、主题没有自带" class="headerlink" title="三、主题没有自带"></a>三、主题没有自带</h2><h3 id="3-1、代码配置"><a href="#3-1、代码配置" class="headerlink" title="3.1、代码配置"></a>3.1、代码配置</h3><p>配置流程：</p><ul><li>创建验证单元，获取VID和Key 。点击创建。  </li><li>将<code>https://v-cn.vaptcha.com/v3.js</code>引入到你的页面。  </li><li>将 VAPTCHA 初始化到你需要的位置，具体 web 端部署请查看：Web 客户端部署。  </li><li>用户验证通过得到token，与表单数据一同提交到服务端。  </li><li>服务端得到token后，向 VAPTCHA 服务器验证token的有效性，验证通过说明此次请求有效，服务端验证流程请查看：服务端二次验证。</li></ul><p>本文不深入探讨具体的部署步骤，若需了解详细的部署流程，您请参阅 <a href="https://images.mingliangstar.com/go/?url=http://CAPTCHA%E5%AE%98%E7%BD%91%E6%B3%A8%E5%86%8C%E5%9C%B0%E5%9D%80%EF%BC%9Ahttps://www.vaptcha.com/">CAPTCHA 官方提供的配置指南</a>。</p><h3 id="3-2、插件"><a href="#3-2、插件" class="headerlink" title="3.2、插件"></a>3.2、插件</h3><blockquote><p>VAPTCHA下载：<a href="https://pan.baidu.com/s/1sqwhLY4g8t0-0iQoPOHKJQ?pwd=kupa">https://pan.baidu.com/s/1sqwhLY4g8t0-0iQoPOHKJQ?pwd=kupa</a><br>提取码：kupa</p></blockquote><p>上传安装插件之后即可在后台配置</p><p><img src="https://images.mingliangstar.com/images/20231214/4.avif"></p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/Wordpress/VAPTCHA/">VAPTCHA</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/Wordpress/">Wordpress</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/VAPTCHA/">VAPTCHA</category>
      
      
      <comments>https://blog.mingliangstar.com/2023/12/14/%E4%BA%BA%E6%9C%BA%E9%AA%8C%E8%AF%81%E8%A7%A3%E5%86%B3VAPTCHA/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>网站提交搜索引擎</title>
      <link>https://blog.mingliangstar.com/2023/05/08/%E7%BD%91%E7%AB%99%E6%8F%90%E4%BA%A4%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/</link>
      <guid>https://blog.mingliangstar.com/2023/05/08/%E7%BD%91%E7%AB%99%E6%8F%90%E4%BA%A4%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/</guid>
      <pubDate>Mon, 08 May 2023 08:35:26 GMT</pubDate>
      
        
        
          
          
      <description>&lt;div id=&quot;postchat_postcontent&quot;&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</description>
          
        
      
      
      
      <content:encoded><![CDATA[<div id="postchat_postcontent"><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><p>将<a href="https://images.mingliangstar.com/go/?url=https://mingliang.net.cn/"><em><strong>网站</strong></em></a>提交给搜索引擎是为了让搜索引擎更早地了解、索引和显示您的网站内容。以下是一些提交网站给搜索引擎的理由：</p><p>提高可见性：通过将您的网站提交给搜索引擎，可以提高您的网站在搜索结果中出现的机会。当用户搜索与您的网站相关的关键词时，搜索引擎将更容易找到并显示您的网站。<br>更快索引网页：搜索引擎通过网络爬虫（也称为<strong>蜘蛛</strong>）来发现新的网页内容。尽管搜索引擎蜘蛛会定期自动抓取和索引网页，但对于新建立的网站或刚发布的新内容，手动提交可以加快搜索引擎对您网站的索引速度。<br>更新通知：如果您的网站经常发布新的内容或更新现有内容，手动提交网站给搜索引擎可以让它们意识到您的网站有新的变化，以便更及时地更新索引。<br>修复索引问题：有时候，搜索引擎可能无法正确索引您的网站或内容，导致网站排名下降或无法出现在搜索结果中。在这种情况下，通过重新提交网站可以帮助搜索引擎重新审视和索引您的网站，以解决问题。</p><p>需要注意的是，尽管提交网站给搜索引擎可以加快索引速度和提高可见性，但并不保证搜索引擎会立即或完全索引您的网站。搜索引擎的索引算法是复杂的，排名和显示结果是基于多个因素综合考虑的。因此，除了提交网站给搜索引擎，还应该关注网站内容的质量、结构优化、外部链接等方面，以提高搜索引擎优化（<em><strong>SEO</strong></em>）效果。</p><h2 id="二、sitemap"><a href="#二、sitemap" class="headerlink" title="二、sitemap"></a>二、sitemap</h2><p>什么是网站地图？</p><p><strong>sitemap</strong>是一种视觉指南，它以图形化的形式展示网站的结构和内容布局。它帮助用户轻松导航，提升用户体验，并辅助搜索引擎优化。网站地图可以是规划、设计和维护网站时的关键工具，确保信息架构的清晰和易于访问。</p><h3 id="2-1、插件生成站点地图"><a href="#2-1、插件生成站点地图" class="headerlink" title="2.1、插件生成站点地图"></a>2.1、插件生成站点地图</h3><p>使用<strong>Yoast SEO</strong>插件可以自动生成<strong>sitemap</strong></p><p><img src="https://images.mingliangstar.com/images/20230508/1.avif"></p><h3 id="2-2、工具生成网站地图"><a href="#2-2、工具生成网站地图" class="headerlink" title="2.2、工具生成网站地图"></a>2.2、工具生成网站地图</h3><p>工具链接：<a href="https://images.mingliangstar.com/go/?url=https://www.xml-sitemaps.com/">https://www.xml-sitemaps.com/</a></p><p><img src="https://images.mingliangstar.com/images/20230508/2.avif"></p><p>将生成的网站 <strong>sitemap.xml</strong> 文件上传至网站根目录后，搜索引擎就能更高效地抓取和索引页面内容，有助于提升网站在搜索结果中的可见性。确保文件路径正确，一般应为类似<code>https://www.yourdomain.com/sitemap.xml</code>的访问方式。</p><p><img src="https://images.mingliangstar.com/images/20230508/3.avif"></p><h2 id="三、Bing"><a href="#三、Bing" class="headerlink" title="三、Bing"></a>三、Bing</h2><p><strong>Bing</strong>搜索引擎提交入口：<a href="https://images.mingliangstar.com/go/?url=https://www.bing.com/webmasters">https://www.bing.com/webmasters</a></p><p><strong>Bing</strong>网站管理后台提交站点<strong>sitemap</strong></p><p><img src="https://images.mingliangstar.com/images/20230508/4.avif"></p><p><strong>Bing</strong>提交相关文章：<a href="https://images.mingliangstar.com/go/?url=https://www.szlogic.net/learn/seo/site-submit/">https://www.szlogic.net/learn/seo/site-submit/</a></p><h2 id="四、百度"><a href="#四、百度" class="headerlink" title="四、百度"></a>四、百度</h2><p>百度搜索引擎提交入口：<a href="https://ziyuan.baidu.com/property/index">https://ziyuan.baidu.com/property/index</a></p><p>百度的平台公告已经发布了“关于回收网站提交配额的通知”该政策是因为需要打击灰产、低质量和未实名认证的网站，官方的完整说明：“由于近期黑产、作弊行为肆虐，大量抢占平台资源，严重影响用户体验，搜索资源平台针对非实名账户内站点、低质站点关停sitemap提交能力并调整API每日推送额度。请各站点做好日常维护和质量管理，资源平台将在节后陆续为合规站点恢复权益、调配额度。</p><h3 id="4-1、sitemap提交"><a href="#4-1、sitemap提交" class="headerlink" title="4.1、sitemap提交"></a>4.1、sitemap提交</h3><p><img src="https://images.mingliangstar.com/images/20230508/5.avif"></p><h3 id="4-2、手动提交"><a href="#4-2、手动提交" class="headerlink" title="4.2、手动提交"></a>4.2、手动提交</h3><p><img src="https://images.mingliangstar.com/images/20230508/6.avif"></p><p><strong>百度</strong>提交相关文章：<a href="https://images.mingliangstar.com/go/?url=https://www.szlogic.net/learn/seo/site-submit/">https://www.szlogic.net/learn/seo/site-submit/</a></p><h2 id="五、Google"><a href="#五、Google" class="headerlink" title="五、Google"></a>五、Google</h2><p><strong>Google</strong>搜索引擎提交入口：<a href="https://images.mingliangstar.com/go/?url=https://search.google.com/search-console/about">https://search.google.com/search-console/about</a></p><p><img src="https://images.mingliangstar.com/images/20230508/7.avif"></p><p>使用<strong>Yoast SEO</strong>插件生成并提交网站的<strong>sitemap</strong>后，有时候可能会遇到<strong>Google</strong>搜索控制台提示<strong>无法检索</strong>的情况，其实这时候不必过于担心，通常过一会儿系统会自动显示成功，或者在你提交第二个网站地图后，问题也会自动解决。</p><p>当然你可以直接使用上面通过在线工具生成的<strong>sitemap.xml</strong>地图，这样能够方便快捷地为网站整理出结构清晰的索引，有助于搜索引擎更好地抓取和识别网页内容。 </p></div>]]></content:encoded>
      
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/SEO/">SEO</category>
      
      <category domain="https://blog.mingliangstar.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/SEO/%E7%BD%91%E7%AB%99%E5%9C%B0%E5%9B%BE/">网站地图</category>
      
      
      <category domain="https://blog.mingliangstar.com/tags/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/">技术分享</category>
      
      <category domain="https://blog.mingliangstar.com/tags/SEO/">SEO</category>
      
      <category domain="https://blog.mingliangstar.com/tags/%E7%BD%91%E7%AB%99%E5%9C%B0%E5%9B%BE/">网站地图</category>
      
      
      <comments>https://blog.mingliangstar.com/2023/05/08/%E7%BD%91%E7%AB%99%E6%8F%90%E4%BA%A4%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
