<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>YUEXIABUG</title>
  
  
  <link href="https://yxbug.ren/atom.xml" rel="self"/>
  
  <link href="https://yxbug.ren/"/>
  <updated>2026-02-16T01:26:15.856Z</updated>
  <id>https://yxbug.ren/</id>
  
  <author>
    <name>月下八哥</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>蛇年总结</title>
    <link href="https://yxbug.ren/2026/02/16/%E8%9B%87%E5%B9%B4%E6%80%BB%E7%BB%93/"/>
    <id>https://yxbug.ren/2026/02/16/%E8%9B%87%E5%B9%B4%E6%80%BB%E7%BB%93/</id>
    <published>2026-02-16T13:30:00.000Z</published>
    <updated>2026-02-16T01:26:15.856Z</updated>
    
    <content type="html"><![CDATA[<br/><p>与处处坎坷的龙年相比，蛇年就顺畅了许多。在这一年里，我考上了事业单位，算是半个上岸；去上海参加了PC3展会；去深圳代表本地参加国际海洋经济博览会；提到了属于自己的Dream Car；养了蚂蚁；买了ns2。这一切都那么顺利，按部就班，仿佛在本命年里，真有玄学在里面，帮我顺风顺水的度过这一年。</p><p>前段时间，BlogClub还在搞《2025年总结》相关的活动，但我并没有参加。显然，我并不认为一年需要写两个总结，而蛇年总结是我今年更想去写下的。</p><h3 id="考公考编"><a href="#考公考编" class="headerlink" title="考公考编"></a>考公考编</h3><p>这个其实也谈不上顺风顺水。一开始笔试通过了本地的公安局，但分数不怎么样（考试当天发烧）。虽说体测通过了，但是面试当天又睡不着，并且序号卡在中午吃完饭的时候（正常考官都在打哈欠，甚至伸懒腰），遗憾下岸。</p><p>这之后我就随便报了个事业单位，随便复习复习了几天，但巧的是，我以笔试第一的成绩参加面试。刚好我有之前参加过公安的底子，面试更是手到擒来。</p><p>于是我很顺利的上岸了。</p><p>但与我想象中不同的是，刚上班第一天就加班到晚上八点半，那一周更是上了六天班，加了五天班。</p><p>我在《围城》一篇中也写到，考公和考研一样，都是城外的人想进去，城里的人想出去。</p><h3 id="YU7"><a href="#YU7" class="headerlink" title="YU7"></a>YU7</h3><p>这是我蛇年最开心的一件事，提到了自己的Dream Car。虽然当时网上小米的风评不太好，但我毅然决然的选择了小米YU7。很显然，当时一个晚上锁单20w，有不少人和我一样信任小米。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://bu.dusays.com/2025/11/19/691db2f7b0373.jpg" data-src="https://bu.dusays.com/2025/11/19/691db2f7b0373.jpg" alt="合照" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="合照" href="https://bu.dusays.com/2025/11/19/691db2f7b0373.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">合照</span></div></div><p>提车之后我每天最开心的时候就是坐在自己的汽车里，听歌、刷B站、按摩……似乎一天的时光都在车里。</p><p>最近，随着小米OTA升级了12.2系统，原先端到端辅助驾驶要1000km的高速辅助驾驶里程，现在只要300km，我最近上下班体验下来都比较顺畅，很少需要主动接管。</p><h3 id="老人"><a href="#老人" class="headerlink" title="老人"></a>老人</h3><p>从去年9月份开始上班，2025年只能拿到6个月的绩效。我拿着这为数不多的绩效，趁着我外婆过生日的时机，在上个月为家里的三位老人都换了新手机。</p><p>其实我一开始就有这个想法，刚好上个月有一天我妈和我说外婆快过生日了，他们准备以我的名义给外婆庆寿。我就把自己的想法说了出来。</p><p>我们挑挑拣拣很多品牌，最后还是选择了小米（我快成米粉了，虽然我是苹果的忠实拥簇）。</p><h3 id="马年畅想"><a href="#马年畅想" class="headerlink" title="马年畅想"></a>马年畅想</h3><p>马年是我工作后的第一年，我对马年还是有很多期待的。</p><p>1.游戏：今年有许多我期待的游戏，比如GTA6、生化危机9、死亡搁浅2等等，我想在今年能够把他们都玩完（可能GTA6首发没有PC端，只能羊年再说了）；<br>2.工作：事业单位只是个跳板，在马年里，我希望能先考到一个中级职称，然后公务员顺利上岸；<br>3.博客：继续顺利的保持博客的稳定更新；<br>4.学习：我想继续学习代码，作为提升自己的手段，我的要求也不高，马年写一个小项目就行；<br>5.摄影：我想在马年买一台相机，在有空的时候去饱览祖国大好河山，记录生活。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;


&lt;p&gt;与处处坎坷的龙年相比，蛇年就顺畅了许多。在这一年里，我考上了事业单位，算是半个上岸；去上海参加了PC3展会；去深圳代表本地参加国际海洋经济博览会；提到了属于自己的Dream Car；养了蚂蚁；买了ns2。这一切都那么顺利，按部就班，仿佛在本命年里，真有玄学在</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="总结" scheme="https://yxbug.ren/tags/%E6%80%BB%E7%BB%93/"/>
    
    <category term="随笔" scheme="https://yxbug.ren/tags/%E9%9A%8F%E7%AC%94/"/>
    
  </entry>
  
  <entry>
    <title>ANTS</title>
    <link href="https://yxbug.ren/2025/12/26/ANTS/"/>
    <id>https://yxbug.ren/2025/12/26/ANTS/</id>
    <published>2025-12-26T12:35:00.000Z</published>
    <updated>2026-02-15T12:49:50.244Z</updated>
    
    <content type="html"><![CDATA[<br/><p>这篇文章早在 8 月份的时候就像动笔写了，当时也在《涂棋子》这篇文章中发过预告，但拖延症的晚期的我一直想着“后面再说”。最近也没什么生活上的文章可以分享，于是就又提起笔写写蚂蚁。不过要注意的是，由于年代久远，部分文字没有配图。</p><p>其实我一直都挺喜欢蚂蚁的，蚂蚁这样的真社会性动物在我看来是非常值得人类学习的。在这样的社会关系中，没有人是真正的高贵和平庸，每个人都是社会运转的一个齿轮，除了用来生育的蚁后，每只蚂蚁都是绝对平等的。哪怕是蚁后，它所享受的权利都是因为它要付出更多的义务（一辈子不再出巢、一辈子不停的生育）。可以这么说，我们观察和学习蚂蚁不能把一只只蚂蚁单独分割开来看，我们要把蚂蚁作为一个完整的整体去看。</p><p>这样对蚂蚁的喜爱就为我现在养蚂蚁做了很好的铺垫。</p><p>我在今年 7 月份的时候就开始养第一批蚂蚁。我听从大佬的建议，在淘宝店买一窝 40-50 工蚁的工匠收获蚁以及一套另一家淘宝店的蚂蚁入门套装（包含一个蚁巢、一套工具、防逃液、三根 18 口径的试管）。</p><p>到家后我就把蚁巢组装好，然后刷上防逃液。由于第一次懂得不多，刷完防逃液没多久我就把蚂蚁暴力放了进去，之后因为防逃液中有酒精的缘故，很多工蚁就死了，后面这只蚁后也没再产卵。可以说，这只蚁后被我养成了孤后。</p><p>啥都不懂的我在网上求助网友，有网友就说可能是温度原因。刚好那个网友有一套保温装置不用了，就送给我了。</p><h3 id="新后"><a href="#新后" class="headerlink" title="新后"></a>新后</h3><p>在这期间我又买了一窝工匠收获蚁的新后（新后就是才交配完但没有出工蚁的蚁后）和一窝 20-30 工的工匠收获蚁，这只新后到家的时候已经有几枚卵了。我就把它放在保温箱里，尽量不去打扰它。</p><p>在等待出工蚁的途中，我买了很多面包虫回来，供蚁群补充蛋白质。</p><p>没过一个月，新后的第一批工蚁就开始出了，并且蚁后又生了几枚卵。我把面包虫切段后放在了试管里，刚放下去就看见蚁后迫不及待的扑上来大快朵颐。</p><p>这里说明一下，新后在从娘家吃饱了出来交配之后就不再进食，它们会找到一个适合筑巢的地方，把自己深埋进土地里，然后靠着自己储存的能量以及自己的部分肌肉和大脑来产下第一批工蚁，接着第一批工蚁就担任出去觅食和照顾卵幼的责任。至此，蚁后就不再过问蚁巢的事，只是待在深处不断地产卵。</p><p>在这之后这只蚁后就一直在稳定发育，不快不慢，我也给它们还了一个比较大的蚁巢，初步估算够它们发育一年有余。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:640/480;"><img class="lazy" src="https://bu.dusays.com/2025/12/26/694e7c7801ea4.jpg" data-src="https://bu.dusays.com/2025/12/26/694e7c7801ea4.jpg" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/12/26/694e7c7801ea4.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:640/480;"><img class="lazy" src="https://bu.dusays.com/2025/12/26/694e7c78163d1.jpg" data-src="https://bu.dusays.com/2025/12/26/694e7c78163d1.jpg" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/12/26/694e7c78163d1.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><h3 id="爆产"><a href="#爆产" class="headerlink" title="爆产"></a>爆产</h3><p>在养工匠收获蚁新后的过程中我耐不住寂寞，于是又买了一窝尼科巴弓背蚁。尼科巴弓背蚁属于弓背蚁的一种，与收获蚁不同的是它们喜欢吃甜食和蛋白质。平时可以放块冰糖挂机，也可以买那种营养均衡的巴特尔配方。</p><p>这窝尼科巴我买的时候三后 20 工，一到家我就把它们暴力移到了家里准备的大巢。一开始还好，我一个星期只需喂 1.5ml 的巴特尔配方。在养了两个月以后，这窝尼科巴就开始了爆产。</p><p>它们发育的速度非常夸张，蚁后越生越多，越生越快。现在试管里都堆满了卵幼和茧子。现在平均下来一天我就要喂 1.5ml 的巴特尔配方，每半个月喂两个水煮虾仁。其实我也想着要不要买大瓶固体配方回来自己配，因为 1.5ml 的固体配方就能配将近 10ml 的蚁粮。但自己配的要求比较高，需要精确到毫克，还要弄蜂蜜什么的，嫌麻烦就没搞。</p><p>现在这个巢我已经开满四根试管，蚂蚁们已经也快住满了，得找个时间给它们换个更大的蚁巢。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:640/480;"><img class="lazy" src="https://bu.dusays.com/2025/12/26/694e7c78113ea.jpg" data-src="https://bu.dusays.com/2025/12/26/694e7c78113ea.jpg" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/12/26/694e7c78113ea.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:640/480;"><img class="lazy" src="https://bu.dusays.com/2025/12/26/694e7c781c6ad.jpg" data-src="https://bu.dusays.com/2025/12/26/694e7c781c6ad.jpg" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/12/26/694e7c781c6ad.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><h3 id="原生收获蚁"><a href="#原生收获蚁" class="headerlink" title="原生收获蚁"></a>原生收获蚁</h3><p>11 月 20 日左右是原生收获蚁公主的婚飞的时间，在它们交配完成后就变成了新后。我也趁这个季节入手了三只原生收获蚁的新后。</p><p>由于之前那个保温箱已经不能满足我养蚂蚁的需求后，就又重新买了一个大一点的保温箱。而这个淘汰的小保温箱我就用来养这三只新后。一方面把新后和之前养的蚂蚁分开来养，在喂食之前养的蚂蚁的时候不会打扰到新后。另一方面，把新后统一养到小箱子里也便于我区分。</p><p>到家半个月后，我发现仅有一只新后产卵了，另外两只还是没有产卵。于是我就联系商家，商家说这是正常现象，原生收获蚁就是要过冬的，放在保温箱里只能促产，不是比产。最久可以等到开春后再看。</p><p>无奈下我也只能等着了。</p><h3 id="未来计划"><a href="#未来计划" class="headerlink" title="未来计划"></a>未来计划</h3><p>今年由于是刚入坑，只敢养一些便宜的蚂蚁。明年我就打算养养肯尼亚收获蚁。肯尼亚收获蚁是体型最大的收获蚁，身体呈暗红色，非常漂亮。最主要的是今年价格降下来了。明年要是价格保持不变的话，我就打算养一窝肯尼亚。无论是放在家里自己发育观赏，还是日后卖茧子，都是稳赚不亏的。</p><p>同时，我也想买一个好一点的保温箱。现在我的保温箱只能制热，无法制冷。而饲养的蚂蚁一般都是在 28℃~30℃ 发育最好，等到夏天的时候，气温能到 40℃，这时候就需要制冷了。我稍微看了下现在市面上的这种保温箱，自己做的话 300 左右能搞定，但是比较麻烦。定制化的就要 1000 左右了。要不怎么说养蚂蚁花钱的大头不是蚂蚁而是蚁巢和保温箱呢？</p><h3 id="越狱"><a href="#越狱" class="headerlink" title="越狱"></a>越狱</h3><p>我养的那窝尼科巴弓背蚁，它们非常聪明，它们会协同合作进行“越狱”。</p><p>它们会从蚁巢的一个角落里逃出来，几只蚂蚁顶着盖子，其他蚂蚁往外逃。或者是当我打开盖子的时候，时间久了它们会搭“蚁梯”往外逃。</p><p>蚂蚁的聪明不仅仅体现在这里。</p><p>在给收获蚁喂食种子的时候，它们会把种子变成种子面包储存起来，然后在食物不足的时候再吃；喂水煮虾仁的时候，蚂蚁会把大块的虾仁咬碎，方便后期进食；蚂蚁会主动设置垃圾区，把平时的垃圾堆放在一起，这种行为是可以人为驯养干涉的，训的好可以方便我们日后清理垃圾。</p><h3 id="饲养建议"><a href="#饲养建议" class="headerlink" title="饲养建议"></a>饲养建议</h3><p>下面我来给想入坑的蚁友一些建议。<br>首先要有一定的蚂蚁知识，比方说国内能养什么蚂蚁、蚂蚁分为哪几种、每种蚂蚁的食物习性等。比如国内就不能养红火蚁，白蚁也不建议饲养（而且白蚁也不是蚂蚁）；我们一般养的蚂蚁就是切叶蚁、弓背蚁、收获蚁等；切叶蚁因为要养菌落从而对蚁巢要求比较高，弓背蚁喜欢吃甜食，收获蚁吃种子。</p><p>这里也建议多去搜搜饲养蚂蚁相关的视频，可以看看<a href="https://space.bilibili.com/1632978110?spm_id_from=333.337.0.0">阿韬 ANTS</a>、<a href="https://space.bilibili.com/54716491?spm_id_from=333.337.search-card.all.click">PADA 蚁匠</a>（买蚂蚁和蚁巢工具啥的也可以去他们的淘宝店买，这两位是蚁圈比较大的UP主）</p><p>第二，选定自己想要饲养的蚂蚁后，先购买保温箱、加热垫、控温器并组装测试。同时也要买蚁巢和镊子、桌面吸尘器、试管、PVA 棉等工具。蚁巢我个人推荐阿韬 ANTS、PADA 蚁匠和<a href="https://space.bilibili.com/15711082?spm_id_from=333.337.search-card.all.click">茧子王隔壁老王</a>。这里注意一下，新到家的蚁巢刷完防逃液后一定要放在通风处至少 10 分钟！</p><p>之后就可以购买自己想要饲养的蚂蚁。大家要知道每种蚂蚁婚飞的时间不一样，一般来说买当季的新后或者是去年的强后。这就要求我们对蚂蚁婚飞的时间要了解，具体婚飞时间可以自行去网上查询。了解过后我们就可以避免购买到去年的弱后。比如说收获蚁，一年发展到 100 多工是正常的，要是发展到 200 工以上就属于强后。要是你在当年婚飞季买那种 40 工的，那毫无疑问是去年的弱后。</p><p>买蚂蚁呢我推荐去阿韬 ANTS、PADA 蚁匠和飘落的雪—蚂蚁阁买，这三家都比较正规。飘雪会稍微比较贵。要是想养肯尼亚收获蚁可以去找茧子王隔壁老王购买，价格便宜，还都是强后。他会先帮忙饲养到 20 工稳定下来后再发货，要是中途死了他会重新再养，对于新手来说比较无忧。</p><p>买到家后，要是新后就不要打扰，放在那静养即可，最多一周打扰一次。在出第一批工后再喂食。</p><p>在购买的时候一定要根据气候条件购买加热包或冰袋，避免路上死亡。到家后第一件就是根据要求全程拍摄拆包视频，万一出现残后、死亡等情况能够找到商家进行补发。</p><p>商家一般发过来的都是一根试管，可以在家静置一天再把它们移到巢里，也可以直接暴力换巢，蚂蚁没那么脆弱。</p><p>后续的话就是该咋养就咋养。</p><p>可以多加群，有不懂的在群里问，老哥们都是很友善的，有些老哥还会送淘汰的工具啥的。</p><h3 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h3><p>养蚂蚁对我而言是一个非常享受的过程。为什么这么说呢？我买了很多战锤棋子和颜料，但到现在没怎么涂；我买了很多游戏，但是现在已经感觉在和上班一样，不想打开；我学了 70 天的日语，然后也渐渐放弃。</p><p>只有养蚂蚁这件事我一直很有兴趣。我分析了一下原因：我认为养蚂蚁是一种“寸止”的过程，因为不能过多的打扰蚂蚁，平均下来一周最多观察两三次，新后的话一周最好就只观察一次。这就使得我平时不观察的时候就心痒痒，等到喂食日到的时候，就迫不及待取出来观察。看着它们把食物一点点吃下，一点点带到巢里喂其他蚂蚁。这个过程真的很有趣。</p><p>清理巢穴的时候也要和蚂蚁斗智斗勇，稍不留神就逃出来好几只。</p><p>每次拿出来观察的时候，看着蚂蚁四处乱窜，越来越多的卵幼都感觉很有成就感。</p><p>但养蚂蚁最好玩的时期就是新后发育的时期，你看着蚂蚁从一只新后到两三只工蚁，再到后面的 30 只工蚁。你每次喂食它们都会扑上来吃。这种成就感不亚于看着自己孩子长大成才，仅次于孩子第一次开口叫“爸爸”和“妈妈”。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;


&lt;p&gt;这篇文章早在 8 月份的时候就像动笔写了，当时也在《涂棋子》这篇文章中发过预告，但拖延症的晚期的我一直想着“后面再说”。最近也没什么生活上的文章可以分享，于是就又提起笔写写蚂蚁。不过要注意的是，由于年代久远，部分文字没有配图。&lt;/p&gt;
&lt;p&gt;其实我一直都挺喜</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="蚂蚁" scheme="https://yxbug.ren/tags/%E8%9A%82%E8%9A%81/"/>
    
    <category term="工匠收获蚁" scheme="https://yxbug.ren/tags/%E5%B7%A5%E5%8C%A0%E6%94%B6%E8%8E%B7%E8%9A%81/"/>
    
    <category term="尼科巴弓背蚁" scheme="https://yxbug.ren/tags/%E5%B0%BC%E7%A7%91%E5%B7%B4%E5%BC%93%E8%83%8C%E8%9A%81/"/>
    
  </entry>
  
  <entry>
    <title>YU7 提车记</title>
    <link href="https://yxbug.ren/2025/11/19/YU7%20%E6%8F%90%E8%BD%A6%E8%AE%B0/"/>
    <id>https://yxbug.ren/2025/11/19/YU7%20%E6%8F%90%E8%BD%A6%E8%AE%B0/</id>
    <published>2025-11-19T12:13:00.000Z</published>
    <updated>2025-11-20T12:29:27.113Z</updated>
    
    <content type="html"><![CDATA[<br/><p>芜湖~也是在5个月的漫长等待之后提到自己的Dream Car了，在今年6月26日晚上的时候小米发布了YU7，然后在6月28日去我们这的体验中心看了看就下定了，我定的是YU7 MAX。目前网络上一直对小米充满敌意，各种标签贴不过来，但我依然认为绝大多数事故都是驾驶员的问题。</p><p>说回正事，我们这目前没有交付中心，所以只能去隔壁市提车。我们早上出发，差不多是10点半到的。一进去工作人员就带着我们验车，要不说我爸以前是干运车物流的，他检查的贼仔细，我们其他人转了几圈都没看到问题，他就能发现一些小问题。但这些小问题可以说是每辆车都会有的小问题，比如说在根本不会去看的缝隙角落里发现了浅浅的痕迹、在很隐蔽的地方发现了一点飞漆（一个小点）。</p><p>验完车就是付尾款、买保险、蹭饭了。让我没想到的是这家交付中心没有自己的食堂，员工都是点老乡鸡，负责人给我们每人点了一份老乡鸡，虽说有点简陋了，但味道还算不错。比我之前去上海参加 PC3 展会自己点的老乡鸡要好吃不少。</p><p>吃完午饭办完临时牌照，小米员工就开始带我一点一点学习小米汽车的设置。一开始我还担心我是苹果手机，和小米汽车的适配度有限，但小米员工却说对苹果手机的适配是非常好的，基本所有功能都能使用。</p><p>不过说实话，提车过程没我想的那么“精彩”。之前我在社交平台上看到提车vlog时，都感觉很正式、很热闹，自己来提时却比较平淡。或许有摄像机的缘故会多出更多的表演成分。</p><p>回来的时候我是全程高速“辅助驾驶”，有的方面差、有的方面好。比如在前车慢速的时候，它不会自己超车，而是会提醒一下，然后让你选择是否超车；又比如在旁边车道有车靠近我这边的车道的时候，车会自己往另一边靠一点，并且会自动选择是加速过去还是减速拉开距离。</p><p>现在，我也开了两天YU7了，说实话，真的很好开。开着让人感觉很舒心，再加上便捷的自动停车，我每天最开心的时候就是坐在车上的时候。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://bu.dusays.com/2025/11/19/691db2f7b0373.jpg" data-src="https://bu.dusays.com/2025/11/19/691db2f7b0373.jpg" alt="合照" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="合照" href="https://bu.dusays.com/2025/11/19/691db2f7b0373.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">合照</span></div></div><p>但借此文我还想聊聊目前的互联网贴标签的这样一个环境。从上了大学以后（新冠疫情之后），社会怨气越来越多，互联网上的二极管也越来越多。从米哈游到黑神话、从华为到小米、从地域歧视到性别对立，各个地方都是二极管。就比如小米造车后的网络舆情，一旦出了车祸，没人关注这个车祸的原因，只会一味的批判小米，华为车亦然。于是现在网络上车祸层出不穷，油车粉和电车粉互相嘲讽，华为小米互相辱骂攻击。标签可以说都不够贴的了。只要你上网，网络就会自动给你戴几顶帽子，贴好多个标签。稍微激进点的被贴上“极左”的标签，稍微保守一点的就是“极右”（此处左与右不是政治上的左与右，仅仅是借用坐标轴方便理解），理智一点的就是“理中客”，可以说目前网络环境是史无前例的差，如果这样下去只会更差。但若是强行管控，又只会适得其反。</p><p>同时这几年营销号和部分官号过于强调“自信”，过分的自信本身就是一种不自信。就像我看过一个博主说的，中国人去外国旅游举中国国旗就是“好样的”，外国人来中国旅游举外国旗子就是不好的，这种行为和现象无关自信，纯粹是双标。这种过于“自信”的问题也让政府的公信力变得越来越低，因为一旦政府的行为没有符合人民群众“高傲的自信”，那么百姓们就会质疑政府的做法（参考佩洛西访台），从而最终对政府失去信心。</p><p>经济下行的这几年很多人都过得并不如意，考研考公内卷严重，岗位稀少，不想浪费十几年的寒窗苦读去干不需要学历和知识的工作还要被骂“孔乙己”和“小镇做题家”，这段时间的大学生们可以说都是前途一片迷茫。社会上的人也并不好过，创业的很难生存、上班的要面对裁员、在家待着的是啃老，每个人都有属于自己的标签。</p><p>但我并不认为标签就一定是坏事，在目前这种社会环境中，年轻人们需要标签来满足自己“原子化”的社交方式（摆脱传统熟人网络、集体关系束缚，基于兴趣、需求等临时组件轻量化、弱连接社交方式，取自豆包），贴标签行为则能更好的帮助现在年轻人来根据兴趣选择圈子并进行社交。</p><p>所以，我个人认为，贴标签是为了让自己更准确的找到自己的圈子并进行社交，而不是攻击他人。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;


&lt;p&gt;芜湖~也是在5个月的漫长等待之后提到自己的Dream Car了，在今年6月26日晚上的时候小米发布了YU7，然后在6月28日去我们这的体验中心看了看就下定了，我定的是YU7 MAX。目前网络上一直对小米充满敌意，各种标签贴不过来，但我依然认为绝大多数事故都是</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="提车" scheme="https://yxbug.ren/tags/%E6%8F%90%E8%BD%A6/"/>
    
    <category term="小米 YU7 MAX" scheme="https://yxbug.ren/tags/%E5%B0%8F%E7%B1%B3-YU7-MAX/"/>
    
  </entry>
  
  <entry>
    <title>深圳</title>
    <link href="https://yxbug.ren/2025/11/03/%E6%B7%B1%E5%9C%B3/"/>
    <id>https://yxbug.ren/2025/11/03/%E6%B7%B1%E5%9C%B3/</id>
    <published>2025-11-03T04:00:00.000Z</published>
    <updated>2025-11-20T12:29:27.124Z</updated>
    
    <content type="html"><![CDATA[<p>才上班两个月就被派去深圳出差，26 号飞深圳，30 号飞回来。不过实话说，这也确实是最有“性价比”的方案，毕竟以我们工作的强度，其他两位同事谁出差对我们的工作都是毁灭性的打击。这次出差的任务是带着我们这的企业展品参加海博会，来宣传一下我们这边的海洋经济。</p><p>深圳和我们这的气温差别有点大，在我们这我已经开始穿秋衣秋裤了，到了深圳那还是穿着短衣短袖。</p><p>出差住的宾馆因为海博会的原因大涨价，但这宾馆一是离机场比较近，这就导致晚上隔个几分钟就有飞机起飞和降落，让人晚上睡不好觉。二来呢，你很难相信大几百一晚的宾馆早餐的面条用的是方便面，还是那种便宜的火锅面。给我真实真无语了。三来这宾馆位置很偏，去哪里都要一个小时起步。</p><p>但好在展会的这几天不是很忙，主要负责的人和我说没我什么事，于是我就逛了逛展，其他时间就是在宾馆或者去深圳其他地方转转。我问住在深圳的群友深圳有哪些好玩的地方，群友让我去华强北淘点电子产品或者是去香港。但我并没有带港澳通行证和护照，而华强北又离我 20 多公里，坐地铁要两个小时，于是我果断选择在海拉鲁当了几天的流氓。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://bu.dusays.com/2025/11/03/69080c538189b.jpeg" data-src="https://bu.dusays.com/2025/11/03/69080c538189b.jpeg" alt="海博会展会（该展位不是我们展位，仅做展示，若有侵权请联系我）" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="海博会展会（该展位不是我们展位，仅做展示，若有侵权请联系我）" href="https://bu.dusays.com/2025/11/03/69080c538189b.jpeg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">海博会展会（该展位不是我们展位，仅做展示，若有侵权请联系我）</span></div></div><p>在深圳出差的这几天，我基本上每天就是一桶泡面加一份外卖。到深圳的第一天我就到楼下准备买泡面，一看 7 块钱一桶大面饼的康师傅面我都惊呆了。人家老板还一直和我说这是正常价格。虽然我早就知道深圳的物价不会便宜，但最普通的泡面居然要 7 块，这和抢已经没有什么区别了。于是我果断打开淘宝闪购，外卖了几桶泡面，共计花费 1 块多（有活动）。</p><p>巧的是我的生日刚好在出差这几天里，在生日那天本来抠抠搜搜的我还是吃了份肯德基，说实话，还是肯德基好吃。</p><p>其实这几天没出去玩还有一个原因就是我担心展会那边突然有事，因为路途遥远，我不能第一时间赶到。而在最后一天，下午两点就收展了，而我的飞机是晚上九点多的。于是我乘坐地铁去就近的万达广场转了转，又吃了一份肯德基（其实也就一份薯条和圣代）。</p><p>回去的路上，我第一次感受到了深圳的繁华，人山人海，车水马龙。飞机起飞后，我才看见了深圳的灯火辉煌。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://bu.dusays.com/2025/11/03/69080c522c98e.jpeg" data-src="https://bu.dusays.com/2025/11/03/69080c522c98e.jpeg" alt="飞机上的深圳" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="飞机上的深圳" href="https://bu.dusays.com/2025/11/03/69080c522c98e.jpeg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">飞机上的深圳</span></div></div>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;才上班两个月就被派去深圳出差，26 号飞深圳，30 号飞回来。不过实话说，这也确实是最有“性价比”的方案，毕竟以我们工作的强度，其他两位同事谁出差对我们的工作都是毁灭性的打击。这次出差的任务是带着我们这的企业展品参加海博会，来宣传一下我们这边的海洋经济。&lt;/p&gt;
&lt;p&gt;深圳</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="工作" scheme="https://yxbug.ren/tags/%E5%B7%A5%E4%BD%9C/"/>
    
    <category term="生活" scheme="https://yxbug.ren/tags/%E7%94%9F%E6%B4%BB/"/>
    
  </entry>
  
  <entry>
    <title>mac 配置 nvm</title>
    <link href="https://yxbug.ren/2025/09/19/mac%20%E9%85%8D%E7%BD%AE%20nvm/"/>
    <id>https://yxbug.ren/2025/09/19/mac%20%E9%85%8D%E7%BD%AE%20nvm/</id>
    <published>2025-09-19T12:23:00.000Z</published>
    <updated>2025-11-20T12:29:27.115Z</updated>
    
    <content type="html"><![CDATA[<p>很多 mac 用户需要配置 nodejs 的包版本管理工具 npm，而 nvm 则是能够针对 nodejs 和 npm 版本进行管理的工具，本文将介绍如何在 mac 上配置 nvm。</p><p>以下是 nodejs 和 nvm 官方安装文档的链接：<br><a href="https://nodejs.org/zh-cn/download">nodejs 官方安装文档</a><br><a href="https://nvm.uihtm.com/doc/download-nvm.html">nvm 官方安装文档</a></p><p>各位可以自己去查看文档，根据文档的教程进行安装，本文将详细说明我的安装步骤。</p><h2 id="安装-nvm"><a href="#安装-nvm" class="headerlink" title="安装 nvm"></a>安装 nvm</h2><p>打开终端（Terminal），输入以下命令安装 nvm：</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">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash</span><br></pre></td></tr></table></figure><p>若成功安装，则显示以下信息：</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/600;"><img class="lazy" src="https://bu.dusays.com/2025/09/19/68cd10fff1025.png" data-src="https://bu.dusays.com/2025/09/19/68cd10fff1025.png" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/09/19/68cd10fff1025.png"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><p>一般情况下，这个时候就已经安装好了 nvm，但部分用户可能会遇到 nvm 命令无法识别的问题，这是因为环境配置自动完成，所以需要手动配置环境变量。</p><p>输入以下命令查看 nvm 是否安装（配置）成功：</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">nvm -v</span><br></pre></td></tr></table></figure><p>如果成功安装，则会输出 nvm 的版本号，若未成功安装，则会提示 <code>command not found: nvm</code>。</p><h2 id="配置环境变量"><a href="#配置环境变量" class="headerlink" title="配置环境变量"></a>配置环境变量</h2><p>如果 nvm 命令无法识别，则需要手动配置环境变量。</p><p>打开终端，输入一下命令查看 nvm 是否已经安装成功：</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"><span class="built_in">ls</span> -a ~ | grep .nvm</span><br></pre></td></tr></table></figure><p>如果显示 <code>.nvm</code>，则表示 nvm 已经安装成功。如果未显示 <code>.nvm</code>，则表示 nvm 未安装成功，需要重新执行安装命令。</p><p>接着，我们要先知道自己电脑的 Shell 配置文件是什么，输入以下命令：</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"><span class="built_in">echo</span> <span class="variable">$SHELL</span></span><br></pre></td></tr></table></figure><p>一般情况下，mac 的 Shell 配置文件是 <code>~/.bash_profile</code> 或 <code>~/.zshrc</code>，如果输出的是 <code>zsh</code>，则表示 Shell 配置文件是 <code>~/.zshrc</code>；如果输出的是 <code>bash</code>，则表示 Shell 配置文件是 <code>~/.bash_profile</code>。</p><p>我的输出是 <code>zsh</code>，所以我的 Shell 配置文件是 <code>~/.zshrc</code>。以下就以 <code>~/.zshrc</code> 为例进行说明。</p><p>我们可以输入以下命令来打开 <code>~/.zshrc</code> 文件：</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">open -e ~/.zshrc <span class="comment"># macOS 自带的文本编辑器打开</span></span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">vim ~/.zshrc <span class="comment"># 使用 vim 打开</span></span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">nano ~/.zshrc <span class="comment"># 使用 nano 打开</span></span><br></pre></td></tr></table></figure><p>我这里使用 vim 打开，并对 vim 的部分操作命令进行说明。</p><p>在终端中输入 <code>vim ~/.zshrc</code>，打开 <code>~/.zshrc</code> 文件。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/1060;"><img class="lazy" src="https://bu.dusays.com/2025/09/19/68cd05c38ba93.png" data-src="https://bu.dusays.com/2025/09/19/68cd05c38ba93.png" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/09/19/68cd05c38ba93.png"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><p>此时按下 <code>i</code> 键，进入插入模式，可以编辑文件内容。并将以下命令添加到文件末尾：</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="built_in">export</span> NVM_DIR=<span class="string">&quot;<span class="variable">$HOME</span>/.nvm&quot;</span></span><br><span class="line">[ -s <span class="string">&quot;<span class="variable">$NVM_DIR</span>/nvm.sh&quot;</span> ] &amp;&amp; \. <span class="string">&quot;<span class="variable">$NVM_DIR</span>/nvm.sh&quot;</span> <span class="comment"># 加载 nvm</span></span><br><span class="line">[ -s <span class="string">&quot;<span class="variable">$NVM_DIR</span>/bash_completion&quot;</span> ] &amp;&amp; \. <span class="string">&quot;<span class="variable">$NVM_DIR</span>/bash_completion&quot;</span> <span class="comment"># 加载自动补全</span></span><br></pre></td></tr></table></figure><p>即</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/480;"><img class="lazy" src="https://bu.dusays.com/2025/09/19/68cd065f5cda4.png" data-src="https://bu.dusays.com/2025/09/19/68cd065f5cda4.png" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/09/19/68cd065f5cda4.png"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><p>编辑完成后，按下 <code>Esc</code> 键，退出插入模式。然后输入 <code>:wq</code>，按下回车键，保存并退出 vim。</p><p>此时，重新打开一个终端窗口，输入以下命令查看 nvm 是否安装成功：</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">nvm -v</span><br></pre></td></tr></table></figure><p>如果成功安装，则会输出 nvm 的版本号。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/300;"><img class="lazy" src="https://bu.dusays.com/2025/09/19/68cd08679a0cf.png" data-src="https://bu.dusays.com/2025/09/19/68cd08679a0cf.png" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/09/19/68cd08679a0cf.png"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><h2 id="安装-nodejs"><a href="#安装-nodejs" class="headerlink" title="安装 nodejs"></a>安装 nodejs</h2><p>现在，我们就可以跟着 nodejs 官方文档安装 nodejs 了。你可以选择安装最新的 LTS 版本，或者最新的 Current 版本，也可选择自己需要的版本进行安装。</p><p>输入以下命令查看可安装的 nodejs 版本：</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">nvm ls-remote</span><br></pre></td></tr></table></figure><p>接着就是选择自己需要的版本进行安装，比如我选择安装最新的 LTS 版本 <code>v22.19.0</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">nvm install 22</span><br></pre></td></tr></table></figure><p>安装完成后，输入以下命令查看 nodejs 版本：</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">node -v</span><br></pre></td></tr></table></figure><p>如果成功安装，则会输出 nodejs 的版本号。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/350;"><img class="lazy" src="https://bu.dusays.com/2025/09/19/68cd0a59c1f8d.png" data-src="https://bu.dusays.com/2025/09/19/68cd0a59c1f8d.png" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://bu.dusays.com/2025/09/19/68cd0a59c1f8d.png"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><h2 id="配置-npm"><a href="#配置-npm" class="headerlink" title="配置 npm"></a>配置 npm</h2><p>安装完 nodejs 后，npm 就已经自动配置完成，可以输入 <code>npm -v</code> 查看 npm 版本。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;很多 mac 用户需要配置 nodejs 的包版本管理工具 npm，而 nvm 则是能够针对 nodejs 和 npm 版本进行管理的工具，本文将介绍如何在 mac 上配置 nvm。&lt;/p&gt;
&lt;p&gt;以下是 nodejs 和 nvm 官方安装文档的链接：&lt;br&gt;&lt;a href</summary>
      
    
    
    
    <category term="开发工具" scheme="https://yxbug.ren/categories/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="nvm" scheme="https://yxbug.ren/tags/nvm/"/>
    
    <category term="mac" scheme="https://yxbug.ren/tags/mac/"/>
    
    <category term="nodejs" scheme="https://yxbug.ren/tags/nodejs/"/>
    
    <category term="环境配置" scheme="https://yxbug.ren/tags/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
    
    <category term="npm" scheme="https://yxbug.ren/tags/npm/"/>
    
  </entry>
  
  <entry>
    <title>围城</title>
    <link href="https://yxbug.ren/2025/09/17/%E5%9B%B4%E5%9F%8E/"/>
    <id>https://yxbug.ren/2025/09/17/%E5%9B%B4%E5%9F%8E/</id>
    <published>2025-09-17T04:00:00.000Z</published>
    <updated>2025-11-20T12:29:27.118Z</updated>
    
    <content type="html"><![CDATA[<p>钱钟书所著的《围城》中有一句话：“城外的人想冲进去，城里的人想逃出来。”原文中这句话是用来形容婚姻的，而如今我考公考编上岸后发现这句话来形容体制工作也很贴切。</p><p>其实早在我备考公务员、事业编的时候就在贴吧里看到这句话，但当时我并不以为然。在经济下行的大环境下，在老家考取一个稳定的编制是一件非常好的事情，毕竟编制内的工作稳定、福利待遇好、工作压力小；二来在我老家工作，我不用背上房贷，还可以经常回去看看老人。况且去年毕业的时候我也去杭州寻找过工作机会，但要么是工资低，要么是工作强度太高。</p><p>而在今年我考上了本地的事业编，我以为我的前途一片光明。作为一名中共党员，加上面试培训中所培养的为人民服务的意识，我始终认为无论我在哪工作，我的服务对象都是人民群众，我做的每一件事的出发点都是贯彻“为人民服务”这句话。然而，当我正式入职之后，却发现体制内的部分工作是毫无意义的，甚至可以说是浪费人力物力的。这些工作不仅会浪费我们的时间，从任何角度上来看它对于我们国家发展，对于提高群众生活质量来说，都是毫无用处的。而这些工作却很多很多。</p><p>自从我入职以来，一个星期加了六天的班，甚至周末也要我正常上班，但让我生气的是，周末我来了，却不需要我做什么事，我就坐在办公室玩手机、发呆。我不理解这样无意义的加班有什么用。事实就是，除了让我生气之外，毫无用处。</p><p>在入职第二天的时候，我们科长就问我有没有什么兴趣爱好、特长之类的，我说我挺喜欢写代码的，她说这个千万不能丢。体制内的工作对个人能力的提升非常有限，因为每天的工作就是写材料、找数据、开会……一旦你受够了体制内枯燥繁琐的工作，辞职去外面找工作，你会发现你什么都不会，你和年轻人、和大多数社会上的人相比毫无竞争力。</p><p>所以，这篇文章也不是让各位放弃考公考编，毕竟在现在这个大环境下，体制内的工作是相当不错的。但各位也要深思熟虑，体制内的工作真的适合你吗？当你花了一年、两年甚至更多时间备考，花了很多钱去报培训班，然后入职后面对枯燥乏味的工作时，你还能坦然放弃吗？</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;钱钟书所著的《围城》中有一句话：“城外的人想冲进去，城里的人想逃出来。”原文中这句话是用来形容婚姻的，而如今我考公考编上岸后发现这句话来形容体制工作也很贴切。&lt;/p&gt;
&lt;p&gt;其实早在我备考公务员、事业编的时候就在贴吧里看到这句话，但当时我并不以为然。在经济下行的大环境下，在</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="工作" scheme="https://yxbug.ren/tags/%E5%B7%A5%E4%BD%9C/"/>
    
    <category term="生活" scheme="https://yxbug.ren/tags/%E7%94%9F%E6%B4%BB/"/>
    
  </entry>
  
  <entry>
    <title>关于</title>
    <link href="https://yxbug.ren/about/"/>
    <id>https://yxbug.ren/about/</id>
    <published>2025-09-04T12:27:39.000Z</published>
    <updated>2025-11-20T12:29:27.113Z</updated>
    
    <content type="html"><![CDATA[<p>愿指引明路的苍蓝星为你闪耀。<br><br/><br/><br/></p><h3 id="自我介绍"><a href="#自我介绍" class="headerlink" title="自我介绍"></a>自我介绍</h3><hr><p>我的兴趣爱好比较广泛，我喜欢养一些小动物，目前家里养了一只博美，还有几窝蚂蚁。我也喜欢打游戏，主要喜欢 ARPG 类的游戏，对《怪物猎人系列》、《空洞骑士》以及《明日方舟》情有独钟。 但也很喜欢《魔兽世界》、《Dota2》、《博德之门 3》。我也非常喜欢看小说，对悬疑类的比较感兴趣，《克苏鲁神话》我最是喜欢。除此之外，我还喜欢跑团（TRPG），我已经跑过两次网团和两次面团，并参加了 2025 年的 PC3 传送门跑团嘉年华。家里还收藏了很多桌游，比如经典的《三国杀》，《小英雄》、《秘密结社》，之前还有《怪物猎人》桌游版全套，但因为实在没人玩就出了二手。</p><p>写博客的起因是在大二上学期末，实验室的一位 朋友A 向 朋友B 请教了有关搭建博客的问题，当时 B 就问了他为什么要去搭建一个博客。因为我本身学习就没有记笔记的习惯，所以对此也没什么大的想法。直到这学期我开始学习 Vue、学习如何使用 Electron 来打包 Vue。我折腾了两天成功打包完成，然后我就生出了强烈的想要搭建一个自己的博客的想法。我想要去记录自己学习开发中所遇到的问题以及解决问题的办法。我迫不及待。刚巧，我自己还写了名为《丝之歌》的小说，以往我都是私发给朋友，现在就想趁着博客的机会就发表出来。</p><p>我大一跟着学长去学算法，其实就我本人而言算法是不适合我的，而在当时我周围的人都在学算法，我本身又懂得不是很多，所以我也就跟着学了。而学了一年下来我并没有太多的收获。就在大二上学期末我接触到了开发，我花了一段的时间将前端三件套 ( HTML, CSS, JavaScript ) 大略的看了一遍，等到了这个学期才正式开始学习前端。这学期一开始我就奔着去学 Vue，但由于我前置知识的缺乏导致我学得不是很懂。后来我回过头去学完了 ES6、Ajax、Node.js 并跟着视频撰写了 Node.js 的学习文档，打算留给大一以及后面的人学习使用。期末 Web 大作业就是使用的 Node.js 搭建的后端。</p><p>大创项目《基于Web的模拟信笺网站(Letter)》已在2023年4月正式结束，我在该项目中担任前端工程师，负责页面的设计，以及几乎前端所有代码的编写。在考完之后准备一个人将整个项目重构，重新编写并增加新的功能。</p><p>毕设项目是《基于推荐算法的Codelink队友推荐平台》，平台中主要是运用编辑距离算法和协同过滤算法搭建了一个队友推荐平台。用户可以在平台中获取由系统推荐的其他相似用户，以及用户可能感兴趣的项目。</p><p><br/><br/></p><h3 id="博客介绍"><a href="#博客介绍" class="headerlink" title="博客介绍"></a>博客介绍</h3><hr><p>本博客使用的是 <a href="https://xaoxuu.com/wiki/stellar/#start">hexo-theme-stellar</a> 主题搭建的，评论区使用的是 <a href="https://giscus.app/zh-CN">giscus</a>。同时，本博客支持手机阅览，你可以在手机上通过网址来阅读本博客上的内容。本博客所使用的图片都已经上传到 SM.MS 图床中。另外，请善用评论区，提出你的想法和问题是最好的。请不要在评论区发布一些不当的言论。</p><p>目前仅有两个大的板块，一个是“技术”、一个是“杂谈”。“技术”板块是用来展示自己在学习代码过程中遇到的问题和解决的办法，“杂谈”则是用来记录生活中的一些事情和感悟。</p><div class="tag-plugin colorful note" color="orange"><div class="body"><p>原博客的“丝之歌”暂时先不再开放阅览，待我修改完成后再统一发布。</p></div></div><p>本博客目前还存在一些 Bug 和不完善的地方，敬请见谅。日后会逐渐丰富博客的内容以及功能、表达等模块，以丰富读者的阅览体验。</p><p>技术板块内容凡是作者是 “YUEXIABUG” 都可自由转载（<u><strong>标明作者和出处</strong></u>），其余部分都 <u><strong>禁止转载</strong></u>。</p><p>与诸君共勉，变得更强。</p><p><br/><br/></p><h3 id="联系我"><a href="#联系我" class="headerlink" title="联系我"></a>联系我</h3><hr><p>可以每篇文章底下的评论区联系我，或者是通过邮箱来联系我</p><p>邮箱: <a href="mailto:&#x31;&#x38;&#x39;&#49;&#50;&#53;&#50;&#54;&#x30;&#x35;&#x31;&#x40;&#x31;&#x36;&#x33;&#x2e;&#x63;&#x6f;&#x6d;">18912526051@163.com</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;愿指引明路的苍蓝星为你闪耀。&lt;br&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;/p&gt;
&lt;h3 id=&quot;自我介绍&quot;&gt;&lt;a href=&quot;#自我介绍&quot; class=&quot;headerlink&quot; title=&quot;自我介绍&quot;&gt;&lt;/a&gt;自我介绍&lt;/h3&gt;&lt;hr&gt;
&lt;p&gt;我的兴趣爱好比较广泛，我喜欢养一</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>PC3</title>
    <link href="https://yxbug.ren/2025/08/18/PC3/"/>
    <id>https://yxbug.ren/2025/08/18/PC3/</id>
    <published>2025-08-18T07:30:00.000Z</published>
    <updated>2025-11-20T12:29:27.112Z</updated>
    
    <content type="html"><![CDATA[<br/><p>从上一次跑完第一次网团之后，我就一发不可收拾的喜欢上了跑团（TRPG），也是理所当然的抢到了今年 8 月 16 日的 <strong>传送门跑团嘉年华（Portal Con 3，下简称 PC3）</strong> 的两场官方团的票。一场是上午的《疯人院怪诞记》，一场是晚上的《消失的园丁》。原本还想第二天跑一场狂野团，但因为行程冲突就放弃了。</p><p>PC3 的故事是我们要去各个世界冒险，来对抗末世传送门的开启。我们每完成一场冒险，就能让传送门关上一点。</p><h2 id="到达"><a href="#到达" class="headerlink" title="到达"></a>到达</h2><p>本次 PC3 是在上海的东方万国宴会中心，说实话这地儿算比较偏的了。我订的酒店那更是偏中偏，我 15 日下午四点多到达上海火车站的之后，还转乘地铁公交，路上颠簸了一个多小时，到宾馆是在晚上六点左右。到了宾馆之后点了一份老乡鸡，不得不说，老乡鸡的鸡汤确实好喝，就是鸡肉稍微有一点老了。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/dNUrPiDMTB9He18.jpg" data-src="https://s2.loli.net/2025/08/18/dNUrPiDMTB9He18.jpg" alt="酒店楼下" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="酒店楼下" href="https://s2.loli.net/2025/08/18/dNUrPiDMTB9He18.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">酒店楼下</span></div></div><p>吃完晚饭就到楼下转了一圈。这个宾馆在的地方都是老年人，楼下有四个不同的广场舞方阵，外围更是有不计其数的效果广场舞队伍，还有那种露天的 K 歌点，但就是没有什么小吃店。转了一圈我就回到酒店，躺在床上玩着王者，看着投影电影。</p><p>睡觉的时候隔壁房间的客人一直在吵架，吵到将近一点，我戴着耳塞都能听见，最后我只能戴起耳机，放着歌，迷迷糊糊中睡着了。</p><p>第二天我一早就醒了，打了个车到了 PC3 展会的地点，在附近吃了点了一个麦当劳的汉堡早餐，第一次吃这种早餐，味道还不错。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/r8Smgan9cCb5A6I.jpg" data-src="https://s2.loli.net/2025/08/18/r8Smgan9cCb5A6I.jpg" alt="早餐" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="早餐" href="https://s2.loli.net/2025/08/18/r8Smgan9cCb5A6I.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">早餐</span></div></div><p>我在吃早餐的时候，展会就已经开始了。我检完票就在一楼逛了一会。一楼其实也不算多大，但好在摊位还算比较多。我看到了熔炼厂的 <strong>《狩魂者》</strong>，看到了 <strong>《侠界之旅》</strong>，看到了吟游之歌，还找到了三局两胜的摊位。我转了两圈，玩了一个熔炼厂的《狩魂者》小游戏还有罗丝妮的 <strong>《再干一票》</strong> 小游戏。刚玩完就正好看到<a href="https://space.bilibili.com/1022343798">枫笛</a>，于是不要脸的和他照了个照片，问枫笛为什么不睁眼。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/yVd5mzpCqXkblSH.jpg" data-src="https://s2.loli.net/2025/08/18/yVd5mzpCqXkblSH.jpg" alt="和枫笛的合照" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="和枫笛的合照" href="https://s2.loli.net/2025/08/18/yVd5mzpCqXkblSH.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">和枫笛的合照</span></div></div><p>和枫笛照完照片就去开了个骰赏，花了 56 元投了一次骰子，投了个 6，拿了个 D 赏骰子，也是没谁了。之后去吟游之歌的摊位上看了看的东西，买了一盒两个磁吸小棋子。虽然有点贵，但很久之前就馋了，于是也没犹豫就拿下了。</p><p>买完东西就准备上到二楼去跑第一个团了，巧的是这时候刚好看到了熔炼跑团工厂的 <a href="https://space.bilibili.com/3557950">AW</a>，于是也和他合了个照。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/rChfoLpQdtSbRDe.jpg" data-src="https://s2.loli.net/2025/08/18/rChfoLpQdtSbRDe.jpg" alt="和AW的合照" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="和AW的合照" href="https://s2.loli.net/2025/08/18/rChfoLpQdtSbRDe.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">和AW的合照</span></div></div><p><br/><br/></p><h2 id="《疯人院怪诞记》"><a href="#《疯人院怪诞记》" class="headerlink" title="《疯人院怪诞记》"></a>《疯人院怪诞记》</h2><p>《疯人院怪诞记》是一个基于 <strong>克苏鲁的呼唤（COC）第七版</strong> 的一个模组，由<a href="https://space.bilibili.com/385474?spm_id_from=333.337.0.0">彼望黑</a>和墨三乌共同创作，讲述的是在阿卡姆的疯人院中有很多人离奇失踪，各个玩家扮演的角色因为各自的事情就来到了疯人院中开始调查。我在其中扮演的玩家是一位记者，来疯人院寻找自己前来调查却失踪的挚友兼同事。最后竟然得知这货居然和疯人院中的幕后 BOSS 谈恋爱去了，他们夫妻俩居然要召唤 <strong>犹格索托斯</strong>。</p><p>而这次带我们跑团的主持人（KP）就是墨三乌老师。墨三乌老师是一个非常温柔的老师，会给我们这些新人放水，也会愿意顺着我们的意思将团跑下去。</p><p>搞笑的是，我们在开始前都各自拿出了自己的骰子。我拿出的是上午的 D 赏骰子，我一看大家包装都一样，我就询问他们是不是也在底下玩了个骰赏，他们说是的，而且都是 D 赏。我们越聊越生气，严重怀疑底下让我们投的骰子是不是灌铅骰子（开玩笑的）。</p><p>本场团一共有 6 位玩家（PL），可以说是非常壮大的队伍，遇到战斗的时候基本都是一两轮就能解决，人实在太多了，一人一拳都能干碎，更况且这次跑团大成功的次数实在有点多。玩到最后，墨三乌老师都有点无语了。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/8BQkZwjspfT4LHb.jpg" data-src="https://s2.loli.net/2025/08/18/8BQkZwjspfT4LHb.jpg" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://s2.loli.net/2025/08/18/8BQkZwjspfT4LHb.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><p>但三个小时的限制还是太致命了，跑到最后墨三乌老师各种加速，让我们一起投骰子打完一轮，才堪堪结团。但也好在最后顺利结团。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/wxavgy26QMbZdWh.jpg" data-src="https://s2.loli.net/2025/08/18/wxavgy26QMbZdWh.jpg" alt="合影" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="合影" href="https://s2.loli.net/2025/08/18/wxavgy26QMbZdWh.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">合影</span></div></div><p>总的来说，《疯人院怪诞记》算是一个挺有意思的模组，要是没有三个小时的限制，我们应该能更好的去探索探索故事。但这毕竟是个短模组，本次用的还是小改的快速规则，有一些信息给的较为简单。作为一个新人入坑模组的话，这是一个很不错的模组。</p><p>跑完这个模组之后我就去找一位老乡，两个人面基后就开始一起逛展。我回到了吟游之歌的摊位，买了一套 288 的红龙骰子。为什么要买这套骰子呢？是因为刚刚那个团里有位玩家买了一套金属的骰子，我把玩了一会后感觉手感很好，就想着也要下来买一套（纯纯冲动消费）。我精挑细选后买了一套自己看着很喜欢的金属骰子。然后我们又转了转，玩了几个小游戏。这途中我还遇到了<a href="https://space.bilibili.com/24485102">二蛋和二妞</a>团队的<a href="https://space.bilibili.com/11438423">卡特</a>和<a href="https://space.bilibili.com/503649227">教授</a>，也是要到了合照。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/164bGlfopP8aUX9.jpg" data-src="https://s2.loli.net/2025/08/18/164bGlfopP8aUX9.jpg" alt="和卡特和教授的合影" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="和卡特和教授的合影" href="https://s2.loli.net/2025/08/18/164bGlfopP8aUX9.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">和卡特和教授的合影</span></div></div><p>在这里疯狂安利<a href="https://space.bilibili.com/3557950">AW</a>以及<a href="https://space.bilibili.com/24485102">二蛋和二妞</a>，<em>二蛋和二妞</em>做的跑团视频真是深得我心，绝对是跑团界的宝藏 UP，而熔炼跑团工厂是国内最早一批做跑团的俱乐部。</p><p>那位老兄买了几套小众的规则后就回去了，我就又转了一圈，看有没有自己喜欢的东西买一买。但最后也没有买什么东西，但和彼望黑以及<a href="https://space.bilibili.com/503302?spm_id_from=333.337.0.0">高原守</a>合了张照。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/Ty8JD3onx9qZzrB.jpg" data-src="https://s2.loli.net/2025/08/18/Ty8JD3onx9qZzrB.jpg" alt="和彼望黑的合影" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="和彼望黑的合影" href="https://s2.loli.net/2025/08/18/Ty8JD3onx9qZzrB.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">和彼望黑的合影</span></div></div><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/Wd3BZJiODIG8bNH.jpg" data-src="https://s2.loli.net/2025/08/18/Wd3BZJiODIG8bNH.jpg" alt="和高原守的合影" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="和高原守的合影" href="https://s2.loli.net/2025/08/18/Wd3BZJiODIG8bNH.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">和高原守的合影</span></div></div><p>之后我就吃了点晚餐，就准备跑下一场团了。</p><p><br/><br/></p><h2 id="《消失的园丁》"><a href="#《消失的园丁》" class="headerlink" title="《消失的园丁》"></a>《消失的园丁》</h2><p><strong>龙与地下城（DnD）</strong> 绝对是现代 RPG 电子游戏、跑团、剧本杀的祖宗，其中所创造的<em>等级</em>、<em>职业</em>、<em>加点</em>等设定都对后世的 RPG 类游戏有着深远的影响，可以说，没有 DnD，那么我们玩到的电子游戏绝对不是现在这样的。所以我们都戏称 DnD 是万物始祖。但威世智的脑残管理层就是不愿意让 DnD 进入中国，宁愿放弃一整个中国市场。所以在国内的跑团圈中，一直都是 COC 占据了主要的地位。但在2023年，博德之门 3 的成功，让越来越多的中国人开始看见和接触跑团，也让 DnD 这个 IP 在跑团圈内越来越火。</p><p>而《灵魂迷雾》这个规则是一个基于 DnD5E 并且被 DnD 官方认可的第三方规则。在这个规则下，我们要在一个公转与自转时间完全相同的星球上展开冒险。在颗可星球中，分为三个区域，一个区域永昼，一个区域永夜，一个区域一半昼一半夜。因为各个区域的差异性，有许多奇怪的种族居住在这颗星球上，有福瑞、有能透支自己生命而预知未来的种族、有吸血鬼等等。</p><p>本厂团是由<a href="https://space.bilibili.com/40316073?spm_id_from=333.337.0.0">南京破晓跑团社</a>的主持人（DM）带跑。这边也为这个优秀的跑团社打个小广告，这位来自南京破晓跑团社的主持人很会表演，将每一个 NPC 的特点和性格都很好的表演出来了，让我们这些玩家感觉身临其境，仿佛真的在进行这样的冒险。</p><p>《消失的园丁》这篇模组是讲述几位冒险家去寻找一个被赐予永恒不死但失踪了的园丁的故事，由于时间的问题，我们本次只能体验该模组的一部分内容，所以也是颇有遗憾。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/960;"><img class="lazy" src="https://s2.loli.net/2025/08/18/wM3c9pQKqLbd6gF.jpg" data-src="https://s2.loli.net/2025/08/18/wM3c9pQKqLbd6gF.jpg" alt="《消失的园丁》" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="《消失的园丁》" href="https://s2.loli.net/2025/08/18/wM3c9pQKqLbd6gF.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">《消失的园丁》</span></div></div><p><br/><br/></p><h2 id="传送门"><a href="#传送门" class="headerlink" title="传送门"></a>传送门</h2><p>跑完最后一场，我们就要去见证对抗传送门开启的结局了。我们聚集到一楼的大屏幕前，看着每一位冒险家的骰点。当屏幕上的骰子投到 20（大成功）时，现场所有人都会高呼。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/600;"><img class="lazy" src="https://s2.loli.net/2025/08/18/YqOZ2sGdy5fQV3h.jpg" data-src="https://s2.loli.net/2025/08/18/YqOZ2sGdy5fQV3h.jpg" alt="大成功" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="大成功" href="https://s2.loli.net/2025/08/18/YqOZ2sGdy5fQV3h.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">大成功</span></div></div><p>而当有人投到 1（大失败）时，我们也会一起叹气。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/600;"><img class="lazy" src="https://s2.loli.net/2025/08/18/wkof756udqeGL1O.jpg" data-src="https://s2.loli.net/2025/08/18/wkof756udqeGL1O.jpg" alt="大失败" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" download="大失败" href="https://s2.loli.net/2025/08/18/wkof756udqeGL1O.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div><div class="image-meta"><span class="image-caption center">大失败</span></div></div><p>相信我，当你置身于这个现场时，你也会被感染从而和我们一起高呼。</p><p>最后，传送门终于被我们关闭，我们拯救了世界。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;

&lt;p&gt;从上一次跑完第一次网团之后，我就一发不可收拾的喜欢上了跑团（TRPG），也是理所当然的抢到了今年 8 月 16 日的 &lt;strong&gt;传送门跑团嘉年华（Portal Con 3，下简称 PC3）&lt;/strong&gt; 的两场官方团的票。一场是上午的《疯人院怪诞记》</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="跑团" scheme="https://yxbug.ren/tags/%E8%B7%91%E5%9B%A2/"/>
    
    <category term="PC3 展会" scheme="https://yxbug.ren/tags/PC3-%E5%B1%95%E4%BC%9A/"/>
    
  </entry>
  
  <entry>
    <title>涂棋子</title>
    <link href="https://yxbug.ren/2025/06/24/%E6%B6%82%E6%A3%8B%E5%AD%90/"/>
    <id>https://yxbug.ren/2025/06/24/%E6%B6%82%E6%A3%8B%E5%AD%90/</id>
    <published>2025-06-24T04:32:00.000Z</published>
    <updated>2025-11-20T12:29:27.124Z</updated>
    
    <content type="html"><![CDATA[<br/><p>其实在2023年末的时候就在想着要涂棋子，当时在准备考研，就利用休息的时间买了点棋子、工具以及颜料，等到考研结束后在家一边看剧一边拼。</p><p>去年涂了一部分的棋子，但当时都是跟着 B 站的战锤官方涂，里面有很多的细节并没有讲，我并不懂稀释该怎么稀释、描边渐变该怎么做、貂毛笔对涂装的重要性，所以就涂的迷迷糊糊，效果也就不是那么好。</p><p><img src="https://s2.loli.net/2025/06/23/UcpOIB8TfjqLKoh.jpg" alt="去年涂的枪虫"></p><br/><p>后面呢因为要考公所以就没时间再涂（别看这么一只小虫，一只也能涂个把小时，五只批量涂也要两三个小时），直到今年又有空闲时间就打算再把棋子捡起来继续涂。刚巧——在上一篇《第一次跑团》也提到过——我找到了自己这的桌游俱乐部，顺便就加了战锤群，然后在群里就问万能的群友该怎么学，怎么涂。群友推荐了一个 B 站的 UP <a href="https://space.bilibili.com/3136854?spm_id_from=333.1387.follow.user_card.click">XBALL</a>，于是我就花 25 块入了一个月基础充电，跟着他的基础教学视频开始学买工具、涂装知识与技巧。这是我昨天才涂的，感觉和之前的完全是两个生物哈哈哈哈哈哈。</p><p><img src="https://s2.loli.net/2025/06/23/Y1olOmKtBnZcSzk.jpg" alt="今年涂的枪虫"></p><br/><p>后续呢柜子里还有很多棋子没涂，当时买了新手入门包、利维坦的虫族大包和死亡跳跃者等，最近又买了提丰 KT 包，还有一个诺恩使者，估计又能再涂一两年。</p><p><img src="https://s2.loli.net/2025/06/23/5HT7KteXgpRZqMv.jpg" alt="小阅兵"></p><br/><p>对了，最近还买了养蚂蚁的工具，打算养养蚂蚁。很早之前就喜欢蚂蚁、蜘蛛这类的爬宠，更是对蚂蚁这样的社会性很感兴趣，等我下次更新吧。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;

&lt;p&gt;其实在2023年末的时候就在想着要涂棋子，当时在准备考研，就利用休息的时间买了点棋子、工具以及颜料，等到考研结束后在家一边看剧一边拼。&lt;/p&gt;
&lt;p&gt;去年涂了一部分的棋子，但当时都是跟着 B 站的战锤官方涂，里面有很多的细节并没有讲，我并不懂稀释该怎么稀释、描</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="战锤 40K" scheme="https://yxbug.ren/tags/%E6%88%98%E9%94%A4-40K/"/>
    
    <category term="涂装" scheme="https://yxbug.ren/tags/%E6%B6%82%E8%A3%85/"/>
    
  </entry>
  
  <entry>
    <title>第一次跑团</title>
    <link href="https://yxbug.ren/2025/05/25/%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B7%91%E5%9B%A2/"/>
    <id>https://yxbug.ren/2025/05/25/%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B7%91%E5%9B%A2/</id>
    <published>2025-05-25T09:32:00.000Z</published>
    <updated>2025-11-20T12:29:27.125Z</updated>
    
    <content type="html"><![CDATA[<br/><p>很早之前就想跑团（TRPG），当时馋 DND 和 COC 很久了，但奈何所住的城市是个三线城市，没有桌游店、跑团店，所以基本上我都是自己一个人玩桌游，甚至有些桌游买回来就没打开来玩过。</p><p>恰逢<a href="https://www.modian.com/">摩点</a>上有个新的规则 <a href="https://zhongchou.modian.com/item/138910.html">VHS</a> 在众筹，于是也狠心买了一个大 Allin。在众筹期间我就在纠结是否要购入，但内网上没有任何改规则的视频。众筹结束后，项目发起人发了电子版的规则预览，于是就组了几个人一起来跑跑这个团。</p><p><img src="https://s2.loli.net/2025/05/26/AnerF8GbOU2p7jH.png" alt="封面"></p><br/><p>跑团的全程还是非常开心的，在跑完之后，我也是第一时间开始剪辑跑团全程并上传至 <a href="https://www.bilibili.com/video/BV1dwjJz6EnP?spm_id_from=333.788.videopod.sections&vd_source=214c472e8b4f2e606fc51f86bf928d4d">B站</a>，有兴趣的可以点击链接观看。</p><p>做这个视频的原因就是，我们这个团还有我的视频应该就是这个规则第一次在国内完整地亮相在大众视野中，能够帮助到一些新人来了解规则，也能让更多的人关注到 VHS。</p><p>跑团是一个非常有意思的游戏，DND 作为 TRPG 的老祖宗，也可以说是现代 RPG 游戏的老祖宗。同时，跑团也是剧本杀的前身。在跑团中，每个玩家都要扮演好自己的角色，在 DM（地下城主或主持人）的旁白和管理下一起冒险，书写自己的传奇。很多跑团玩家会把自己的冒险编写成小说进行发表。</p><p>说实话，作为一个社恐人，当时也是壮着胆子跑团，心里一直在打退堂鼓，好在导演和其他玩家都很和善。可惜的是，马上我要出去有事，最早也要 6 月中旬才能再次跑团，所以导演的下个团我可能跑不了了。不过，日子还长，团还很多。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;

&lt;p&gt;很早之前就想跑团（TRPG），当时馋 DND 和 COC 很久了，但奈何所住的城市是个三线城市，没有桌游店、跑团店，所以基本上我都是自己一个人玩桌游，甚至有些桌游买回来就没打开来玩过。&lt;/p&gt;
&lt;p&gt;恰逢&lt;a href=&quot;https://www.modian.</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="跑团" scheme="https://yxbug.ren/tags/%E8%B7%91%E5%9B%A2/"/>
    
    <category term="VHS" scheme="https://yxbug.ren/tags/VHS/"/>
    
  </entry>
  
  <entry>
    <title>Node.js</title>
    <link href="https://yxbug.ren/2025/03/23/nodejs/"/>
    <id>https://yxbug.ren/2025/03/23/nodejs/</id>
    <published>2025-03-23T05:28:39.000Z</published>
    <updated>2025-11-20T12:29:27.116Z</updated>
    
    <content type="html"><![CDATA[<br/><p>配套课程：<a href="https://www.bilibili.com/video/BV1a34y167AZ">黑马程序员Node.js全套入门教程，nodejs最新教程含es6模块化+npm+express+webpack+promise等_Nodejs实战案例详解_哔哩哔哩_bilibili</a></p><p>注意，Node.js 的前置知识很多，比如 JavaScript，ES6，Ajax.js 等内容。建议去自主搜索前端学习路线，网上都有。该文档只针对上面给到的 B 站视频教程，不会额外补充前置知识。前端的知识是非常杂乱繁多的，因为每年都在更新迭代，任何一个作者写出一个 好的.js 模块就可以生成一个新的知识被广大用户使用在日常开发中。学无止境，请读者谨记。</p><p>该 md 文档里面的所有图片都已经上传到了图床中，请读者放心阅读。图片会在文件打开来之后一段时间内加载成功。如果发现图片无法查看或者是材料编写有错误等情况可以直接加我的 <strong>QQ：2247512851</strong>。</p><p>该视频是 2020 年的视频，对于现在来说里面所使用的东西可能会存在落后的情况。但无论如何，整体并不会发生大的变化。</p><p>node.js 是一个可以帮助 js 编写后端的语言 (称不上语言)，其功能还是比较强大的，你可以使用它来做很多的东西。比如我 Web 的大作业后端就是使用 node.js 来编写的，总结下来虽然写得有些困难，但还是挺不错的。</p><p>任何一门语言看过视频、读过文档、写过小段代码都不足以证明你学会了它，你必须使用它去完整地写一个项目，这样才能证明你初步学会了它。我在写 Web 大作业之前将配套视频看完、文档也编写的差不多了，但到了项目里还是觉得无从下手。我不得不去网上查找资料然后再编写大作业。所以，请读者在看完视频和文档之后一定一定要去使用 node.js 以及其它的语言写一个完整的项目来检验自己。</p><p>最后，望各位变得更强。</p><p>由<strong>月下八哥</strong>编写: 平平无奇的苍蓝星，天命人，偶尔写写代码和小说。</p><br/><p>Ps. 一开始单词拼错了，将 test 拼成了 text，写到一半发现拼错就懒得改了。</p><p>本文档归东南大学成贤学院计算机协会所有，严禁转载，但请标明出处。所有解释权归东南大学成贤学院计算机协会。</p><br/><br/><h2 id="一、初识-Node-js"><a href="#一、初识-Node-js" class="headerlink" title="一、初识 Node.js"></a>一、初识 Node.js</h2><h3 id="1、什么是-Node-js"><a href="#1、什么是-Node-js" class="headerlink" title="1、什么是 Node.js"></a>1、什么是 Node.js</h3><p>Node.js 是一个基于 Chrome V8 引擎运行的 JavaScript 运行环境。</p><p>Node.js 官网链接：<a href="https://nodejs.org/en/">Node.js (nodejs.org)</a></p><br/><h3 id="2、Node-js-中的-JavaScript-运行环境"><a href="#2、Node-js-中的-JavaScript-运行环境" class="headerlink" title="2、Node.js 中的 JavaScript 运行环境"></a>2、Node.js 中的 JavaScript 运行环境</h3><p><img src="https://s2.loli.net/2022/04/20/2X6I7wYgMTBhSmu.png"></p><p><strong>注意：</strong></p><ol><li>浏览器是 JavaScript 的前端运行环境</li><li>Node.js 是 JavaScript 的后端运行环境</li><li>Node.js 中无法调用 DOM 和 BOM 等浏览器内置 API</li></ol><br/><h3 id="3、Node-js-可以做什么"><a href="#3、Node-js-可以做什么" class="headerlink" title="3、Node.js 可以做什么"></a>3、Node.js 可以做什么</h3><p>Node.js 作为一个 JavaScript 的运行环境，仅仅提供了基础的功能和 API。然而，基于 Node,js 提供的这些基础功能，很多强大的工具和框架如雨后春笋，层出不穷。所以学会了 Node.js，可以让前端程序员胜任更多的工作和岗位：</p><ol><li>基于 Express 框架 <a href="http://expressjs.com/">Express - Node.js web application framework</a> ，可以快速构建 Web 应用</li><li>基于 Electron 框架 <a href="https://www.electronjs.org/">Electron</a>，可以构建跨平台桌面应用</li><li>基于 Restify 框架 <a href="http://restify.com/">Restify</a>，可以快速构建 API 借口项目</li></ol><br/><h3 id="4、Node-js-怎么学"><a href="#4、Node-js-怎么学" class="headerlink" title="4、Node.js 怎么学"></a>4、Node.js 怎么学</h3><p>JavaScript 基础语法 + Node.js 内置 API 模块（fs、path、http等）+   第三方 API 模块（express、mysql等）</p><br/><br/><h2 id="二、fs-文件系统模块"><a href="#二、fs-文件系统模块" class="headerlink" title="二、fs 文件系统模块"></a>二、fs 文件系统模块</h2><h3 id="1、什么是-fs-文件系统模块"><a href="#1、什么是-fs-文件系统模块" class="headerlink" title="1、什么是 fs 文件系统模块"></a>1、什么是 fs 文件系统模块</h3><p>fs 模块是 Node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性，用来满足用户对文件的操作需求。</p><p>例如：</p><ul><li><code>fs.readFile()</code> 方法，用来<strong>读取</strong>指定文件中的内容</li><li><code>fs.writeFile()</code> 方法，用来向制定文件中<strong>写入</strong>内容</li></ul><p>如果要在 JavaScript 中使用 fs 模块来操作文件，则需要使用如下的方式先导入它：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br></pre></td></tr></table></figure><p>其实 <code>require()</code> 方法是用来加载模块的一个方法，在加载模块的同时会先执行一遍模块里的代码，关于模块会在之后讲解。</p><br/><h3 id="2、读取指定文件中的内容"><a href="#2、读取指定文件中的内容" class="headerlink" title="2、读取指定文件中的内容"></a>2、读取指定文件中的内容</h3><h4 id="2-1-fs-readFile-的语法格式"><a href="#2-1-fs-readFile-的语法格式" class="headerlink" title="2.1 fs.readFile() 的语法格式"></a>2.1 fs.readFile() 的语法格式</h4><p>使用 <code>fs.readFile()</code> 方法，可以读取制定文件中的内容，其语法格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fs.<span class="title function_">readFile</span>(path[,options],callback)</span><br></pre></td></tr></table></figure><ul><li>参数1（path[路径]）：<strong>必选</strong>参数，表示文件的路径</li><li>参数2（options）: <strong>可选</strong>参数，表示以什么编码格式来读取文件</li><li>参数3（callback[回调函数]）：<strong>必选</strong>参数，文件读取完成后，通过回调函数拿到读取的结果</li></ul><h4 id="2-2-fs-readFile-示例代码"><a href="#2-2-fs-readFile-示例代码" class="headerlink" title="2.2 fs.readFile() 示例代码"></a>2.2 fs.readFile() 示例代码</h4><p>成功读取：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 fs 模块</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用 fs.readFile() 方法来读取文件</span></span><br><span class="line"><span class="comment">//如果读取成功，则 err 的值为 null</span></span><br><span class="line"><span class="comment">//如果读取的失败， 则 err 的值为错误对象，dataStr 的值为 undefined</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//成功</span></span><br><span class="line"><span class="comment">//1.txt里面写了111</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(<span class="string">&#x27;./files/1.txt&#x27;</span>,<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(dataStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/oFUHc31aNgnQPDv.png"></p><hr><p>失败读取：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 fs 模块</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用 fs.readFile() 方法来读取文件</span></span><br><span class="line"><span class="comment">//如果读取成功，则 err 的值为 null</span></span><br><span class="line"><span class="comment">//如果读取的失败， 则 err 的值为错误对象，dataStr 的值为undefined</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//失败</span></span><br><span class="line"><span class="comment">//没有11.txt文件</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(<span class="string">&#x27;./files/11.txt&#x27;</span>,<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(dataStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/4kFXtOHLN8zcURS.png"></p><h4 id="2-3-判断文件是否读取成功"><a href="#2-3-判断文件是否读取成功" class="headerlink" title="2.3 判断文件是否读取成功"></a>2.3 判断文件是否读取成功</h4><p>可以通过 err 对象是否为 null，从而知晓文件读取的结果：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line">fs.<span class="title function_">readFile</span>(<span class="string">&#x27;./files/1.txt&#x27;</span>,<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line"><span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取成功！内容是：&#x27;</span>+dataStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/6BDMPnZgO3kfjIq.png"></p><br/><h3 id="3、向指定的文件中写入内容"><a href="#3、向指定的文件中写入内容" class="headerlink" title="3、向指定的文件中写入内容"></a>3、向指定的文件中写入内容</h3><h4 id="3-1-fs-writeFile-的语法格式"><a href="#3-1-fs-writeFile-的语法格式" class="headerlink" title="3.1 fs.writeFile() 的语法格式"></a>3.1 fs.writeFile() 的语法格式</h4><p>使用 <code>fs.writeFile()</code> 方法，可以向指定文件中写入内容，其语法格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fs.<span class="title function_">writeFile</span>(file,data[,options],callback)</span><br></pre></td></tr></table></figure><ul><li>参数1（path[路径]）：<strong>必选</strong>参数，表示文件的存放路径</li><li>参数2（data[内容数据]）：<strong>必选</strong>参数，表示要写入的内容</li><li>参数3（options）：<strong>可选</strong>参数，表示用什么格式将内容写入文件</li><li>参数4（callback[回调函数]）：<strong>必选</strong>参数，文件写入完成后的回调函数</li></ul><h4 id="3-2-fs-writeFile-示例代码"><a href="#3-2-fs-writeFile-示例代码" class="headerlink" title="3.2 fs.writeFile() 示例代码"></a>3.2 fs.writeFile() 示例代码</h4><p>成功写入：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 fs 模块</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用 fs.writeFile() 方法来将内容写入文件</span></span><br><span class="line"><span class="comment">//如果写入成功，则 err 的值为 null</span></span><br><span class="line"><span class="comment">//如果写入失败，则 err 的值等于一个错误对象</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//成功</span></span><br><span class="line">fs.<span class="title function_">writeFile</span>(<span class="string">&#x27;./files/2.txt&#x27;</span>,<span class="string">&#x27;abcd&#x27;</span>,<span class="keyword">function</span>(<span class="params">err</span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/l8OtxIAP5dpUKDe.png"></p><p><img src="https://s2.loli.net/2022/04/21/VQPSu4Ob7WCq8Ko.png"></p><p><strong>注意</strong>：如果要写入的文件不存在，将会自动创建一个文件</p><hr><p>失败写入：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 fs 模块</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用 fs.writeFile() 方法来将内容写入文件</span></span><br><span class="line"><span class="comment">//如果写入成功，则 err 的值为 null</span></span><br><span class="line"><span class="comment">//如果写入失败，则 err 的值等于一个错误对象</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//失败</span></span><br><span class="line"><span class="comment">//我的电脑没有G盘</span></span><br><span class="line">fs.<span class="title function_">writeFile</span>(<span class="string">&#x27;G:/files/2.txt&#x27;</span>,<span class="string">&#x27;abcd&#x27;</span>,<span class="keyword">function</span>(<span class="params">err</span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/zaLwZUshrtORQ4k.png"></p><br/><h3 id="4、练习——考试成绩整理"><a href="#4、练习——考试成绩整理" class="headerlink" title="4、练习——考试成绩整理"></a>4、练习——考试成绩整理</h3><p>使用 fs 模块将 <strong>成绩.txt</strong> 里的内容整理到 <strong>成绩-ok.txt</strong> 文件中</p><p>代码：</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line">fs.<span class="title function_">readFile</span>(<span class="string">&#x27;./files/成绩.txt&#x27;</span>,<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取成功！内容是：&#x27;</span>+dataStr)</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------------------&#x27;</span>)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;第一步将字符串在空格处进行切割&#x27;</span>)</span><br><span class="line">    <span class="comment">//solit可以将一个字符串在指定元素的地方进行分割成字符串数组</span></span><br><span class="line">    <span class="keyword">const</span> arrOld = dataStr.<span class="title function_">split</span>(<span class="string">&#x27; &#x27;</span>)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(arrOld)</span><br><span class="line">    </span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------------------&#x27;</span>)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;第二部将得到的arrOld加入到arrNew中&#x27;</span>)</span><br><span class="line">    <span class="keyword">const</span> arrNew = []</span><br><span class="line">    arrOld.<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">        arrNew.<span class="title function_">push</span>(item.<span class="title function_">replace</span>(<span class="string">&#x27;=&#x27;</span>,<span class="string">&#x27;:&#x27;</span>))</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(arrNew)</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------------------&#x27;</span>)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;第三步将arrNew加入到新的字符串newStr中&#x27;</span>)</span><br><span class="line">    <span class="keyword">const</span> newStr = arrNew.<span class="title function_">join</span>(<span class="string">&#x27;\r\n&#x27;</span>)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(newStr)</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------------------&#x27;</span>)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;第四步将newStr字符串写入成绩-ok.txt中&#x27;</span>)</span><br><span class="line">    fs.<span class="title function_">writeFile</span>(<span class="string">&#x27;./files/成绩-ok.txt&#x27;</span>,newStr,<span class="keyword">function</span>(<span class="params">err</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span>(err)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;成绩整理写入成功！&#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/CIglmo5feAXH4jK.png"></p><br/><h3 id="5、fs-模块，路径动态拼接的问题"><a href="#5、fs-模块，路径动态拼接的问题" class="headerlink" title="5、fs 模块，路径动态拼接的问题"></a>5、fs 模块，路径动态拼接的问题</h3><p>在使用 fs 模块操作文件时，如果提供的操作路径是以 <code>./</code> 或者 <code>../</code> 开头的相对路径时，很容易出现路径动态拼接错误的问题。</p><p>原因：代码在运行的时候，<strong>会以执行 node 命令时所处的目录</strong>，动态拼接出被操作文件的完整路径。</p><p><img src="https://s2.loli.net/2022/04/21/cWoETlp7hBXHtjO.png"></p><p>观察这两个方框框出来的地方，可以发现语句中的路径是刚好可以和终端中的位置对接完成的，如果终端中的操作路径和代码语句中的路径没办法正确对接，那么就会显示如下错误：</p><p><img src="https://s2.loli.net/2022/04/21/RCY92xiWvHXGqfb.png"></p><p><strong>解决办法1</strong>：使用绝对路径</p><p><code>__dirname</code> 可以显示当前文件所处的目录</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;文件的路径为：&quot;</span>+__dirname)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/gKI48bQ7ieEuoPk.png"></p><p>所以就可以引申出来一个<strong>解决办法2</strong>：使用 <code>__dirname</code> 来获得当前文件所处的目录，然后再使用相对路径</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line">fs.<span class="title function_">readFile</span>(__dirname+<span class="string">&#x27;/files/1.txt&#x27;</span>,<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line"><span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取成功！内容是：&#x27;</span>+dataStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/ECsr2mYjxu1IdUD.png"></p><p><strong>注意</strong>：在此处相对路径的前面不要再加 <code>.</code>了。</p><br/><br/><h2 id="三、path-路径模块"><a href="#三、path-路径模块" class="headerlink" title="三、path 路径模块"></a>三、path 路径模块</h2><h3 id="1、什么是-path-路径模块"><a href="#1、什么是-path-路径模块" class="headerlink" title="1、什么是 path 路径模块"></a>1、什么是 path 路径模块</h3><p>path 模块是 Node.js 官方提供的、用来处理路径的模块，它提供了一系列的方法和属性，用来满足用户对路径的处理需求。</p><p>例如:</p><ul><li><code>path.join()</code> 方法，用来<strong>将多个路径片段拼接成一个完整的路径字符串</strong></li><li><code>path.basename()</code> 方法，用来从路径字符串中，将文件名<strong>解析</strong>出来</li></ul><p>如果要在 JavaScript 中使用 path 模块来处理路径，则需要使用如下的方式先导入它：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br></pre></td></tr></table></figure><br/><h3 id="2、路径拼接"><a href="#2、路径拼接" class="headerlink" title="2、路径拼接"></a>2、路径拼接</h3><h4 id="2-1-path-join-的语法格式"><a href="#2-1-path-join-的语法格式" class="headerlink" title="2.1 path.join() 的语法格式"></a>2.1 path.join() 的语法格式</h4><p>使用 <code>path.join()</code> 方法，可以把多个路径片段拼接成一个完整的路径字符串，语法格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">path.<span class="title function_">join</span>([...paths])</span><br></pre></td></tr></table></figure><ul><li>参数1（..paths &lt; string &gt; ）路径片段的序列</li><li>参数2（返回值 &lt; string &gt; ）</li></ul><h4 id="2-2-path-join-示例代码"><a href="#2-2-path-join-示例代码" class="headerlink" title="2.2 path.join() 示例代码"></a>2.2 path.join() 示例代码</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//注意 ../ 会抵消前面的路径</span></span><br><span class="line"><span class="keyword">const</span> pathStr = path.<span class="title function_">join</span>(<span class="string">&#x27;/a&#x27;</span>,<span class="string">&#x27;/b/c&#x27;</span>,<span class="string">&#x27;../&#x27;</span>,<span class="string">&#x27;./d&#x27;</span>,<span class="string">&#x27;e&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(pathStr)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/uBsKmewQgxLv5z4.png"></p><p><code>\c</code> 被 <code>../</code> 给抵消掉了</p><h4 id="2-3-更好地解决拼接问题"><a href="#2-3-更好地解决拼接问题" class="headerlink" title="2.3 更好地解决拼接问题"></a>2.3 更好地解决拼接问题</h4><p>所以上面的路径问题还可以这么写：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"></span><br><span class="line">fs.<span class="title function_">readFile</span>(path.<span class="title function_">join</span>(__dirname,<span class="string">&#x27;/files/1.txt&#x27;</span>),<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line"><span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;文件读取成功！内容是：&#x27;</span>+dataStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/UtmAjL3uYJzrksM.png"></p><p>此时与直接拼接不同的是， <strong>‘.’</strong> 是可以写上去的。</p><br/><h3 id="3、获取路径中的文件名"><a href="#3、获取路径中的文件名" class="headerlink" title="3、获取路径中的文件名"></a>3、获取路径中的文件名</h3><h4 id="3-1-path-basename-的语法格式"><a href="#3-1-path-basename-的语法格式" class="headerlink" title="3.1 path.basename() 的语法格式"></a>3.1 path.basename() 的语法格式</h4><p>使用 <code>path.basename()</code> 方法，可以获取路径中的最后一部分，经常通过这个方法获取路径中的文件名，语法格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">path.<span class="title function_">basename</span>(path[,ext])</span><br></pre></td></tr></table></figure><ul><li>参数1（path &lt; string &gt; ）<strong>必选</strong>参数，表示一个路径的字符串</li><li>参数2（ext &lt; string &gt; ）<strong>可选</strong>参数，表示文件的扩展名</li><li>参数3（返回 &lt; string &gt; ）表示路径中的最后一个部分</li></ul><h4 id="3-2-path-basename-示例代码"><a href="#3-2-path-basename-示例代码" class="headerlink" title="3.2 path.basename() 示例代码"></a>3.2 path.basename() 示例代码</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//文件存放路径</span></span><br><span class="line"><span class="keyword">const</span> fpath = <span class="string">&#x27;/a/b/c/index.html&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//输出index.html</span></span><br><span class="line"><span class="keyword">let</span> fullName = path.<span class="title function_">basename</span>(fpath)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(fullName)</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;---------&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//只输出index,而不输出后缀名</span></span><br><span class="line"><span class="keyword">let</span> nameWithoutExt = path.<span class="title function_">basename</span>(fpath,<span class="string">&#x27;.html&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(nameWithoutExt)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/DlcoYa7uFZrtLsB.png"></p><br/><h3 id="4、获取路径中的扩展名"><a href="#4、获取路径中的扩展名" class="headerlink" title="4、获取路径中的扩展名"></a>4、获取路径中的扩展名</h3><h4 id="4-1-path-extname-的语法格式"><a href="#4-1-path-extname-的语法格式" class="headerlink" title="4.1 path.extname() 的语法格式"></a>4.1 path.extname() 的语法格式</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">path.<span class="title function_">extname</span>(path)</span><br></pre></td></tr></table></figure><ul><li>参数1（path &lt; string &gt; ）<strong>必选</strong>参数，表示一个路径的字符串</li><li>参数2（返回 &lt; string &gt; ）返回得到的扩展名字符串</li></ul><h4 id="4-3-path-extname-示例代码"><a href="#4-3-path-extname-示例代码" class="headerlink" title="4.3 path.extname() 示例代码"></a>4.3 path.extname() 示例代码</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//文件存放路径</span></span><br><span class="line"><span class="keyword">const</span> fpath = <span class="string">&#x27;/a/b/c/index.html&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fext = path.<span class="title function_">extname</span>(fpath)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(fext)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/icqGOQUWKvJH4DL.png"></p><br/><h3 id="5、练习——时钟案例"><a href="#5、练习——时钟案例" class="headerlink" title="5、练习——时钟案例"></a>5、练习——时钟案例</h3><h4 id="要求"><a href="#要求" class="headerlink" title="要求"></a>要求</h4><p>将目录下的 index.html 页面，拆分成三个文件，分别是：</p><ul><li>index.css</li><li>index.js</li><li>index.html</li></ul><p>并且将拆分出来的3个文件，存放到 clock 目录中。</p><p>所需的 index.html 代码：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></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">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">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;ie=edge&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">title</span>&gt;</span>index首页<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css">    <span class="selector-tag">html</span>,</span></span><br><span class="line"><span class="language-css">    <span class="selector-tag">body</span> &#123;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">margin</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">padding</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">height</span>: <span class="number">100%</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">background-image</span>: <span class="built_in">linear-gradient</span>(to bottom right, red, gold);</span></span><br><span class="line"><span class="language-css">    &#125;</span></span><br><span class="line"><span class="language-css"></span></span><br><span class="line"><span class="language-css">    <span class="selector-class">.box</span> &#123;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">width</span>: <span class="number">400px</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">height</span>: <span class="number">250px</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">background-color</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">0.6</span>);</span></span><br><span class="line"><span class="language-css">      <span class="attribute">border-radius</span>: <span class="number">6px</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">position</span>: absolute;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">left</span>: <span class="number">50%</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">top</span>: <span class="number">40%</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">transform</span>: <span class="built_in">translate</span>(-<span class="number">50%</span>, -<span class="number">50%</span>);</span></span><br><span class="line"><span class="language-css">      <span class="attribute">box-shadow</span>: <span class="number">1px</span> <span class="number">1px</span> <span class="number">10px</span> <span class="number">#fff</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">text-shadow</span>: <span class="number">0px</span> <span class="number">1px</span> <span class="number">30px</span> white;</span></span><br><span class="line"><span class="language-css"></span></span><br><span class="line"><span class="language-css">      <span class="attribute">display</span>: flex;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">justify-content</span>: space-around;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">align-items</span>: center;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">font-size</span>: <span class="number">70px</span>;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">user-select</span>: none;</span></span><br><span class="line"><span class="language-css">      <span class="attribute">padding</span>: <span class="number">0</span> <span class="number">20px</span>;</span></span><br><span class="line"><span class="language-css"></span></span><br><span class="line"><span class="language-css">      <span class="comment">/* 盒子投影 */</span></span></span><br><span class="line"><span class="language-css">      -webkit-box-reflect: below <span class="number">0px</span> <span class="built_in">-webkit-gradient</span>(linear, left top, left bottom, <span class="built_in">from</span>(transparent), <span class="built_in">color-stop</span>(<span class="number">0%</span>, transparent), <span class="built_in">to</span>(<span class="built_in">rgba</span>(<span class="number">250</span>, <span class="number">250</span>, <span class="number">250</span>, .<span class="number">2</span>)));</span></span><br><span class="line"><span class="language-css">    &#125;</span></span><br><span class="line"><span class="language-css">  </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;box&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;HH&quot;</span>&gt;</span>00<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span>:<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;mm&quot;</span>&gt;</span>00<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span>:<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;ss&quot;</span>&gt;</span>00<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><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="variable language_">window</span>.<span class="property">onload</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="comment">// 定时器，每隔 1 秒执行 1 次</span></span></span><br><span class="line"><span class="language-javascript">      <span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> dt = <span class="keyword">new</span> <span class="title class_">Date</span>()</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> <span class="variable constant_">HH</span> = dt.<span class="title function_">getHours</span>()</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> mm = dt.<span class="title function_">getMinutes</span>()</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">var</span> ss = dt.<span class="title function_">getSeconds</span>()</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="language-javascript">        <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;#HH&#x27;</span>).<span class="property">innerHTML</span> = <span class="title function_">padZero</span>(<span class="variable constant_">HH</span>)</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;#mm&#x27;</span>).<span class="property">innerHTML</span> = <span class="title function_">padZero</span>(mm)</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;#ss&#x27;</span>).<span class="property">innerHTML</span> = <span class="title function_">padZero</span>(ss)</span></span><br><span class="line"><span class="language-javascript">      &#125;, <span class="number">1000</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="language-javascript">    <span class="keyword">function</span> <span class="title function_">padZero</span>(<span class="params">n</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">return</span> n &gt; <span class="number">9</span> ? n : <span class="string">&#x27;0&#x27;</span> + n</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><p>案例代码：</p><p>以下案例使用到了部分<strong>正则表达式</strong>的知识，可以先去以下网址学习一下正则表达式</p><p><a href="https://www.bilibili.com/video/BV1da4y1p7iZ">10分钟快速掌握正则表达式_哔哩哔哩_bilibili</a></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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入两个模块</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//匹配 style 标签的正则表达式</span></span><br><span class="line"><span class="comment">//其中 \s 表示空白字符，\S 表示非空白字符，* 表示匹配任意次</span></span><br><span class="line"><span class="comment">//将包括 &lt;style&gt; 和 &lt;/style&gt;内的所有内容放到 regStyle中</span></span><br><span class="line"><span class="keyword">const</span> regStyle = <span class="regexp">/&lt;style&gt;[\s\S]*&lt;\/style&gt;/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//匹配 script 标签的正则</span></span><br><span class="line"><span class="comment">//将包括 &lt;script&gt; 和 &lt;/script&gt;内的所有内容放到 regScript中</span></span><br><span class="line"><span class="keyword">const</span> regScript = <span class="regexp">/&lt;script&gt;[\s\S]*&lt;\/script&gt;/</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//读取需要被处理的 html 文件</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(path.<span class="title function_">join</span>(__dirname,<span class="string">&#x27;./files/index.html&#x27;</span>),<span class="string">&#x27;utf8&#x27;</span>,<span class="function">(<span class="params">err,dataStr</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//读取失败</span></span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;读取 html 文件失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//读取成功，调用相应的方法来解析 style，script，html</span></span><br><span class="line">    <span class="title function_">resolveCSS</span>(dataStr)</span><br><span class="line">    <span class="title function_">resolveJS</span>(dataStr)</span><br><span class="line">    <span class="title function_">resolveHTML</span>(dataStr)</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="keyword">function</span> <span class="title function_">resolveCSS</span>(<span class="params">htmlStr</span>)&#123;</span><br><span class="line">    <span class="comment">//使用正则提取页面中的 &lt;style&gt;&lt;/style&gt; 标签</span></span><br><span class="line">    <span class="keyword">const</span> r1 = regStyle.<span class="title function_">exec</span>(htmlStr)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//将提取出来的样式字符串作进一步处理，将 &lt;style&gt; 和 &lt;/style&gt; 用空格符替换掉</span></span><br><span class="line">    <span class="keyword">const</span> newCSS = r1[<span class="number">0</span>].<span class="title function_">replace</span>(<span class="string">&#x27;&lt;style&gt;&#x27;</span>,<span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="string">&#x27;&lt;/style&gt;&#x27;</span>,<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//将提取出来的 CSS 样式，写入到 index.css 中</span></span><br><span class="line">    fs.<span class="title function_">writeFile</span>(path.<span class="title function_">join</span>(__dirname,<span class="string">&#x27;./clock/index.css&#x27;</span>),newCSS,<span class="function"><span class="params">err</span>=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(err)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;写入 CSS 样式失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;写入 CSS 成功！&#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">//自定义 JS 脚本</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">resolveJS</span>(<span class="params">htmlStr</span>)&#123;</span><br><span class="line">    <span class="comment">//使用正则提取页面中的 &lt;script&gt;&lt;/script&gt; 标签</span></span><br><span class="line">    <span class="keyword">const</span> r2 = regScript.<span class="title function_">exec</span>(htmlStr)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//将提取出来的脚本字符串作进一步处理，将 &lt;script&gt; 和 &lt;/script&gt; 用空格符替换掉</span></span><br><span class="line">    <span class="keyword">const</span> newJS = r2[<span class="number">0</span>].<span class="title function_">replace</span>(<span class="string">&#x27;&lt;script&gt;&#x27;</span>,<span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="string">&#x27;&lt;/script&gt;&#x27;</span>,<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//将提取出来的 JS 脚本，写入到 index.js 中</span></span><br><span class="line">    fs.<span class="title function_">writeFile</span>(path.<span class="title function_">join</span>(__dirname,<span class="string">&#x27;./clock/index.js&#x27;</span>),newJS,<span class="function"><span class="params">err</span>=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(err)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;写入 JS 脚本失败！&#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;写入 JS 成功！&#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">//处理 html 文件</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">resolveHTML</span>(<span class="params">htmlStr</span>)&#123;</span><br><span class="line">    <span class="comment">//使用字符串中的 replace 方法，把内嵌的 &lt;style&gt; 和 &lt;script&gt; 标签，替换为外联的 &lt;link&gt; 和 &lt;script&gt; 标签</span></span><br><span class="line">    <span class="keyword">const</span> newHTML = htmlStr</span><br><span class="line">    .<span class="title function_">replace</span>(regStyle,<span class="string">&#x27;&lt;link rel=&quot;stylesheet&quot; href=&quot;./index.css&quot; /&gt;&#x27;</span>)</span><br><span class="line">    .<span class="title function_">replace</span>(regScript,<span class="string">&#x27;&lt;script src=&quot;./index.js&quot;&gt;&lt;/script&gt;&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment">//将替换完成后的的 html 代码，写入到 index.html 文件中</span></span><br><span class="line">    fs.<span class="title function_">writeFile</span>(path.<span class="title function_">join</span>(__dirname,<span class="string">&#x27;./clock/index.html&#x27;</span>),newHTML,<span class="function"><span class="params">err</span>=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(err)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;写入 HTML 文件失败！&#x27;</span>,err.<span class="property">message</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;写入 HTML 文件成功！&#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/21/lFkb8NczeIvDowd.png"></p><p>并且在 clock 文件内已经有了 index.html、index.css 和 index.js 三个文件了</p><p><img src="https://s2.loli.net/2022/04/21/TxrIWL6CXtfZhpA.png"></p><p><strong>注意</strong>：</p><ul><li><p><code>fs.writeFile()</code> 方法只能用来创建文件，不能用来创建路径。也就是说，可以创建一个 .txt 文件，但不能创建一个用以存放这个文件的文件夹</p></li><li><p>重复调用 <code>fs.writeFile()</code> 方法写入的新内容会覆盖就内容，而不是在后面添加</p></li></ul><br/><br/><h2 id="四、http-模块"><a href="#四、http-模块" class="headerlink" title="四、http 模块"></a>四、http 模块</h2><h3 id="1、什么是-http-模块"><a href="#1、什么是-http-模块" class="headerlink" title="1、什么是 http 模块"></a>1、什么是 http 模块</h3><p>http 模块是 Node.js 官方提供的、用来创建 Web 服务器的模块。通过 http 模块提供的 <code>http.createServer()</code> 方法，写几行简单的代码，就能轻松地手写一个服务器软件，方便地把一台普通的电脑，变成一台 Web 服务器，从而对外提供 Web 资源服务。</p><p>如果希望使用 http 模块创建 Web 服务器，则需要先导入它：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br></pre></td></tr></table></figure><br/><h3 id="2、和服务器有关的概念"><a href="#2、和服务器有关的概念" class="headerlink" title="2、和服务器有关的概念"></a>2、和服务器有关的概念</h3><h4 id="（1）IP-地址"><a href="#（1）IP-地址" class="headerlink" title="（1）IP 地址"></a>（1）IP 地址</h4><p><strong>IP 地址</strong>就是互联网上每台计算机的<strong>唯一地址</strong>，因此 IP 地址具有<strong>唯一性</strong>。只有在知道对方 IP 地址的前提下，才能与对应的电脑之间进行数据通信。</p><ul><li>互联网上，每台计算机都有自己的 IP 地址</li><li>在开发期间，自己的电脑既是一台服务器，也是一个客户端。为了方便测试，可以在自己的浏览器中输入 127.0.0.1 这个 IP 地址，就能把自己的电脑当做一台服务器进行访问</li></ul><h4 id="（2）域名和域名服务器"><a href="#（2）域名和域名服务器" class="headerlink" title="（2）域名和域名服务器"></a>（2）域名和域名服务器</h4><p>由于 IP 地址不方便记忆，所以人们又发明了一套字符型的地址方案，就是所谓的域名<strong>地址</strong>。</p><p><strong>IP 地址</strong>和<strong>域名</strong>是<strong>一一对应</strong>的关系，这份对应关系存放在一种叫做<strong>域名服务器</strong>的电脑中。使用者只需通过好记的域名访问对应的服务器即可，对应的转换工作由域名服务器实现。因此，<strong>域名服务器就是提供 IP 地址和域名之间的转换服务的服务器</strong>。</p><ul><li>单纯使用 IP 地址，也能进行访问</li><li>在开发测试期间，127.0.0.1 对应的域名是 localhost，它们都代表我们自己的这台电脑，在使用效果上没有任何区别。</li></ul><h4 id="（3）端口号"><a href="#（3）端口号" class="headerlink" title="（3）端口号"></a>（3）端口号</h4><p>计算机中的端口号，就像是现实生活中的门牌号一样，通过门牌号可以在整栋大楼若干个房间中找到唯一的那个房间。</p><p>同样的道理，在一台电脑中可以运行成百上千个 Web 服务，每个 Web 服务都对应一个唯一的端口号。客户端发送过来的网络请求，通过端口号，可以准确地交给对应的 Web 服务进行处理。</p><p><img src="https://s2.loli.net/2022/04/22/hANkFzmU9cZVB6a.png"></p><ul><li>每个端口号不能同事被多个 Web 服务占用</li><li>在实际应用中，URL 中的 80 端口可以被省略</li></ul><br/><h3 id="3、创建最基本的-Web-服务器"><a href="#3、创建最基本的-Web-服务器" class="headerlink" title="3、创建最基本的 Web 服务器"></a>3、创建最基本的 Web 服务器</h3><h4 id="3-1-创建-Web-服务器的基本步骤"><a href="#3-1-创建-Web-服务器的基本步骤" class="headerlink" title="3.1 创建 Web 服务器的基本步骤"></a>3.1 创建 Web 服务器的基本步骤</h4><p>（1）导入 http 模块</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br></pre></td></tr></table></figure><p>（2）创建 Web 服务器实例</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br></pre></td></tr></table></figure><p>（3）为服务器实例绑定 <strong>request</strong> 事件，监听客户端的请求</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用服务器实例 .on() 方法，为服务器绑定一个 request 事件</span></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//只要有客户端来请求我们自己的服务器，就会触发 request 事件，从而调用这个事件处理函数</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Someone visit our web server.&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>（4）启动服务器</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//调用 server.listen(端口号，cb回调)方法，即可启动 Web 服务器</span></span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;http server running at http://127.0.01&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>总代码：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//使用服务器实例 .on() 方法，为服务器绑定一个 request 事件</span></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//只要有客户端来请求我们自己的服务器，就会触发 request 事件，从而调用这个事件处理函数</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Someone visit our web server.&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用 server.listen(端口号，cb回调)方法，即可启动 Web 服务器</span></span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;http server running at http://127.0.0.1:8080&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/22/85ohaPJuR6jQg79.png"></p><p>按住 ctrl 然后单击 ‘<a href="http://127.0.0.1/">http://127.0.01</a>‘ 就可以进入页面</p><h4 id="3-2-req-请求对象"><a href="#3-2-req-请求对象" class="headerlink" title="3.2 req 请求对象"></a>3.2 req 请求对象</h4><p>只要服务器接收到了客户端的请求，就会调用通过 <code>server.on()</code> 为服务器绑定的 <strong>request</strong> 事件处理函数。如果想在事件处理函数中，访问与客户端相关的<strong>数据</strong>或<strong>属性</strong>，可以使用如下的方式：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//req.url 是客户端请求的 URL 地址</span></span><br><span class="line"><span class="keyword">const</span> url = req.<span class="property">url</span></span><br><span class="line">    </span><br><span class="line"><span class="comment">//req.method 是客户端请求的 method 类型</span></span><br><span class="line"><span class="keyword">const</span> method = req.<span class="property">method</span></span><br><span class="line"><span class="keyword">const</span> str = <span class="string">`Your request url is <span class="subst">$&#123;url&#125;</span>,and request method is <span class="subst">$&#123;method&#125;</span>`</span></span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(str)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行截图：</p><p><img src="https://s2.loli.net/2022/04/22/JAIxT9CvBX7jlWS.png"></p><p>但当打开页面的时候，会发现我们并没有拿到东西，或者说客户端没有响应一些内容，这我们就要用到下面的方法。</p><h4 id="3-3-res-响应对象"><a href="#3-3-res-响应对象" class="headerlink" title="3.3 res 响应对象"></a>3.3 res 响应对象</h4><p>在服务器的 <strong>request</strong> 事件处理函数中，如果想访问与服务器相关的数据或属性，可以使用如下的方式：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//req.url 是客户端请求的 URL 地址</span></span><br><span class="line"><span class="keyword">const</span> url = req.<span class="property">url</span></span><br><span class="line">    </span><br><span class="line"><span class="comment">//req.method 是客户端请求的 method 类型</span></span><br><span class="line"><span class="keyword">const</span> method = req.<span class="property">method</span></span><br><span class="line"><span class="keyword">const</span> str = <span class="string">`Your request url is <span class="subst">$&#123;url&#125;</span>,and request method is <span class="subst">$&#123;method&#125;</span>`</span></span><br><span class="line"></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(str)</span><br><span class="line">    </span><br><span class="line"><span class="comment">//调用 res.end() 方法，向客户端响应一些内容，并结束指定内容</span></span><br><span class="line">res.<span class="title function_">end</span>(str)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>此时的运行结果：</p><p><img src="https://s2.loli.net/2022/04/22/AsQLT4cItjlSezZ.png"></p><p>当打开页面之后终端会显示</p><p><img src="https://s2.loli.net/2022/04/22/cHGg4MB2sVw5zCy.png"></p><p>并且页面内会显示</p><p><img src="https://s2.loli.net/2022/04/22/bUrymoHaJEL5YNV.png"></p><p>我们拿到了东西了。</p><h4 id="3-4-解决中文乱码问题"><a href="#3-4-解决中文乱码问题" class="headerlink" title="3.4 解决中文乱码问题"></a>3.4 解决中文乱码问题</h4><p>输入以下代码：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//定义一个字符串，包含中文内容</span></span><br><span class="line"><span class="keyword">const</span> str = <span class="string">`您请求的 URL 地址是 <span class="subst">$&#123;req.url&#125;</span>, 请求的 method 类型为 <span class="subst">$&#123;req.method&#125;</span>`</span></span><br><span class="line">    </span><br><span class="line"><span class="comment">//调用 res.end() 方法来讲内容响应给客户端</span></span><br><span class="line">res.<span class="title function_">end</span>(str)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/22/5lu4VtrmEeiqnXI.png"></p><p>会发现这里面都是乱码，此时我们就要设置响应头来解决乱码问题</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//定义一个字符串，包含中文内容</span></span><br><span class="line"><span class="keyword">const</span> str = <span class="string">`您请求的 URL 地址是 <span class="subst">$&#123;req.url&#125;</span>, 请求的 method 类型为 <span class="subst">$&#123;req.method&#125;</span>`</span></span><br><span class="line">    </span><br><span class="line"><span class="comment">//为了解决中文乱码问题，需要设置响应头 Content-Type 的值为 text/html;charset=utf-8</span></span><br><span class="line">res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Content-Type&#x27;</span>,<span class="string">&#x27;text/html;charset=utf-8&#x27;</span>)</span><br><span class="line">    </span><br><span class="line"><span class="comment">//调用 res.end() 方法来讲内容响应给客户端</span></span><br><span class="line">res.<span class="title function_">end</span>(str)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>此时的运行结果：</p><p><img src="https://s2.loli.net/2022/04/22/9IipeKNjUO8v4rQ.png"></p><h4 id="3-5-根据不同的-url-响应不同的-html-内容"><a href="#3-5-根据不同的-url-响应不同的-html-内容" class="headerlink" title="3.5 根据不同的 url 响应不同的 html 内容"></a>3.5 根据不同的 url 响应不同的 html 内容</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//获取请求的 url 地址</span></span><br><span class="line"><span class="keyword">const</span> url = req.<span class="property">url</span></span><br><span class="line">    </span><br><span class="line"><span class="comment">//设置默认的内容为 404 Not Found</span></span><br><span class="line"><span class="keyword">let</span> content = <span class="string">&#x27;&lt;h1&gt;404 Not Found&lt;/h1&gt;&#x27;</span></span><br><span class="line">    </span><br><span class="line"><span class="comment">//如果用户请求的是首页</span></span><br><span class="line"><span class="keyword">if</span>(url === <span class="string">&#x27;/&#x27;</span> || url === <span class="string">&#x27;/index.html&#x27;</span>)&#123;</span><br><span class="line">content = <span class="string">&#x27;&lt;h1&gt;首页&lt;/h1&gt;&#x27;</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">else</span> <span class="keyword">if</span>(url === <span class="string">&#x27;/about.html&#x27;</span>)&#123;</span><br><span class="line">content = <span class="string">&#x27;&lt;h1&gt;关于页面&lt;/h1&gt;&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Content-Type&#x27;</span>,<span class="string">&#x27;text/html;charset=utf-8&#x27;</span>)</span><br><span class="line">res.<span class="title function_">end</span>(content)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>此时，当我们打开页面的时候，会显示</p><p><img src="https://s2.loli.net/2022/04/22/ZsHloCqyVgBa6cM.png"></p><p>当我们接着网址后输入 ‘&#x2F;about.html’ 时，会显示</p><p><img src="https://s2.loli.net/2022/04/22/Ag93wIlo1z4s6EK.png"></p><p>我们可以发现，这时我们已经可以从服务器内切换不同的页面。</p><br/><h3 id="4、练习——实现-clock-时钟的-Web-服务器"><a href="#4、练习——实现-clock-时钟的-Web-服务器" class="headerlink" title="4、练习——实现 clock 时钟的 Web 服务器"></a>4、练习——实现 clock 时钟的 Web 服务器</h3><h4 id="4-1-基本完成需求"><a href="#4-1-基本完成需求" class="headerlink" title="4.1 基本完成需求"></a>4.1 基本完成需求</h4><p>代码：</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><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//创建服务器</span></span><br><span class="line"><span class="keyword">const</span> server = http.<span class="title function_">createServer</span>()</span><br><span class="line"></span><br><span class="line">server.<span class="title function_">on</span>(<span class="string">&#x27;request&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//获取请求的 url 地址</span></span><br><span class="line"><span class="keyword">const</span> url = req.<span class="property">url</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//把请求的 URL 地址映射为具体具体文件的存放地址</span></span><br><span class="line"><span class="keyword">const</span> fpath = path.<span class="title function_">join</span>(__dirname,url)</span><br><span class="line"></span><br><span class="line"><span class="comment">//根据映射过来的文件路径来读取文件的内容</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(fpath,<span class="string">&#x27;utf8&#x27;</span>,<span class="function">(<span class="params">err,dataStr</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//读取失败，向客户响应固定的错误消息</span></span><br><span class="line"><span class="keyword">if</span>(err)&#123;</span><br><span class="line"><span class="keyword">return</span> res.<span class="title function_">end</span>(<span class="string">&#x27;&lt;h1&gt;404 Not Found&lt;/h1&gt;&#x27;</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">else</span>&#123;</span><br><span class="line">            res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Content-Type&#x27;</span>,<span class="string">&#x27;text/html;charset=utf-8&#x27;</span>)</span><br><span class="line">res.<span class="title function_">end</span>(dataStr)</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">server.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>当我们运行时，会显示</p><p><img src="https://s2.loli.net/2022/04/22/JkIiAOlyeZrGatg.png"></p><p>而当我们在地址后面输入 <code>/clock/index.html</code> 后，会显示我们的主界面</p><p><img src="https://s2.loli.net/2022/04/22/Rlu38bGYSrdt4Q7.png"></p><h4 id="4-2-优化资源的请求路径"><a href="#4-2-优化资源的请求路径" class="headerlink" title="4.2 优化资源的请求路径"></a>4.2 优化资源的请求路径</h4><p>我们不难发现，当且仅当我们在地址栏输入 <code>/clock/index.html</code> 时我们才能访问时钟首页，这种输入还是太过于复杂。其根本原因是请求的 URL 地址是服务器的地址，其中并没有包含 <code>/clock</code> 。所以，我们需要重新编写有关路径的代码。</p><p>用</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//重新编写</span></span><br><span class="line"><span class="comment">//预定义空白的文件来存放路径</span></span><br><span class="line"><span class="keyword">let</span> fpath = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="comment">//判断所请求的路径是否为 &#x27;/&#x27;，如果是的话，则直接进行拼接 index.html</span></span><br><span class="line"><span class="keyword">if</span>(url === <span class="string">&#x27;/&#x27;</span>)&#123;</span><br><span class="line">fpath = path.<span class="title function_">join</span>(__dirname,<span class="string">&#x27;./clock/index.html&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//如果不为 &#x27;/&#x27;，那么动态拼接文件的存放路径，将中间的 /clock 去掉</span></span><br><span class="line"><span class="keyword">else</span>&#123;</span><br><span class="line">fpath = path.<span class="title function_">join</span>(__dirname,<span class="string">&#x27;./clock&#x27;</span>,url)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>代替原代码中的</p><figure class="highlight js"><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">//把请求的 URL 地址映射为具体具体文件的存放地址</span></span><br><span class="line"><span class="keyword">const</span> fpath = path.<span class="title function_">join</span>(__dirname,url)</span><br></pre></td></tr></table></figure><p>即可。（但是貌似会有样式和脚本文件丢失的情况，我也有这个问题，目前不知道该怎么解决）</p><br/><br/><h2 id="五、模块化"><a href="#五、模块化" class="headerlink" title="五、模块化"></a>五、模块化</h2><h3 id="1、什么是模块化"><a href="#1、什么是模块化" class="headerlink" title="1、什么是模块化"></a>1、什么是模块化</h3><p>编程领域中的模块化，就是遵守固定的规则，把一个大文件拆成若干个独立并且相互依赖的小模块。</p><p>使用模块化的好处有：</p><ul><li>提高代码的复用性</li><li>提高代码的可维护性</li><li>可以实现按需加载</li></ul><br/><h3 id="2、模块的分类"><a href="#2、模块的分类" class="headerlink" title="2、模块的分类"></a>2、模块的分类</h3><p>Node.js 中根据模块来源的不同，将模块分为了三大类，分别是：</p><ul><li>内置模块（由官方提供，比如 fs、http、path 等）</li><li>自定义模块（用户创建的每个 .js 文件都是一个自定义模块）</li><li>第三方模块（由第三方开发出来的模块，并非官方提供的内置模块，也不是用户自定义的模块，使用前需下载）</li></ul><br/><h3 id="3、模块作用域"><a href="#3、模块作用域" class="headerlink" title="3、模块作用域"></a>3、模块作用域</h3><h4 id="3-1-什么是模块作用域"><a href="#3-1-什么是模块作用域" class="headerlink" title="3.1 什么是模块作用域"></a>3.1 什么是模块作用域</h4><p>和函数作用域类似，在自定义模块中定义的变量、方法等成员，只能在当前模块内被访问，这种模块级别的访问限制，叫做<strong>模块作用域</strong>。</p><h4 id="3-2-模块作用域的好处"><a href="#3-2-模块作用域的好处" class="headerlink" title="3.2 模块作用域的好处"></a>3.2 模块作用域的好处</h4><p>模块作用域的好处是防止全局变量污染的问题</p><h4 id="3-3-向外共享模块作用域的成员"><a href="#3-3-向外共享模块作用域的成员" class="headerlink" title="3.3 向外共享模块作用域的成员"></a>3.3 向外共享模块作用域的成员</h4><h5 id="3-3-1-module-对象"><a href="#3-3-1-module-对象" class="headerlink" title="3.3.1 module 对象"></a>3.3.1 module 对象</h5><p>在每个 .js 自定义模块中都有一个 <code>module</code> 对象，它里面<strong>存储了和当前模块有关的信息</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">module</span>)</span><br></pre></td></tr></table></figure><p>打印如下：</p><p><img src="https://s2.loli.net/2022/04/22/2PuRvwcHIpXb8AW.png"></p><h5 id="3-3-2-module-exports-对象"><a href="#3-3-2-module-exports-对象" class="headerlink" title="3.3.2 module.exports 对象"></a>3.3.2 module.exports 对象</h5><p>在自定义模块中，可以使用 <code>module.exports</code> 对象，讲模块内的成员共享出去，供外界使用。</p><p>外界用 <code>require()</code> 方法导入自定义模块时，得到的就是 <code>module.exports</code> 所指向的对象。</p><figure class="highlight js"><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="keyword">const</span> m = <span class="built_in">require</span>(<span class="string">&#x27;./自定义模块.js&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(m)</span><br></pre></td></tr></table></figure><p>这里 <strong>‘自定义模块.js’</strong> 里什么也没写，那么当我们 node text.js 时会显示</p><p><img src="https://s2.loli.net/2022/04/23/D4k5qMv7YxhCOdL.png"></p><p>我们可以观察到这里显示了一个 <strong>‘{}’</strong> 这是因为 <code>module.exports</code> 里默认指向的是一个空对象。那我们就可以在 <strong>‘自定义模块.js’</strong> 文件中使用 <code>module.export</code> 方法来设置对象</p><p><img src="https://s2.loli.net/2022/04/23/R8H9xKLkbMcU45f.png"></p><p>注意：</p><p>使用 <code>require()</code> 方法导入模块的时候，导入的结果，永远以 <code>module.exports</code> 指向的对象为准，即新的会覆盖旧的，如下图</p><p><img src="https://s2.loli.net/2022/04/23/hJEzX1PU25DIAw9.png"></p><h5 id="3-3-3-exports-对象"><a href="#3-3-3-exports-对象" class="headerlink" title="3.3.3 exports 对象"></a>3.3.3 exports 对象</h5><p>由于  <code>module.exports</code> 单词写起来比较复杂，为了简化向外共享成员的代码，Node 提供了<code>exports</code> 对象。默认情况下，<code>exports</code>和 <code>module.exports</code> 指向同一个对象。最终共享的结果，还是以 <code>module.exports</code> 指向的对象为准。</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></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="built_in">exports</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">module</span>.<span class="property">exports</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="built_in">exports</span> === <span class="variable language_">module</span>.<span class="property">exports</span>)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/23/RpFvHyxulMcg2WN.png"></p><p>到此我们可以证明所谓的 <code>module.exports</code> 和 <code>exports</code> 指向的是同一个对象。</p><h5 id="3-3-4-exports-和-module-exports-的使用注意点"><a href="#3-3-4-exports-和-module-exports-的使用注意点" class="headerlink" title="3.3.4 exports 和 module.exports 的使用注意点"></a>3.3.4 exports 和 module.exports 的使用注意点</h5><p>时刻谨记， <code>require()</code> 模块时，得到的永远是 <code>module.exports</code> 指向的对象。</p><p>我们上面已经讲过 <code>module.exports</code> 指向的对象和 <code>exports</code> 指向的对象是同一个对象，但其实严格上来说是不准确的。我们来看看以下代码：</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></pre></td><td class="code"><pre><span class="line"><span class="built_in">exports</span>.<span class="property">username</span> = <span class="string">&#x27;zs&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = &#123;</span><br><span class="line">    sex : <span class="string">&#x27;男&#x27;</span>,</span><br><span class="line">    age : <span class="number">22</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这段代码首先会创建一个拥有 “ username &#x3D; ‘zs’ “ 的属性，<code>exports</code> 和 <code>module.exports</code> 都指向了这个属性。接着，又创建一个拥有 sex 和 age 的对象，此时 <code>module.exports</code> 指向了这个对象。而当我们调用 <code>require()</code> 方法的时候，其只会得到 <code>module.exports</code> 指向的对象。(建议去b站上看配套视频， P24，视频讲解的更清楚)</p><p>运行代码，其结果如下：</p><p><img src="https://s2.loli.net/2022/04/23/dDtxIVzJML8RAYl.png"></p><p>但当我们将 exports 和 module.exports 都指向属性的时候，则都可以调用，如下：</p><p><img src="https://s2.loli.net/2022/04/23/Pq5onMRL9KTFVAj.png"></p><hr><p>接着我们再来看看以下代码：</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></pre></td><td class="code"><pre><span class="line"><span class="built_in">exports</span> = &#123;</span><br><span class="line">    username : <span class="string">&#x27;zs&#x27;</span>,</span><br><span class="line">    sex : <span class="string">&#x27;男&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">modules.<span class="property">exports</span> = <span class="built_in">exports</span></span><br><span class="line">modules.<span class="property">exports</span>.<span class="property">age</span> = <span class="string">&#x27;20&#x27;</span></span><br></pre></td></tr></table></figure><p>这里就简单的讲解一下这段代码，不再运行。</p><p>首先，exports 指向了一个包含 username 和 sex 的对象，接着 module.exports 又指向了这个对象，然后 module.exports 又指向了一个属性，此时我们运行则会打印所有的东西。</p><p>为了防止混乱，在一个模块中不要同时使用 <code>exports</code> 和 <code>module.exports</code>。</p><br/><h3 id="4、Node-js-中的模块化规范"><a href="#4、Node-js-中的模块化规范" class="headerlink" title="4、Node.js 中的模块化规范"></a>4、Node.js 中的模块化规范</h3><p>Node.js 遵循了 CommonJS 模块化规范，CommonJS 规定了模块的特性和各模块之间如何相互依赖。</p><p>CommonJS 规定：</p><ol><li>每个模块内部，module 变量代表当前模块</li><li>module 变量是一个对象，它的 exports 属性（即 module.exports）是对外的接口</li><li>加载某个模块，其实是加载该模块的 module.exports 属性，<code>require()</code> 方法用于加载模块</li></ol><br/><h3 id="5、模块的加载机制"><a href="#5、模块的加载机制" class="headerlink" title="5、模块的加载机制"></a>5、模块的加载机制</h3><h4 id="5-1-优先从缓存中加载"><a href="#5-1-优先从缓存中加载" class="headerlink" title="5.1 优先从缓存中加载"></a>5.1 优先从缓存中加载</h4><p>模块在第一次加载后会被缓存。这也意味着多次调用 <code>require()</code> 不会导致模块的代码被执行多次。</p><p>注意：不论是内置模块、用户自定义模块、还是第三方模块，他们都会优先从缓存中加载，从而提高模块的加载效率。</p><p>例如</p><p><img src="https://s2.loli.net/2022/04/30/Spcwur2KiVxeO6P.png"></p><p>尽管我们调用了四次这个模块，但是它只输出了一个 ok。</p><h4 id="5-2-内置模块的加载机制"><a href="#5-2-内置模块的加载机制" class="headerlink" title="5.2 内置模块的加载机制"></a>5.2 内置模块的加载机制</h4><p>内置模块是由 Node.js 官方提供的模块，内置模块的加载优先级最高。比如说你自己再定义一个叫做 ‘fs’ 的自定义个模块，但</p><p><code>require (&#39;fs&#39;)</code> 始终返回内置的 fs 模块</p><h4 id="5-3-自定义模块的加载机制"><a href="#5-3-自定义模块的加载机制" class="headerlink" title="5.3 自定义模块的加载机制"></a>5.3 自定义模块的加载机制</h4><p>使用 <code>require()</code> 加载自定义模块时，必须制定以 <code>./</code> 或者 <code>../</code> 开头的路径标识符。在加载自定义模块时，如果没有制定 <code>./</code> 或者 <code>../</code> 这样的路径标识符，则 node 会把它当做内置模块或第三方模块进行加载。这与上一节可以形成对应，当我们指定加载的模块的路径时，它就会加载我们指定的路径的模块。</p><p>同时，在使用 <code>require()</code> 导入自定义模块时，如果省略了文件的扩展名，则 Node.js 会按顺序分别尝试加载以下的文件：</p><ol><li>按照确切的文件名进行加载</li><li>补全 .js 扩展名进行加载</li><li>补全 .json 扩展名进行加载</li><li>补全 .node 扩展名进行加载</li><li>加载失败，终端报错</li></ol><p>这也是为什么我们在调用的时候不写 .js 也能调用成功。</p><h4 id="5-4-第三方模块的加载机制"><a href="#5-4-第三方模块的加载机制" class="headerlink" title="5.4 第三方模块的加载机制"></a>5.4 第三方模块的加载机制</h4><p>如果传递给 <code>require()</code> 的模块标识符不是一个内置模块，也没有以 .&#x2F; 或者 ..&#x2F; 开头，则 Node.js 会从当前模块的父级目录开始，尝试从 &#x2F;node_modules 文件夹中加载第三方模块。</p><p>如果没有找到对应的第三方模块，则移动到再上一层父目录中，进行加载，知道文件系统的根目录。例如，假设在 ‘C:\Users\YUEXIABUG\project\foo.js’ 文件里调用了 <code>require(&#39;tools&#39;)</code>，则 Node.js 会按一下顺序进行查找：</p><ol><li>C:\Users\YUEXIABUG\project\node_modules\tools</li><li>C:\Users\YUEXIABUG\node_modules\tools</li><li>C:\Users\node_modules\tools</li><li>C:\node_modules\tools</li><li>加载失败，终端报错</li></ol><h4 id="5-5-目录作为模块"><a href="#5-5-目录作为模块" class="headerlink" title="5.5 目录作为模块"></a>5.5 目录作为模块</h4><p>当把目标作为模块标识符，传递给 <code>require()</code> 进行加载的时候，有三种加载方式：</p><ol><li>在被加载的目录下查找一个叫做 package.json 的文件，并寻找 main 属性，作为 <code>require()</code> 加载的入口</li><li>如果目录中没有 package.json 文件， 或者 main 入口不存在或者无法解析，则Node.js 将会试图加载目录下的 index.js 文件</li><li>如果以上两步都失败了，则 Node.js 会在终端打印错误消息，报告模块的缺失：Error:Cannot find module ‘xxx’</li></ol><br/><br/><h2 id="六、npm-与包"><a href="#六、npm-与包" class="headerlink" title="六、npm 与包"></a>六、npm 与包</h2><h3 id="1、什么是包"><a href="#1、什么是包" class="headerlink" title="1、什么是包"></a>1、什么是包</h3><p>Node.js 中的第三方模块又叫做<strong>包</strong>，不同于 Node.js 中的内置模块与自定义模块，包是由第三方个人或者团队开发出来的，免费供所有人使用。因为 Node.js 的内置模块仅提供了一些底层的 API，导致了在基于内置模块进行项目开发的时候，效率很低。包是基于内置模块封装出来的，提供了更高级、更方便的 API，极大地提高了开发效率。包和内置模块之间的关系，类似于 jQuery 和浏览器内置 API 之间的关系。</p><p> <strong>npm,Inc.</strong> 是有一个著名的网站：<a href="https://www.npmjs.com/">npm (npmjs.com)</a>，它是全球最大的包共享平台，可以在这个网站上搜索到任何你需要的包。而使用地址为 <a href="https://registry.npmjs.org/">https://registry.npmjs.org/</a> 的服务器，就可以下载自己所需要的包。</p><p><strong>npm,Inc.</strong> 公司提供了一个包下载工具——<strong>npm</strong>，这个工具随着我们下载安装 Node.js 时一起安装到了用户的电脑上。</p><p>我们在终端内输入 <code>npm -v</code> 就可以来查看自己电脑上 npm 包管理工具的版本号了。</p><p><img src="https://s2.loli.net/2022/04/23/FdMEl6sRpqyC9BV.png"></p><p>通过终端输入 npm i 或者 npm install 都可以在项目中安装包。</p><br/><h3 id="2、npm初体验——格式化时间"><a href="#2、npm初体验——格式化时间" class="headerlink" title="2、npm初体验——格式化时间"></a>2、npm初体验——格式化时间</h3><p>安装包可在终端输入 <code>npm install 包的名字</code> 或是 <code>npm i 包的名字</code> 来进行安装。</p><p>首先在项目文件夹中安装包</p><p><img src="https://s2.loli.net/2022/04/23/psICftkBXiRbd1c.png"></p><p>这样就显示安装完成了。</p><p>之后在 text.js 文件中输入</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入需要的包</span></span><br><span class="line"><span class="keyword">const</span> moment = <span class="built_in">require</span>(<span class="string">&#x27;moment&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dt = <span class="title function_">moment</span>().<span class="title function_">format</span>(<span class="string">&#x27;YYYY-MM-DD HH:mm:ss&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(dt)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/23/AyeRYIb3pTwiDoS.png"></p><p>这相比于之前硬敲会显得很方便。</p><p>在我们初次安装包之后，在项目文件夹下面会多出一个叫做 node_modules 的文件夹和 package-lock,json 的配置文件。</p><p>其中，<strong>node_modules</strong> 文件夹用来存放所有已经安装到项目中的包。<code>require()</code> 导入第三方包时，就是从这个项目中查找并加载包。</p><p><strong>pack-lock.json</strong> 配置文件用来记录 node_modules 目录下的每一个包的下载信息，例如包的名字、版本号、下载地址等。</p><p>**注意：**尽量不要去手动修改这两个东西中的任何代码，npm 包管理工具会帮助我们自动维护它们。</p><br/><h3 id="3、包管理配置文件"><a href="#3、包管理配置文件" class="headerlink" title="3、包管理配置文件"></a>3、包管理配置文件</h3><p>npm 规定，在项目根目录中，必须提供一个叫做 package.json 的包管理配置文件。用来记录与项目有关的一些配置信息。比如说<strong>包的名称、版本号</strong>等·</p><h4 id="3-1-多人协作的问题"><a href="#3-1-多人协作的问题" class="headerlink" title="3.1 多人协作的问题"></a>3.1 多人协作的问题</h4><p>由于在实际开发中我们肯定要引用模块，这时候我们就会发现对于整个项目的体积，第三方包的体积占了将近百分之 95%，而源代码的体积只占了不到 5%。而这么大的体积就会使得团队成员之间共享项目源代码不是那么方便。解决办法就是剔除 node_modules 这个文件夹。那么问题又来了，当你把 node_modules 这个文件夹剔除之后，你的团队成员要怎么知道你安装了哪些包呢？</p><h4 id="3-2-如何记录项目中安装了哪些包"><a href="#3-2-如何记录项目中安装了哪些包" class="headerlink" title="3.2 如何记录项目中安装了哪些包"></a>3.2 如何记录项目中安装了哪些包</h4><p>在项目根目录中，创建一个叫做 <strong>package.json</strong> 的配置文件，即可用来记录项目中安装了哪些包。从而方便剔除 node_modules 目录之后，在团队成员之间共享源代码。</p><p>注意：今后在项目中，一定要把 node_modules 文件夹添加到 .gitignore 忽略文件中。</p><h4 id="3-3-如何快速的创建-package-json"><a href="#3-3-如何快速的创建-package-json" class="headerlink" title="3.3 如何快速的创建 package.json"></a>3.3 如何快速的创建 package.json</h4><p>npm 包管理工具提供了一个快捷命令，可以在执行命令时所处的目录中，快速创建 package.json 这个包管理配置文件：</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">npm init -y</span><br></pre></td></tr></table></figure><p>该命令在项目创建之初就要执行，且整个项目开发阶段只执行一次。</p><p>当然，大部分项目开发的时候都是使用框架，在创建项目的时候会自动创建好 package.json 文件，无需手动创建。</p><p>注意：</p><ul><li>上述命令只能在英文的目录下成功运行！所以，项目文件夹的名称一定要使用英文命名，不要使用中文，不要出现空格</li><li>运行 <code>npm install 包的名字</code> 命令安装包的时候，npm 包管理工具会自动把包的名称和版本号记录到 package.json 文件中</li></ul><h4 id="3-4-dependencies-节点"><a href="#3-4-dependencies-节点" class="headerlink" title="3.4 dependencies 节点"></a>3.4 dependencies 节点</h4><p>在创建 package.json 的时候是没有 dependencies 节点的，当我们第一次使用 <code>npm install</code> 来安装包的时候，会自动在 package.json 中创建这个节点。</p><p>dependencies 节点专门用来记录使用 npm install 命令安装了哪些包。</p><h4 id="3-5-一次性安装的所有的包"><a href="#3-5-一次性安装的所有的包" class="headerlink" title="3.5 一次性安装的所有的包"></a>3.5 一次性安装的所有的包</h4><p>可以在终端内输入 <code>npm install</code> 来一次性安装 package.json 中记录过的所有依赖包。</p><h4 id="3-6-卸载包"><a href="#3-6-卸载包" class="headerlink" title="3.6 卸载包"></a>3.6 卸载包</h4><p>在终端内输入 <code>npm uninstall 包的名字</code> 来卸载指定名字的包，并将其从 package.json 中移除掉。</p><h4 id="3-7-devDependencies-节点"><a href="#3-7-devDependencies-节点" class="headerlink" title="3.7 devDependencies 节点"></a>3.7 devDependencies 节点</h4><p>如果某些只在项目开发阶段会用到，在项目上线之后不会用到，则建议把这些包记录到 devDependencies 节点中。与之对应的，如果某些包在开发和项目上线之后都需要用到，则建议把这些包记录到 dependencies 节点中。</p><p>当我们在终端中输入 <code>npm install 包的名字 --save-dev</code>  或者 <code>npm i 包的名字 -D</code> 来将包安装到devDependencies 节点中。而是否要将包记录到 devDependencies 节点中，可以自己去 npm 官网中查询。</p><br/><h3 id="4、npm-在国内的镜像服务器（可提供更快的下载包的速度）"><a href="#4、npm-在国内的镜像服务器（可提供更快的下载包的速度）" class="headerlink" title="4、npm 在国内的镜像服务器（可提供更快的下载包的速度）"></a>4、npm 在国内的镜像服务器（可提供更快的下载包的速度）</h3><p>因为 npm 的服务器在国外，众所周知的原因我们在使用普通 npm 下载包的时候经常会发生下载缓慢甚至是下载失败的情况。而淘宝在国内搭建了一个服务器，专门吧国外官方服务器上的包同步到国内的服务器中，然后在国内提供下载包的服务，从而极大地提高了下载包的速度和稳定性。</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">npm config set registry=https://registry.npmmirror.com/</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">npm config get registry</span><br></pre></td></tr></table></figure><p>来查看镜像源是否转换成功。</p><p>如果显示：</p><p><img src="https://s2.loli.net/2022/04/26/WEBz4tuYv89magN.png"></p><p>则转换成功了。</p><br/><h3 id="5、nrm"><a href="#5、nrm" class="headerlink" title="5、nrm"></a>5、nrm</h3><p>nrm 是一个可以让用户自主切换下载包的镜像源的工具，在终端内输入 <code>npm i nrm -g</code> 来对 nrm 进行全局安装。</p><p>显示如下界面则表示安装完成</p><p><img src="https://s2.loli.net/2022/04/26/2BJF65axMRTA8lS.png"></p><p>接着我们再输入 <code>nrm ls</code> 来查看可以使用的镜像源</p><p><img src="https://s2.loli.net/2022/04/26/cT38GRHpaYz4dBt.png"></p><p>接着我们就可以在这里面转换镜像源了，镜像源转换的语句为 <code>nrm use 你想要转换的镜像源名字</code> 如下：</p><p><img src="https://s2.loli.net/2022/04/26/LqmvUpbs8dCgiSy.png"></p><br/><h3 id="6、包的分类"><a href="#6、包的分类" class="headerlink" title="6、包的分类"></a>6、包的分类</h3><h4 id="6-1-项目包"><a href="#6-1-项目包" class="headerlink" title="6.1 项目包"></a>6.1 项目包</h4><p>那些被安装到项目的 node_modules 目录中的包，仅限安装了该包的项目使用这个包。</p><h4 id="6-2-全局包"><a href="#6-2-全局包" class="headerlink" title="6.2 全局包"></a>6.2 全局包</h4><p>全局包是可以在所有项目中使用的包。这种包通常只需要下载一次就可以在所有的项目中使用。其被安装在了C:\Users\YUEXIABUG\AppData\Roaming\npm\node_modules 目录下。</p><p>注意：</p><ul><li>只有工具性质的包，才有全局安装的必要性。因为它们提供了好用的终端命令。</li><li>判断某个包是否要全局安装后才能使用，可以参考官方提供的使用说明。</li></ul><br/><h3 id="7、包的结构规范"><a href="#7、包的结构规范" class="headerlink" title="7、包的结构规范"></a>7、包的结构规范</h3><ul><li>包必须以单独的目录而存在</li><li>包的顶级目录下必须要包含 package.json 这个包管理配置文件</li><li>package.json 中必须要包含 name(包的名字)，version(版本号)，main(包的入口)这三个属性</li></ul><br/><h3 id="8、开发自己的包"><a href="#8、开发自己的包" class="headerlink" title="*8、开发自己的包"></a>*8、开发自己的包</h3><h4 id="8-1-实现功能"><a href="#8-1-实现功能" class="headerlink" title="8.1 实现功能"></a>8.1 实现功能</h4><ul><li>格式化日期</li><li>转义 html 中的特殊字符</li><li>还原 html 中的特殊字符</li></ul><h4 id="8-2-初始化包的基本结构"><a href="#8-2-初始化包的基本结构" class="headerlink" title="8.2 初始化包的基本结构"></a>8.2 初始化包的基本结构</h4><ol><li><p>新建 package-test-yxbg 文件夹，作为包的根目录（先去 npm 官网上搜一下有没有同名的，有同名就要改）</p></li><li><p>在 package-test-yxbg 文件夹中，新建以下三个文件：</p><ul><li><p>package.json   <em>(包管理配置文件)</em></p></li><li><p>index.js               <em>(包的入口文件)</em></p></li><li><p>README.md     <em>(包的说明文档)</em></p></li></ul></li></ol><h4 id="8-3-初始化-package-json"><a href="#8-3-初始化-package-json" class="headerlink" title="8.3 初始化 package.json"></a>8.3 初始化 package.json</h4><p>package.json 里的元素要有</p><ul><li>name：包的名字</li><li>version：版本号</li><li>main：包的入口</li><li>description：包的介绍</li><li>keywords：关键字</li><li>license：开源许可协议</li></ul><p>我们在 package.json 中写入下方的代码即可</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span><span class="string">&quot;package-test-yxbg&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;version&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1.0.0&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;main&quot;</span><span class="punctuation">:</span> <span class="string">&quot;index.html&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;description&quot;</span><span class="punctuation">:</span><span class="string">&quot;提供了格式化时间,HTMLEscape的功能&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;keywords&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;ityxbg&quot;</span><span class="punctuation">,</span><span class="string">&quot;dataFormat&quot;</span><span class="punctuation">,</span><span class="string">&quot;secape&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;license&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ISC&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h4 id="8-4-编写-index-js"><a href="#8-4-编写-index-js" class="headerlink" title="8.4 编写 index.js"></a>8.4 编写 index.js</h4><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></pre></td><td class="code"><pre><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">//定义格式化时间函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">dateFormat</span>(<span class="params">datestr</span>)&#123;</span><br><span class="line">    <span class="keyword">const</span> dt = <span class="keyword">new</span> <span class="title class_">Date</span>(datestr)</span><br><span class="line"></span><br><span class="line">    <span class="comment">//获得时间</span></span><br><span class="line">    <span class="keyword">const</span> y = dt.<span class="title function_">getFullYear</span>()</span><br><span class="line">    <span class="keyword">const</span> m = <span class="title function_">padZero</span>(dt.<span class="title function_">getMonth</span>()+<span class="number">1</span>)</span><br><span class="line">    <span class="keyword">const</span> d = <span class="title function_">padZero</span>(dt.<span class="title function_">getDate</span>())</span><br><span class="line">    <span class="keyword">const</span> hh = <span class="title function_">padZero</span>(dt.<span class="title function_">getHours</span>())</span><br><span class="line">    <span class="keyword">const</span> mm = <span class="title function_">padZero</span>(dt.<span class="title function_">getMinutes</span>())</span><br><span class="line">    <span class="keyword">const</span> ss = <span class="title function_">padZero</span>(dt.<span class="title function_">getSeconds</span>())</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="string">`<span class="subst">$&#123;y&#125;</span>-<span class="subst">$&#123;m&#125;</span>-<span class="subst">$&#123;d&#125;</span> <span class="subst">$&#123;hh&#125;</span>:<span class="subst">$&#123;mm&#125;</span><span class="subst">$&#123;ss&#125;</span>`</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//定义一个补零的函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">padZero</span>(<span class="params">n</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> n &gt; <span class="number">9</span> ? <span class="attr">n</span>:<span class="string">&#x27;0&#x27;</span>+n</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//转义 html 字符</span></span><br><span class="line"><span class="comment">//定义转义 html 字符的函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">htmlEscape</span>(<span class="params">htmlstr</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> htmlstr.<span class="title function_">replace</span>(<span class="regexp">/&lt;|&gt;|&quot;|&amp;/g</span>,<span class="function">(<span class="params">match</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">switch</span>(match)&#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&lt;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&amp;lt;&#x27;</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&gt;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&amp;gt;&#x27;</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&quot;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&amp;quot;&#x27;</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&amp;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&amp;amp;&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//还原 html 字符</span></span><br><span class="line"><span class="comment">//定义还原 html 字符的函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">htmlUnEscape</span>(<span class="params">str</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> str.<span class="title function_">replace</span>(<span class="regexp">/&amp;lt;|&amp;gt;|&amp;quot;|&amp;amp;/g</span>,<span class="function">(<span class="params">match</span>)=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">switch</span>(match)&#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&amp;lt;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&lt;&#x27;</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&amp;gt;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&gt;&#x27;</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&amp;quot;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&quot;&#x27;</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;&amp;amp;&#x27;</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&#x27;&amp;&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//向外暴露需要的成员</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>=&#123;</span><br><span class="line">    dateFormat,</span><br><span class="line">    htmlEscape,</span><br><span class="line">    htmlUnEscape</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后在 test.js 中进行测试</p><p>测试代码：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//先导入包</span></span><br><span class="line"><span class="keyword">const</span> ityxbg = <span class="built_in">require</span>(<span class="string">&#x27;./package-test-yxbg/index&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//格式化时间功能</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;格式化时间功能---------------&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> dtStr = ityxbg.<span class="title function_">dateFormat</span>(<span class="keyword">new</span> <span class="title class_">Date</span>())</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(dtStr)</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//转义 html 字符</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;转义 html 字符---------------&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> htmlstr = <span class="string">&#x27;&lt;h1 title=&quot;abc&quot;&gt;这是一个 h1 标签&lt;span&gt;1234&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;&#x27;</span></span><br><span class="line"><span class="keyword">const</span> str = ityxbg.<span class="title function_">htmlEscape</span>(htmlstr)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(str)</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//还原 html 字符</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;还原 html 字符---------------&quot;</span>)</span><br><span class="line"><span class="keyword">const</span> newstr = ityxbg.<span class="title function_">htmlUnEscape</span>(str)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(newstr)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/26/fejAQ4hcYa8TCKd.png"></p><h4 id="8-5-根据不同的功能拆分模块"><a href="#8-5-根据不同的功能拆分模块" class="headerlink" title="8.5 根据不同的功能拆分模块"></a>8.5 根据不同的功能拆分模块</h4><ol><li>将格式化时间的功能 拆分到 src-&gt; dateFormat.js 中</li><li>将处理 html 字符串的功能拆分到 src-&gt; htmlEscape.js 中</li><li>在 index.js 中，导入两个模块，得到需要向外共享的方法</li><li>在 index.js 中，使用 module.exports 把对应的方法共享出去</li></ol><p>(1) 首先我们先将格式化时间和处理 html 字符串的代码粘贴到 dateFormat.js 和 htmlEscape.js 中，如下：</p><p><img src="https://s2.loli.net/2022/04/27/VKS4UnrZw1NfbXW.png"></p><p>那在这个时候我们就会发现原来 index.js 中 module.exports 中的元素不存在了，这是因为我们把不同功能拆分到不同模块之后原 index.js 中是没有这些模块功能的，所以我们就要在模块中进行暴露以及在 index.js 中进行导入。</p><p>(2) 在 dateFormat.js 和 htmlEscape.js 中进行暴露，其代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//暴露</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>=&#123;</span><br><span class="line">    htmlEscape,</span><br><span class="line">    htmlUnEscape</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//暴露</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>=&#123;</span><br><span class="line">    dateFormat</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在暴露完之后我们还要在 index.js 中进行导入。</p><p>(3) 在 index.js 中进行导入</p><p>首先使用 <code>require</code> 来进行导入响应的模块</p><figure class="highlight js"><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="keyword">const</span> date = <span class="built_in">require</span>(<span class="string">&#x27;./src/dateFormat&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> <span class="built_in">escape</span> = <span class="built_in">require</span>(<span class="string">&#x27;./src/htmlEscape&#x27;</span>)</span><br></pre></td></tr></table></figure><p>但问题又来了，<code>date</code> 里面只有一个方法，但是 <code>escape</code> 中有两个方法，那我们就可以回顾以前学到的一个语法 ‘…’  可以进行展开。既然知道了方法，那我们直接向外暴露的时候展开即可，如下</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//向外暴露需要的成员</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span>=&#123;</span><br><span class="line">    ...date,</span><br><span class="line">    ...<span class="built_in">escape</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>接着再在 test.js 中进行测试，其测试代码和上面的一样，我们来看看测试结果</p><p><img src="https://s2.loli.net/2022/04/27/PAxkVGefvHQqdWj.png"></p><p>没问题。那我们已经成功将不同的功能进行拆分了。</p><h4 id="8-6-编写说明文档-README-md"><a href="#8-6-编写说明文档-README-md" class="headerlink" title="8.6 编写说明文档 README.md"></a>8.6 编写说明文档 README.md</h4><p>包根目录中的 README.md 文件，是包的使用说明文档。通过它，我们可以事先把包的使用说明，以 markdown 的格式写出来，方便用户参考。</p><p>README.md 文件中具体写什么内容，没有强制性的要求，只要能够清晰地把包的作用、用法、注意事项等描述清楚即可。我们所创建的这个包的 README.md 文档中，会包含以下 6 项内容：</p><p>安装方式、导入方式、格式化时间、转义 html 中的特殊字符、还原 html 中的特殊字符、开源协议</p><p>编写如下（利用 md 语法编写，其实大家完全可以使用 Typora 来进行直接编写）</p><figure class="highlight md"><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 class="section">### 下载安装</span></span><br><span class="line"><span class="code">```</span></span><br><span class="line"><span class="code">npm install package-test-yxbg</span></span><br><span class="line"><span class="code">```</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="section">### 导入</span></span><br><span class="line"><span class="code">```js</span></span><br><span class="line"><span class="code">const ityxbg = require(&#x27;package-test-yxbg&#x27;)</span></span><br><span class="line"><span class="code">```</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="section">### 格式化时间</span></span><br><span class="line"><span class="code">```js</span></span><br><span class="line"><span class="code">//调用 dateFormat 对时间进行格式化</span></span><br><span class="line"><span class="code">const dtStr = ityxbg.dateFormat(new Date())</span></span><br><span class="line"><span class="code">console.log(dtStr)</span></span><br><span class="line"><span class="code">```</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="section">### 转义 html 字符</span></span><br><span class="line"><span class="code">```js</span></span><br><span class="line"><span class="code">//待转换的 html 字符串</span></span><br><span class="line"><span class="code">const htmlstr = &#x27;&lt;h1 title=&quot;abc&quot;&gt;这是一个 h1 标签&lt;span&gt;1234&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;&#x27;</span></span><br><span class="line"><span class="code">//调用 htmlEscape 方法进行转换</span></span><br><span class="line"><span class="code">const str = ityxbg.htmlEscape(htmlstr)</span></span><br><span class="line"><span class="code">//转换结果为 &amp;lt;h1 title=&amp;quot;abc&amp;quot;&amp;gt;这是一个 h1 标签&amp;lt;span&amp;gt;1234&amp;amp;nbsp;&amp;lt;/span&amp;gt;&amp;lt;/h1&amp;gt;</span></span><br><span class="line"><span class="code">console.log(str)</span></span><br><span class="line"><span class="code">```</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="section">### 还原 html 字符</span></span><br><span class="line"><span class="code">```js</span></span><br><span class="line"><span class="code">//待还原的 html 字符串</span></span><br><span class="line"><span class="code">const newstr = ityxbg.htmlUnEscape(str)</span></span><br><span class="line"><span class="code">//还原结果为 &lt;h1 title=&quot;abc&quot;&gt;这是一个 h1 标签&lt;span&gt;1234&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;</span></span><br><span class="line"><span class="code">console.log(newstr)</span></span><br><span class="line"><span class="code">```</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="section">### 开源协议</span></span><br><span class="line">ISC</span><br></pre></td></tr></table></figure><h4 id="8-7-发布包"><a href="#8-7-发布包" class="headerlink" title="8.7 发布包"></a>8.7 发布包</h4><p>请读者自己去看<a href="https://blog.csdn.net/u010059669/article/details/109715342">npm包发布详细教程_醉逍遥neo的博客-CSDN博客_npm 发布</a> 或者是去配套视频看P36</p><br/><br/><h2 id="七、Express"><a href="#七、Express" class="headerlink" title="七、Express"></a>七、Express</h2><h3 id="1、什么是-Express"><a href="#1、什么是-Express" class="headerlink" title="1、什么是 Express"></a>1、什么是 Express</h3><p>Express 是基于 Node.js 平台，快速、开放、极简的 Web 开发框架。其作用和 Nnode.js 内置 http 模块类似，是专门用来创建 Web 服务器的。Express 的本质就是一个 npm 上的第三方包，提供了快速创建 Web 服务器的便捷方法。相比于 http 内置模块，Express 模块能极大地提高开发效率。</p><p>官方网址：<a href="https://www.expressjs.com.cn/">Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网 (expressjs.com.cn)</a></p><br/><h3 id="2、安装-Express"><a href="#2、安装-Express" class="headerlink" title="2、安装 Express"></a>2、安装 Express</h3><p>因为视频是使用的 4.17.1 版本的包，所以我们这里也将以 4.17.1 版本的包来作示范。同时，以下所有有关 Express 的操作使用的都是 4.17.1 版本的包。</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">npm i express@4.17.1</span><br></pre></td></tr></table></figure><p>通过在终端内输入以上代码来安装相应版本的包。</p><br/><h3 id="3、Express-的基本使用"><a href="#3、Express-的基本使用" class="headerlink" title="3、Express 的基本使用"></a>3、Express 的基本使用</h3><h4 id="3-1-创建最基本的-Web-服务器"><a href="#3-1-创建最基本的-Web-服务器" class="headerlink" title="3.1 创建最基本的 Web 服务器"></a>3.1 创建最基本的 Web 服务器</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 Express 包</span></span><br><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="comment">//创建 Web 服务器</span></span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//启动 Web 服务器</span></span><br><span class="line"><span class="comment">//调用 app.listen(端口号，启动成功后的回调函数)，启动服务器</span></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/28/eKQ3vljtcrW6aFS.png"></p><h4 id="3-2-监听-GET-请求"><a href="#3-2-监听-GET-请求" class="headerlink" title="3.2 监听 GET 请求"></a>3.2 监听 GET 请求</h4><p><strong>什么是 GET 请求？</strong></p><p>GET 请求是最常见的一种请求方式，当客户端要从服务器中读取文档时，当点击网页上的链接或者通过在浏览器的地址栏输入网址来浏览网页的，使用的都是GET方式。GET方法要求服务器将URL定位的资源放在响应报文的数据部分，回送给客户端。</p><p>通过 <code>app.get()</code> 方法，可以监听到客户端的  GET 请求，具体语法格式如下：</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></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;请求 URL&#x27;</span>, <span class="keyword">function</span>(<span class="params">req,res</span>)&#123;</span><br><span class="line"><span class="comment">//处理函数</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><ul><li>参数1：客户端请求的 URL 地址</li><li>参数2：请求对应的处理函数<ol><li>req：请求对象（包含了与请求相关的属性与方法）</li><li>res：响应对象（包含了与响应相关的属性与方法）</li></ol></li></ul><h4 id="3-3-监听-POST-请求"><a href="#3-3-监听-POST-请求" class="headerlink" title="3.3 监听 POST 请求"></a>3.3 监听 POST 请求</h4><p><strong>什么是 POST 请求？</strong></p><p>对于上面提到的不适合使用GET方式的情况，可以考虑使用POST方式，因为使用POST方法可以允许客户端给服务器提供信息较多。POST方法将请求参数封装在HTTP请求数据中，以名称&#x2F;值的形式出现，可以传输大量数据，这样POST方式对传送的数据大小没有限制，而且也不会显示在URL中。</p><p>通过 <code>app.post()</code> 方法，可以监听客户端的 POST 请求，具体语法格式如下：</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></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;请求 URL&#x27;</span>, <span class="keyword">function</span>(<span class="params">req,res</span>)&#123;</span><br><span class="line"><span class="comment">//处理函数</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><ul><li><p>参数1：客户端请求的 URL 地址</p></li><li><p>参数2：请求对应的处理函数</p><ol><li><p>req：请求对象（包含了与请求相关的属性与方法）</p></li><li><p>res：响应对象（包含了与响应相关的属性与方法）</p></li></ol></li></ul><h4 id="3-4-把内容响应给客户端"><a href="#3-4-把内容响应给客户端" class="headerlink" title="3.4 把内容响应给客户端"></a>3.4 把内容响应给客户端</h4><p>通过 res.send() 方法，可以把处理好的内容，发送给客户端，具体语法格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">res.<span class="title function_">send</span>(<span class="comment">/*发送内容*/</span>)</span><br></pre></td></tr></table></figure><h4 id="3-5-有关-GET-和-POST-和-SEND-方法的样例"><a href="#3-5-有关-GET-和-POST-和-SEND-方法的样例" class="headerlink" title="3.5 有关 GET 和 POST 和 SEND 方法的样例"></a>3.5 有关 GET 和 POST 和 SEND 方法的样例</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 Express 包</span></span><br><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="comment">//创建 Web 服务器</span></span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//监听客户端的 GET 和 POST 请求</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/user&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//调用 res.send() 方法，向客户端响应一个 JSON 对象</span></span><br><span class="line">    res.<span class="title function_">send</span>(&#123;name :<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">20</span>,<span class="attr">sex</span>:<span class="string">&#x27;男&#x27;</span>&#125;)</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;user&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//调用 res.,send() 方法，向客户端响应一个文本字符串</span></span><br><span class="line">    res.<span class="title function_">send</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="comment">//调用 app.listen(端口号，启动成功后的回调函数)，启动服务器</span></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>按住 ctrl 并单击地址，然后在打开的浏览器上的地址后输入 <code>/user</code> ，会有以下结果：</p><p><img src="https://s2.loli.net/2022/04/28/JrcQaOGBiyeAXPo.png"></p><p>但此时我们无法看到 POST 的结果。</p><p>所以在这里我们可以使用一个叫做 <strong>Postman</strong> 的软件，在这个软件上可以进行服务器的操作。</p><p>下载地址：<a href="https://www.postman.com/downloads/">Download Postman | Get Started for Free</a></p><p>下载安装注册完账号之后就可以开始使用了。</p><p>我们打开 Postman 并登录账号，然后点击 Overview 旁边的 ‘+’ 号创建新的页面：</p><p><img src="https://s2.loli.net/2022/04/28/VfxnZtgSpKhd6lE.png"></p><p>在新的页面中有一个文本输入框，左边有 GET 的字样，在这个文本框中输入 <a href="http://127.0.0.1/user">http://127.0.0.1/user</a> ，并单击右边的 Send 来得到客户端的请求：</p><p><img src="https://s2.loli.net/2022/04/28/gUf6mhr8Vd7QyDv.png"></p><p>然后我们再新建一个页面，这次我们将 GET 换成 POST 并再次重复之前的操作：</p><p><img src="https://s2.loli.net/2022/04/28/w2y89E4ijepnKso.png"></p><h4 id="3-6-获取-URL-中携带的查询参数"><a href="#3-6-获取-URL-中携带的查询参数" class="headerlink" title="3.6 获取 URL 中携带的查询参数"></a>3.6 获取 URL 中携带的查询参数</h4><p>通过 <code>req.query()</code> 对象，可以访问到客户端通过查询字符串的形式，发送到服务器的参数：</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></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//req.query 默认是一个空对象</span></span><br><span class="line"><span class="comment">//客户端使用 ?=name=zs&amp;age=20 这种查询字符串形式，发送到服务器的参数</span></span><br><span class="line"><span class="comment">//可以通过 req.query 对象访问到，例如：</span></span><br><span class="line"><span class="comment">//req.query.name   req.query.age</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(req.<span class="property">query</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>样例代码：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/user&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(&#123;name :<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">20</span>,<span class="attr">sex</span>:<span class="string">&#x27;男&#x27;</span>&#125;)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/user&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;请求成功！&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//通过 req.query 可以获取到客户端发送过来的查询参数</span></span><br><span class="line">    <span class="comment">//默认情况下是一个空对象</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(req.<span class="property">query</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(req.<span class="property">query</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p>我们重启服务器，然后再 Postman 上 GET 一下，会发现底下是一个空对象</p><p><img src="https://s2.loli.net/2022/04/29/1WSnBZ5XxaDNCJE.png"></p><p>这证明了默认情况下 <code>req.query</code> 是一个空对象。接着我们再在地址后面输入 <code>?name=zs&amp;age=20</code> 点击 send，会发现以下结果：</p><p><img src="https://s2.loli.net/2022/04/29/jdn7ewxPiBXgoO3.png"></p><p>我们发现当我们在 ① 位置通过查询字符串形式输入 <code>?name=zs&amp;age=20</code> 这样的方式来设置参数的时候，在 ② 位置会实时同步进行更新。所以我们也可以在 ② 位置设置参数，而当我们在 ② 位置设置参数的时候，会发现 ① 位置也会实时同步更新，读者可以自行尝试。</p><h4 id="3-7-获取-URL-中的动态参数"><a href="#3-7-获取-URL-中的动态参数" class="headerlink" title="3.7 获取 URL  中的动态参数"></a>3.7 获取 URL  中的动态参数</h4><p>通过 <code>req.params</code> 对象，可以访问到 URL 中，通过 ： 匹配到的动态参数：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//URL 地址中，可以通过 :参数名 的形式，匹配动态参数值</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/user/:id&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//req.params 默认是一个空对象</span></span><br><span class="line"><span class="comment">//里面存放着通过 : 动态匹配到的参数值</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(req.<span class="property">params</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>样例代码：</p><p>在上一节代码的后面插入以下语句</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//注意这里的 :id 是一个动态的参数</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/user/:id&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//req.params 是动态匹配到的 URL 参数，默认是一个空对象</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(req.<span class="property">params</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(req.<span class="property">params</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/29/a1X4MkbxHDrIYCK.png"></p><p>注意：</p><ul><li><p>我们在 <code>user/</code> 后面输入的  <code>:id</code> 是一个动态参数的值，你输入 5 后面显示的就是 5；如果后面输入的 1 后面显示的就是 1</p><p><img src="https://s2.loli.net/2022/04/29/ynAqmkoPZetwvsQ.png"></p></li><li><p>代码中 : 后的 id 是参数的名字，是可以自行输入的，只要合法就行</p><p><img src="https://s2.loli.net/2022/04/29/p6aejLUBfPNVWw7.png"></p></li><li><p><code>user/</code> 后可以加若干动态参数</p><p><img src="https://s2.loli.net/2022/04/29/fvuZJk6bdWE3xUC.png"></p></li></ul><br/><h3 id="4、托管静态资源"><a href="#4、托管静态资源" class="headerlink" title="4、托管静态资源"></a>4、托管静态资源</h3><h4 id="4-1-express-static"><a href="#4-1-express-static" class="headerlink" title="4.1 express.static()"></a>4.1 express.static()</h4><p>express 提供了一个非常好用的函数，叫做 <code>express.static()</code>，通过它我们可以非常方便地创建一个静态资源服务器。例如，通过以下代码可以将 public 目录下的图片、CSS 文件。JavaScript 文件对外开放访问了：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">static</span>(<span class="string">&#x27;public&#x27;</span>))</span><br></pre></td></tr></table></figure><p>注意：Express 在指定的静态目录中查找文件，并对外提供资源的访问路径。因此存放静态文件的目录名不会出现在 URL 中。</p><p>样例代码：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用 express.static() 方法，快速的对外提供静态资源</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">static</span>(<span class="string">&#x27;./clock&#x27;</span>))</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/29/FurgOBK1Sobajxm.png"></p><p>可以正常访问该网页。</p><p>如果要托管多个静态资源目录就需要多次调用 <code>express.static()</code> 函数，该函数会根据目录的添加顺序查找所需的文件。</p><h4 id="4-2-挂载路径前缀"><a href="#4-2-挂载路径前缀" class="headerlink" title="4.2 挂载路径前缀"></a>4.2 挂载路径前缀</h4><p>如果希望再拖管的静态资源访问路径之前，挂载路径前缀，则可以使用如下的方式：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">use</span>(<span class="string">&#x27;./public&#x27;</span>,express.<span class="title function_">static</span>(<span class="string">&#x27;public&#x27;</span>))</span><br></pre></td></tr></table></figure><p>样例代码：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//挂载路径前缀 /abc</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">&#x27;/abc&#x27;</span>,express.<span class="title function_">static</span>(<span class="string">&#x27;./clock&#x27;</span>))</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/29/mYVuBDOs7WdzScp.png"></p><br/><h3 id="5、nodemon"><a href="#5、nodemon" class="headerlink" title="5、nodemon"></a>5、nodemon</h3><h4 id="5-1-什么是-nodemon"><a href="#5-1-什么是-nodemon" class="headerlink" title="5.1 什么是 nodemon"></a>5.1 什么是 nodemon</h4><p>在编写调试 Node.js 项目的时候，如果修改了项目的代码，则需要频繁的手动 close 掉，然后再重新启动，非常繁琐。现在，我们可以使用 nodemon 这个工具来监听项目文件的变动。当代码被修改之后，nodemon 会自动帮我们重启项目，极大方便开发和调试。</p><h4 id="5-2-安装-nodemon"><a href="#5-2-安装-nodemon" class="headerlink" title="5.2 安装 nodemon"></a>5.2 安装 nodemon</h4><p>我们在终端内输入 <strong><code>npm i -g nodemon</code></strong> 来安装全局的 nodemon。</p><p><img src="https://s2.loli.net/2022/04/29/ytnGrps261NMekY.png"></p><h4 id="5-3-使用-nodemon"><a href="#5-3-使用-nodemon" class="headerlink" title="5.3 使用 nodemon"></a>5.3 使用 nodemon</h4><p>现在，我们可以用 <code>nodemon</code> 命令开替换 <code>node</code> 命令，使用 <code>nodemon test.js</code> 来启动项目。这样做的好处是：代码被修改之后，会被 nodemon 监听到，从而实现自动重启项目的效果。</p><p>样例代码 (这里使用第一章第一节的代码，readFile)：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//成功，1.txt 文件中写了 &#x27;111&#x27;</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(<span class="string">&#x27;./files/1.txt&#x27;</span>,<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(dataStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/29/gGiRwtm14BMfEqx.png"></p><p>会发现多了很多行。现在我们将再原代码的底下添加以下代码：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//失败,没有11.txt文件</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(<span class="string">&#x27;./files/11.txt&#x27;</span>,<span class="string">&#x27;utf8&#x27;</span>,<span class="keyword">function</span>(<span class="params">err,dataStr</span>)&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;--------&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(dataStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>然后，我们按下 Ctrl + S 来保存项目。我们会发现终端内瞬间刷新了，并且执行了新的代码</p><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/29/C7bnEhPJkou9Oe6.png" alt="image-20220429145720656"></p><p>Ctrl + C 来结束。</p><br/><h3 id="6、Express-路由"><a href="#6、Express-路由" class="headerlink" title="6、Express 路由"></a>6、Express 路由</h3><h4 id="6-1-什么是路由"><a href="#6-1-什么是路由" class="headerlink" title="6.1 什么是路由"></a>6.1 什么是路由</h4><p>广义上来讲，路由就是映射关系。在 Expresss 中，路由指的是<strong>客户端的请求</strong>与<strong>服务期处理函数</strong>之间的映射关系。</p><p>Express 中的路由分 3 部分组成，分别是<strong>请求的类型</strong>、<strong>请求的 URL 地址</strong>、<strong>处理函数</strong>，其具体格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">METHOD</span>(<span class="variable constant_">PATH</span>,<span class="variable constant_">HANDLER</span>)</span><br></pre></td></tr></table></figure><ul><li>参数1：METHOD 对应的是请求的类型，可以是 GET 或者是 POST</li><li>参数2：PATH 对应的是请求的 URL 地址</li><li>参数3：HANDLER 对应的是处理函数，通过前面的请求类型和请求的地址，然后来调用处理函数</li></ul><h4 id="6-2-Express-中的路由的例子"><a href="#6-2-Express-中的路由的例子" class="headerlink" title="6.2 Express 中的路由的例子"></a>6.2 Express 中的路由的例子</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//匹配 GET 请求，并且请求 URL 为 /</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Hello World!&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//匹配 POST 请求，且请求为 URL 为 /</span></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Got a POST request&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//启动 Web 服务器</span></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p>GET</p><p><img src="https://s2.loli.net/2022/04/29/aGqhkQsRA5KWXtJ.png"></p><p>POST</p><p><img src="https://s2.loli.net/2022/04/29/9xXNsAlIJngVhp2.png"></p><h4 id="6-3-路由匹配过程"><a href="#6-3-路由匹配过程" class="headerlink" title="6.3 路由匹配过程"></a>6.3 路由匹配过程</h4><p>每当一个请求到达服务器之后，需要先经过路由的匹配，只有匹配成功之后，才会调用对应的处理函数。</p><p>在匹配时，会按照路由的顺序进行匹配，如果请求类型和请求 URL 同时匹配成功，则 Express 会将这次请求，转交给对应的 function 函数进行处理。</p><p><img src="https://s2.loli.net/2022/04/29/yFtDmscgw8n4WEB.png"></p><p>注意：</p><ul><li>按照定义的先后顺序进行匹配</li><li>请求类型和请求的 URL 同时匹配成功，才会调用对应的处理函数</li></ul><h4 id="6-4-路由的使用"><a href="#6-4-路由的使用" class="headerlink" title="6.4 路由的使用"></a>6.4 路由的使用</h4><h5 id="6-5-1-最简单的用法"><a href="#6-5-1-最简单的用法" class="headerlink" title="6.5.1 最简单的用法"></a>6.5.1 最简单的用法</h5><p>在 Express 中使用路由最简单的方式，就是把路由挂载到 app 上，具体代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//挂载路由</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Hello World!&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Post Request.&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">//启动 Web 服务器</span></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p>GET</p><p><img src="https://s2.loli.net/2022/04/29/aGqhkQsRA5KWXtJ.png"></p><p>POST</p><p><img src="https://s2.loli.net/2022/04/29/4iWaXoJd3TFkC1U.png"></p><h5 id="6-5-2-模块化路由"><a href="#6-5-2-模块化路由" class="headerlink" title="6.5.2 模块化路由"></a>6.5.2 模块化路由</h5><p>为了方便对路由进行模块化的管理，Express 不建议将路由直接挂载到 app 上，而是推荐将路由抽离为单独的模块。</p><p>将路由抽离为单独模块的步骤如下：</p><ol><li>创建路由模块对应的 .js 文件</li><li>调用 <code>express.Router()</code> 函数创建路由对象</li><li>向路由对象上挂载具体路由</li><li>使用 <code>module.exports</code> 向外共享路由对象</li><li>使用 <code>app.use()</code> 函数注册路由模块</li></ol><p>我们在文件夹下新建一个 router.js 的文件，在里面写入代码</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//创建具体的路由</span></span><br><span class="line"><span class="keyword">var</span> router = express.<span class="property">Router</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//挂载具体的路由</span></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&#x27;/user/list&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Get user list.&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">router.<span class="title function_">post</span>(<span class="string">&#x27;/user/add&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Add new user.&#x27;</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="variable language_">module</span>.<span class="property">exports</span> = router</span><br></pre></td></tr></table></figure><p>在这之后我们就可以在 test.js 中注册路由了</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</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> router = <span class="built_in">require</span>(<span class="string">&#x27;./router.js&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//注册路由模块</span></span><br><span class="line">app.<span class="title function_">use</span>(router)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p>GET</p><p><img src="https://s2.loli.net/2022/04/30/Qcm4TFxW1KDpX6Y.png"></p><p>POST</p><p><img src="https://s2.loli.net/2022/04/30/SvKlHkVf3jAPGUu.png"></p><p>注意：<code>app.use()</code> 函数的作用就是用来注册全局中间件</p><h4 id="6-5-为路由模块添加前缀"><a href="#6-5-为路由模块添加前缀" class="headerlink" title="6.5 为路由模块添加前缀"></a>6.5 为路由模块添加前缀</h4><p>与之前挂载路径前缀一样，我们也可以为路由添加前缀，其具体语法格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">use</span>(<span class="string">&#x27;/api&#x27;</span>,router)</span><br></pre></td></tr></table></figure><p>在这里我们就已经为 router 路由添加了 <strong><code>/api</code></strong> 的前缀。</p><br/><h3 id="7、Express-中间件"><a href="#7、Express-中间件" class="headerlink" title="7、Express 中间件"></a>7、Express 中间件</h3><h4 id="7-1-什么是中间件"><a href="#7-1-什么是中间件" class="headerlink" title="7.1 什么是中间件"></a>7.1 什么是中间件</h4><p>中间件（Middleware），特指业务流程的中间处理环节。</p><p>这就好比是日常处理污水的时候一般都要经历三个环节，从而保证处理过后的污水能够达到排放标准。</p><p><img src="https://s2.loli.net/2022/04/30/l6Dy1KmHPQiGSfp.png"></p><p>而这中间处理污水的三个环节就可以称为**“中间件”**</p><h5 id="7-1-1-Express-中间件的调用流程"><a href="#7-1-1-Express-中间件的调用流程" class="headerlink" title="7.1.1 Express 中间件的调用流程"></a>7.1.1 Express 中间件的调用流程</h5><p>当一个请求到达 Express 服务器之后，可以连续调用多个中间件，从而对这次请求进行预处理。</p><p><img src="https://s2.loli.net/2022/04/30/gFshnVvj1Zu2wbC.png"></p><h5 id="7-1-2-Express-中间件的格式"><a href="#7-1-2-Express-中间件的格式" class="headerlink" title="7.1.2 Express 中间件的格式"></a>7.1.2 Express 中间件的格式</h5><p>Express 中间件本质上就是一个 function 处理函数，其具体结构如下：</p><p><img src="https://s2.loli.net/2022/04/30/mJ9faWNObxcVsLB.png"></p><p>这个 <code>next()</code> 函数是实现多个中间件连续调用的关键，它表示把流转关系转交给下一个中间件或者路由。</p><h4 id="7-2-定义一个最简单的中间件"><a href="#7-2-定义一个最简单的中间件" class="headerlink" title="7.2 定义一个最简单的中间件"></a>7.2 定义一个最简单的中间件</h4><p>根据上面的中间件的格式我们就可以来试着定义一个最简单的中间件，其代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义一个最简单的中间件</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">mw</span> = (<span class="params">req,res,next</span>)=&gt;&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;这是最简单的一个中间件&#x27;</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//把流转关系，转交给下一个中间件或者是路由</span></span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="7-3-全局中间件"><a href="#7-3-全局中间件" class="headerlink" title="7.3 全局中间件"></a>7.3 全局中间件</h4><h5 id="7-3-1-定义全局中间件"><a href="#7-3-1-定义全局中间件" class="headerlink" title="7.3.1 定义全局中间件"></a>7.3.1 定义全局中间件</h5><p>客户端发起的任何请求到达服务器之后，都会触发的中间件叫做全局生效的中间件。在定义完一个中间件之后通过 <code>app.use()</code> 函数就可以注册一个全局生效的中间件，其代码如下：</p><figure class="highlight js"><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">//将 mw 注册成为全局生效的中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(mw)</span><br></pre></td></tr></table></figure><p>知道了这么多我们就可以来编写一个简单的需要用到中间件的代码了：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</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> <span class="title function_">mw</span> = (<span class="params">req,res,next</span>)=&gt;&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;这是最简单的一个中间件&#x27;</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//把流转关系，转交给下一个中间件或者是路由</span></span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//将 mw 注册成为全局生效的中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(mw)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/30/mac4LpDKYBTvQMF.png"></p><h5 id="7-3-2-全局生效的中间件的简化形式"><a href="#7-3-2-全局生效的中间件的简化形式" class="headerlink" title="7.3.2 全局生效的中间件的简化形式"></a>7.3.2 全局生效的中间件的简化形式</h5><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></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;这是一个简单的中间件&#x27;</span>)</span><br><span class="line"><span class="title function_">next</span>()</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h5 id="7-3-3-定义多个全局中间件"><a href="#7-3-3-定义多个全局中间件" class="headerlink" title="7.3.3 定义多个全局中间件"></a>7.3.3 定义多个全局中间件</h5><p>可以使用 <code>app.use()</code> 函数来连续定义多个中间件。客户端请求到达服务器之后，会按照中间件定义的先后顺序一次进行调用，示例代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">mw1</span> = (<span class="params">req,res,next</span>)=&gt;&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;这是中间件1&#x27;</span>)</span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">mw2</span> = (<span class="params">req,res,next</span>)=&gt;&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;这是中间件2&#x27;</span>)</span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(mw1,mw2)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>当我们点击 Send 之后控制台内会显示如下：</p><p><img src="https://s2.loli.net/2022/04/30/34gH9Bvqo2RINAX.png"></p><h4 id="7-4-局部中间件"><a href="#7-4-局部中间件" class="headerlink" title="7.4 局部中间件"></a>7.4 局部中间件</h4><p>不适用 <code>app.use()</code> 定义的中间件就叫做局部生效的中间件，示例代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</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> <span class="title function_">mw</span> = (<span class="params">req,res,next</span>)=&gt;&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;这是中间件函数&#x27;</span>)</span><br><span class="line">    <span class="title function_">next</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">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,mw,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/user&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;User page&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行的时候我们发现在 <code>/</code> 下 <code>send</code> 时，终端无任何反应，而当在 <code>/user</code> 下 <code>send</code> 时，终端会显示 <strong>‘这是中间件函数’</strong>。</p><h5 id="7-4-1-定义多个局部中间件"><a href="#7-4-1-定义多个局部中间件" class="headerlink" title="7.4.1 定义多个局部中间件"></a>7.4.1 定义多个局部中间件</h5><p>可以在路由中通过以下两种等价的方式，使用多个局部中间件：</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></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,mw1,mw2,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,[mw1,mw2],<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>这里就不再进行多的代码演示，请自主完成。</p><h4 id="7-5-中间件的作用"><a href="#7-5-中间件的作用" class="headerlink" title="7.5 中间件的作用"></a>7.5 中间件的作用</h4><p>多个中间件之间共同享用一份 req 和 res 。基于这样的特性，我们可以在上游的中间件中，统一为 req 和 res 对象添加自定义的属性和方法，供下游的中间件或者是路由进行使用。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">mw</span> = (<span class="params">req,res,next</span>)=&gt;&#123;</span><br><span class="line">    <span class="comment">//获取到请求到达服务器的时间</span></span><br><span class="line">    <span class="keyword">const</span> time = <span class="title class_">Date</span>.<span class="title function_">now</span>()</span><br><span class="line">    <span class="comment">//为 req 对象，挂载自定义属性，从而把时间共享给后面的所有路由</span></span><br><span class="line">    req.<span class="property">startTime</span> = time</span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;</span><br><span class="line">app.<span class="title function_">use</span>(mw)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page, &#x27;</span>+req.<span class="property">startTime</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/30/OboW6FsD8Mx2wHQ.png"></p><h4 id="7-6-中间件的五个使用注意事项"><a href="#7-6-中间件的五个使用注意事项" class="headerlink" title="7.6 中间件的五个使用注意事项"></a>7.6 中间件的五个使用注意事项</h4><ol><li>一定要在路由之前注册中间件</li><li>客户端发送过来的请求，可以连续调用多个中间件进行处理</li><li>执行完中间件的业务代码之后，不要忘记调用 <code>next()</code> 函数</li><li>为了防止代码逻辑混乱，调用 <code>next()</code> 函数后不要再写额外的代码</li><li>连续调用多个中间件时，多个中间件之间，共享 <code>req</code> 和 <code>res</code> 对象</li></ol><h4 id="7-7-中间件的分类"><a href="#7-7-中间件的分类" class="headerlink" title="7.7 中间件的分类"></a>7.7 中间件的分类</h4><h5 id="7-7-1-应用级别的中间件"><a href="#7-7-1-应用级别的中间件" class="headerlink" title="7.7.1 应用级别的中间件"></a>7.7.1 应用级别的中间件</h5><p>通过 <code>app.use()</code> 或者 <code>app.get()</code> 或者 <code>app.post()</code>，绑定到 app 实例上的中间件，叫做应用级别的中间件，代码示例如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//应用级别的中间件(全局中间件)</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="title function_">next</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">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,mw,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h5 id="7-7-2-路由级别的中间件"><a href="#7-7-2-路由级别的中间件" class="headerlink" title="7.7.2 路由级别的中间件"></a>7.7.2 路由级别的中间件</h5><p>绑定到 express.Router() 实例上的中间件，都可以叫做是路由级别的中间件。它的用法和应用级别中间没有任何区别。只不过，应用级别中间是绑定到 app 实例上，路由级别中间件绑定到 router 实例上，代码示例如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"><span class="keyword">const</span> router = express.<span class="title class_">Router</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//路由级别的中间件</span></span><br><span class="line">router.<span class="title function_">use</span>(<span class="function">(<span class="params">req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Time:&#x27;</span>,<span class="title class_">Date</span>.<span class="title function_">now</span>())</span><br><span class="line">    <span class="title function_">next</span>()</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">&#x27;/&#x27;</span>,router)</span><br></pre></td></tr></table></figure><h5 id="7-7-3-错误级别的中间件"><a href="#7-7-3-错误级别的中间件" class="headerlink" title="7.7.3 错误级别的中间件"></a>7.7.3 错误级别的中间件</h5><p>错误级别的中间件的作用：专门用来捕获整个项目中发生的异常错误，从而防止项目异常崩溃的问题。</p><p>在错误级别的中间件中的 function 处理函数中，必须包含 4 个形参，形参顺序从前到后，分别是 (err, req, res, next)。</p><p>首先我们来测试一下什么是崩溃</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//人为的制造错误</span></span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;服务期内部发生错误！&#x27;</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>在 vscode 中会发现 <code>res.send(&#39;Home page&#39;)</code> 这一句被隐去了，然后我们再在 Postman 中测试一下，会得到以下结果：</p><p><img src="https://s2.loli.net/2022/04/30/nOyP8d6Fu45bsaB.png"></p><p>那么整个项目就已经崩溃了。</p><p>那接下来我们就可以使用错误级别的中间件来防止崩溃，代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//人为的制造错误</span></span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;服务期内部发生错误！&#x27;</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Home page&#x27;</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">app.<span class="title function_">use</span>(<span class="function">(<span class="params">err,req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;发生了错误！ &#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Error: &#x27;</span>+err.<span class="property">message</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/04/30/Od8Hyzi9cxLTw5k.png"></p><p>项目虽然有错误，但却没有崩溃。</p><p>注意：错误级别的中间件必须注册在所有路由之后。</p><h5 id="7-7-4-Express-内置的中间件"><a href="#7-7-4-Express-内置的中间件" class="headerlink" title="7.7.4 Express 内置的中间件"></a>7.7.4 Express 内置的中间件</h5><p>自从 Express 4.16.0 版本开始，Express 内置了 3 个常用的中间件，极大的提高了 Express 项目的开发效率和体验：</p><ol><li><code>express.static</code> 快速托管静态资源的内置中间件，例如：HTML 文件、图片、CSS  样式等（无兼容性）</li><li><code>express.json</code> 解析 JSON 格式的请求体数据（有兼容性，尽在 4.16.0+ 版本中可用）</li><li><code>express.urlencoded</code> 解析 URL-encoded 格式的请求体数据（有兼容性，仅在 4.16.0+ 版本中可用）</li></ol><p>其使用方法很简单，如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//配置解析 application/json 格式数据的内置中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">json</span>())</span><br><span class="line"><span class="comment">//配置解析 application/x-www-urlencoded 格式数据的内置中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>(&#123;<span class="attr">extended</span>:<span class="literal">false</span>&#125;))</span><br></pre></td></tr></table></figure><p>接下来我们先来看看 <code>express.json()</code> 的有关使用：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//通过 express.json() 这个中间件，解析表单中的 JSON 格式的数据</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">json</span>())</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/user&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//在服务器，可以使用 req.body 这个属性，来接收客户端发送过来的请求体数据</span></span><br><span class="line">    <span class="comment">//默认情况下，如果不配置解析表单数据的中间件，则 req.body 默认等于 undefined</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(req.<span class="property">body</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;OK&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>在 Postman 中运行之后我们进行如下操作：</p><p><img src="https://s2.loli.net/2022/05/03/7uQ3qI2pnXARNCj.png"></p><p>之后我们在主体框里面编写代码：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span><span class="string">&quot;zs&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;age&quot;</span><span class="punctuation">:</span><span class="number">20</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>我们再次 send 一下，然后回到 vscode 里可以看到控制台显示：</p><p><img src="https://s2.loli.net/2022/05/03/QZXdr9SzAN62HgY.png"></p><hr><p>接着再来看看 express.urlencoded() 的有关使用：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//通过 express.urlencoded() 这个中间件，来解析表单中的 url-encoded 格式的数据</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>(&#123;<span class="attr">extended</span>:<span class="literal">false</span>&#125;))</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/book&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//在服务端内，可以通过 req.body 来获取 JSON 格式的表单数据和 url-encoded 格式的数据</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(req.<span class="property">body</span>)</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;ok&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>在 Postman 中进行如下操作：</p><p><img src="https://s2.loli.net/2022/05/03/i3TB5YorGhbpM4a.png"></p><p>我们回到 vscode 中，可以在控制台内看到：</p><p><img src="https://s2.loli.net/2022/05/03/8BMVcJvSrndExeT.png"></p><h5 id="7-7-5-第三方中间件"><a href="#7-7-5-第三方中间件" class="headerlink" title="7.7.5 第三方中间件"></a>7.7.5 第三方中间件</h5><p>非 Express 官方内置的，而是由第三方开发出来的中间级看，叫做第三方中间件。在项目中，大家可以按需下载并配置第三方中间件，从而提高项目的开发效率。</p><p>其使用步骤如下：</p><ol><li>运行 <code>npm install body-parser</code> 安装中间件</li><li>使用 <code>require</code> 导入中间件</li><li>调用 <code>app.use()</code> 注册并使用中间件</li></ol><h5 id="7-7-6自定义中间件"><a href="#7-7-6自定义中间件" class="headerlink" title="7.7.6自定义中间件"></a>7.7.6自定义中间件</h5><p>步骤：</p><ol><li>定义中间件</li><li>监听 req 的 data 事件</li><li>监听 req 的 end 事件</li><li>使用 querystring 模块解析请求体数据</li><li>讲解洗出来的数据对象挂载为 req.body</li><li>将自定义中间件封装为模块</li></ol><p>下面我们手动模拟一个类似于 <code>express.urlencoded</code> 这样的中间件，来解析 POST 提交到服务器的表单数据。</p><p><strong>首先我们定义一个全局中间件</strong></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//这是解析表单数据的中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//定义中间件具体的业务逻辑</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><hr><p><strong>第二步我们来编写监听 req 的 data 事件的代码</strong></p><p>在中间件中，需要监听 req 对象的 data 事件，来获取客户端发送到服务器的数据。</p><p>如果数据量比较大，无法一次性发送完毕，则客户端会把数据切割后，分批发送到服务器。所以 data 事件可能会触发多次，每一次触发 data 事件时，获取到数据只是完整数据的一部分，需要手动对接受到的数据进行拼接。</p><p>代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//1、定义一个 str 字符串，专门用来存储客户端发送过来的请求体数据</span></span><br><span class="line"><span class="keyword">let</span> str = <span class="string">&#x27;&#x27;</span></span><br><span class="line">   <span class="comment">//2、监听 req 的 data 事件</span></span><br><span class="line">   req.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>,<span class="function">(<span class="params">chunk</span>)=&gt;</span>&#123;</span><br><span class="line">       str += chunk</span><br><span class="line">   &#125;)</span><br></pre></td></tr></table></figure><hr><p><strong>第三步我们来编写监听 req 的 end 事件的代码</strong></p><p>当请求体数据接收完毕之后，会自动触发 req 的 end 事件。</p><p>因此，我们可以在 req 的 end 事件中，拿到并处理完整的请求体数据。</p><p>代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//3、监听 req 的 end 事件</span></span><br><span class="line">   req.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">       <span class="comment">//在 str 中存储的就是完整的请求体数据</span></span><br><span class="line">       <span class="variable language_">console</span>.<span class="title function_">log</span>(str)</span><br><span class="line">       <span class="comment">//<span class="doctag">TODO:</span> 把字符串格式的请求体数据，解析成对象格式</span></span><br><span class="line">   &#125;)</span><br></pre></td></tr></table></figure><p>我们可以尝试着先来看看能不能打印出请求体的数据</p><p><img src="https://s2.loli.net/2022/05/04/FEzaBI8n1NhTL5D.png"></p><hr><p><strong>第三步我们使用 querystring 模块解析请求体数据</strong></p><p>Node.js 中内置了一个 querystring 模块，专门用来处理查询字符串。通过这个模块提供的 <code>parse()</code> 函数，可以轻松把查询字符串，解析成对象的格式。</p><p>先在开头导入 querystring 模块</p><figure class="highlight js"><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">//导入 querystring 模块</span></span><br><span class="line"><span class="keyword">const</span> qs = <span class="built_in">require</span>(<span class="string">&#x27;querystring&#x27;</span>)</span><br></pre></td></tr></table></figure><p>然后在 end 中写进代码：</p><figure class="highlight js"><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="keyword">const</span> body = qs.<span class="title function_">parse</span>(str)</span><br><span class="line">   <span class="variable language_">console</span>.<span class="title function_">log</span>(body)</span><br></pre></td></tr></table></figure><p>并重复第二步的测试步骤会发现：</p><p><img src="https://s2.loli.net/2022/05/04/n8loa5WqyFMSp21.png"></p><hr><p><strong>第四步将解析出来的数据对象挂载为 req.body</strong></p><p>上游的中间件和下游的中间件以及路由之间，共享用一份 req 和 res。因此，我们可以将解析出来的数据挂在为 req 的自定义属性，命名为 <code>req.body</code>，供下游使用。</p><p>在 end 中写进代码：</p><figure class="highlight js"><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">req.<span class="property">body</span> = body</span><br><span class="line">  <span class="title function_">next</span>()</span><br></pre></td></tr></table></figure><p>并且将 <code>res.send(&#39;ok&#39;)</code> 更改成 <code>res.send(req.body)</code></p><p>之后我们再进行测试：</p><p><img src="https://s2.loli.net/2022/05/04/mU9ItScAVX5Zuzr.png"></p><p>服务器能够接受到返回的结果。</p><hr><p><strong>最后一步将自定义中间件封装为模块</strong></p><p>为了优化代码的结构，我们可以把自定义的中间件函数，封装为独立的模块。</p><p>先定义一个常量将 <code>res.use()</code> 内的内容封装起来，然后再向外导入</p><p>代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bodyParser = (<span class="function">(<span class="params">req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;）</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = bodyParser</span><br></pre></td></tr></table></figure><p>删去我们不需要的代码，其整个代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 querystring 模块</span></span><br><span class="line"><span class="keyword">const</span> qs = <span class="built_in">require</span>(<span class="string">&#x27;querystring&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//这是解析表单数据的中间件</span></span><br><span class="line"><span class="keyword">const</span> bodyParser = (<span class="function">(<span class="params">req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//定义中间件具体的业务逻辑</span></span><br><span class="line">    <span class="comment">//1、定义一个 str 字符串，专门用来存储客户端发送过来的请求体数据</span></span><br><span class="line">    <span class="keyword">let</span> str = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//2、监听 req 的 data 事件</span></span><br><span class="line">    req.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>,<span class="function">(<span class="params">chunk</span>)=&gt;</span>&#123;</span><br><span class="line">        str += chunk</span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//3、监听 req 的 end 事件</span></span><br><span class="line">    req.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">        <span class="comment">//在 str 中存储的就是完整的请求体数据</span></span><br><span class="line">        <span class="comment">//<span class="doctag">TODO:</span> 把字符串格式的请求体数据，解析成对象格式</span></span><br><span class="line">        <span class="keyword">const</span> body = qs.<span class="title function_">parse</span>(str)</span><br><span class="line">        req.<span class="property">body</span> = body</span><br><span class="line">        <span class="title function_">next</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="variable language_">module</span>.<span class="property">exports</span> = bodyParser</span><br></pre></td></tr></table></figure><p>至此，自定义一个中间件已经全部完成，现在只需要在 test.js 中进行导入就可使用。</p><p>测试代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</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> customBody = <span class="built_in">require</span>(<span class="string">&#x27;./类urlencoded的中间件&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//将自定义的2中间件函数，注册成为全局可用的中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(customBody)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/book&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(req.<span class="property">body</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/05/04/mU9ItScAVX5Zuzr.png"></p><br/><h3 id="8、Express-接口"><a href="#8、Express-接口" class="headerlink" title="8、Express 接口"></a>8、Express 接口</h3><h4 id="8-1-什么是接口"><a href="#8-1-什么是接口" class="headerlink" title="8.1 什么是接口"></a>8.1 什么是接口</h4><p>API (Application Programming Interface，应用程序编程接口 ) 是一些预先定义的函数，目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力，而又无需访问源码，或理解内部工作机制的细节。API除了有应用“应用程序接口”的意思外，还特指 API的说明文档，也称为帮助文档。 </p><h4 id="8-2-创建-API-路由模块"><a href="#8-2-创建-API-路由模块" class="headerlink" title="8.2 创建 API 路由模块"></a>8.2 创建 API 路由模块</h4><p>创建 API 路由模块的方法十分简单，和之前创建自定义模块的方法几乎一样，所以就不再赘述。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> apiRouter = express.<span class="title class_">Router</span>()</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = apiRouter</span><br></pre></td></tr></table></figure><p>然后我们在 test.js 中注册路由：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> apiRouter = <span class="built_in">require</span>(<span class="string">&#x27;./apiRouter&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">&#x27;/api&#x27;</span>,apiRouter)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>这样我们就可以直接在 API 路由模块中写相应的路由，然后在 test.js 中调用即可。</p><h4 id="8-3-编写-GET-接口"><a href="#8-3-编写-GET-接口" class="headerlink" title="8.3 编写 GET 接口"></a>8.3 编写 GET 接口</h4><p>我们直接在 API 路由模块中编写路由代码。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义 GET 接口</span></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&#x27;/get&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//调用 res.send() 方法，向客户端响应处理的结果</span></span><br><span class="line">    res.<span class="title function_">send</span>(&#123;</span><br><span class="line">        <span class="attr">status</span>:<span class="number">0</span>,<span class="comment">//0 表示处理成功，1 表示处理失败</span></span><br><span class="line">        <span class="attr">msg</span>:<span class="string">&#x27;GET 请求成功！&#x27;</span>,<span class="comment">//状态的描述</span></span><br><span class="line">        <span class="attr">data</span>:req.<span class="property">query</span><span class="comment">//通过 req.query 来获取客户端通过查询字符串发送到服务器的数据</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>然后运行 nodemon test.js 来看看运行结果：</p><p><img src="https://s2.loli.net/2022/05/05/4lrz1iaE5wc23IV.png"></p><h4 id="8-4-编写-POST-接口"><a href="#8-4-编写-POST-接口" class="headerlink" title="8.4 编写 POST 接口"></a>8.4 编写 POST 接口</h4><p>和上面一样，我们直接在 API 接口中编写路由代码</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义 POST 接口</span></span><br><span class="line">router.<span class="title function_">post</span>(<span class="string">&#x27;/post&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//调用 res.send() 方法，向客户端响应结果</span></span><br><span class="line">    res.<span class="title function_">send</span>(&#123;</span><br><span class="line">        <span class="attr">status</span>:<span class="number">0</span>,</span><br><span class="line">        <span class="attr">msg</span>:<span class="string">&#x27;POST 请求成功&#x27;</span>,</span><br><span class="line">        <span class="attr">data</span>:req.<span class="property">body</span> <span class="comment">//通过 req.body 获取请求体包含的 url-encoded 格式的数据</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>然后还需要在 test.js 中配置一段代码</p><figure class="highlight js"><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">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>(&#123;<span class="attr">extended</span>:<span class="literal">false</span>&#125;))</span><br></pre></td></tr></table></figure><p>完整代码：</p><p><strong>apiRouter.js</strong></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> router = express.<span class="title class_">Router</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//定义 GET 接口</span></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&#x27;/get&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//调用 res.send() 方法，向客户端响应处理的结果</span></span><br><span class="line">    res.<span class="title function_">send</span>(&#123;</span><br><span class="line">        <span class="attr">status</span>:<span class="number">0</span>, <span class="comment">//0 表示处理成功，1 表示处理失败</span></span><br><span class="line">        <span class="attr">msg</span>:<span class="string">&#x27;GET 请求成功！&#x27;</span>, <span class="comment">//状态的描述</span></span><br><span class="line">        <span class="attr">data</span>:req.<span class="property">query</span> <span class="comment">//通过 req.query 来获取客户端通过查询字符串发送到服务器的数据</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">//定义 POST 接口</span></span><br><span class="line">router.<span class="title function_">post</span>(<span class="string">&#x27;/post&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//调用 res.send() 方法，向客户端响应结果</span></span><br><span class="line">    res.<span class="title function_">send</span>(&#123;</span><br><span class="line">        <span class="attr">status</span>:<span class="number">0</span>,</span><br><span class="line">        <span class="attr">msg</span>:<span class="string">&#x27;POST 请求成功&#x27;</span>,</span><br><span class="line">        <span class="attr">data</span>:req.<span class="property">body</span> <span class="comment">//通过 req.body 获取请求体包含的 url-encoded 格式的数据</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_">module</span>.<span class="property">exports</span> = router</span><br></pre></td></tr></table></figure><p><strong>test.js</strong></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> apiRouter = <span class="built_in">require</span>(<span class="string">&#x27;./apiRouter&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">//配置解析表单数据的中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>(&#123;<span class="attr">extended</span>:<span class="literal">false</span>&#125;))</span><br><span class="line">    </span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">&#x27;/api&#x27;</span>,apiRouter)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">80</span>,<span class="function">()=&gt;</span>&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Express server running at http://127.0.0.1&#x27;</span>)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/05/05/uIAtg9vL2V6cXRp.png"></p><h4 id="8-5-CORS-跨域资源共享"><a href="#8-5-CORS-跨域资源共享" class="headerlink" title="8.5 CORS 跨域资源共享"></a>8.5 CORS 跨域资源共享</h4><p>刚刚编写的 GET 和 POST 接口，存在一个很严重的问题：不支持跨域请求。我们来看看下面的效果（需要 jQuery 和 Ajax.js 前置知识）</p><p>先来简单介绍一下<strong>跨域请求</strong>：当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念：我们认为若协议 + 域名 + 端口号均相同，那么就是同域。</p><p>举个例子：假如一个域名为<code>aaa.cn</code>的网站，它发起一个资源路径为<code>aaa.cn/books/getBookInfo</code>的 Ajax 请求，那么这个请求是同域的，因为资源路径的协议、域名以及端口号与当前域一致（例子中协议名默认为http，端口号默认为80）。但是，如果发起一个资源路径为<code>bbb.com/pay/purchase</code>的 Ajax 请求，那么这个请求就是跨域请求，因为域不一致，与此同时由于安全问题，这种请求会受到同源策略限制。</p><p>我们编写一个用以测试的 .html 文件：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><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"><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">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;IE=edge&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">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.staticfile.org/jquery/1.10.0/jquery.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btnGet&quot;</span>&gt;</span>GET<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">br</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">id</span>=<span class="string">&quot;btnPOST&quot;</span>&gt;</span>POST<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"></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="comment">//测试 GET接口</span></span></span><br><span class="line"><span class="language-javascript">            $(<span class="string">&#x27;#btnGet&#x27;</span>).<span class="title function_">on</span>(<span class="string">&#x27;click&#x27;</span>,<span class="keyword">function</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                $.<span class="title function_">ajax</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">type</span>:<span class="string">&#x27;GET&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">url</span>:<span class="string">&#x27;http://127.0.0.1/api/get&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">data</span>:&#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">20</span>&#125;,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">success</span>:<span class="keyword">function</span>(<span class="params">res</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">console</span>.<span class="title function_">log</span>(res)</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></span><br><span class="line"><span class="language-javascript">            <span class="comment">//测试 POST 接口</span></span></span><br><span class="line"><span class="language-javascript">            $(<span class="string">&#x27;#btnPOST&#x27;</span>).<span class="title function_">on</span>(<span class="string">&#x27;click&#x27;</span>,<span class="keyword">function</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                $.<span class="title function_">ajax</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">type</span>:<span class="string">&#x27;POST&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">url</span>:<span class="string">&#x27;http://127.0.0.1/api/post&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">data</span>:&#123;<span class="attr">bookname</span>:<span class="string">&#x27;《水浒传》&#x27;</span>,<span class="attr">author</span>:<span class="string">&#x27;施耐庵&#x27;</span>&#125;,</span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">success</span>:<span class="keyword">function</span>(<span class="params">res</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">console</span>.<span class="title function_">log</span>(res)</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><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2022/05/05/Fq65ODUGNHIjc3t.png"></p><p>结局接口跨域问题的方案主要有两种：</p><ol><li>CORS（主流的解决方案，推荐使用）</li><li>JSONP（有缺陷的解决方案，只能支持 GET 请求）</li></ol><h5 id="8-5-1使用-CORS-中间件解决跨域问题"><a href="#8-5-1使用-CORS-中间件解决跨域问题" class="headerlink" title="8.5.1使用 CORS 中间件解决跨域问题"></a>8.5.1使用 CORS 中间件解决跨域问题</h5><p>CORS 是 Express 的一个第三方中间件。通过安装和配置 CORS 中间件，可以很方便地解决跨域问题。使用步骤分为如下 3 步：</p><ol><li>运行 <code>npm install cors</code> 安装中间件</li><li>使用 <code>const cors = require(&#39;cors&#39;)</code> 导入中间件</li><li>在路由之前调用 <code>app.use(cors())</code> 配置中间件</li></ol><p>安装完 CORS 中间件之后，在 test.js 路由之前导入并配置 CORS 中间件，其代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//一定要在路由之前配置 cors 这个中间件，从而解决接口跨域的问题</span></span><br><span class="line"><span class="keyword">const</span> cors = <span class="built_in">require</span>(<span class="string">&#x27;cors&#x27;</span>)</span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">cors</span>())</span><br></pre></td></tr></table></figure><p>接着我们再运行 test.js 并且回到页面中，刷新一下页面，获得以下结果：</p><p><img src="https://s2.loli.net/2022/05/05/dK2fjIYkbXa1TNV.png"></p><h5 id="8-5-2-什么是-CORS"><a href="#8-5-2-什么是-CORS" class="headerlink" title="8.5.2 什么是 CORS"></a>8.5.2 什么是 CORS</h5><p>通过第一小节的案例，我们已经初步使用了 CORS 中间件来进行跨域资源共享，那什么是 CORS 呢？</p><p>CORS（Cross-Origin Resource Sharing，跨域资源共享）由一系列 HTTP 响应头组成，这些 HTTP 响应头决定浏览请是否阻止前端 JS 代码跨域获取资源。</p><p>浏览器的同源安全策略默认会阻止网页 “跨域” 获取资源</p><p><img src="https://s2.loli.net/2022/05/06/9sroY4W3QBERlKX.png"></p><p>但如果接口服务器配置了 CORS 相关的 HTTP 响应头，就可以接触浏览器端的跨域访问限制</p><p><img src="https://s2.loli.net/2022/05/05/uTwdIGB165rZLab.png"></p><p><strong>注意：</strong></p><ul><li>CORS 主要在服务器端进行配置，客户端浏览器无需做任何额外的配置，即可请求开启了 CORS 的接口。</li><li>CORS 在浏览器中有兼容性。只有支持 XMLHttpRequest Level2 的浏览器，才能正常访问开启了 CORS 的服务端口。</li></ul><h5 id="8-5-3-CORS-响应头部-Access-Control-Allow-Origin"><a href="#8-5-3-CORS-响应头部-Access-Control-Allow-Origin" class="headerlink" title="8.5.3 CORS 响应头部 - Access-Control-Allow-Origin"></a>8.5.3 CORS 响应头部 - Access-Control-Allow-Origin</h5><p>响应头部中可以携带一个 <code>Access-Control-Allow-Origin</code> 字段，其语法格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Access</span>-<span class="title class_">Control</span>-<span class="title class_">Allow</span>-<span class="title class_">Origin</span>: &lt;origin&gt; | *</span><br></pre></td></tr></table></figure><p>其中，origin 参数指定了<strong>允许访问该资源的外域 URL</strong>。</p><p>例如，下面的字段值将<strong>只允许</strong>来自 <a href="http://itcast.cn/">http://itcast.cn</a> 的请求：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>,<span class="string">&#x27;http://itcast.cn&#x27;</span>)</span><br></pre></td></tr></table></figure><p>如果指定了 <code>Access-Control-Allow-Origin</code> 字段的值为通配符 *，表示允许来自任何域的请求，示例代码如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>,<span class="string">&#x27;*&#x27;</span>)</span><br></pre></td></tr></table></figure><h5 id="CORS-响应头部-Access-Control-Allow-Headers"><a href="#CORS-响应头部-Access-Control-Allow-Headers" class="headerlink" title="CORS 响应头部 - Access-Control-Allow-Headers"></a>CORS 响应头部 - Access-Control-Allow-Headers</h5><p>默认情况下，CORS 仅支持客户端向服务器发送如下的九个请求头：</p><ul><li>Accept</li><li>Accept-Language</li><li>Content-Language</li><li>DPR</li><li>Downlink</li><li>Save-Data</li><li>Viewport-Width</li><li>Width</li><li>Content-Type (值仅限于 text&#x2F;plain、multipart&#x2F;form-data、application&#x2F;x-www-form-urlencoded 三者之一)</li></ul><p>如果客户端向服务器发送了额外的请求头信息，则需要在服务器端通过 <code>Access-Control-Allow-Headers</code> 对额外的请求头进行声明，否则这次请求会失败。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//允许客户端额外向服务器发送 Content-Type 请求头和 X-Custom-Header 请求头</span></span><br><span class="line"><span class="comment">//注意：多个请求头之间使用英文的逗号进行分割</span></span><br><span class="line">res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Access-Control-Allow-Headers&#x27;</span>,<span class="string">&#x27;Content-Type,X-Custom-Header&#x27;</span>)</span><br></pre></td></tr></table></figure><h5 id="CORS-响应头部-Access-Control-Allow-Methods"><a href="#CORS-响应头部-Access-Control-Allow-Methods" class="headerlink" title="CORS 响应头部 - Access-Control-Allow-Methods"></a>CORS 响应头部 - Access-Control-Allow-Methods</h5><p>默认情况下，CORS 仅支持客户端发起 GET、POST、HEAD 请求。如果客户端希望通过 PUT、DELETE 等方式请求服务器的资源，则需要在服务器端，通过 <code>Access-Control-Allow-Methods</code> 来指明实际请求所允许使用的 HTTP 方法。</p><p>示例代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//只允许 POST、GET、DELETE、HEAD 请求方法</span></span><br><span class="line">res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Access-Control-Allow-Methods&#x27;</span>,<span class="string">&#x27;POST,GET,DELETE,HEAD&#x27;</span>)</span><br><span class="line"><span class="comment">//允许所有的 HTTP 请求方法</span></span><br><span class="line">res.<span class="title function_">setHeader</span>(<span class="string">&#x27;Access-Control-Allow-Methods&#x27;</span>,<span class="string">&#x27;*&#x27;</span>)</span><br></pre></td></tr></table></figure><h5 id="CORS-请求的分类"><a href="#CORS-请求的分类" class="headerlink" title="CORS 请求的分类"></a>CORS 请求的分类</h5><p>客户端在请求 CORS 接口时，根据请求方式和请求头的不同，可以将 CORS 的请求分为两大类，分别是：</p><ol><li>简单请求</li><li>预检请求</li></ol><p><strong>简单请求：</strong></p><ul><li>请求方式是 GET、POST、HEAD</li><li>HTTP 头部信息不超过以下几种字段：物资定义头部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width、Content-Type (值仅限于 text&#x2F;plain、multipart&#x2F;form-data、application&#x2F;x-www-form-urlencoded 三者之一)</li></ul><p><strong>预检请求（只要满足以下任何一个请求）：</strong></p><ul><li>请求方式为 GET、POST、HEAD 之外的请求 Method 类型</li><li>请求投中包含自定义头部字段</li><li>向服务器发送了 application&#x2F;json 格式的数据</li></ul><p>在浏览器与服务器正式通信之前，浏览器会发送 OPTION 请求进行预检，已获知服务器是否允许该实际请求，所以一次的 OPTION 请求称为 “预检请求”。服务器成功响应预检请求后，才会发送真正的请求，并且携带真实数据。</p><p><strong>简单请求的特点：客户端与服务器之间只会发送一次请求</strong></p><p><strong>预检请求的特点：客户端之间会发生两次请求，OPTION 预检请求成功之后，才会发起真正的请求</strong></p><p>下面我们来实际的体验一下：</p><p>首先在测试接口的 .html 文件下添加测试 DELETE 的接口：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><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">button</span> <span class="attr">id</span>=<span class="string">&quot;btnDELETE&quot;</span>&gt;</span>DELETE<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"></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="comment">//测试 DELETE 接口</span></span></span><br><span class="line"><span class="language-javascript">$(<span class="string">&#x27;#btnDELETE&#x27;</span>).<span class="title function_">on</span>(<span class="string">&#x27;click&#x27;</span>,<span class="keyword">function</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">$.<span class="title function_">ajax</span>(&#123;</span></span><br><span class="line"><span class="language-javascript"><span class="attr">type</span>:<span class="string">&#x27;DELETE&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript"><span class="attr">url</span>:<span class="string">&#x27;http://127.0.0.1/api/delete&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript"> <span class="attr">success</span>:<span class="keyword">function</span>(<span class="params">res</span>)&#123;</span></span><br><span class="line"><span class="language-javascript"><span class="variable language_">console</span>.<span class="title function_">log</span>(res)</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><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></pre></td></tr></table></figure><p>然后再在 apiRouter.js 文件里添加定义 DELETE 接口的代码：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义 DELEET 接口</span></span><br><span class="line">router.<span class="title function_">delete</span>(<span class="string">&#x27;/delete&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">0</span>,<span class="attr">message</span>:<span class="string">&#x27;DELETE 请求成功&#x27;</span>&#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>然后我们就可以试着运行了</p><p>我们打开控制台的网络页面，然后点击 GET 可以得到一下结果：</p><p><img src="https://s2.loli.net/2022/05/06/cFaqmulCXPZs649.png"></p><p>我们会发现 GET 发送了一次请求，然后我们再点击 DELETE：</p><p><img src="https://s2.loli.net/2022/05/06/RWQvgjkY9wTFlD1.png"></p><p>发现 DELETE 向服务器发送了两次请求，其中有一次是被标记为<strong>预检</strong>。</p><h4 id="8-6-JSONP-接口"><a href="#8-6-JSONP-接口" class="headerlink" title="8.6 JSONP 接口"></a>8.6 JSONP 接口</h4><h5 id="8-6-1-什么是-JSONP-接口"><a href="#8-6-1-什么是-JSONP-接口" class="headerlink" title="8.6.1 什么是 JSONP 接口"></a>8.6.1 什么是 JSONP 接口</h5><p>浏览器端通过 <code>&lt;script&gt;</code> 标签的 src 属性，请求服务器上的数据。同时，服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP。</p><p><strong>特点：</strong></p><ul><li>JSONP 不属于真正的 Ajax 请求，因为它没有使用 XMLHttpRequest 这个对象</li><li>JSONP 仅支持 GET 请求，不支持 POST、PUT、DELETE 等请求</li></ul><h5 id="8-6-2-创建JSONP-接口的注意事项"><a href="#8-6-2-创建JSONP-接口的注意事项" class="headerlink" title="8.6.2 创建JSONP 接口的注意事项"></a>8.6.2 创建JSONP 接口的注意事项</h5><p>如果项目中已经配置了 CORS 跨域资源共享，为了防止冲突，必须在配置 CORS 中间件之前声明 JSONP 的接口。否则 JSONP 接口会被处理成开了了 CORS 的接口，示例代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//必须在配置 cors 中间件之前，配置 JSONP 的接口</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/api/jsonp&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//<span class="doctag">TODO:</span>定义 JSONP 接口具体的实现过程</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h5 id="8-6-3-实现-JSONP-接口"><a href="#8-6-3-实现-JSONP-接口" class="headerlink" title="8.6.3 实现 JSONP 接口"></a>8.6.3 实现 JSONP 接口</h5><p>步骤如下：</p><ol><li>获取客户端发送过来的回调函数的名字</li><li>得到要通过 JSONP 形式发送给客户端的数据</li><li>根据前两步得到的数据，拼接出一个函数调用的字符串</li><li>把上一步拼接得到的字符串响应给客户端的 <code>&lt;script&gt;</code> 标签进行解析执行</li></ol><p>那根据步骤我们就可以在 test.js 中实现 JSONP 接口，其代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//必须在配置 cors 中间件之前，配置 JSONP 的接口</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/api/jsonp&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//<span class="doctag">TODO:</span>定义 JSONP 接口具体的实现过程</span></span><br><span class="line">    <span class="comment">//1、获取客户端发送过来的回调函数的名字</span></span><br><span class="line">    <span class="keyword">const</span> funcName = req.<span class="property">query</span>.<span class="property">callback</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//2、得到要通过 JSONP 形式发送给客户端的数据</span></span><br><span class="line">    <span class="keyword">const</span> data = &#123;<span class="attr">name</span>:<span class="string">&#x27;zs&#x27;</span>,<span class="attr">age</span>:<span class="number">20</span>&#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//3、根据前两步得到的数据，拼接出一个函数调用的字符串</span></span><br><span class="line">    <span class="keyword">const</span> scripStr = <span class="string">`<span class="subst">$&#123;funcName&#125;</span>(<span class="subst">$&#123;<span class="built_in">JSON</span>.stringify(data)&#125;</span>)`</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//4、把上一步拼接得到的字符串响应给客户端</span></span><br><span class="line">    res.<span class="title function_">send</span>(scripStr)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>接下来我们就可以在 html 中调用 <code>$.ajax()</code>，提供 JSONP 的配置选项来发起 JSONP 请求，其代码如下：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><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">button</span> <span class="attr">id</span>=<span class="string">&quot;btnJSONP&quot;</span>&gt;</span>JSONP<span class="tag">&lt;/<span class="name">button</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="comment">//为 JSONP 按钮绑定点击事件处理函数</span></span></span><br><span class="line"><span class="language-javascript">$(<span class="string">&#x27;#btnJSONP&#x27;</span>).<span class="title function_">on</span>(<span class="string">&#x27;click&#x27;</span>,<span class="keyword">function</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">$.<span class="title function_">ajax</span>(&#123;</span></span><br><span class="line"><span class="language-javascript"><span class="attr">type</span>:<span class="string">&#x27;GET&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript"><span class="attr">url</span>:<span class="string">&#x27;http://127.0.0.1/api/JSONP&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript"><span class="attr">dataType</span>:<span class="string">&#x27;jsonp&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript"><span class="attr">success</span>:<span class="keyword">function</span>(<span class="params">res</span>)&#123;</span></span><br><span class="line"><span class="language-javascript"><span class="variable language_">console</span>.<span class="title function_">log</span>(res)</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><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></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/05/06/F46VohLmx2EdC7v.png"></p><br/><br/><h2 id="八、数据库与身份认证"><a href="#八、数据库与身份认证" class="headerlink" title="八、数据库与身份认证"></a>八、数据库与身份认证</h2><h3 id="1、数据库的基本概念"><a href="#1、数据库的基本概念" class="headerlink" title="1、数据库的基本概念"></a>1、数据库的基本概念</h3><h4 id="1-1-什么是数据库"><a href="#1-1-什么是数据库" class="headerlink" title="1.1 什么是数据库"></a>1.1 什么是数据库</h4><p><strong>数据库</strong>是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。</p><p>当今世界是一个充满着数据的互联网世界，比如说消费记录、浏览记录、出行记录等等。除了我们一般认为的文本类型的数据，图像、音乐、声音其实都是数据。</p><p>而面对这庞大的数据，我们就需要有一个工具去方便地管理管理这些数据，数据库管理系统 (简称：数据库) 这一概念也就应运而生。用户可以通过数据库来对数据进行增、删、改、查等操作。</p><p>数据库大致分为两种，一种是 <strong>传统型数据库</strong>， 包括：MySQL、sql server等；另一种是 <strong>新型数据库</strong>， 包括：Mongodb数据库。</p><p>而我们最常使用的就是 MySQL 数据库。其官网地址：<a href="https://www.mysql.com/cn/">MySQL</a></p><h4 id="1-2-传统型数据库的数据组织结构"><a href="#1-2-传统型数据库的数据组织结构" class="headerlink" title="1.2 传统型数据库的数据组织结构"></a>1.2 传统型数据库的数据组织结构</h4><p>在传统型数据库中，数据的组织结构分为**数据库 (database)、数据表 (table)、数据行 (row)、字段 (filed)**这 4 大部分组成。</p><p><strong>注意：</strong></p><ul><li>在实际项目开发中，一般情况下，每个项目都对应独立的数据库</li><li>不同的数据，要存储到数据库的不同的表中。</li><li>每个表中具体存储哪些信息有字段来决定。</li><li>表中的行代表每一条具体的数据</li></ul><br/><h3 id="2、安装并配置-MySQL"><a href="#2、安装并配置-MySQL" class="headerlink" title="2、安装并配置 MySQL"></a>2、安装并配置 MySQL</h3><p>这里不做过多的演示，请读者自行去阅读以下两个链接并安装好 MySQL。</p><p><strong>win 系统安装：</strong><a href="https://zhuanlan.zhihu.com/p/37152572">超级详细的mysql数据库安装指南 - 知乎 (zhihu.com)</a></p><p><strong>mac 系统安装：<a href="https://www.bilibili.com/video/BV1a34y167AZ?p=59">安装并配置 MySQL</a></strong></p><p>对于使用 win 系统的同学，我们这里有 navicat15 (一个可视化编辑数据库的软件，非常方便) 的破解包，大家可以自行下载安装 navicat15。</p><br/><h3 id="3、使用-navicat15-新建数据库和表"><a href="#3、使用-navicat15-新建数据库和表" class="headerlink" title="3、使用 navicat15 新建数据库和表"></a>3、使用 navicat15 新建数据库和表</h3><ol><li>打开 <strong>navicat15</strong> </li><li>在右上角点击<strong>文件</strong>，并找到<strong>新建连接</strong>，选择第一个 MySQL</li></ol><p><img src="https://s2.loli.net/2022/05/07/PQgIfJXVMpL5UN9.png"></p><ol start="3"><li>输入自己的<strong>用户名</strong>和<strong>密码</strong>，单击<strong>确定</strong></li></ol><p><img src="https://s2.loli.net/2022/05/07/Cy69D5l1YOa8NRT.png"></p><ol start="4"><li>双击<strong>连接</strong>数据库</li></ol><p><img src="https://s2.loli.net/2022/05/07/dRzwD5To6OsyWiq.png"></p><ol start="5"><li>右击连接，点击<strong>新建数据库</strong></li></ol><p><img src="https://s2.loli.net/2022/05/07/WvfZQOE2i36ekTl.png" alt="image-20220507143826669"></p><p>或者在<strong>查询</strong>中<strong>新建查询</strong>使用查询语句来新建数据库</p><p><img src="https://s2.loli.net/2022/05/07/n1LjfD8d3HaEYhW.png"></p><p><img src="https://s2.loli.net/2022/05/07/N9lkBHSqb26ysKM.png"></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> DATABASE test;</span><br></pre></td></tr></table></figure><ol start="6"><li>双击 <strong>test</strong> 连接数据库，右键表来<strong>新建表</strong>，或者使用查询语句来新建表：</li></ol><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></pre></td><td class="code"><pre><span class="line">USE test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE TABLE</span> stu(</span><br><span class="line">name <span class="type">VARCHAR</span>(<span class="number">20</span>),</span><br><span class="line">age     <span class="type">INT</span>(<span class="number">3</span>),</span><br><span class="line">id      <span class="type">VARCHAR</span>(<span class="number">20</span>)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>并先运行 <code>USE test；</code> 再运行底下的代码。在 navicat15 中，我们可以选择单条语句进行运行。</p><ol start="7"><li>在查询中执行 sql 语句来<strong>插入数据</strong>：</li></ol><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">INSERT INTO</span> stu <span class="keyword">VALUES</span>(<span class="string">&#x27;张三&#x27;</span>,<span class="number">20</span>,<span class="string">&#x27;112233&#x27;</span>);</span><br></pre></td></tr></table></figure><ol start="8"><li>在查询中执行 sql 语句来<strong>查询数据</strong>：</li></ol><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> stu;</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/05/08/FpG9mZTISuYMVdk.png"></p><p>接下来有关数据库的基础语句等我们在这里都不再多展示，请各位自行去本文档的配套教程中观看 <strong>P58 - P67</strong>，或者单独学习有关数据库的知识，文档后面的内容会直接从配套教程的 <strong>P68</strong> 开始。</p><br/><h3 id="4、mysql-模块"><a href="#4、mysql-模块" class="headerlink" title="4、mysql 模块"></a>4、mysql 模块</h3><p>以下所有数据库的操作都将建立在以下 sql 语句的基础上，请读者自行复制粘贴建议相应的数据库：</p><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><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> DATABASE test;</span><br><span class="line"></span><br><span class="line">USE test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE TABLE</span> stu(</span><br><span class="line">name <span class="type">VARCHAR</span>(<span class="number">20</span>),</span><br><span class="line">age  <span class="type">INT</span>(<span class="number">3</span>),</span><br><span class="line">sex  <span class="type">VARCHAR</span>(<span class="number">5</span>),</span><br><span class="line">id   <span class="type">VARCHAR</span>(<span class="number">20</span>)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">INSERT INTO</span> stu</span><br><span class="line"><span class="keyword">VALUES</span>(<span class="string">&#x27;陈二&#x27;</span>,<span class="number">20</span>,<span class="string">&#x27;男&#x27;</span>,<span class="string">&#x27;112233&#x27;</span>),</span><br><span class="line">(<span class="string">&#x27;张三&#x27;</span>,<span class="number">20</span>,<span class="string">&#x27;男&#x27;</span>,<span class="string">&#x27;113344&#x27;</span>),</span><br><span class="line">(<span class="string">&#x27;李四&#x27;</span>,<span class="number">21</span>,<span class="string">&#x27;女&#x27;</span>,<span class="string">&#x27;223344&#x27;</span>),</span><br><span class="line">(<span class="string">&#x27;王五&#x27;</span>,<span class="number">22</span>,<span class="string">&#x27;男&#x27;</span>,<span class="string">&#x27;334455&#x27;</span>),</span><br><span class="line">(<span class="string">&#x27;赵六&#x27;</span>,<span class="number">20</span>,<span class="string">&#x27;女&#x27;</span>,<span class="string">&#x27;114455&#x27;</span>),</span><br><span class="line">(<span class="string">&#x27;孙七&#x27;</span>,<span class="number">21</span>,<span class="string">&#x27;女&#x27;</span>,<span class="string">&#x27;224455&#x27;</span>),</span><br><span class="line">(<span class="string">&#x27;钱八&#x27;</span>,<span class="number">22</span>,<span class="string">&#x27;男&#x27;</span>,<span class="string">&#x27;335566&#x27;</span>);</span><br></pre></td></tr></table></figure><h4 id="4-1-安装-mysql-模块"><a href="#4-1-安装-mysql-模块" class="headerlink" title="4.1 安装 mysql 模块"></a>4.1 安装 mysql 模块</h4><p>Express 项目和 MySQL 数据库之间的关系如下图，我们通过安装和使用 mysql 模块来连接 MySQL 数据库以及对其进行操作。</p><p><img src="https://s2.loli.net/2022/05/08/z5YOMeEUJPnmGF2.png" alt="image-20220508153228679"></p><p>那我们就先来安装 mysql 模块，在终端中执行 <code>npm i mysql</code> 语句来安装 mysql 模块。</p><h4 id="4-2-连接数据库"><a href="#4-2-连接数据库" class="headerlink" title="4.2 连接数据库"></a>4.2 连接数据库</h4><p>在安装完 mysql 模块之后我们就可以尝试连接数据库了，连接数据库主要有两个步骤，一个是导入 mysql 模块，一个是连接数据库，代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//导入 mysql 模块</span></span><br><span class="line"><span class="keyword">const</span> mysql = <span class="built_in">require</span>(<span class="string">&#x27;mysql&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//建立与 mysql 数据库的连接关系</span></span><br><span class="line"><span class="keyword">const</span> db = mysql.<span class="title function_">createPool</span>(&#123;</span><br><span class="line">    <span class="attr">host</span>:<span class="string">&#x27;127.0.0.1&#x27;</span>,<span class="comment">//数据库的 IP 地址</span></span><br><span class="line">    <span class="attr">user</span>:<span class="string">&#x27;root&#x27;</span>,<span class="comment">//登录数据库的账号</span></span><br><span class="line">    <span class="attr">password</span>:<span class="string">&#x27;123456&#x27;</span>,<span class="comment">//数据库的密码</span></span><br><span class="line">    <span class="attr">database</span>:<span class="string">&#x27;test&#x27;</span><span class="comment">//指定要操作那个数据库</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>连接完数据库之后我们就要去测试 mysql 模块是否能够正常的工作，或者说我们是否真的已经连接上了数据库。我们在这里调用 <code>db.query()</code> 函数，通过回调函数来拿到执行的结果，代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//检测 mysql 模块是否能够正常工作</span></span><br><span class="line">db.<span class="title function_">query</span>(<span class="string">&#x27;SELECT 1&#x27;</span>,<span class="function">(<span class="params">err,results</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(results)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/05/08/ajVs9oWOGenUFuE.png"></p><p>当显示这样的信息时就表示已经连接成功。</p><p><strong>注意</strong>，这里可能会有 <code>Client does not support authentication protocol requested by server; consider upgrading MySQL client</code> 这样的报错，这是因为 node 没有办法解析 mysql 数据库的密码。我们只需要在 cmd 中打开 MySQL 文件的 bin，然后输入代码即可：</p><p><img src="https://s2.loli.net/2022/05/08/dPQa1mLAk3WB2wE.png"></p><p>然后输入</p><figure class="highlight cmd"><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">mysql&gt; alter user &#x27;root&#x27;@&#x27;localhost&#x27; identified with mysql_native_password by &#x27;<span class="number">123456</span>&#x27;;</span><br><span class="line">mysql&gt; flush privileges;</span><br></pre></td></tr></table></figure><h4 id="4-3-查询数据表中的数据"><a href="#4-3-查询数据表中的数据" class="headerlink" title="4.3 查询数据表中的数据"></a>4.3 查询数据表中的数据</h4><p>我们之前已经成功连接上了数据库，那我们就可以使用 sql 语法来操作数据库了。我们先来试试查询：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//查询数据库</span></span><br><span class="line">db.<span class="title function_">query</span>(<span class="string">&#x27;SELECT * FROM stu&#x27;</span>,<span class="function">(<span class="params">err,results</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(results)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/05/11/BVfW8hLIQeoJ1pH.png"></p><p>通过这个例子我们可以知道，在调用 <code>db.query()</code> 函数的时候，前面的单引号的内容就是用来写要执行的 sql 语句。但一般来说我们并不会直接在单引号里面写 sql 语句，而是采用变量的形式来写，代码示例如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义一个 sqlStr 的常量用来写 sql 语句</span></span><br><span class="line"><span class="keyword">const</span> sqlStr = <span class="string">&#x27;SELECT * FROM stu&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//直接调用即可</span></span><br><span class="line">db.<span class="title function_">query</span>(sqlStr,<span class="function">(<span class="params">err,results</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(results)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>其运行结果和上面的相同。这样书写的好处是大大增加的代码的可读性，能够更加方便了自己日后维护的成本以及他人阅读。</p><p>那接下来我们再来试试插入语句：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//向数据库中插入数据</span></span><br><span class="line"><span class="keyword">const</span> stuinfo = &#123;<span class="attr">name</span>:<span class="string">&#x27;张大三&#x27;</span>,<span class="attr">age</span>:<span class="number">21</span>,<span class="attr">sex</span>:<span class="string">&#x27;男&#x27;</span>,<span class="attr">id</span>:<span class="string">&#x27;225566&#x27;</span>&#125;</span><br><span class="line"><span class="comment">//？表示占位符</span></span><br><span class="line"><span class="keyword">const</span> sqlInsert = <span class="string">&#x27;INSERT INTO stu (name,age,sex,id) VALUES (?,?,?,?)&#x27;</span></span><br><span class="line"><span class="comment">//向 sqlInsert 语句中插入数据，然后再通过语句插入到数据库</span></span><br><span class="line">db.<span class="title function_">query</span>(sqlInsert,[stuinfo.<span class="property">name</span>,stuinfo.<span class="property">age</span>,stuinfo.<span class="property">sex</span>,stuinfo.<span class="property">id</span>],<span class="function">(<span class="params">err,results</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">message</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="comment">//注意：如果执行的是 INSERT INTO 插入语句，则 results 是一个对象</span></span><br><span class="line">    <span class="comment">//可以通过 affectedRows 属性，来判断是否插入数据成功</span></span><br><span class="line">    <span class="keyword">if</span>(results.<span class="property">affectedRows</span> === <span class="number">1</span>)&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;数据插入成功！&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>运行结果：</p><p><img src="https://s2.loli.net/2022/05/11/ayiO3Dlo7Ge1LnK.png"></p><p>我们再使用查询语句来查询一下数据库：</p><p><img src="https://s2.loli.net/2022/05/11/p5BO1eDW6FK4gMq.png"></p><p>我们的插入语句成功运行了！</p><p>那我们再回头来看看我们的代码，我们会发现我们再 <code>db.query()</code> 中一个一个插入数据很是麻烦，而且显得代码很杂乱，所以我们可以使用简便的插入语句：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> stuinfo = &#123;<span class="attr">name</span>:<span class="string">&#x27;张大三&#x27;</span>,<span class="attr">age</span>:<span class="number">21</span>,<span class="attr">sex</span>:<span class="string">&#x27;男&#x27;</span>,<span class="attr">id</span>:<span class="string">&#x27;225566&#x27;</span>&#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> sqlInsert = <span class="string">&#x27;INSERT INTO stu SET ?&#x27;</span></span><br><span class="line"></span><br><span class="line">db.<span class="title function_">query</span>(sqlInsert,stuinfo,<span class="function">(<span class="params">err,results</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(err)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">message</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(results.<span class="property">affectedRows</span> === <span class="number">1</span>)&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;数据插入成功！&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>这样，我们的代码可读性大大增加了。</p><br/><h3 id="5、身份认证"><a href="#5、身份认证" class="headerlink" title="5、身份认证"></a>5、身份认证</h3><p>**注意：**身份认证后面所讲内容会牵涉部分后端内容，所以部分代码没有办法直接进行。笔者会在代码块相应的位置标注 *****，读者需要自行去看原视频获取代码资料自行尝试。同时由于这部分的内容过于抽象，并且脱离项目没有意义，所以建议读者在学完这张之后一定要写个项目来巩固知识。</p><h4 id="5-1-什么是身份认证"><a href="#5-1-什么是身份认证" class="headerlink" title="5.1 什么是身份认证"></a>5.1 什么是身份认证</h4><p>身份认证 (Authentication) 又称为 “身份验证” 、“鉴权”，指的是<strong>通过一定的手段，完成对用户身份的确认</strong>。</p><ul><li>日常生活中的身份认证随处可见，例如：高铁的验票乘车，手机的密码或指纹解锁，支付宝或微信的支付密码等。</li><li>在 Web 开发中，也涉及到用户身份的认证，例如：各大网站中的手机验证码登录、邮箱密码登录、二维码登录等。</li></ul><h4 id="5-2-不同开发模式下的身份认证"><a href="#5-2-不同开发模式下的身份认证" class="headerlink" title="5.2 不同开发模式下的身份认证"></a>5.2 不同开发模式下的身份认证</h4><p>对于服务器渲染和前后端分离这两种开发模式来说，分别有着不同的身份认证方案：</p><ol><li>服务器渲染推荐使用 <strong>Session 认证机制</strong></li><li>前后端分离推荐使用 <strong>JWT 认证机制</strong></li></ol><h4 id="5-3-Session-认证机制"><a href="#5-3-Session-认证机制" class="headerlink" title="5.3 Session 认证机制"></a>5.3 Session 认证机制</h4><h5 id="5-3-1-HTTP-协议的无状态性"><a href="#5-3-1-HTTP-协议的无状态性" class="headerlink" title="5.3.1 HTTP 协议的无状态性"></a>5.3.1 HTTP 协议的无状态性</h5><p>了解 HTTP 协议的无状态性是进一步学习 Session 认证机制的必要前提。</p><p>HTTP 协议的无状态性，指的是客户端的每次 HTTP 请求都是独立的，连续多个请求之后没有直接的关系，服务器不会主动保留每次 HTTP 请求的状态。</p><h5 id="5-3-2-如何突破-HTTP-无状态的限制"><a href="#5-3-2-如何突破-HTTP-无状态的限制" class="headerlink" title="5.3.2 如何突破 HTTP 无状态的限制"></a>5.3.2 如何突破 HTTP 无状态的限制</h5><p>对于超市来说，为了方便收银员的进行结算时给 VIP 用户打折，超时可以为每个 VIP 用户发放会员卡。</p><p><img src="https://s2.loli.net/2022/06/14/ApoUdXuLYM5qPKT.png"></p><p>身份认证方法一个关键的东西<em>Cookie</em></p><h5 id="5-3-3-什么是-Cookie"><a href="#5-3-3-什么是-Cookie" class="headerlink" title="5.3.3 什么是 Cookie"></a>5.3.3 什么是 Cookie</h5><p>Cookie 是存储在用户浏览器中的一段不超过 4KB 的字符串。它由一个名称 (Name)、一个值 (Value) 和其它几个用于控制 Cooke <strong>有效期</strong>、安全性、<strong>使用范围</strong>的可选属性的组织。</p><p>不同域名下的 Cookie 各自独立，每当客户端发起请求的时候，会自助把当前域名下所有未过期的 Cookie 一同发送到服务器。</p><p>Cookie 几大特性：</p><ol><li>自动发送</li><li>域名独立</li><li>过期时限</li><li>4KB 限制</li></ol><p>而因为 Cookie 是存储在浏览器中，而非是本地的，所以不具备<em>安全性</em>是可以被伪造的。因此，不建议将用户的隐私数据使用 Cookie 进行存储。</p><h5 id="5-3-4-Cookie-身份认证过程"><a href="#5-3-4-Cookie-身份认证过程" class="headerlink" title="5.3.4 Cookie 身份认证过程"></a>5.3.4 Cookie 身份认证过程</h5><p>客户端第一次请求服务器的时候，服务器通过响应头的形式，向客户端发送一个身份认证的 Cookie，客户端会自动将 Cookie 保存在浏览器中。随后，当客户端浏览器每次请求服务器的时候，浏览器会自动将身份认证相关的 Cookie，通过请求头的形式发送给服务器，服务器即可验明客户端的身份</p><p><img src="https://s2.loli.net/2022/06/14/41JtCZ6ExljVaFS.png"></p><h5 id="5-3-5-提高身份认证的安全性"><a href="#5-3-5-提高身份认证的安全性" class="headerlink" title="5.3.5 提高身份认证的安全性"></a>5.3.5 提高身份认证的安全性</h5><p>为了提高 Cookie 的安全性，我们可以选择将一些数据放在<strong>本地</strong> 。这就类似于在之前的 VIP 例子，我们不仅仅要出示会员卡（因为会员卡的外观是可以伪造的），而且还要刷卡进行验证（会员卡磁条是没办法进行伪造的）。</p><p>而这种 “会员卡+刷卡” 的设计理念就是 Session 认证机智的精髓。</p><h5 id="5-3-6-什么是-Session"><a href="#5-3-6-什么是-Session" class="headerlink" title="5.3.6 什么是 Session"></a>5.3.6 什么是 Session</h5><p>在计算机中，尤其是在网络应用中，称为 “会话控制”。<a href="https://baike.baidu.com/item/Session%E5%AF%B9%E8%B1%A1/5250998">Session对象</a>存储特定用户会话所需的属性及配置信息。这样，当用户在应用程序的Web页之间跳转时，存储在Session对象中的变量将不会丢失，而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时，如果该用户还没有会话，则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后，服务器将终止该会话。</p><h5 id="5-3-7-Session-工作原理"><a href="#5-3-7-Session-工作原理" class="headerlink" title="5.3.7 Session 工作原理"></a>5.3.7 Session 工作原理</h5><p><img src="https://s2.loli.net/2022/06/14/uWeI8MaJPFfpcih.png"></p><h4 id="5-4-Session-中间件"><a href="#5-4-Session-中间件" class="headerlink" title="5.4 Session 中间件"></a>5.4 Session 中间件</h4><h5 id="5-4-1-安装-express-session中间件"><a href="#5-4-1-安装-express-session中间件" class="headerlink" title="5.4.1 安装 express-session中间件"></a>5.4.1 安装 express-session中间件</h5><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i express-session</span><br></pre></td></tr></table></figure><h5 id="5-4-2-配置-express-session-中间件"><a href="#5-4-2-配置-express-session-中间件" class="headerlink" title="5.4.2 配置 express-session 中间件"></a>5.4.2 配置 express-session 中间件</h5><p>express-session 中间件安装成功后，需要通过 app.use() 来注册 session 中间件，其示例代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1、导入 express-session 中间件</span></span><br><span class="line"><span class="keyword">var</span> session = <span class="built_in">require</span>(<span class="string">&#x27;express-session&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> &#123; append &#125; = <span class="built_in">require</span>(<span class="string">&#x27;express/lib/response&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、配置 Session 中间件</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title class_">Sesson</span>(&#123;</span><br><span class="line"><span class="attr">secret</span>:<span class="string">&#x27;keyboard cat&#x27;</span>, <span class="comment">// secret 属性的值可以为任意字符串</span></span><br><span class="line"><span class="attr">resave</span>:<span class="literal">false</span>,          <span class="comment">// 固定写法</span></span><br><span class="line"><span class="attr">saveUninitialized</span>:<span class="literal">true</span> <span class="comment">// 固定写法</span></span><br><span class="line">&#125;))</span><br></pre></td></tr></table></figure><h5 id="5-4-3-向-Sesssion-中存储数据"><a href="#5-4-3-向-Sesssion-中存储数据" class="headerlink" title="5.4.3 向 Sesssion 中存储数据"></a>5.4.3 向 Sesssion 中存储数据</h5><p>当 express-session 中间件配置成功之后，即可通过 req.session 来访问和使用 session 对象，从而存储用户的关键信息，其示例代码如下：</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></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line"><span class="comment">// 3、向 Session 中存储数据</span></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/api/login&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">//判断用户提交的登录信息是否正确</span></span><br><span class="line"><span class="keyword">if</span>(req.<span class="property">body</span>.<span class="property">username</span> !== <span class="string">&#x27;admin&#x27;</span> || req.<span class="property">body</span>.<span class="property">password</span> !== <span class="string">&#x27;000000&#x27;</span>)&#123;</span><br><span class="line"><span class="keyword">return</span> res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">1</span>,<span class="attr">message</span>:<span class="string">&#x27;登录失败&#x27;</span>&#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">req.<span class="property">session</span>.<span class="property">user</span> = req.<span class="property">body</span> <span class="comment">// 将用户的信息存储在 Session 中</span></span><br><span class="line">req.<span class="property">session</span>.<span class="property">islogin</span> = <span class="literal">true</span> <span class="comment">// 将用户的登录状态存储在 Session 中</span></span><br><span class="line"></span><br><span class="line">res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">0</span>,<span class="attr">message</span>:<span class="string">&#x27;登陆成功&#x27;</span>&#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h5 id="5-4-4-从-Session-中取出数据"><a href="#5-4-4-从-Session-中取出数据" class="headerlink" title="5.4.4 从 Session 中取出数据"></a>5.4.4 从 Session 中取出数据</h5><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></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line"><span class="comment">// 4、向 Session 中取出数据</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/api/username&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">// 判断用户是否登录</span></span><br><span class="line"><span class="keyword">if</span>(!req.<span class="property">session</span>.<span class="property">islogin</span>)&#123;</span><br><span class="line"><span class="keyword">return</span> res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">1</span>,<span class="attr">message</span>:<span class="string">&#x27;fail&#x27;</span>&#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">0</span>,<span class="attr">message</span>:<span class="string">&#x27;success&#x27;</span>,<span class="attr">username</span>:res.<span class="property">session</span>.<span class="property">user</span>.<span class="property">username</span>&#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h5 id="5-4-5-清空-Session-中的信息"><a href="#5-4-5-清空-Session-中的信息" class="headerlink" title="5.4.5 清空 Session 中的信息"></a>5.4.5 清空 Session 中的信息</h5><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></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line"><span class="comment">// 5、清空 Session 中的信息</span></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/api/logout&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line">req.<span class="property">session</span>.<span class="title function_">destroy</span>()</span><br><span class="line">res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">0</span>,<span class="attr">message</span>:<span class="string">&#x27;退出登录成功！&#x27;</span>&#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h4 id="5-5-JWT-认证机制"><a href="#5-5-JWT-认证机制" class="headerlink" title="5.5 JWT 认证机制"></a>5.5 JWT 认证机制</h4><h5 id="5-5-1-了解-Session-认证的局限性"><a href="#5-5-1-了解-Session-认证的局限性" class="headerlink" title="5.5.1 了解 Session 认证的局限性"></a>5.5.1 了解 Session 认证的局限性</h5><p>Session 认证机制需要配合 Cookie 才能实现，由于 Cookie 默认不支持跨域访问，所以当涉及到前端跨域请求后端接口的时候，需要做很多额外的配置，才能实现跨域 Session 认证。</p><p><strong>注意：</strong></p><ul><li>当前端请求后端接口不存在跨域问题的时候，推荐使用 Session 身份认证机制</li><li>当前端需要跨域请求后端接口，不推荐使用 Session 身份认证机制，推荐使用 JWT 认证机制</li></ul><h5 id="5-5-2-什么是-JWT-认证机制"><a href="#5-5-2-什么是-JWT-认证机制" class="headerlink" title="5.5.2 什么是 JWT 认证机制"></a>5.5.2 什么是 JWT 认证机制</h5><p>JWT (JSON Web Token)：是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准<a href="https://link.jianshu.com/?t=https://tools.ietf.org/html/rfc7519">(RFC 7519)</a>.该token被设计为紧凑且安全的，特别适用于分布式站点的单点登录（SSO）场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息，以便于从资源服务器获取资源，也可以增加一些额外的其它业务逻辑所必须的声明信息，该token也可直接被用于认证，也可被加密。</p><h5 id="5-5-3-JWT-认证原理"><a href="#5-5-3-JWT-认证原理" class="headerlink" title="5.5.3 JWT 认证原理"></a>5.5.3 JWT 认证原理</h5><p><img src="https://s2.loli.net/2022/06/14/sa3X5EwKvloeYSj.png"></p><p>总结：用户的信息通过 Token 字符串的形式保存在客户端浏览器中。服务器通过还原 Token 字符串的形式来认证用户的身份。</p><h5 id="5-5-4-JWT-的组成部分"><a href="#5-5-4-JWT-的组成部分" class="headerlink" title="5.5.4 JWT 的组成部分"></a>5.5.4 JWT 的组成部分</h5><p>JWT 通常由三部分组成，分别是 Header（头部）、Payload（有效荷载）、Signature（签名）。</p><ul><li>Payload 部分才是<strong>真正的用户信息</strong>，它是用户信息经过加密之后生成的字符串</li><li>Header 以及 Signature 是<strong>安全性相关</strong>的部分，只是为了保证 Token 的安全性</li></ul><p><img src="https://s2.loli.net/2022/06/14/BRdfCeYU1WANHi8.png"></p><h5 id="5-5-5-JWT-的使用方式"><a href="#5-5-5-JWT-的使用方式" class="headerlink" title="5.5.5 JWT 的使用方式"></a>5.5.5 JWT 的使用方式</h5><p>客户端收到服务器返回的 JWT 之后，通常会将它存储在 localStorage 或者 sessionStorage 中。此后，客户端每次与服务器通信，都要带上这个 JWT 的字符串，从而进行身份验证。推荐的做法是把 JWT 放在 HTTP 请求头的 Authorizatiom 字段中，格式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Authorization</span>:<span class="title class_">Bearer</span>&lt;token&gt;</span><br></pre></td></tr></table></figure><h4 id="5-6-在-Express-中使用-JWT"><a href="#5-6-在-Express-中使用-JWT" class="headerlink" title="5.6 在 Express 中使用 JWT"></a>5.6 在 Express 中使用 JWT</h4><h5 id="5-6-1-安装-JWT-相关的包"><a href="#5-6-1-安装-JWT-相关的包" class="headerlink" title="5.6.1 安装 JWT 相关的包"></a>5.6.1 安装 JWT 相关的包</h5><p>在使用 JWT 之前，我们需要安装相关的两个包，分别是 <strong>jsonwebtoken</strong> 以及 <strong>express-jwt</strong> ：</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i jsonwebtoken express-jwt</span><br></pre></td></tr></table></figure><p>其中：</p><ul><li>jsonwebtoken 用于生成 JWT 字符串 </li><li>express-jwt 用于将 JWT 字符串解析还原成 JSON 对象</li></ul><h5 id="5-6-2-导入-JWT-相关的包"><a href="#5-6-2-导入-JWT-相关的包" class="headerlink" title="5.6.2 导入 JWT 相关的包"></a>5.6.2 导入 JWT 相关的包</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入用于生成 JWT 字符串的包</span></span><br><span class="line"><span class="keyword">const</span> jwt = <span class="built_in">require</span>(<span class="string">&#x27;jsonwebtoken&#x27;</span>)</span><br><span class="line"><span class="comment">// 导入用于将客户端发送给过来的 JWT 字符串解析还原成 JSON 对象的包</span></span><br><span class="line"><span class="keyword">const</span> expressJWT = <span class="built_in">require</span>(<span class="string">&#x27;express-jwt&#x27;</span>)</span><br></pre></td></tr></table></figure><h5 id="5-6-3-定义-secret-秘钥"><a href="#5-6-3-定义-secret-秘钥" class="headerlink" title="5.6.3 定义 secret 秘钥"></a>5.6.3 定义 secret 秘钥</h5><p>为了保证 JWT 字符串的安全性，防止 JWT 字符串在网络传输过程中被别人破解，我们需要专门定义一个用于加密和解密的 secret 秘钥：</p><ol><li>当生成 JWT 字符串的时候，需要使用 secret 秘钥对用户的信息进行加密，最终得到加密好的 JWT 字符串</li><li>当把 JWT 字符串解析还原成 JSON 对象的时候，需要使用 secret 秘钥进行解密</li></ol><p>那接下来就先弄个 secret 字符串看看：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义一个 secret 字符串</span></span><br><span class="line"><span class="keyword">const</span> secretKey = <span class="string">&#x27;hello world&#x27;</span></span><br><span class="line"><span class="comment">// 通常将秘钥字符串的名字命名为 secretKey</span></span><br><span class="line"><span class="comment">// 现在还只是一个普通的字符串，并没有其他用途</span></span><br></pre></td></tr></table></figure><h5 id="5-6-4-生成-JWT-字符串"><a href="#5-6-4-生成-JWT-字符串" class="headerlink" title="5.6.4 生成 JWT 字符串"></a>5.6.4 生成 JWT 字符串</h5><p>调用 jsonwebtoken 包提供的 <code>sign()</code> 方法将用户的信息加密成 JWT 字符串然后响应给客户端，其示例代码如下：</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></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/api/login&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">// 用户登录成功之后，生成 JWT 字符串，通过 token 属性响应给客户端</span></span><br><span class="line">res.<span class="title function_">send</span>(&#123;</span><br><span class="line"><span class="attr">status</span>:<span class="number">200</span>,</span><br><span class="line"><span class="attr">message</span>:<span class="string">&#x27;登陆成功！&#x27;</span>,</span><br><span class="line"><span class="attr">token</span>:jwt.<span class="title function_">sign</span>(&#123;<span class="attr">username</span>:userinfo.<span class="property">username</span>&#125;,secretKet,&#123;<span class="attr">expiresIn</span>:<span class="string">&#x27;30s&#x27;</span>&#125;)</span><br><span class="line">        <span class="comment">// 从生成开始算 30s，在这时间内这个 token 是有效的（有效时间）</span></span><br><span class="line">&#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h5 id="5-6-5-将-JWT-字符串还原为-JSON-对象"><a href="#5-6-5-将-JWT-字符串还原为-JSON-对象" class="headerlink" title="5.6.5 将 JWT 字符串还原为 JSON 对象"></a>5.6.5 将 JWT 字符串还原为 JSON 对象</h5><p>客户端每次在访问那些有权限接口的时候，都需要主动通过请求头中的 Authorization 字段，将 Token 字符串发送到服务器进行身份验证。</p><p>此时，服务器可以通过 express-jwt 这个中间件，自动将客户端发送过来的 Token 解析还原成 JSON 对象，其示例代码如下：</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></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line"><span class="comment">// 将 JWT 字符串还原成 JSON 对象</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">expressJWT</span>(&#123;<span class="attr">secret</span>:secretKey&#125;).<span class="title function_">unless</span>(&#123;<span class="attr">path</span>:[<span class="regexp">/^\/api\//</span>]&#125;))</span><br><span class="line"><span class="comment">// 其中 .usless() 是说明哪些接口不需要访问权限</span></span><br></pre></td></tr></table></figure><h5 id="5-6-6-使用-req-user-获取用户信息"><a href="#5-6-6-使用-req-user-获取用户信息" class="headerlink" title="5.6.6 使用 req.user 获取用户信息"></a>5.6.6 使用 req.user 获取用户信息</h5><p>当 express-jwt 这个中间件配置成功之后，即可在那些有权限的接口中使用 req.user 对象，来访问从 JWT 字符串中解析出来的用户信息，示例代码如下：</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></pre></td><td class="code"><pre><span class="line">*</span><br><span class="line"><span class="comment">// 这是一个有权限的接口</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/admin/getinfo&#x27;</span>,<span class="function">(<span class="params">req,res</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">// 此处的 user 是在我们配置成功 express-jwt 这个中间件，就可以把解析出来的用户信息挂载到 req 上</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(req.<span class="property">user</span>)</span><br><span class="line">res.<span class="title function_">send</span>(&#123;</span><br><span class="line"><span class="attr">status</span>:<span class="number">200</span>,</span><br><span class="line"><span class="attr">message</span>:<span class="string">&#x27;获取用户信息成功！&#x27;</span>,</span><br><span class="line"><span class="attr">data</span>:req.<span class="property">user</span></span><br><span class="line">&#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h5 id="捕获解析-JWT-失败后产生的错误"><a href="#捕获解析-JWT-失败后产生的错误" class="headerlink" title="捕获解析 JWT 失败后产生的错误"></a>捕获解析 JWT 失败后产生的错误</h5><p>当使用 express-jwt 解析 Token 字符串的时候，如果客户端发送过来的 Token 字符串过期或不合法，会产生一个解析失败的错误，影响项目的正常运行，我们可以通过 Express 的错误中间件来捕获这个错误并进行相关的处理，其示例代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用全局错误处理中间件，来捕获 JWT 产生的错误</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="function">(<span class="params">err,req,res,next</span>)=&gt;</span>&#123;</span><br><span class="line"><span class="comment">// token 解析失败导致的错误</span></span><br><span class="line"><span class="keyword">if</span>(err.<span class="property">name</span> === <span class="string">&#x27;UnauthorizedError&#x27;</span>)&#123;</span><br><span class="line"><span class="keyword">return</span> res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">401</span>,<span class="attr">message</span>:<span class="string">&#x27;无效的 token&#x27;</span>&#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 其他原因导致的错误</span></span><br><span class="line">res.<span class="title function_">send</span>(&#123;<span class="attr">status</span>:<span class="number">500</span>,<span class="attr">message</span>:<span class="string">&#x27;未知错误&#x27;</span>&#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><br/><br/><h2 id="九、项目实战"><a href="#九、项目实战" class="headerlink" title="九、项目实战"></a>九、项目实战</h2><p>此处的项目实战不再在文档中编写，请读者自行去原视频或是以下链接处学习编写：<a href="http://escook.cn:8088/#/">Headline - api_server_ev (escook.cn)</a></p><br/><br/><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><ol><li><a href="https://www.bilibili.com/video/BV1a34y167AZ">黑马程序员Node.js全套入门教程，nodejs最新教程含es6模块化+npm+express+webpack+promise等_Nodejs实战案例详解_哔哩哔哩_bilibili</a></li><li><a href="https://blog.csdn.net/u010059669/article/details/109715342">npm包发布详细教程_醉逍遥neo的博客-CSDN博客_npm 发布</a> </li><li><a href="https://www.bilibili.com/video/BV1da4y1p7iZ">10分钟快速掌握正则表达式_哔哩哔哩_bilibili</a></li><li><a href="https://blog.csdn.net/android_zhengyongbo/article/details/75452305">Http请求头和响应头_未来可期-2022的博客-CSDN博客_请求头和响应头</a></li><li><a href="https://www.jianshu.com/p/f880878c1398">什么是跨域请求以及实现跨域的方案 - 简书 (jianshu.com)</a></li><li><a href="https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93/103728?fr=aladdin">数据库（电子化的文件柜）_百度百科 (baidu.com)</a></li><li><a href="https://zhuanlan.zhihu.com/p/37152572">超级详细的mysql数据库安装指南 - 知乎 (zhihu.com)</a></li><li><a href="https://baike.baidu.com/item/Session/479100">session（计算机术语）_百度百科 (baidu.com)</a></li><li><a href="https://www.jianshu.com/p/576dbf44b2ae">什么是 JWT – JSON WEB TOKEN - 简书 (jianshu.com)</a></li><li><a href="http://escook.cn:8088/#/">Headline - api_server_ev (escook.cn)</a></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;


&lt;p&gt;配套课程：&lt;a href=&quot;https://www.bilibili.com/video/BV1a34y167AZ&quot;&gt;黑马程序员Node.js全套入门教程，nodejs最新教程含es6模块化+npm+express+webpack+promise等_Node</summary>
      
    
    
    
    <category term="后端" scheme="https://yxbug.ren/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="知识点" scheme="https://yxbug.ren/tags/%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
    
    <category term="node" scheme="https://yxbug.ren/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>龙年总结</title>
    <link href="https://yxbug.ren/2025/01/27/%E9%BE%99%E5%B9%B4%E6%80%BB%E7%BB%93/"/>
    <id>https://yxbug.ren/2025/01/27/%E9%BE%99%E5%B9%B4%E6%80%BB%E7%BB%93/</id>
    <published>2025-01-27T09:00:00.000Z</published>
    <updated>2025-12-26T12:19:08.258Z</updated>
    
    <content type="html"><![CDATA[<br/><p>写到这篇文章的时候长叹一口气：“龙年总算是结束了……”</p><h2 id="考公"><a href="#考公" class="headerlink" title="考公"></a>考公</h2><p>在这个经济下行，就业环境非常恶劣的年代，我作为一个在这个时期毕业的大学生，前途无疑是明暗未知的。在七月份时候我也收到过杭州一个公司的 offer，但工资太低了，以至于不能够满足我作为一个非本地人基本的生活需要，所以我拒绝了。也正因此，我才下定决心准备考公考编。</p><p>与考研相比，考公的科目难度要低许多，难在岗位少人多，再简单的科目也会被卷出不简单的分数。</p><p>我从七月份开始复习，在参加省考之前总共参加了 3 次事业编制的考试和一次国考，事业编制和国考的成绩都不错，但都差一点就近面试。省考倒是进了面试，但分数却又有点低了。但总归是进了面试，还是报了面试班，好好准备。</p><p>下面就考公给出一点建议。</p><p>考公尽量最晚在七月份之前就开始学习，我的建议是有那个毅力报线下辅导班就最好去报线下辅导班。不方便的可以先买一个粉笔 980 的课，用一到两个月左右的时间把粉笔的课都看完，然后可以去看花生的课。到了九、十月份就要去刷题，每次刷题都要根据自己报考的考试的设置并掐表来做。只有这样才能够真正的锻炼自己的解题速度。与考研不一样的是，考研的时间是充裕的，而考公的时间是及其紧张的。特别是形策，两个小时要写 130 左右的题，平均一道题 50s，还要保证正确率，这是非常难的。在刷题的一开始可以先放慢速度，保证正确率，然后就要不断加快速度，直到能够稳定在时间限制内做完并保证一定的正确率。</p><p>我把近几年的真题卷放在了考试之前当做模拟题来做，但我感觉这样做是错误的。真题可以在刷题阶段结束之后就开始写，不要怕不够写。粉笔上的模拟卷以及其他机构出的一些卷子质量都还行，完全可以在模拟阶段拿来做。并且真题在平时刷题过程中都会遇见，要是把真题放在最后阶段用来模拟，一是分数不能代表真实成绩，二是对于自身的题量累积没有什么太大的帮助。</p><p>粉笔上每个星期都有一次模拟，我个人感觉不需要每个星期都做，可以两个星期参加一次。</p><p><br/><br/></p><h2 id="爷爷"><a href="#爷爷" class="headerlink" title="爷爷"></a>爷爷</h2><p>我的爷爷在过年前不久去世了，在我知道我爷爷要不行的时候我从没想过我的家人有一天也会离开，而且这么快。</p><p>在 2024 年九月份的时候，家里有个亲戚去世了。虽说那个亲戚年龄也不大，也才 60 多岁，但是她已患糖尿病多年，并且自己不注意，所以她的离开我并没有太大意外。当时，我奶奶还过去帮忙操办后事，爷爷还在斗地主。但这件事也对我有了一个提醒，事情办完之后我就在想过年的时候要在家里拍一个全家福，以防万一。</p><p>但谁也没想到年还没过呢，爷爷从开始感觉不舒服，到过世只有短短的两个月不到。两个月不到的时间里，我爷爷就从一个能干活的大男人变成一个躺在病床上生活不能自理的皮包骨，最后变成了一盒轻飘飘的灰。</p><p>爷爷得的是一个叫“间质瘤”的病，在之前的文章中也写过了。一开始检查出来的时候只是说腹部有些微扩散，但身体其他地方没事，可以回去吃吃药，还能活个几年。但爷爷出院之后却发现吃了药就呕吐，本来以为这就是副作用，多吃两天药就行了，但爷爷反应不但没有变轻，反而愈演愈烈，只能送往医院，但等再送到医院的时候已经回天乏术了。</p><p>最让我感到悲哀的是，因为这个病，我爷爷两个月没有吃过正经饭菜，临死前都是在吊营养液。</p><p>我爷爷自生下来就是一个极度要强的人，并且是一个吃苦耐劳的人。可以这么说，一整个村子里，除了再上一辈的人，同辈和晚辈中就没有一个能和我爷爷一样能吃苦的人，他一辈子都是在吃苦当中度过的。要说现在生活已经变好了，他年纪也大，家里也有存款，但他就是要出去打工。这几年爷爷一直在帮别人搬墓碑，不靠工具，靠他那 70 多岁的背。</p><p>2024 年开年的时候爷爷出了车祸，大腿骨折，但万幸的是只要装一个钢板就可以和正常人一样活动。本来我想着这也是个好事，人没啥大事，还能逼着他在家好好休息，安心养老。但他在家躺了一段时间之后就又出去干活，甚至又去搬墓碑。而这次他发现不舒服就是在搬墓碑的过程中发现身上没有力气，腿软，然后还胀气。</p><p>办丧事的时候，街坊邻居无一不说我爷爷吃了一辈子苦，现在终于可以不用吃苦了。</p><p>到了现在我早已接受现实，我明白不能和老人说什么“以后”，因为老人可能根本没有以后。意外、疾病可以非常快的将老人的带走，不给一点反应的机会。但直到我无意间看到我在去年给家里人建的一个群。</p><p><img src="https://s2.loli.net/2025/01/13/2bEesrNaTKvYWGm.png" alt="1736742881377.png"></p><p><br/><br/></p><h2 id="快乐"><a href="#快乐" class="headerlink" title="快乐"></a>快乐</h2><p>龙年也有属于我的快乐。</p><p>在龙年，我成功毕业（虽然这本来就是一件简单的事）；我和朋友成功去重庆玩了一次（虽然过程有点坎坷，吃坏肚子拉了一天）；见证了无畏契约EDG夺得了世界冠军；玩到了中国第一款真正意义上的 3A 游戏《黑神话：悟空》。这些快乐说大也不大，说小也不小，但对于悲惨了一年的我来说，这些快乐都是我在龙年的一点点继续生活的勇气。</p><p>在黑猴成功发售之前，我和朋友的都笑称“为了玩黑猴，我都好好活下去”。当在 8 月 20 日的时候，我玩到了这款梦寐以求的游戏。显然，根据我之前的文章，我对这款游戏是非常满意的，作为国内的第一款 3A 大作，黑猴令我感到惊喜。在游玩黑猴之前以及之后我有相当长的一段时间都陷入到了“电子阳痿”之中。这就像是获得了自己一直想要得到的东西之后会陷入一段时间的空虚一样。可笑的是，十二月份的 TGA 将年度最佳游戏颁给了《宇宙机器人》。</p><p>去重庆的旅行是我近几年来最开心的一次旅行。我和朋友在晚上一落地就去吃了重庆老火锅，火锅是好吃的，但我的肠胃也是真生气了。第二天一天我拉了十几次肚子，直到傍晚吃了肠炎宁才得以平息下来。在晚上睡觉的时候，因为我精神比较差，遭遇了“鬼压床”，在慢慢清醒的时候，被正对着床的房门吓了一跳，我以为是一个拿着刀的人站在我的床尾。这导致我第三天晚上就去找朋友一起睡了。</p><p>在重庆，我们去了解放碑，看了晚上的洪崖洞，坐了长江索道，吃了重庆小面和重庆老火锅。还去了成都看大熊猫（大熊猫繁育基地没有几个大熊猫我是没想到的，地上的松鼠和孔雀都比大熊猫多）和逛了宽窄巷子。</p><p>PS：有一家烤鸭店，又贵又难吃，我的评价是泡面都比这家店的东西好吃。</p><p><br/><br/></p><h2 id="本命年"><a href="#本命年" class="headerlink" title="本命年"></a>本命年</h2><p>蛇年是我的本命年，已经买好了红内裤、红袜子。但除此以外，今年我们家却不能张贴红色的春联，不能放烟花爆竹。我只希望在蛇年一切都能够变好。我能够成功上岸，家人身体健康，一切顺利。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;



&lt;p&gt;写到这篇文章的时候长叹一口气：“龙年总算是结束了……”&lt;/p&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;在这个经济下行，就业环境非常恶劣的年代，我作为一个在</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="总结" scheme="https://yxbug.ren/tags/%E6%80%BB%E7%BB%93/"/>
    
    <category term="随笔" scheme="https://yxbug.ren/tags/%E9%9A%8F%E7%AC%94/"/>
    
  </entry>
  
  <entry>
    <title>病</title>
    <link href="https://yxbug.ren/2024/12/17/%E7%97%85/"/>
    <id>https://yxbug.ren/2024/12/17/%E7%97%85/</id>
    <published>2024-12-17T04:00:00.000Z</published>
    <updated>2025-11-20T12:29:27.124Z</updated>
    
    <content type="html"><![CDATA[<br/><p>爷爷胃病有了一些时日了，上个月爷爷突然胃部长时间胀气，就来市里的医院检查，因为肚子里还有胀气和食物，所以没有查出原因。父亲把爷爷转去的苏州的一个医院，经过将近一周的检查之后医生说是“间质瘤”。现在这个阶段手术不能做，只能靠吃一种靶向药或者是放化疗来延长生命。但靶向药效果好，痛苦少，爷爷吃了药后面甚至能回归正产生活、正常吃喝，再活个十年。</p><p>医生在爷爷的胃部撑起了一个架子来扩大胃部，这样爷爷还能少量的摄入一些食物，否则就要全程靠营养液撑着。</p><p>检查完爷爷能够吃这种靶向药并且拿到药之后父亲就把爷爷带回了家，让爷爷在家吃药休息。但胃部的架子歪了，加上有一些对药物的不良反应，爷爷在家的一个星期一点药都没能吃。所以父亲又把爷爷带来市里的医院，但市里的医院搞了一个星期还是什么名堂都没搞出来。无奈只能再带去苏州。这样算下来，爷爷已经被耽误了两个星期。</p><p>去苏州之后，医生给他做了穿刺，先把肚子里的积水排除，又插了管，直接将药物送到胃部，但爷爷还是一天不如一天。</p><p>父亲和奶奶去苏州照顾爷爷，我和母亲在家只能每天打电话过去问问情况，母亲已经哭了很多次了，我也很担心爷爷的身体状况，但我们毫无办法，只能寄希望于医生。</p><p>我想，小时候的我和以后成家立业的我都不害怕爷爷离开，因为小时候的我还不懂得亲情，可能只是哭一哭；成家立业后的我懂得了人总有生老病死，况且还有家庭作为生活下去的希望。但现在我很害怕。我只能把注意力转移到学习和游戏中，但又显的不懂事。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;



&lt;p&gt;爷爷胃病有了一些时日了，上个月爷爷突然胃部长时间胀气，就来市里的医院检查，因为肚子里还有胀气和食物，所以没有查出原因。父亲把爷爷转去的苏州的一个医院，经过将近一周的检查之后医生说是“间质瘤”。现在这个阶段手术不能做，只能靠吃一种靶向药或者是放化疗来延长生命</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="生活" scheme="https://yxbug.ren/tags/%E7%94%9F%E6%B4%BB/"/>
    
    <category term="家人" scheme="https://yxbug.ren/tags/%E5%AE%B6%E4%BA%BA/"/>
    
  </entry>
  
  <entry>
    <title>我也要做天命人</title>
    <link href="https://yxbug.ren/2024/08/25/%E6%88%91%E4%B9%9F%E8%A6%81%E5%81%9A%E5%A4%A9%E5%91%BD%E4%BA%BA/"/>
    <id>https://yxbug.ren/2024/08/25/%E6%88%91%E4%B9%9F%E8%A6%81%E5%81%9A%E5%A4%A9%E5%91%BD%E4%BA%BA/</id>
    <published>2024-08-25T11:35:00.000Z</published>
    <updated>2025-11-20T12:29:27.119Z</updated>
    
    <content type="html"><![CDATA[<br/><p>中国的第一款 3A 游戏《黑神话：悟空》在 2024 年 8 月 20 日正式发售，作为一个从第一个 pv 就关注的玩家，第一时间就上手了这款游戏。很显然，这款游戏已经完全超出了我的预期，以下是我对《黑神话：悟空》的个人评测。</p><p><strong>评测分：9分</strong></p><h4 id="不俗的战斗"><a href="#不俗的战斗" class="headerlink" title="不俗的战斗"></a>不俗的战斗</h4><p>《黑神话：悟空》的战斗元素非常多，三种不同的棍势，每种棍势都可以在对局中有一些特殊的用处，比如可以规避地面伤害的立棍，攻击范围较大的戳棍。战斗中还有两种变身系统，一种是长时间变身，一种是化身妖怪打出单个动作。这两个变身系统在战斗中非常有用，最高级的青蛙化身可以轻松打掉 BOSS 将近 15% 的血量。同时，还拥有一个神器系统，神器系统也非常强大，针对具有一定特点的敌人有奇效，比如使用“定风珠”可以直接破解黄风大王的技能，也能让在天上飞的怪物坠地，从而打出一套连招。</p><p>BOSS 的演出是我玩过的单机游戏里数一数二的，和《战神》、《艾尔登法环》这些顶级作品相比都毫不逊色。每一个 BOSS 都给我留下了深刻的印象。</p><p>但令人遗憾的是，《黑神话：悟空》的战斗系统虽然元素众多，但都不是很深。虽然有三种不同的棍势，但是轻攻击只有一套，棍势的不同点只在于重攻击。而且在一周目打到第五和第六章时，就会形成一套固定连招，打完一套连招之后就会陷入一段时间的冷却期。这大大减少了游戏战斗的乐趣，我在战斗时候甚至形成了一定的肌肉记忆。</p><p>总体来说，《黑神话：悟空》的战斗还是能给 <strong>8</strong> 分。</p><h4 id="非常优秀的美术"><a href="#非常优秀的美术" class="headerlink" title="非常优秀的美术"></a>非常优秀的美术</h4><p>《黑神话：悟空》的美术和画面不用我多说，只需看过一眼就会大呼“分不清现实和游戏”。游科大量扫描国内的古建，让人足不出户也能体会到美丽的古建筑景色。很喜欢杨奇的一句话“老祖宗赏饭吃”。《黑神话：悟空》的画面精美到纯当做一个风景模拟器，268 元的价格也可以值回票价。</p><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/660;"><img class="lazy" src="https://s2.loli.net/2024/09/05/smfxtyNrZcdVKM8.jpg" data-src="https://s2.loli.net/2024/09/05/smfxtyNrZcdVKM8.jpg" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://s2.loli.net/2024/09/05/smfxtyNrZcdVKM8.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><div class="tag-plugin image"><div class="image-bg" style="aspect-ratio:1280/660;"><img class="lazy" src="https://s2.loli.net/2024/09/05/ankXWfV1NTIRSdE.jpg" data-src="https://s2.loli.net/2024/09/05/ankXWfV1NTIRSdE.jpg" data-fancybox="true"onerror="this.src=&quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2rem' height='2rem' viewBox='0 0 24 24'%3E%3C!-- Icon from Solar by 480 Design - https://creativecommons.org/licenses/by/4.0/ --%3E%3Cpath fill='%23F44336' d='M22 12.698c-.002 1.47-.013 2.718-.096 3.743c-.097 1.19-.296 2.184-.74 3.009a4.2 4.2 0 0 1-.73.983c-.833.833-1.893 1.21-3.237 1.39C15.884 22 14.2 22 12.053 22h-.106c-2.148 0-3.83 0-5.144-.177c-1.343-.18-2.404-.557-3.236-1.39c-.738-.738-1.12-1.656-1.322-2.795c-.2-1.12-.236-2.512-.243-4.241Q1.999 12.737 2 12v-.054c0-2.148 0-3.83.177-5.144c.18-1.343.557-2.404 1.39-3.236s1.893-1.21 3.236-1.39c1.168-.157 2.67-.175 4.499-.177a.697.697 0 1 1 0 1.396c-1.855.002-3.234.018-4.313.163c-1.189.16-1.906.464-2.436.994S3.72 5.8 3.56 6.99C3.397 8.2 3.395 9.788 3.395 12v.784l.932-.814a2.14 2.14 0 0 1 2.922.097l3.99 3.99a1.86 1.86 0 0 0 2.385.207l.278-.195a2.79 2.79 0 0 1 3.471.209l2.633 2.37c.265-.557.423-1.288.507-2.32c.079-.972.09-2.152.091-3.63a.698.698 0 0 1 1.396 0' opacity='.5'/%3E%3Cpath fill='%23F44336' fill-rule='evenodd' d='M17.5 11c-2.121 0-3.182 0-3.841-.659S13 8.621 13 6.5s0-3.182.659-3.841S15.379 2 17.5 2s3.182 0 3.841.659S22 4.379 22 6.5s0 3.182-.659 3.841S19.621 11 17.5 11m-1.47-7.03a.75.75 0 1 0-1.06 1.06l1.47 1.47l-1.47 1.47a.75.75 0 0 0 1.06 1.06l1.47-1.47l1.47 1.47a.75.75 0 1 0 1.06-1.06L18.56 6.5l1.47-1.47a.75.75 0 0 0-1.06-1.06L17.5 5.44z' clip-rule='evenodd'/%3E%3C/svg%3E&quot;"/><div class="lazy-icon" style="background-image:url(https://api.iconify.design/eos-icons:three-dots-loading.svg?color=%231cd0fd);"></div><a class="image-download blur" style="opacity:0" target="_blank" href="https://s2.loli.net/2024/09/05/ankXWfV1NTIRSdE.jpg"><svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3734"><path d="M561.00682908 685.55838913a111.03077546 111.03077546 0 0 1-106.8895062 0L256.23182837 487.72885783a55.96309219 55.96309219 0 0 1 79.13181253-79.18777574L450.70357448 523.88101491V181.55477937a55.96309219 55.96309219 0 0 1 111.92618438 0v344.06109173l117.07478902-117.07478901a55.96309219 55.96309219 0 0 1 79.13181252 79.18777574zM282.81429711 797.1487951h447.70473912a55.96309219 55.96309219 0 0 1 0 111.92618438H282.81429711a55.96309219 55.96309219 0 0 1 0-111.92618438z" p-id="3735"></path></svg></a></div></div><p>（图片均来源于网友）<br>美术部分，评分 <strong>10</strong> 分。</p><h4 id="堪称无敌的音乐"><a href="#堪称无敌的音乐" class="headerlink" title="堪称无敌的音乐"></a>堪称无敌的音乐</h4><p>与画面美术一样的是，《黑神话：悟空》的音乐也堪称无敌。当我在看第三回小雷音寺的动画时，响起的背景音乐《屁》一下子就震撼我了，配合起令人震惊的剧情，让我直呼牛逼。当变身成为刀郎教头广智的时候，那一下哨音以及后续的唢呐简直能让人的耳朵直接怀孕。第四回盘丝岭的片尾曲《勿听》又能让人潸然泪下。</p><p>音乐部分，评分 <strong>10</strong> 分。</p><h4 id="褒贬不一的剧情"><a href="#褒贬不一的剧情" class="headerlink" title="褒贬不一的剧情"></a>褒贬不一的剧情</h4><p>《黑神话：悟空》的剧情采用了和魂类一样的碎片化叙事，而且将很多的信息融合在了人物图鉴“影神图”中，这大大加强了玩游戏时探索剧情的乐趣，打完一些妖怪之后阅读影神图中的小传，有凄美地、有滑稽的、有可怖的。而与魂类不同是，游戏总有一条主线，即寻找大圣的六根复活大圣来贯穿全文。这又不会让人完全搞不懂自己从哪来，要干什么去。</p><p>但《黑神话：悟空》得剧情实在是说不上什么好。老套的阴谋论，不知是谁的老猴子都让人对故事提不上什么兴趣。</p><p>剧情部分，评分 <strong>7</strong> 分。</p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>《黑神话：悟空》作为国产的第一款 3A 游戏无疑是成功的，这大大增强了国内资本对于单机游戏的信心，也让世界看到了中国的文化以及中国的购买力。我相信，随着《黑神话：悟空》的成功，国内会出现越来越多的单机工作室以及他们所创作出的媲美日本和欧美一线游戏的作品。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;



&lt;p&gt;中国的第一款 3A 游戏《黑神话：悟空》在 2024 年 8 月 20 日正式发售，作为一个从第一个 pv 就关注的玩家，第一时间就上手了这款游戏。很显然，这款游戏已经完全超出了我的预期，以下是我对《黑神话：悟空》的个人评测。&lt;/p&gt;
&lt;p&gt;&lt;strong</summary>
      
    
    
    
    <category term="游戏评测" scheme="https://yxbug.ren/categories/%E6%B8%B8%E6%88%8F%E8%AF%84%E6%B5%8B/"/>
    
    
    <category term="游戏" scheme="https://yxbug.ren/tags/%E6%B8%B8%E6%88%8F/"/>
    
    <category term="评测" scheme="https://yxbug.ren/tags/%E8%AF%84%E6%B5%8B/"/>
    
  </entry>
  
  <entry>
    <title>服务器部署 Vue 项目，报找不到路由错</title>
    <link href="https://yxbug.ren/2024/06/23/%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%83%A8%E7%BD%B2%20Vue%20%E9%A1%B9%E7%9B%AE%EF%BC%8C%E6%8A%A5%E6%89%BE%E4%B8%8D%E5%88%B0%E8%B7%AF%E7%94%B1%E9%94%99/"/>
    <id>https://yxbug.ren/2024/06/23/%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%83%A8%E7%BD%B2%20Vue%20%E9%A1%B9%E7%9B%AE%EF%BC%8C%E6%8A%A5%E6%89%BE%E4%B8%8D%E5%88%B0%E8%B7%AF%E7%94%B1%E9%94%99/</id>
    <published>2024-06-23T02:35:00.000Z</published>
    <updated>2025-11-20T12:29:27.124Z</updated>
    
    <content type="html"><![CDATA[<br /><p>错误截图如下</p><p><img src="https://s2.loli.net/2024/06/24/lUtYQCwcHh71zF8.png" alt="错误截图"></p><p>想解决这个问题，我们需要先了解 Vue 路由中的三种模式，分别是 Hash、History 以及 Abstract。</p><h2 id="一、Vue-中的三个路由模式"><a href="#一、Vue-中的三个路由模式" class="headerlink" title="一、Vue 中的三个路由模式"></a>一、Vue 中的三个路由模式</h2><h4 id="1-Hash-模式"><a href="#1-Hash-模式" class="headerlink" title="1. Hash 模式"></a>1. Hash 模式</h4><p>在 URL 中使用带有 # 符号的哈希值来管理路由，例如：<a href="http://xxxx.com/#/path%E3%80%82%E4%BD%86%E8%BF%99%E6%A0%B7%E4%BC%9A%E6%98%BE%E5%BE%97%E5%9C%B0%E5%9D%80%E6%A0%8F%E4%B8%8D%E7%BE%8E%E8%A7%82%E3%80%82">http://xxxx.com/#/path。但这样会显得地址栏不美观。</a><br>在 Hash 模式下，当 URL 的哈希值发生变化时，浏览器不会向服务器发送请求，而是通过监听 hashchange 事件来进行路由导航，因此前端能够通过哈希值来恢复应用的状态。</p><h4 id="2-History-模式"><a href="#2-History-模式" class="headerlink" title="2. History 模式"></a>2. History 模式</h4><p>使用 HTML5 的 History API 来管理路由。这种模式下，URL 不再需要使用哈希值，而是直接使用正常的 URL 地址。例如：<a href="http://xxxx.com/path%E3%80%82">http://xxxx.com/path。</a><br>在 History 模式下，当 URL 发生变化时，浏览器会向服务器发送请求，服务器需要配置相应的路由规则，以确保在刷新页面或直接访问 URL 时能正确响应路由。</p><h4 id="3-Abstract-模式"><a href="#3-Abstract-模式" class="headerlink" title="3. Abstract 模式"></a>3. Abstract 模式</h4><p>这种模式主要用于非浏览器环境，比如在服务器端渲染（Server-Side Rendering）时使用。<br>在 Abstract 模式下，Vue Router 不会对 URL 进行任何处理，而是将路由信息保存在内存中，通过编程方式进行路由导航。</p><h2 id="二、错误原因"><a href="#二、错误原因" class="headerlink" title="二、错误原因"></a>二、错误原因</h2><p>主要原因是我们在前端中使用的是 History 模式的路由，在这个模式下，浏览器会直接请求例如 &#x2F;path 的路径，而不是请求包含哈希的 URL。而服务器端是不认识这样的 URL 的，服务器需要正确配置来支持这种模式，即对于所有的前端路由请求，都应返回入口文件（通常是 index.html）。</p><h2 id="三、解决办法"><a href="#三、解决办法" class="headerlink" title="三、解决办法"></a>三、解决办法</h2><p>用 宝塔 Linux 面板做演示</p><p>打开前端网页的设置，点击伪静态，然后输入以下代码</p><div class="tag-plugin colorful note" color="green" child="codeblock"><div class="body"><!-- cell --><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">location / &#123;</span><br><span class="line">    try_files $uri $uri/ /index.html;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></div><p>以上代码就是定义了入口文件，也就是 index.html。</p><p>如图</p><p><img src="https://s2.loli.net/2024/06/24/HXU7ZlQLu51MrVY.png" alt="解决办法"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;br /&gt;


&lt;p&gt;错误截图如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2024/06/24/lUtYQCwcHh71zF8.png&quot; alt=&quot;错误截图&quot;&gt;&lt;/p&gt;
&lt;p&gt;想解决这个问题，我们需要先了解 Vue 路由中的三种模式，分别是 </summary>
      
    
    
    
    <category term="服务器" scheme="https://yxbug.ren/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    <category term="前端" scheme="https://yxbug.ren/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="知识点" scheme="https://yxbug.ren/tags/%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
    
    <category term="报错" scheme="https://yxbug.ren/tags/%E6%8A%A5%E9%94%99/"/>
    
  </entry>
  
  <entry>
    <title>关于开站的一个DNS问题</title>
    <link href="https://yxbug.ren/2024/05/07/%E5%85%B3%E4%BA%8E%E5%BC%80%E7%AB%99%E7%9A%84%E4%B8%80%E4%B8%AADNS%E9%97%AE%E9%A2%98/"/>
    <id>https://yxbug.ren/2024/05/07/%E5%85%B3%E4%BA%8E%E5%BC%80%E7%AB%99%E7%9A%84%E4%B8%80%E4%B8%AADNS%E9%97%AE%E9%A2%98/</id>
    <published>2024-05-07T10:35:00.000Z</published>
    <updated>2025-11-20T12:29:27.117Z</updated>
    
    <content type="html"><![CDATA[<br /><p>宝塔面板开站的时候，有时会出现无法连接网络的情况，这种情况往往就是DNS解析的问题。<br>我在迁移博客的时候，就遇到了这个问题，我在宝塔面板上开站，然后在域名解析那里添加了A记录，但是就是无法访问。我尝试ping博客网站，发现可以ping的通，但就是无法连接网站。我尝试解析更多的二级域名，然后用这些二级域名开站，发现都可以正常开站。百度之后说DNS的变化有时间，并且我要先把原服务器上的网站给删了。所以我删除原服务器上的网站之后又等了两天，但博客网站还是无法连接网络。<br>最后我找到了解决的办法，以下是遇到网站无法连接网络的几个解决办法。</p><ol><li>域名需要正确解析至该服务器IP地址</li><li>服务器需要开启相应的端口，通常都是80端口</li><li>服务器上需要正确配置网站</li><li>如果是迁移网站的话，需要删除原服务器上的网站，更改DNS设置后需要等待一段时间</li><li>删除浏览器缓存，因为浏览器记录了原来的DNS信息，所以会导致无法连接网络（这就是我无法正常访问博客的原因）</li><li>重启服务器，重启Nginx服务</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;br /&gt;

&lt;p&gt;宝塔面板开站的时候，有时会出现无法连接网络的情况，这种情况往往就是DNS解析的问题。&lt;br&gt;我在迁移博客的时候，就遇到了这个问题，我在宝塔面板上开站，然后在域名解析那里添加了A记录，但是就是无法访问。我尝试ping博客网站，发现可以ping的通，但就是无法连</summary>
      
    
    
    
    <category term="服务器" scheme="https://yxbug.ren/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    
    <category term="知识点" scheme="https://yxbug.ren/tags/%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
    
    <category term="DNS" scheme="https://yxbug.ren/tags/DNS/"/>
    
  </entry>
  
  <entry>
    <title>南邮 811 考研复习建议</title>
    <link href="https://yxbug.ren/2023/12/27/%E5%8D%97%E9%82%AE811%E8%80%83%E7%A0%94%E5%A4%8D%E4%B9%A0%E5%BB%BA%E8%AE%AE/"/>
    <id>https://yxbug.ren/2023/12/27/%E5%8D%97%E9%82%AE811%E8%80%83%E7%A0%94%E5%A4%8D%E4%B9%A0%E5%BB%BA%E8%AE%AE/</id>
    <published>2023-12-27T10:35:00.000Z</published>
    <updated>2025-11-20T12:29:27.117Z</updated>
    
    <content type="html"><![CDATA[<br/><br/><h2 id="一、前言"><a href="#一、前言" class="headerlink" title="一、前言"></a>一、前言</h2><p>24 年的考研在两天之前已经结束了，虽然本次考研我不一定能够取得满意的成绩，但是对于考研这个事情我还是能够提出一定的建议，至少可以帮助后面参加考研的学弟学妹们避坑。本文章只针对报考院校为南京邮电大学计算机专硕（数二英二 811）的同学，并分别将自己的考研复习过程和建议，分数学、专业课、英语以及政治写在本文章中，各位可以选择阅读。</p><p>首先对于考研这个事情，各位需要考虑清楚自己是否真的需要考研，是自己为了提升自己而考研、为了以后能够更好地就业考研，还是跟风考研。如果是跟风考研的话，我建议各位就不要考研，而是提升自己的专业知识。原因有二：一是考研的过程非常痛苦，越到后面越痛苦，如果你是跟风考研的话，那这个苦你不一定吃的下来，而导致自己之前的努力全部浪费；二是考研缩招已经成了定局，今年考研难度明显比去年高出一大截，跟风考研的话会导致本身学起来就比较困难，效果较差。而如果你是自己想要考研，那么认准这个目标努力下去就行。你的努力不一定能让你成功上岸，但是对于你以后的人生路一定会有所帮助。</p><p>再次提醒，本文章经针对报考南京邮电大学计算机专硕的同学，如果你目前对自己的未来还不够确定，那么可以用这个寒假的时间来好好想想自己是否真的需要考研，是否要去考公或者考编、好好去研究研究专业以及院校。</p><p>同时，本文章内会推荐一些老师、辅导机构等，这些东西都需要同学们自己去尝试，毕竟适合我的老师不一定也适合你们。同学们可以在早期的时候多去尝试一些老师，然后根据自己的喜好来选择老师。同时推荐去买买网盘盗版课。</p><p>对于一整个考研复习规划，我建议就从大三上学期和大三下学期之间的这个寒假（下面所指的寒假也是这个阶段的寒假）开始，先好好研究一下考研相关的信息，确定好自己的目标院校和专业，然后再进入复习过程。</p><br/><h2 id="二、数学"><a href="#二、数学" class="headerlink" title="二、数学"></a>二、数学</h2><p>数学在整个考研中是最重要的一门学科，不仅内容多，而且非常难。得数学者得天下这句话依然适用于考研。数学的复习在寒假就可以开始了，下面是我的复习过程以及我的建议。</p><h3 id="1、-我的过程"><a href="#1、-我的过程" class="headerlink" title="1、 我的过程"></a>1、 我的过程</h3><ol><li>我是在大三上学期就开始数学的复习，那时候跟的是汤家凤老师的高数基础，不得不说汤家凤老师的基础讲的是真的好，非常适合零基础的小白，而汤家凤老师在 B 站上还免费更新零基础课程。有兴趣的可以用很短的时间来零基础入门一下。</li><li>当时我还买了<a href="https://bestzixue.com/index_b.html">知能行</a>，这是一个刷题网站，按章节将题目归类好，并通过算法让用户能够从基础难度的题慢慢做到接近考研难度的题。这个网站很适合想要按章节大量刷题的同学。</li><li>大三下学期的时候我就把高数基础过了一轮，并把李永乐的线代过了一遍。并将 660 做了一小半。</li><li>暑假的时候我跟张宇的高数强化课和凯哥的线代课，并将 660 全部做了一遍。</li><li>九月份的时候做了 880 的基础篇，然后就去开始做真题试卷。</li><li>十月份狂刷真题试卷，一直做到2020年（因为2020年以后改革了），并将错题二刷，搞懂每个错题。</li><li>十一月份前 20 天就刷模拟试卷。张宇八套卷、李永乐六套卷、李林六套卷，其中李林六套卷只做了一套。真题又把 2021 年和 2022 年的刷了。</li><li>11.21-12.10 都用来全真模拟，最后一次做 2023 年的真题。</li></ol><h3 id="2、建议"><a href="#2、建议" class="headerlink" title="2、建议"></a>2、建议</h3><ol><li>数学最迟寒假也要开始一轮复习了基础可以跟汤家凤老师，汤家凤老师讲的真的很详细，如果你看了汤家凤老师的零基础课程，那么可以在一轮复习的时候（零基础只能说是前置课程，谈不上一轮复习）直接去跟张宇老师。张宇的技巧性非常强，对零基础的同学可能难度颇高。</li><li>复习过程中我推荐张宇的《1000 题》。《1000 题》偏难，但如果你全啃下来了那么你也可以说是大成了。很多人推荐李林的《880》，但就今年来说考研难度远超李林的《880》，有时间的可以做一做，没时间就别做了。</li><li>在 4-6 月份的时候就要将高数部分的一轮复习结束了，这个时候可以先去看看线代课，把行列式、矩阵、向量、秩这些基础的知识看懂就行，随便看哪个老师的，只要能把这些基础的东西搞懂就行。</li><li>7-8 月份就要开始高数的强化和线代正式的复习了，高数强化我非常推荐张宇的《闭关修炼 18 讲》，真的非常好，而且还是书课包，买了书就有了正版课。线代跟凯哥，凯哥的线代课真的是来头猪都能听懂，讲的非常好。不用去听其他人的诋毁，一个老师讲的好不好只有自己真的去听了才知道。而且买凯哥的正版课还有答疑班服务，老师的回答很快很好，一定能把你讲懂。同时，这个时间段可以去找找以前的模拟卷做做。</li><li>9 月份上旬就要结束强化了，转而去做真题，只需要做近 20 年的真题就可以了，21年及以后的可以先不做，之前的一定要多刷几遍。做真题不推荐一天一套，最好是两天一套这样的速度，第一天上午做完下午批改订正，第二天再去复习一遍错题以及做的时候就不太会做的题。</li><li>10 月中旬就要开始做模拟卷和冲刺卷，看今年这个情况李林的卷子用处不大，可以去做张宇、李艳芳、合工大超越的卷子。记住每张卷子每道题都要能够搞懂，做的少没关系，但一定要吃透知识点。</li><li>到了 11 月份下旬，可以开始模考了，我的建议是 11.21-12.10，每三天模拟一轮，严格按照考研标准来进行。</li><li>模考完最后两个星期就是来把之前的错题再过一遍，把自己不懂的点搞懂。</li></ol><br/><h2 id="三、专业课"><a href="#三、专业课" class="headerlink" title="三、专业课"></a>三、专业课</h2><p>南邮的专业课只考一门 811 数据结构，用的是南邮自己老师出版的《数据结构（王海艳）》版。我推荐在这个之外再买一本王道数据结构和邮学考研辅导机构的课。下面是我的复习过程以及我的建议。</p><h3 id="1、我的过程"><a href="#1、我的过程" class="headerlink" title="1、我的过程"></a>1、我的过程</h3><ol><li>我是大三下学期开始复习专业课的，一个学期把一轮过了一遍，看的是王道的课和书，做王道书后的习题。</li><li>暑假的时候看王海艳的书，同时做了笔记，笔记的下载地址我会放在本节的最后。</li><li>9 月份开学跟着邮学考研的课把知识点又过了一遍，然后做书后的习题，做群里的 PPT 题目。这个过程很快，一两个星期就行。然后去做 01 年到 16 年的真题，做了两遍。</li><li>11.21-12.10 进行模考，把剩下的真题全做了。</li></ol><h3 id="2、建议-1"><a href="#2、建议-1" class="headerlink" title="2、建议"></a>2、建议</h3><ol><li>寒假就要开始数据结构的复习，因为不知道会不会转 408，所以提前一点开始总没错，可以复习的慢一点。后面如果真说了改 408，那么就建议去网上找 408 复习的帖子安排自己的复习，本文章进针对 811。</li><li>一轮复习数据结构的时候就跟着王道好了，王道是计算机考研专业课绝对的王者。</li><li>由于寒假已经过完一遍数据结构，那么大三下学期可以不用再看了，到了暑假看王海艳的书就行。我也建议你们根据王海艳的书来整理笔记，一定要把顺序表、单链表、树、图的存储结构自己敲一遍，背上！</li><li>9月份开学跟着邮学考研课把知识点再次巩固一遍，然后二刷王道书后的题目或者是群里的 PPT 都行。反正要把自己不懂的知识点全部搞懂。</li><li>然后就是做真题，把真题册上的真题全做一遍，一直做到把18年做完。</li><li>11.21-12.10 进行模考，把剩下的真题全做了。</li><li>最后两周多做点代码题，巩固知识点。</li></ol><h3 id="3、百度网盘链接"><a href="#3、百度网盘链接" class="headerlink" title="3、百度网盘链接"></a>3、百度网盘链接</h3><p>链接: <a href="https://pan.baidu.com/s/1tgjLc2FR_qxYT-8RaKrAUQ?pwd=mehg">https://pan.baidu.com/s/1tgjLc2FR_qxYT-8RaKrAUQ?pwd=mehg</a> 提取码: mehg</p><br/><h2 id="四、英语"><a href="#四、英语" class="headerlink" title="四、英语"></a>四、英语</h2><p>英语其实没有特别要说的点，每天记得背单词，一直背到考试的当天，每天背单词的量自己掌握，反正至少要把考纲词汇至少都过一遍。我自己是用的不背单词和墨墨背单词，用不背单词来过考纲词汇，然后用墨墨背单词把平时刷真题遇到的不会的单词记录下来背诵。就今年的情况，建议各位在暑假就要开始阅读刷题，英一英二的都要刷，英一刷一遍，英二刷两遍。有时间的话英一后五年的卷子要刷第二遍。然后英二留近三年的卷子用以全真模拟。</p><p>在 10 月份的时候就需要开始准备作文了，背石雷鹏或者是王江涛的都可以，最好是小作文大作文都背十篇，一定要背熟。</p><br/><h2 id="五、政治"><a href="#五、政治" class="headerlink" title="五、政治"></a>五、政治</h2><h3 id="1、我的过程-1"><a href="#1、我的过程-1" class="headerlink" title="1、我的过程"></a>1、我的过程</h3><ol><li>7 月份开始看腿姐的课并一刷《肖秀荣1000题》。</li><li>9 月份二刷《肖1000》。并开始看腿姐的《背诵手册》。</li><li>11 月份到 12 月上旬背腿姐《背诵手册（分析题篇）》刷《肖八》，来回刷了八遍。</li><li>12 月中旬刷《肖四》，并背其中的分析题。</li></ol><h3 id="2、建议-2"><a href="#2、建议-2" class="headerlink" title="2、建议"></a>2、建议</h3><ol><li>7 月份看课，徐涛和腿姐的都可以，很多人说政治 9 月份开始也行，但拿着之前的分数来说，南邮政治是要 70 分的。9 月份再开始是大概率不太来的及的。这其中把《肖秀荣1000题》刷一遍。</li><li>9 月份可以开始二刷《肖1000题》了，这里推荐去买个小程序刷题，遇到不会的还可以看看评论区。相信我，当你看到有人和你一起吐槽的时候你原本生气的情绪会明显好转的。然后去买背诵手册，把选择题部分看一遍就行。</li><li>到了 11 月份《肖八》也要出来了，《肖八》出来就直接去刷《肖八》，不用太在意分数。</li><li>12 月份直接背《肖四》大题，肖秀荣的分析题真是杀疯了。你永远可以相信肖秀荣，去年我们的大题全是《肖四》上的。</li></ol><br/><h2 id="六、结束语"><a href="#六、结束语" class="headerlink" title="六、结束语"></a>六、结束语</h2><p>考研终究只是人生中的一站，如果没有成功上岸也不用太过于懊悔。人生不止考研这一条路，但你的勤奋努力、你的坚韧不拔都会在你以后的人生路上一直帮助到你。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;
&lt;br/&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;24 年的考研在两天之前已经结束了，虽然本次考研我不一定能够取得满意的成绩，但是对于考研这个</summary>
      
    
    
    
    <category term="学习" scheme="https://yxbug.ren/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="考研" scheme="https://yxbug.ren/tags/%E8%80%83%E7%A0%94/"/>
    
    <category term="建议" scheme="https://yxbug.ren/tags/%E5%BB%BA%E8%AE%AE/"/>
    
  </entry>
  
  <entry>
    <title>从熊猫到人</title>
    <link href="https://yxbug.ren/2023/03/18/%E4%BB%8E%E7%86%8A%E7%8C%AB%E5%88%B0%E4%BA%BA/"/>
    <id>https://yxbug.ren/2023/03/18/%E4%BB%8E%E7%86%8A%E7%8C%AB%E5%88%B0%E4%BA%BA/</id>
    <published>2023-03-18T11:35:00.000Z</published>
    <updated>2025-11-20T12:29:27.116Z</updated>
    
    <content type="html"><![CDATA[<br/><p>鸡鸣寺的樱花在三月开放了，在网上看的多了别人拍的照片我也就想过去看看，刚巧父母带着外婆过来探望，便打算周末和家人一起玩一下南京。</p><p>第一站是周六下午的红山森林动物园。这个动物园我小学的时候去过，当时因为时间紧也就只完了一点，印象里只有走不完的园区和回四川探亲的大熊猫。红山森林动物园网传是第一个结束动物表演的动物园，而且门票相当便宜，十年前三十几的票价现在也只要四十几。在这个物价飞涨、工资不变的年代，红山森林动物园的门票是极少数能够和人们增长的收入相匹配的东西了。</p><p>进了园区没过多久就是大熊猫馆，里面有三只大熊猫分别住在三个地方。第一只和第二只都在睡觉，外婆说这大熊猫怎么这么像猪。</p><p><img src="https://s2.loli.net/2023/03/19/QXrPzt9nfO6hWGq.jpg" alt="第一只熊猫"></p><p><img src="https://s2.loli.net/2023/03/19/mXce9nSJoBQy1Or.jpg" alt="第二只熊猫"></p><p>熊猫馆很大，但是人也很多，每个人都想多看两眼熊猫，堵在路上。后面的人想挤进去，里面的人不愿意出来。</p><p>第三只熊猫就要可爱的多了，它坐在台子上一开始吃着竹子，然后开始蹭屁股，貌似是在擦屁股。擦完屁股接着又坐在台子上，许久才抬起头，像是在思考着什么。身前的一个女生说这辈子看到熊猫真是值了。</p><p><img src="https://s2.loli.net/2023/03/19/5XMqPRelxgIpAf3.jpg" alt="第三只熊猫"></p><p>日本的香香一家在前段时间回国了，我在媒体网站看到很多日本人排着队去看它，甚至有位大妈说她觉得香香比她孙子还聪明。我当时只觉得日本人对大熊猫的喜爱有点极端，在中国定不会有这样的现象。但是我也确实发现中国人对大熊猫的喜爱有过之而无不及。当然，我并不对这个抱有消极态度。</p><p>大熊猫之后就是热带鸟类的管所，我记得小时候这里是有鸟类的表演的，小鹦鹉非常聪明可爱。今日再见却正如网传一样没有了动物表演。刚进去时一条修长的木栈道，头顶是一道道横着的木架，小鹦鹉们就站在上面，有的睡觉、有的叽叽喳喳。好几对鹦鹉情侣相互依偎着睡觉。</p><p>木栈的尽头是收费喂食和鸟类主管所，秉持着不花冤枉钱的原则，我们直接选择进主管所里面看看热带鸟类。</p><p><img src="https://s2.loli.net/2023/03/19/EcPoTwW2fOS8rze.jpg" alt="犀鸟"></p><p>出了主管所是一些珍禽和其他鸟类，有幸见到求偶期的孔雀开屏。雄孔雀缓缓展开美丽的羽毛快速抖动，试图吸引雌孔雀的注意力，但显然这几只雌孔雀对吃更感兴趣。</p><p><img src="https://s2.loli.net/2023/03/19/sMCNXmh4dDk1cGZ.jpg" alt="孔雀开屏"></p><p>出了鸟类园我们下一站就是长颈鹿馆、象馆、考拉馆和高黎贡展区。</p><p>长颈鹿馆中有四只长颈鹿，两两分在两个馆中，中间用一个铁杆分隔开来。其中一只长颈鹿一边看着对面两只正在恩恩爱爱，一边用头敲打着铁杆。我一开始以为是长颈鹿脑袋痒，所以敲铁杆缓解一下。旁边一个人说可能是他自己的媳妇不理他，所以他在试图吸引隔壁长颈鹿媳妇的注意。我当时就觉得对这种包办婚姻制充满了愤慨之情。</p><p>后来我们去看了狼馆，狼馆的人是真多啊。四五只狼，几万号人，狼见人如长江流水，人见狼如刹那一瞬。</p><p>最有意思的我觉得是本土物种保育区，因为里面有我的老熟人野猪大哥。不吹不黑，南京几乎所有学校都出国野猪，尤其是我们江北靠山的学校。那真是老熟人，大二的时候，在我们学校才抓了两只野猪。据说晚上夜不归宿的人都会有野猪大哥来惩罚他。</p><p><img src="https://s2.loli.net/2023/03/19/hVdBtZxTmbNWaiH.jpg" alt="学校里的野猪"></p><p>红山森林动物园和我印象中的一样，非常大，大到我根本没有力气一次性逛完。四个小时的时间里不是在走路就是在人挤人。这完美符合了我对疫情开放之后中国人的报复性旅游的想象。遥想当年，偌大的动物园游客三三两两。而如今，红山似要被这人海淹没一般。</p><p>第二日原本的行程是去鸡鸣寺看樱花，结果到了停车场才发现要排队入场。队伍已经排了一里开外，在来之前舅舅说鸡鸣寺要排两个小时队，我一开始表示不屑，不管是玄武湖还是鸡鸣寺都不是迪士尼游乐项目那样固定人数才能开玩。结果万万没想到是停车要排队。我与父母都不打算再等下去，于是驱车离开。</p><p>我们早早地到了商场里，逛了商场，吃了午饭，接下来就是送我回学校了。</p><p>这两日的行程中，我总是需要回头去注意着外婆，害怕她走丢。在从商场出来的路上，我一次回头，看着满脸皱纹的外婆，一声不吭地在后面走着。阳光照在她的脸上，老态龙钟。</p><p>我忽然想这几天外婆都没有怎么说话，就像是一个聋哑人一般。我们年轻人识字、会使用手机，到哪都能很快的融入进去。而老人却不一样，在他们那个年代里绝大多数老人都是不识字的，他们用不惯手机，最多只能用手机来看看抖音，打打微信视频。这些操作更多的是靠肌肉记忆和图像记忆，并不是他们理解了如何去使用手机。我的外婆在这动物园里、走在商场里就像是个孩子一样无助。</p><p>在动物园中我和外婆开玩笑，你现在走丢了和孩子走丢了是一样的。</p><p>老人们对这个快节奏的信息化时代是害怕的，因为无法使用手机等智能设备，所以他们只能依靠着年轻人。他们无法理解手机一扫就能点菜，然后什么都不要说人家就能准确的上菜；他们无法理解为什么手机一打开来就能让别人知道你的相关信息；他们无法理解为什么现在现金越来越不好使了，在十年前红色的钞票还能吸引孩子，而现在钞票只会让孩子们吐槽一句：“这个不好用！”</p><p>但更让我伤感的是外婆老了。她不像以前那般有生气，说话那么开心，她的每一个动作都在告诉周围的人们她老了，老得没有办法了。</p><p>我害怕她老了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;



&lt;p&gt;鸡鸣寺的樱花在三月开放了，在网上看的多了别人拍的照片我也就想过去看看，刚巧父母带着外婆过来探望，便打算周末和家人一起玩一下南京。&lt;/p&gt;
&lt;p&gt;第一站是周六下午的红山森林动物园。这个动物园我小学的时候去过，当时因为时间紧也就只完了一点，印象里只有走不完的园</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="景点" scheme="https://yxbug.ren/tags/%E6%99%AF%E7%82%B9/"/>
    
    <category term="家人" scheme="https://yxbug.ren/tags/%E5%AE%B6%E4%BA%BA/"/>
    
  </entry>
  
  <entry>
    <title>mac 启动项目报permission denied错</title>
    <link href="https://yxbug.ren/2023/02/24/mac%20%E5%90%AF%E5%8A%A8%E9%A1%B9%E7%9B%AE%E6%8A%A5permission%20denied%E9%94%99/"/>
    <id>https://yxbug.ren/2023/02/24/mac%20%E5%90%AF%E5%8A%A8%E9%A1%B9%E7%9B%AE%E6%8A%A5permission%20denied%E9%94%99/</id>
    <published>2023-02-24T13:00:00.000Z</published>
    <updated>2025-11-20T12:29:27.114Z</updated>
    
    <content type="html"><![CDATA[<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">sudo chmod -R 777 + 文件路径</span><br></pre></td></tr></table></figure><p>文件路径在访达中选择文件然后 command + option + c 进行复制</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在终端中输入&lt;/p&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;co</summary>
      
    
    
    
    <category term="前端" scheme="https://yxbug.ren/categories/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="知识点" scheme="https://yxbug.ren/tags/%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
    
    <category term="报错" scheme="https://yxbug.ren/tags/%E6%8A%A5%E9%94%99/"/>
    
  </entry>
  
  <entry>
    <title>鸡鸣寺、玄武湖和花</title>
    <link href="https://yxbug.ren/2023/02/20/%E9%B8%A1%E9%B8%A3%E5%AF%BA%E3%80%81%E7%8E%84%E6%AD%A6%E6%B9%96%E5%92%8C%E8%8A%B1/"/>
    <id>https://yxbug.ren/2023/02/20/%E9%B8%A1%E9%B8%A3%E5%AF%BA%E3%80%81%E7%8E%84%E6%AD%A6%E6%B9%96%E5%92%8C%E8%8A%B1/</id>
    <published>2023-02-20T10:35:00.000Z</published>
    <updated>2025-11-20T12:29:27.125Z</updated>
    
    <content type="html"><![CDATA[<br/><p>2月18日是开学的日子，与以往不同的是由于全面开放的政策，这次父母可以进校参观，亦可以进入宿舍。</p><p>在得知此消息的时候，我分母亲就是十分的激动，于她而言，终于可以看看儿子的学校了。</p><p>我们到学校的时候是正中午，已经没有早上那么挤，所以很顺畅的找到了位置停了车。先带父母去宿舍收拾了一下，然后就带着父母在学校食堂吃了个午饭，并带他们参观了整个学校。</p><p>学校并不大，没过一会就参观完了，从东门的食堂，到中间的教学区，以及西南角的新生宿舍。参观完之后我们就去附近的一个商场陪母亲逛街，并商量着第二天去哪里旅游。说来悲哀，上大学三年了，竟然连这座城市有哪些地方好玩都不知道，甚至连学校的门都没有出过几次。所以当父母问到我的时候，我只能找本地人同学问问这座城市有哪些好玩的地方。</p><p>父亲见我一问三不知的样子，嘲笑我白上了个大学。</p><p>在老一辈眼里，大学是一个神圣的地方，那里有知识、有友情、有爱情、有对一座城市和未来的热爱。但上了大学的我只有三年的疫情和考研的压力。</p><p>原本准备父母在校门口找个宾馆住一晚上，第二天玩完了再回去，但是很不巧的是家里突然有了急事，父母半夜赶了回去。</p><p>遂罢。</p><p>翌日，有个舍友说想出去玩，转念一想，甚妙。于是结伴而行，问好友，看地图，定景点，寺和湖。</p><p>到了鸡鸣寺景点，一人交了10块钱的门票，每人领了3根香，进香。有舍友言：“今日赠之十元，吾且为之一日之父。”</p><p><img src="https://s2.loli.net/2023/02/20/dw4DMCf6NIJcHbq.jpg" alt="鸡鸣寺"></p><p>我与另一人大笑。</p><p>寺庙内人山人海，尤其是财神庙前，香火鼎盛，跪拜之人可排一里开外，由此可见当代年轻人对财富是非常虔诚的。</p><p>鸡鸣寺不大，小到在水泄不通的情况下逛个15分钟就可以走完全流程了。</p><p>可幸的是鸡鸣寺和玄武就靠在了一起。而在玄武湖和鸡鸣寺之间的小道两旁个长了一排樱花树，樱花的开花时节是在3月份到4月份，可稀稀落落的也有一树粉红。</p><p>玄武湖就大的多了，沿着大路走没过多久就会走到岔路口。径直往前的是著名的相亲角————“情侣园”，往左转就是玄武湖。</p><p>三个单身汉相视一笑，迅速左转进入玄武湖，曰：“我是来看湖的！”</p><p>下了桥，在湖边所见皆是水，近处是水、远处也是水，水与水之间还夹了几艘船、几座山。</p><p><img src="https://s2.loli.net/2023/02/20/pnVQdNmz8xZ4aeJ.jpg" alt="玄武湖"></p><p>自上大学以来，因为疫情的原因就很少走出校门，把南京走下来、看过去。可笑的是，在这疫情解封之后，大三的我要准备考研，也没什么时间出来走走了。但如今解封与舍友出来走走，见如此多的人在阳光下沐浴着新鲜的空气，心中只觉得惊喜。三年疫情的压抑貌似就这么一扫而空。</p><p>玄武湖我们走了许久，进了银杏树园休息了一小会就离开了。</p><p>自玄武湖出门，又见一两棵樱花树上开着朵朵粉色。</p><p><img src="https://s2.loli.net/2023/02/20/E1gWvdNU2Rnq8Qj.jpg" alt="樱花"></p><p>鸡鸣寺很小，但敬香的人很多；玄武湖很大，但装不下这人山人海；樱花虽稀稀落落，但朵朵灿烂，风雨之后，向阳而开。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;br/&gt;



&lt;p&gt;2月18日是开学的日子，与以往不同的是由于全面开放的政策，这次父母可以进校参观，亦可以进入宿舍。&lt;/p&gt;
&lt;p&gt;在得知此消息的时候，我分母亲就是十分的激动，于她而言，终于可以看看儿子的学校了。&lt;/p&gt;
&lt;p&gt;我们到学校的时候是正中午，已经没有早上那么挤，所</summary>
      
    
    
    
    <category term="随笔" scheme="https://yxbug.ren/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="景点" scheme="https://yxbug.ren/tags/%E6%99%AF%E7%82%B9/"/>
    
    <category term="开学" scheme="https://yxbug.ren/tags/%E5%BC%80%E5%AD%A6/"/>
    
  </entry>
  
</feed>
