<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>NotionNext BLOG</title>
        <link>https://blg.milkcoff.com/</link>
        <description>这是一个由NotionNext生成的站点</description>
        <lastBuildDate>Tue, 23 Apr 2024 06:56:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-CN</language>
        <copyright>All rights reserved 2024, tr1gv0n</copyright>
        <item>
            <title><![CDATA[Go测试-二十条]]></title>
            <link>https://blg.milkcoff.com/article/6f082c95-4376-4dd3-a6da-0840b3e15ad2</link>
            <guid>https://blg.milkcoff.com/article/6f082c95-4376-4dd3-a6da-0840b3e15ad2</guid>
            <pubDate>Thu, 29 Feb 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-6f082c9543764dd3a6da0840b3e15ad2"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><blockquote class="notion-quote notion-block-38e1210818134d9d9b15c0aad4f1ec52"><div>Golang测试的20条使用建议</div></blockquote><div class="notion-blank notion-block-dbf2729fd6204a1fa49920dd6c157d40"> </div><ol start="1" class="notion-list notion-list-numbered notion-block-7e68a56042584a61a3dc5e9d77e2e4ba"><li>让添加新测试代码变得容易</li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-5c815ee91c804e8e9b92f55240f8ca18"><li>使用测试覆盖率来发现未经测试的代码</li></ol><ol start="3" class="notion-list notion-list-numbered notion-block-a094e95204144df1b54b63c7d3d66ed5"><li>覆盖率不能替代思考</li></ol><ol start="4" class="notion-list notion-list-numbered notion-block-53ecec59030f404ebf594703c8fddb92"><li>编写全面的测试</li></ol><ol start="5" class="notion-list notion-list-numbered notion-block-d7bb777c38f5441cb243464a432a697e"><li>将测试用例与测试逻辑分开</li></ol><ol start="6" class="notion-list notion-list-numbered notion-block-c8a10076274f4bd3a87928bc4b077e46"><li>寻找特殊情况</li></ol><ol start="7" class="notion-list notion-list-numbered notion-block-39dbd1ef0f8f44d9aad59d1de2d0e749"><li>如果你没有添加测试，那就没有修复bug</li></ol><ol start="8" class="notion-list notion-list-numbered notion-block-e0a8140d00df42158d195b48d94b5fb5"><li>并非所有东西都适合放在表中</li></ol><ol start="9" class="notion-list notion-list-numbered notion-block-7f9affdc85cf4e57bef49ef379cb1b4b"><li>测试用例可以放在testdate文件中</li></ol><ol start="10" class="notion-list notion-list-numbered notion-block-251bc340921a40a9b5fa00c9842bbc11"><li>与其他实现进行比较</li></ol><ol start="11" class="notion-list notion-list-numbered notion-block-c17440e6ee234272b268f1b5cc2b7856"><li>使测试失败易读</li></ol><ol start="12" class="notion-list notion-list-numbered notion-block-c4449c74a11e4f0288afd50df40c9ecc"><li>如果答案可能会改变，编写代码来更新它们</li></ol><ol start="13" class="notion-list notion-list-numbered notion-block-450cca220ae2405485dcf676f66514e1"><li>使用txtar进行多文件测试用例</li></ol><ol start="14" class="notion-list notion-list-numbered notion-block-242479f8c22e4f81a693b7da4565c205"><li>对现有格式进行注解来创建测试迷你语言</li></ol><ol start="15" class="notion-list notion-list-numbered notion-block-dae17c5784d042fdbb971c86d50caf97"><li>编写解析器和打印器来简化测试</li></ol><ol start="16" class="notion-list notion-list-numbered notion-block-b7bc52504a3343dd87bc5cfbb41969a8"><li>代码质量受测试质量限制</li></ol><ol start="17" class="notion-list notion-list-numbered notion-block-6d8798733b7f4d609a314cbffd7c04a9"><li>使用脚本可以编写很好的测试</li></ol><ol start="18" class="notion-list notion-list-numbered notion-block-474e8f64304346eca9a25d0b03d356b5"><li>尝试使用rsc.io/script来创建基于脚本的测试用例</li></ol><ol start="19" class="notion-list notion-list-numbered notion-block-ef6d19c5e0554bfda78a76bcbe5beb5f"><li>随着时间的推移改进你的测试</li></ol><ol start="20" class="notion-list notion-list-numbered notion-block-146f36b9adb04828b7e49ff518d1a7f6"><li>追求持续部署</li></ol></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[go性能分析-pprof]]></title>
            <link>https://blg.milkcoff.com/article/01691829-2f9c-467f-a6a1-01d2dd9d803a</link>
            <guid>https://blg.milkcoff.com/article/01691829-2f9c-467f-a6a1-01d2dd9d803a</guid>
            <pubDate>Thu, 22 Feb 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-016918292f9c467fa6a101d2dd9d803a"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><h3 class="notion-h notion-h2 notion-h-indent-0 notion-block-07ec8aeeb554475781a7368c01bf6982" data-id="07ec8aeeb554475781a7368c01bf6982"><span><div id="07ec8aeeb554475781a7368c01bf6982" class="notion-header-anchor"></div><a class="notion-hash-link" href="#07ec8aeeb554475781a7368c01bf6982" title="前言"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>前言</b></span></span></h3><div class="notion-text notion-block-20261d19bb5045e2809020d50543e52a">作为一名gopher,不知道你是否遇到过以下问题？</div><ol start="1" class="notion-list notion-list-numbered notion-block-56cbe04ce71e4fe38aef8458141e6c45"><li>CPU突然飙高(甚至死循环,CPU跑满)？</li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-0e9d016f76ca4176ae6f9c0ffe12aa80"><li>某个功能接口QPS在压测中一直压不上去？</li></ol><ol start="3" class="notion-list notion-list-numbered notion-block-1f28d3397fec4b4eb032e905a81c6d8b"><li>应用出现goroutine泄露？</li></ol><ol start="4" class="notion-list notion-list-numbered notion-block-de6d75c20e154eb7b8a34e629b1d7bbc"><li>内存居高不下？</li></ol><ol start="5" class="notion-list notion-list-numbered notion-block-551d921bf5f74b64b2dd46607688adf8"><li>在某处加锁的逻辑中，迟迟得不到锁？</li></ol><div class="notion-text notion-block-98c0adb8fc054c15920c99a5f919d709">你是否能得心应手的找到问题的症结所在，你又是使用什么方法或工具解决的呢？今天我将介绍下我经常使用的工具pprof.它是golang自带的性能分析大杀器，基本上能快速解决上述问题。</div><h3 class="notion-h notion-h2 notion-h-indent-0 notion-block-bc8bf7bfce614f0196a82fd069df924a" data-id="bc8bf7bfce614f0196a82fd069df924a"><span><div id="bc8bf7bfce614f0196a82fd069df924a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#bc8bf7bfce614f0196a82fd069df924a" title="如何使用pprof"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>如何使用pprof</b></span></span></h3><div class="notion-text notion-block-a268f591a25445799622d3cad1fc6899">使用pprof有三种姿势，一种是使用<code class="notion-inline-code">runtime/pprof/pprof.go</code>另一种是使用<code class="notion-inline-code">net/http/pprof/pprof.go</code>（底层也是使用<code class="notion-inline-code">runtime/pprof</code>）,还有一种是在单元测试中生成profile 数据。详细的方法在对应的<code class="notion-inline-code">pprof.go</code>文件开头有说明。</div><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-9ecb4ef15d4d47b8913d3ce4b44c7ad2" data-id="9ecb4ef15d4d47b8913d3ce4b44c7ad2"><span><div id="9ecb4ef15d4d47b8913d3ce4b44c7ad2" class="notion-header-anchor"></div><a class="notion-hash-link" href="#9ecb4ef15d4d47b8913d3ce4b44c7ad2" title="1. runtime/pprof 方式pprof"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1. runtime/pprof 方式pprof</b></span></span></h4><div class="notion-text notion-block-8840a6a71d234d82a3f607c222da5657">这种方式需要你手动启动需要pprof的类型，比如，开启CPU profile 还是heap profile 等等，pprof 会在应用启动到结束的整个生命周期生成profile 文件。其实生成profile 数据是会损耗性能的，生产环境不建议一直开启，可以在需要分析的时候临时采集那个时刻的数据，如通过监听系统信号的方式开启/关闭pprof,示例代码如下：</div><div class="notion-text notion-block-c95491eda1a6492382e5f7bfb0c3575c">不过本人还是更加喜欢第二种方式<code class="notion-inline-code">net/http/pprof</code></div><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-bca3f614c1ef47ecb711477e2acb1e08" data-id="bca3f614c1ef47ecb711477e2acb1e08"><span><div id="bca3f614c1ef47ecb711477e2acb1e08" class="notion-header-anchor"></div><a class="notion-hash-link" href="#bca3f614c1ef47ecb711477e2acb1e08" title="2. net/http/pprof 方式pprof"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>2. net/http/pprof 方式pprof</b></span></span></h4><div class="notion-text notion-block-86a4b7397dfd49afad47c85c4992af82">是不是很简单，这种方式只需要开启http服务，并且<code class="notion-inline-code">import _ &quot;net/http/pprof&quot;</code>,他会自动把相应的http的handleFunc 注册上去，若你使用的不是<code class="notion-inline-code">DefaultServeMux</code>,需要自己手动注册下。</div><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-cd879e75b65441ed9e951f11201d878f" data-id="cd879e75b65441ed9e951f11201d878f"><span><div id="cd879e75b65441ed9e951f11201d878f" class="notion-header-anchor"></div><a class="notion-hash-link" href="#cd879e75b65441ed9e951f11201d878f" title="3. 单元测试中进行profile"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>3. 单元测试中进行profile</b></span></span></h4><h3 class="notion-h notion-h2 notion-h-indent-0 notion-block-88fedfcc7bec4c5e94669bc5079765bb" data-id="88fedfcc7bec4c5e94669bc5079765bb"><span><div id="88fedfcc7bec4c5e94669bc5079765bb" class="notion-header-anchor"></div><a class="notion-hash-link" href="#88fedfcc7bec4c5e94669bc5079765bb" title="分析pprof"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>分析pprof</b></span></span></h3><div class="notion-text notion-block-131ef882f2e64c7b8bd68d56b3fc35ed">在上文<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://segmentfault.com/a/1190000041261187#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8pprof">如何使用pprof</a>中介绍的三种开启pprof的方式，他们都会生成profile二进制文件，有三种方式可以分析这个二进制文件</div><ol start="1" class="notion-list notion-list-numbered notion-block-70e0964e53fb4b72a334a7fc8a0271b4"><li>姿势一：通过交互命令行,方法：<code class="notion-inline-code">go tool pprof {profile文件}</code>命令交互行如下</li><ol class="notion-list notion-list-numbered notion-block-70e0964e53fb4b72a334a7fc8a0271b4"><div class="notion-text notion-block-c7445b73d3d8410d8bc7167272b5aa84">若是通过http方式开启pprof，可以</div><div class="notion-text notion-block-f94ec94b03ee422680bf7fa108f6bf02"><code class="notion-inline-code">go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30</code></div><div class="notion-text notion-block-5a0eace23eb14eb4814d69a675bfafeb">若是通过方式1和3生成文件,可以</div><div class="notion-text notion-block-c672d2da0c8e4551ba9b06d90c4e14aa"><code class="notion-inline-code">go tool pprof cpu.prof</code></div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-block-b9782a46dd1041a0a895c527169ec063"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:672px;max-width:100%;flex-direction:column;height:130px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261190&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure></ol></ol><ol start="2" class="notion-list notion-list-numbered notion-block-169eff7b6e3140cb92503e9b1c0f91de"><li>姿势二：通过web方式查看，方法 <code class="notion-inline-code">go tool pprof -http=:6060 {profile文件}</code></li><ol class="notion-list notion-list-numbered notion-block-169eff7b6e3140cb92503e9b1c0f91de"><div class="notion-text notion-block-a3373a1c54bf4d85ae09122fd9460372">然后就可以在浏览器中访问 <a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=CUQu7Ug3%2F9bk%2Bsyr9mRykw%3D%3D.HKpSUgy7ZtSF06%2FvsgyxpymBGNm922zN3hOBTszsCvw%3D">http://localhost:6060/</a></div><div class="notion-text notion-block-253868d9d65b4135a043f71ba5417f12">当然也有一种方式在姿势一中介绍的命令行交互中输入<code class="notion-inline-code">web</code>会生成 .svg文件，不过需要安装graphviz来打开这个文件，不推荐，还是建议使用命令行或本地启动web服务来查看profile 数据.</div></ol></ol><h3 class="notion-h notion-h2 notion-h-indent-0 notion-block-58a849c179f446ab96137e76487ff864" data-id="58a849c179f446ab96137e76487ff864"><span><div id="58a849c179f446ab96137e76487ff864" class="notion-header-anchor"></div><a class="notion-hash-link" href="#58a849c179f446ab96137e76487ff864" title="实战演练"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>实战演练</b></span></span></h3><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-a4bc2765d9164f2cace0c7386e0c89c4" data-id="a4bc2765d9164f2cace0c7386e0c89c4"><span><div id="a4bc2765d9164f2cace0c7386e0c89c4" class="notion-header-anchor"></div><a class="notion-hash-link" href="#a4bc2765d9164f2cace0c7386e0c89c4" title="1.定位CPU问题"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.定位CPU问题</b></span></span></h4><div class="notion-text notion-block-92dd9fc927e3472298e4c88d19586367">自己写了一个模拟程序，模拟CPU问题，</div><div class="notion-text notion-block-d02f2b36c8ee4da3b5f45604c692f88f">按照上述姿势一打开命令行交互，执行<code class="notion-inline-code">top10</code>,输出采样期间CPU使用最高的10个方法</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-e501dbb74c97457e8ab32877f18b5265"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:505px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261191&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-0a8c2f9ee1ff4b2d8a38826bc2089180">这里简单介绍下flat flat% sum% cum cum%这五个参数的含义,详细可以查看<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=kbtOs5p3fhGgQw0kAI7Rbw%3D%3D.dOAD%2BCrIvkEDYO3piasFDzdUqwicE8Lu9%2FGmup8mabg%2Fw7utm%2FMMFAEXiVpu6uB42XImO0sqnTHTb2B%2FI%2Fn2Zttko64L7zTiz8%2BpwiwY24zZAXiHUa96jJVHSZ6m0KVS">Pprof and golang - how to interpret a results?</a></div><div class="notion-text notion-block-49dd054adb714fcebc813edf555150ed">flat：指的是该方法所占用的CPU时间（不包含这个方法中调用其他方法所占用的时间）</div><div class="notion-text notion-block-4561e3bc505843fdb47a147cdb9ed1cd">flat%: 指的是该方法flat时间占全部采样时间的比例</div><div class="notion-text notion-block-4cca98e54fcf4888ab3722a90afe13e8">cum：指的是该方法以及方法中调用其他方法所占用的CPU时间总和，这里注意区别于flat</div><div class="notion-text notion-block-d3aec968fa294a16aa7f2b1b3bdc3d71">cum%:指的是该方法cum时间占全部采样时间的比例</div><div class="notion-text notion-block-ef644d1a9367433aa19c23b533b617b9">sum%: 指的是执行到当前方法累积占用的CPU时间总和，也即是前面flat%总和</div><div class="notion-text notion-block-3505d9096baf4b29b9367c95ae33ab46">上图可以看出worker()占用CPU时间较久，我们可以</div><div class="notion-text notion-block-076aae66d93c406eb36375a1bc8fbb83">查看具体代码</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-a0093f8ea41947079f5308d7a9370e2b"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:460px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261192&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-313bdae53509486981a519c60f1c611a">当然也可以通过上述姿势二，启动web服务查看火焰图<code class="notion-inline-code">go tool pprof -http=:6061 cpu.profile</code></div><div class="notion-text notion-block-e711ebc036c24215a23374d7509bca91">打开<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=4EgVBmsJj1MC%2FuOkbARfHg%3D%3D.idl7snNnaE8nsJ1QgXFG2rz98KwIJbRwCFIW9TriMT8%3D">http://localhost:6061/ui/</a> 火焰图如下，其中颜色越红代表占用的CPU时间越多</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-block-60ed57626e5d4e6b841d668cba5e4a0f"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:1419px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fimage-static.segmentfault.com%2F911%2F318%2F911318399-2db6ef529566f8e1_fix732&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-bb96b35d48f1400b92db8c36d318c090">找到了耗时比较久的地方，就能看看正常的业务代码还是可以优化的逻辑，就可以优化后在pprof</div><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-c0039e08fd53411b9dcd9154e1d2745d" data-id="c0039e08fd53411b9dcd9154e1d2745d"><span><div id="c0039e08fd53411b9dcd9154e1d2745d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#c0039e08fd53411b9dcd9154e1d2745d" title="2. 定位内存问题"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>2. 定位内存问题</b></span></span></h4><div class="notion-text notion-block-bfd1e16ff3f54bdd8508d2df5faf27d2">排查内存再用过高问题</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-6290a99fe6c34de48686fb4f8e350910"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:257px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261194&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-65f7ab031d40413e8bc3ab74f05fc830">其中<code class="notion-inline-code">inuse_space</code>表示查看常驻内存的使用情况</div><div class="notion-text notion-block-0b5f9597bb23416581e1c1fbe00250f1">list 查看相应的函数</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-block-05b7eb6a3560429b817ca9f37453d23b"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:332px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261195&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-d19ab5a65903465ea1f73c329be2a5a3">原来是一致在append内存，并持有到1GB不释放</div><div class="notion-text notion-block-5b93dc3dc4994d8b94e889ddd2132249">当然还可以使用<code class="notion-inline-code">alloc_objects</code>：分析应用程序的内存临时分配情况</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-2e9ae9c33b8848a284c7f002377fdd66"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:350px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261196&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-ea09f57a90c84266b1564cd54ff88d18">可以看到应用稳定后，除了上面初始分配1GB外，应用临时内存分配主要在worker中</div><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-c33ceb38a0db434d93f1240609b94baf" data-id="c33ceb38a0db434d93f1240609b94baf"><span><div id="c33ceb38a0db434d93f1240609b94baf" class="notion-header-anchor"></div><a class="notion-hash-link" href="#c33ceb38a0db434d93f1240609b94baf" title="3.定位goroutine问题"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>3.定位goroutine问题</b></span></span></h4><div class="notion-text notion-block-c450e5d5237847fe8ddf1fc6f428d543">例如goroutine泄露等问题，方法如下</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-a6e2760681b24da78577c5ad5ae90c67"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:294px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261197&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-38071eb99af7460f95d7a318a45cbceb">可以打出各个goroutine的调用栈</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-b9a4a70dceeb43b99055e69708a7bcc1"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:930px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261198&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-9544bf19cc2b454cab75d8305ef36617">可以看到有900+ 的goroutine 阻塞在<code class="notion-inline-code">runtime/gopark</code>并且是由<code class="notion-inline-code">main.goroutine.fun1</code>方法引起的 list 查看方法内容<code class="notion-inline-code">list main.goroutine.fun1</code></div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-761a47e3a0eb4dfe84c7db9c369153fb"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:348px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261199&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-f4819bf950ab480bac652c5952ae48bc">可以看出主要是阻塞在channel c 上.当然也可以通过<code class="notion-inline-code">traces runtime.gopark</code> 查看那些方法最终阻塞在<code class="notion-inline-code">gopark</code>上，另外也可以在web页面<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=3axgudvK4xv7TqTJc42rcw%3D%3D.Rnk8eww5bMP%2FFGd2s65obH5Se%2FiA5ORaxyIhdkO1ilE%2BY8HBY1dUnooDpayq1EyCtr7V%2BVS%2FDH9Phliaf6HJIQ%3D%3D">http://localhost:6060/debug/p...</a>直接查看。</div><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-78f9a0e68e3f43609a83f8afb309098c" data-id="78f9a0e68e3f43609a83f8afb309098c"><span><div id="78f9a0e68e3f43609a83f8afb309098c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#78f9a0e68e3f43609a83f8afb309098c" title="4.定位锁问题"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>4.定位锁问题</b></span></span></h4><div class="notion-text notion-block-7dbe76b8ab9248eba42a06592f44b53f">锁的问题可能导致程序运行缓慢，pprof mutex 相关的需要设置采样率</div><div class="notion-text notion-block-f4c9f40706fb44bd900b9a419b9142f2"><code class="notion-inline-code">runtime.SetMutexProfileFraction(1)</code>,若采样率&lt;0 将不进行采样</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-33ac9cfa447e4eaca3e25c3924b0f394"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:276px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261200&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-d3b0035b47564651947f81dcd1ae3836">可以看出，主要在<code class="notion-inline-code">main.mutex.func1</code>上，可以查看调用链</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-914a87e7665c4ec99cb0531ffef3d017"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:555px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261201&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-362b3119a779402bac47ca3e3254dbf9"><code class="notion-inline-code">list main.mutex.func1</code></div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-block-e5e63640f778445aae500e8d392ee777"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:260px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261202&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-07eefc45e6684c19be3ad75618af1a64">可以看出主要阻塞在锁<code class="notion-inline-code">m</code>上</div><h4 class="notion-h notion-h3 notion-h-indent-1 notion-block-da1ce0b0f84d4bd0977b1b133bda4a6c" data-id="da1ce0b0f84d4bd0977b1b133bda4a6c"><span><div id="da1ce0b0f84d4bd0977b1b133bda4a6c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#da1ce0b0f84d4bd0977b1b133bda4a6c" title="5. 定位goroutine阻塞等待同步问题"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>5. 定位goroutine阻塞等待同步问题</b></span></span></h4><div class="notion-text notion-block-f3e13490906249a48699db0723fa85d1">区别于4 ，这里主要是记录goroutine阻塞等待同步的位置,而4中主要是互斥锁分析，报告互斥锁的竞争情况。同样需要设置采样率<code class="notion-inline-code">runtime.SetBlockProfileRate(1)</code></div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-block-6f6330a118004bf9a5f993d36c033846"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:344px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261203&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-22f3cc71daad4333bde05076ef58ba63">主要阻塞在chanrecv1上，查看源码</div><figure class="notion-asset-wrapper notion-asset-wrapper-embed notion-asset-wrapper-full notion-block-805f65bb863a40d3af25cc5a043f01bc"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100vw;max-width:100%;flex-direction:column;height:649px"><iframe class="notion-asset-object-fit" src="https://embed.notion.co/api/iframe?url=https%3A%2F%2Fsegmentfault.com%2Fimg%2Fremote%2F1460000041261204&amp;key=656ac74fac4fff346b811dca7919d483" title="iframe embed" frameBorder="0" allowfullscreen="" loading="lazy" scrolling="auto"></iframe></div></figure><div class="notion-text notion-block-920ac2e09d6b42278160ffdbd2acce61">可以发现主要阻塞在channel c 上</div><h3 class="notion-h notion-h2 notion-h-indent-0 notion-block-ef9a121066f542259b57ba2e4f543095" data-id="ef9a121066f542259b57ba2e4f543095"><span><div id="ef9a121066f542259b57ba2e4f543095" class="notion-header-anchor"></div><a class="notion-hash-link" href="#ef9a121066f542259b57ba2e4f543095" title="参考文献"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>参考文献</b></span></span></h3><ol start="1" class="notion-list notion-list-numbered notion-block-91517b6e90be44bd9b2679d8d20d8718"><li><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=j5vzZSwi8qSBnu%2BPpPrK4A%3D%3D.jWm1rSJv20oblHfH9QW07C%2BOxwfyJ9YhsI%2B6msAQJgQMgur7EoaqB6WhqVusYp82J1KA4tPsl8KmY0W6fv%2Fz%2FQ%3D%3D">pprof 官方README</a></li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-1877fa8f3e90488aa2f91337c560ca04"><li><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=I9JSu8qiuaTe8lORgke7rw%3D%3D.0x84HQeFQ6%2F1J5o4V2Cs%2FFtAmFxZqniTaP8nnpSZdvk%3D">Profiling Go Programs</a></li></ol><ol start="3" class="notion-list notion-list-numbered notion-block-aa929c63f7ea48db980e2d8ccfad8546"><li><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://segmentfault.com/a/1190000016412013">Golang 大杀器之性能剖析 PProf</a></li></ol><ol start="4" class="notion-list notion-list-numbered notion-block-ed4df12070df4f5e989c498809111694"><li><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=gouhN%2FdfLhNc9z6l0GFkpQ%3D%3D.nADhVxb1510%2BhcXXY%2FNoq%2FnSNOdM6CONhX8tdvZcggwaY2ZZFMTBLcn7SWQqxuCrn1TpU7cJCMOpNYXJkhb4gw%3D%3D">golang pprof 实战</a></li></ol><ol start="5" class="notion-list notion-list-numbered notion-block-fd1ae43814214d3fbbb8616a87cf218d"><li><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://link.segmentfault.com/?enc=PfcCG24CEA7gZSKstA5H2A%3D%3D.QNFHUrMTXtQyW7c%2F8%2BzIkqYAgsnJCtmImAuX%2FA0Su1g4Qt5AidMIko1unV%2BgzNn5prZFY9W1S3nqDUMl94kMfA%3D%3D">https://golang2.eddycjy.com/p...</a></li></ol><div class="notion-blank notion-block-eb000f5a32d5458aa44fff548d385399"> </div></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[用 Go 语言实现刘谦 2024 春晚魔术，还原尼格买提汗流浃背的尴尬瞬间!]]></title>
            <link>https://blg.milkcoff.com/article/5970e796-cc4d-445e-bad6-e5b4e7e8d51d</link>
            <guid>https://blg.milkcoff.com/article/5970e796-cc4d-445e-bad6-e5b4e7e8d51d</guid>
            <pubDate>Thu, 22 Feb 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-5970e796cc4d445ebad6e5b4e7e8d51d"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-d78beb1a29754206b837150d33002925">龙年春晚如期而至，想必大家都看（<s>没</s>）完（<s>眼</s>）了（<s>看</s>）吧，今年春晚最搞笑节目，当属刘谦的魔术：《守岁共此时》，不过笑点不是节目本身，而是本场魔术的 <s>托儿</s>（主持人）尼格买提。</div><div class="notion-text notion-block-7449b59fe2c5447f8b6e408d7108f1e6">小尼：已经开始流汗了 😅。</div><div class="notion-text notion-block-2e674cc70bb248a9b71e386196a39689">本文将带大家一起用 Go 语言来还原下整个魔术的过程。</div><div class="notion-text notion-block-d4c917a8ddf049e0ba539bfd526931d1">在开始写代码前，翻车画面必须置顶 🤣：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-e7f746297f4a406ea3f5776e5cb98b24"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/0.png?t=e7f74629-7f4a-406e-a3f5-776e5cb98b24" alt="notion image" loading="lazy" decoding="async"/></div></figure><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-dff792959a444a91844ac754de880734" data-id="dff792959a444a91844ac754de880734"><span><div id="dff792959a444a91844ac754de880734" class="notion-header-anchor"></div><a class="notion-hash-link" href="#dff792959a444a91844ac754de880734" title="魔术：《守岁共此时》"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">魔术：《守岁共此时》</span></span></h4><div class="notion-text notion-block-bd33848f593649b2a31f6952e4d8533e">这是一个公式魔术，即有着固定的套路，从数学角度来看是一个「约瑟夫问题」（严格证明可以在网上搜到，如果你感兴趣可以去看下）。</div><div class="notion-text notion-block-feec246b24984e1b8117ce8b0461b6c5">不过，咱们今天不讲枯燥的数学公式，固定套路是程序的强项，今天就用 Go 语言实现这个魔术的套路。</div><div class="notion-text notion-block-ba8aa97ec0804825a850066b76254fb9">接下来，咱们直奔主题，回忆每一个步骤的同时，用程序将其实现。</div><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-a36d9145709846229fa79315e45e69e2" data-id="a36d9145709846229fa79315e45e69e2"><span><div id="a36d9145709846229fa79315e45e69e2" class="notion-header-anchor"></div><a class="notion-hash-link" href="#a36d9145709846229fa79315e45e69e2" title="步骤"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">步骤</span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-04ecf5ba2d1548feb5965255ac09df85" data-id="04ecf5ba2d1548feb5965255ac09df85"><span><div id="04ecf5ba2d1548feb5965255ac09df85" class="notion-header-anchor"></div><a class="notion-hash-link" href="#04ecf5ba2d1548feb5965255ac09df85" title="一、 准备 4 张扑克牌，随意打乱，完成洗牌。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">一、 准备 4 张扑克牌，随意打乱，完成洗牌。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-ecc09292692443c2a7ebd98595b3528d"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/1.png?t=ecc09292-6924-43c2-a7eb-d98595b3528d" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-c30449215c7c4ac7a8f87ab5d2453f43">步骤一</div><div class="notion-text notion-block-3d7ad3baa01d4109a043b557c127db88">代码实现如下：</div><div class="notion-text notion-block-544a450d730b4e3fad81e880828deda7">我们以截图中刘谦手里持有的 4 张扑克牌为例，用一个 <code class="notion-inline-code">int</code> 类型的 <code class="notion-inline-code">slice</code> 存储这些牌。</div><div class="notion-text notion-block-0a5278cb780f4011a65d8cc6ca1d96a1">在 Go 中可以使用 <code class="notion-inline-code">rand.Shuffle</code> 方法来打乱 <code class="notion-inline-code">slice</code> 的顺序。</div><div class="notion-text notion-block-3ce32d747f474057a250c1b0b45061c5">执行程序，得到洗牌后的结果如下：</div><table class="notion-simple-table notion-block-a85fd154e3824a2b97b4d0b2a25247ea"><tbody><tr class="notion-simple-table-row notion-block-304c905836ec49628e3f58383e8b5093"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[6 7 5 2]</code></div></td></tr></tbody></table><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-5799428eb40542748a4f3e7661fe7ce2" data-id="5799428eb40542748a4f3e7661fe7ce2"><span><div id="5799428eb40542748a4f3e7661fe7ce2" class="notion-header-anchor"></div><a class="notion-hash-link" href="#5799428eb40542748a4f3e7661fe7ce2" title="二、 对折，然后撕开，接着叠在一起，相当于扑克牌变成了两份，double 了，4 张变 8 张。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">二、 对折，然后撕开，接着叠在一起，相当于扑克牌变成了两份，double 了，4 张变 8 张。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-8c40f8953a884d52a90c0aff5b35c197"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/2.png?t=8c40f895-3a88-4d52-a90c-0aff5b35c197" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-ad9c7bb3fc524671aabcbf62dbb0568e">步骤二</div><div class="notion-text notion-block-37ccd6e7b128490ba5205dd870cba97d">这一步相当于 <code class="notion-inline-code">pokers</code> 内容 * 2，代码实现如下：</div><div class="notion-text notion-block-1a86402ca26c49e5b320ebe0e5adfacd">复制后的 <code class="notion-inline-code">pokers</code> 如下：</div><table class="notion-simple-table notion-block-0272fa33d8804abfb446f1ea68f42007"><tbody><tr class="notion-simple-table-row notion-block-ea93061633ed46f8b7427f617344d31e"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[6 7 5 2 6 7 5 2]</code></div></td></tr></tbody></table><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-2a10758ac9914a82b993db1225ac6196" data-id="2a10758ac9914a82b993db1225ac6196"><span><div id="2a10758ac9914a82b993db1225ac6196" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2a10758ac9914a82b993db1225ac6196" title="三、 问问自己名字有几个字，就从最上面拿出对应个数的牌放到底部。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">三、 问问自己名字有几个字，就从最上面拿出对应个数的牌放到底部。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-0032a755208d4166b2d92e08b22e1e5a"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/3.png?t=0032a755-208d-4166-b2d9-2e08b22e1e5a" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-701567e125784f508df7079c5b5231c5">步骤三</div><div class="notion-text notion-block-78cff3fa545b48fab4f610ec27e74b1f">例如「刘谦」名字有 2 个字，即将 <code class="notion-inline-code">slice</code> 前 2 个元素取出，并放到 <code class="notion-inline-code">slice</code> 最后，代码实现如下：</div><div class="notion-text notion-block-cfef3b185a414e43a14defda293ae620">得到新 <code class="notion-inline-code">pokers</code>：</div><table class="notion-simple-table notion-block-edded331ddf74c90b47896c89ca3a27c"><tbody><tr class="notion-simple-table-row notion-block-b28ba450df854325a926e54a6e5bf89e"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[5 2 6 7 5 2 6 7]</code></div></td></tr></tbody></table><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-50cf919442f548fba761a2aa96134f00" data-id="50cf919442f548fba761a2aa96134f00"><span><div id="50cf919442f548fba761a2aa96134f00" class="notion-header-anchor"></div><a class="notion-hash-link" href="#50cf919442f548fba761a2aa96134f00" title="四、 拿起最上面的 3 张牌，插入中间任意位置。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">四、 拿起最上面的 3 张牌，插入中间任意位置。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-93512b4bb1aa436fad644723ae1bcdd6"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/4.png?t=93512b4b-b1aa-436f-ad64-4723ae1bcdd6" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-74e735a2dc324a5487b1177799e6af91">步骤四</div><div class="notion-text notion-block-f81fac3b37db474594696052a70d10a6">代码实现如下：</div><div class="notion-text notion-block-4379b55bafbc45a292d98f8cd1309b8d">这里将 <code class="notion-inline-code">pokers</code> 前 3 个元素取出，并插入最后一个元素之前，得到新 <code class="notion-inline-code">pokers</code>：</div><table class="notion-simple-table notion-block-ae018bfac58e41e2a6a78ea274af089a"><tbody><tr class="notion-simple-table-row notion-block-dd619e75d3004dbfaa88fb436688ccd7"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[7 5 2 6 5 2 6 7]</code></div></td></tr></tbody></table><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-213ad0d04e9c44e88621606823b17d4b" data-id="213ad0d04e9c44e88621606823b17d4b"><span><div id="213ad0d04e9c44e88621606823b17d4b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#213ad0d04e9c44e88621606823b17d4b" title="五、 拿出最上面的 1 张牌，藏于秘密的地方，比如屁股下。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">五、 拿出最上面的 1 张牌，藏于秘密的地方，比如屁股下。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-9ce79898ed51437cb05d9acaad3d186b"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/5.png?t=9ce79898-ed51-437c-b05d-9acaad3d186b" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-ed198290239642ec9deda1819c8704b3">步骤五</div><div class="notion-text notion-block-995ab191ea044aab9c6b18ab5e04399e">代码实现如下：</div><div class="notion-text notion-block-6bd26ab2013641b595090201a0190db5">这里使用 top 变量暂存最上面的 1 张牌：</div><table class="notion-simple-table notion-block-30e5dc3b6cc94b408df20b6191ce14ff"><tbody><tr class="notion-simple-table-row notion-block-1a009ce4561846e59c20ca31c6f82467"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">7, [5 2 6 5 2 6 7]</code></div></td></tr></tbody></table><div class="notion-text notion-block-ef29c88dbc104b03b5f9e676d5c7badf">此时得到 <code class="notion-inline-code">top</code> 值为 7，<code class="notion-inline-code">pokers</code> 还剩 7 个元素。</div><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-202860a3b0cc4e8ab9b009b00f5b3621" data-id="202860a3b0cc4e8ab9b009b00f5b3621"><span><div id="202860a3b0cc4e8ab9b009b00f5b3621" class="notion-header-anchor"></div><a class="notion-hash-link" href="#202860a3b0cc4e8ab9b009b00f5b3621" title="六、 如果你是南方人，从上面拿起 1 张牌；如果你是北方人，则从上面拿起 2 张牌；假如我们不确定自己是南方人还是北方人，那就干脆拿起 3 张牌，然后插入中间任意位置。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">六、 如果你是南方人，从上面拿起 1 张牌；如果你是北方人，则从上面拿起 2 张牌；假如我们不确定自己是南方人还是北方人，那就干脆拿起 3 张牌，然后插入中间任意位置。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-05062a135e03408d91199386bed91183"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/6.png?t=05062a13-5e03-408d-9119-9386bed91183" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-23c99b2903d54f54acbaf7e6709064bc">步骤六</div><div class="notion-text notion-block-0561560aeb8443bfbc94821478b3922a">这一步其实同第四步操作一样，假设我们是北方人，代码实现如下：</div><div class="notion-text notion-block-55c934abeab34420b63af44940225554">得到新 <code class="notion-inline-code">pokers</code>：</div><table class="notion-simple-table notion-block-de96c4af6a634dd882e34b7361963fa0"><tbody><tr class="notion-simple-table-row notion-block-01bb40f7904b4008928e320e7b0b5cef"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[6 5 2 6 5 2 7]</code></div></td></tr></tbody></table><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-34eaf3e914a3445785f8c41d5f6296a2" data-id="34eaf3e914a3445785f8c41d5f6296a2"><span><div id="34eaf3e914a3445785f8c41d5f6296a2" class="notion-header-anchor"></div><a class="notion-hash-link" href="#34eaf3e914a3445785f8c41d5f6296a2" title="七、 如果你是男生，从上面拿起 1 张牌；如果你是女生，则从上面拿起 2 张牌，撒到空中（扔掉）。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">七、 如果你是男生，从上面拿起 1 张牌；如果你是女生，则从上面拿起 2 张牌，撒到空中（扔掉）。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-42a382333a834a69bc3b20439dc4ae29"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/7.png?t=42a38233-3a83-4a69-bc3b-20439dc4ae29" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-0abe40dad9b54f1ead0814dba2cd4b7a">步骤七</div><div class="notion-text notion-block-d9d8ec7db28b438e9fa7f94632014ff1">假设是男生，代码实现如下：</div><div class="notion-text notion-block-5d77f62ccd3c4715846d4beb916e7339">得到新 <code class="notion-inline-code">pokers</code>：</div><table class="notion-simple-table notion-block-d506ccfa7785409b93688cdb4b37c3f2"><tbody><tr class="notion-simple-table-row notion-block-1ed91a1f3f5b4a43b8a934c346d2b08b"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[5 2 6 5 2 7]</code></div></td></tr></tbody></table><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-461a3d7891e8467d8723ed5e3e582cec" data-id="461a3d7891e8467d8723ed5e3e582cec"><span><div id="461a3d7891e8467d8723ed5e3e582cec" class="notion-header-anchor"></div><a class="notion-hash-link" href="#461a3d7891e8467d8723ed5e3e582cec" title="八、 魔法时刻，在遥远的魔术的历史上，流传了一个七字真言「见证奇迹的时刻」，可以带给我们幸福。现在，我们每念一个字，从上面拿一张放到最底部，即需要完成 7 次同样的操作。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">八、 魔法时刻，在遥远的魔术的历史上，流传了一个七字真言「见证奇迹的时刻」，可以带给我们幸福。现在，我们每念一个字，从上面拿一张放到最底部，即需要完成 7 次同样的操作。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-2f0fc57bc5054d9fb7736317a743492e"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/8.png?t=2f0fc57b-c505-4d9f-b773-6317a743492e" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-0a817a76ac98429d8ae48e50c8d478c7">步骤八</div><div class="notion-text notion-block-4569e6e39ac54cdbbc44d84297041b7b">我们可以用 <code class="notion-inline-code">for loop</code> 来完成重复操作，代码实现如下：</div><div class="notion-text notion-block-f3f56b094d2847a7a3859b07d1f21cb2">得到新 <code class="notion-inline-code">pokers</code>：</div><table class="notion-simple-table notion-block-3f8d03374bcf4108b5e59b4c2eac2652"><tbody><tr class="notion-simple-table-row notion-block-2bc853197c034c97909739f0d59e9f2c"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[2 6 5 2 7 5]</code></div></td></tr></tbody></table><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-68d7738a78944177ada0b5a388692f37" data-id="68d7738a78944177ada0b5a388692f37"><span><div id="68d7738a78944177ada0b5a388692f37" class="notion-header-anchor"></div><a class="notion-hash-link" href="#68d7738a78944177ada0b5a388692f37" title="九、 最后一个环节，叫「好运留下来，烦恼丢出去」，在念到「好运留下来」时，从上面拿起 1 张牌放入底部；在念到「烦恼丢出去」时，从上面拿起 1 张牌扔掉，女生需要完成 4 次同样的操作，男生需要完成 5 次同样的操作。"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">九、 最后一个环节，叫「好运留下来，烦恼丢出去」，在念到「好运留下来」时，从上面拿起 1 张牌放入底部；在念到「烦恼丢出去」时，从上面拿起 1 张牌扔掉，女生需要完成 4 次同样的操作，男生需要完成 5 次同样的操作。</span></span></h4><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-ffa60c5ac5c442e6aab246833b750528"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/9-1.png?t=ffa60c5a-c5c4-42e6-aab2-46833b750528" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-bddf714df0514f6e9838a3111dfd541f">步骤九 - 好运留下来</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-e1b298c6ef0f4fa89f11f89c92ea468c"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/9-2.png?t=e1b298c6-ef0f-4fa8-9f11-f89c92ea468c" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-b56da9b1236342779a8bfedf7321ceaf">步骤九 - 烦恼丢出去</div><div class="notion-text notion-block-342bfb5b4c0040e2978bc13b78636d02">因为第七步中我们选择了男生，所以现在要完成 5 次同样的操作，同样适用 <code class="notion-inline-code">for loop</code> 来完成，代码实现如下：</div><div class="notion-text notion-block-a3ffb82ceb15490fbdebece9ec7df666">最终得到的 <code class="notion-inline-code">pokers</code>：</div><table class="notion-simple-table notion-block-8ed4a1ef986e42e8a600345777eabb22"><tbody><tr class="notion-simple-table-row notion-block-9feee5e7772e4b6982ab9e4debba7613"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">[7]</code></div></td></tr></tbody></table><div class="notion-text notion-block-89793fac03fc4082b5bb92dd7d5e5fab">切片 <code class="notion-inline-code">pokers</code> 中仅存一个元素，即手中只剩一张牌。</div><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-03dcaaf6dad4454e9b74852791c08542" data-id="03dcaaf6dad4454e9b74852791c08542"><span><div id="03dcaaf6dad4454e9b74852791c08542" class="notion-header-anchor"></div><a class="notion-hash-link" href="#03dcaaf6dad4454e9b74852791c08542" title="见证奇迹"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">见证奇迹</span></span></h4><div class="notion-text notion-block-caa2ad338c7c49038bec6a65d481d092">接下来就是见证奇迹的时刻，拿出藏于屁股下的牌和手里唯一剩下的一张牌对比，正是同一张牌：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-7c86f9a5b78a4f0cb9e71b35d6c2cc55"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/10.png?t=7c86f9a5-b78a-4f0c-b9e7-1b35d6c2cc55" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-46e638fc4a8d4c20a1afcdefa9f06eed">见证奇迹</div><div class="notion-text notion-block-678c17bdb40f48f48f75645a9a824b8b">打印 <code class="notion-inline-code">top</code> 值和 <code class="notion-inline-code">pokers</code> 中仅存的元素。</div><div class="notion-text notion-block-a3aead26e0a14bb4af2f8d3364086008">结果毫无悬念：</div><table class="notion-simple-table notion-block-de29f36461d746a188f106ad013c92f0"><tbody><tr class="notion-simple-table-row notion-block-6cb84161777c4c96a785ae0a9f58e1d3"><td class="" style="width:120px"><div class="notion-simple-table-cell"><code class="notion-inline-code">见证奇迹：7 == 7</code></div></td></tr></tbody></table><div class="notion-text notion-block-8da2743c715841d8aac6bd04d746704c">程序完整日志输出如下：</div><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-0b875c31da1d455bb36a1c37f00ba1a8" data-id="0b875c31da1d455bb36a1c37f00ba1a8"><span><div id="0b875c31da1d455bb36a1c37f00ba1a8" class="notion-header-anchor"></div><a class="notion-hash-link" href="#0b875c31da1d455bb36a1c37f00ba1a8" title="还原「尼格买提」神操作"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">还原「尼格买提」神操作</span></span></h4><div class="notion-text notion-block-c07e7115561e42b8b7d63bbd542a4414">在此必须回顾一下尼格买提尴尬瞬间，反复尴尬 🤣：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-ce5c70dd1f4c42f781432b04a19ffd45"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/0.png?t=ce5c70dd-1f4c-42f7-8143-2b04a19ffd45" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-50ce2ae6a6ec4e959ee7cd56ced1c71d">仔细观看回放就能发现，其实小尼错在了第六步，小尼是北方人，所以应该从上面拿起 2 张牌，插入中间任意位置，但由于操作失误，错将拿起的第 2 张牌插入到最底部。</div><div class="notion-text notion-block-d7b1606ed92d4bfeaf2124e66ddb7be7">神操作在此：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-7a4df2d1b5c54c4fb3246cac85cfed0c"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/6-1.png?t=7a4df2d1-b5c5-4c4f-b324-6cac85cfed0c" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-60bb2e6329154f49b4c5bf61bde6eebe">即第六步代码原本应该如下：</div><div class="notion-text notion-block-6b315c8c712347878ba9a137aefc09f9">到小尼这里变成了：</div><div class="notion-text notion-block-71590d72dcf746dbab399fa1c977e047">读者可以自行修改代码后尝试运行下，我就不展示结果了，怕尴尬 😅，哈哈哈。</div><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-4fc285d4fde34d1e8acec890ea7636ee" data-id="4fc285d4fde34d1e8acec890ea7636ee"><span><div id="4fc285d4fde34d1e8acec890ea7636ee" class="notion-header-anchor"></div><a class="notion-hash-link" href="#4fc285d4fde34d1e8acec890ea7636ee" title="彩蛋"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">彩蛋</span></span></h4><div class="notion-text notion-block-c0a7dc7d57cd43e6b2afe805f0ebd770">不知道大家有没有注意到，在魔术表演结束时，观众席镜头左下角那个手里拿着 AJ 的姐姐！</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-cf08ea6e2b8640e3a0a0cb07b9cc5ce3"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/a-j-1.png?t=cf08ea6e-2b86-40e3-a0a0-cb07b9cc5ce3" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-62c4ec22b4054935a23309f21b1e60de">观众席</div><div class="notion-text notion-block-13b3c417f47d45519f5a9aa2dc9af2c8">放大特写：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-8dddccdaeeb640bd9714b549ffe7bf46"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/a-j.png?t=8dddccda-eeb6-40bd-9714-b549ffe7bf46" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-9c7a3ead0fcb42078c52d85d9d2f2487">AJ 姐姐满脸洋溢着尴尬的笑容 🤣。</div><h4 class="notion-h notion-h3 notion-h-indent-0 notion-block-2f9a07e1cd344c6fa51dcc7b46646416" data-id="2f9a07e1cd344c6fa51dcc7b46646416"><span><div id="2f9a07e1cd344c6fa51dcc7b46646416" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2f9a07e1cd344c6fa51dcc7b46646416" title="总结"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">总结</span></span></h4><div class="notion-text notion-block-e8bca9e1e05f411ca291ad8b0381f5f3">没有总结。</div><div class="notion-text notion-block-e272178dccfd4dd1bf69f40d2de0168e">本文仅供大家消遣娱乐，顺便学点编程 😄。</div><div class="notion-text notion-block-4ae7784051f64e6a85db44f4d4e2e88e">本文完整代码示例我放在了 <a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://github.com/jianghushinian/blog-go-example/tree/main/2024-spring-festival-gala-magic/main.go">GitHub</a> 上，欢迎点击查看。</div><div class="notion-blank notion-block-bdc78ee5840846c4ab9f773d10adffa1"> </div><div class="notion-text notion-block-9f36fc4c78bb4cf7aa891ab466ab247d">转载自：<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/">https://jianghushinian.cn/2024/02/10/use-go-to-realize-liu-qian-s-2024-spring-festival-gala-magic/</a></div><div class="notion-blank notion-block-ce39125eda1745bd8c7362eb82242423"> </div></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Go安全指南]]></title>
            <link>https://blg.milkcoff.com/article/7aa34a35-f3d8-4797-83fd-71081a6b8d81</link>
            <guid>https://blg.milkcoff.com/article/7aa34a35-f3d8-4797-83fd-71081a6b8d81</guid>
            <pubDate>Thu, 22 Feb 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-7aa34a35f3d8479783fd71081a6b8d81"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-b6aec193981e44189949808c1f3ef7cf" data-id="b6aec193981e44189949808c1f3ef7cf"><span><div id="b6aec193981e44189949808c1f3ef7cf" class="notion-header-anchor"></div><a class="notion-hash-link" href="#b6aec193981e44189949808c1f3ef7cf" title="通用类"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>通用类</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-d88acc35c6ce471ab4fc1d2c03f87961" data-id="d88acc35c6ce471ab4fc1d2c03f87961"><span><div id="d88acc35c6ce471ab4fc1d2c03f87961" class="notion-header-anchor"></div><a class="notion-hash-link" href="#d88acc35c6ce471ab4fc1d2c03f87961" title="1. 代码实现类"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1. 代码实现类</b></span></span></h3><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-9de7ffc342394c11b369daaaafd2e017" data-id="9de7ffc342394c11b369daaaafd2e017"><span><div id="9de7ffc342394c11b369daaaafd2e017" class="notion-header-anchor"></div><a class="notion-hash-link" href="#9de7ffc342394c11b369daaaafd2e017" title="1.1 内存管理"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1 内存管理</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-24e02106a809403ca779a392caf8c683" data-id="24e02106a809403ca779a392caf8c683"><span><div id="24e02106a809403ca779a392caf8c683" class="notion-header-anchor"></div><a class="notion-hash-link" href="#24e02106a809403ca779a392caf8c683" title="1.1.1【必须】切片长度校验"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.1【必须】切片长度校验</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-077c3b374ec54a3fbd0706b46b3d322e"><li>在对slice进行操作时，必须判断长度是否合法，防止程序panic</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-0607953c37594bb8985500f4643093ef" data-id="0607953c37594bb8985500f4643093ef"><span><div id="0607953c37594bb8985500f4643093ef" class="notion-header-anchor"></div><a class="notion-hash-link" href="#0607953c37594bb8985500f4643093ef" title="1.1.2【必须】nil指针判断"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.2【必须】nil指针判断</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-77096e345e7b491c90a4d2cb29ab104c"><li>进行指针操作时，必须判断该指针是否为nil，防止程序panic，尤其在进行结构体Unmarshal时</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-c7467632a4864676a66aaa7d801f9c53" data-id="c7467632a4864676a66aaa7d801f9c53"><span><div id="c7467632a4864676a66aaa7d801f9c53" class="notion-header-anchor"></div><a class="notion-hash-link" href="#c7467632a4864676a66aaa7d801f9c53" title="1.1.3【必须】整数安全"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.3【必须】整数安全</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-d0d8ecb2f8fc42328714c63fd0216744"><li>在进行数字运算操作时，需要做好长度限制，防止外部输入运算导致异常：</li><ul class="notion-list notion-list-disc notion-block-d0d8ecb2f8fc42328714c63fd0216744"><li>确保无符号整数运算时不会反转</li><li>确保有符号整数运算时不会出现溢出</li><li>确保整型转换时不会出现截断错误</li><li>确保整型转换时不会出现符号错误</li></ul></ul><ul class="notion-list notion-list-disc notion-block-393960973c0d4b27beb8d3d298f678f1"><li>以下场景必须严格进行长度限制：</li><ul class="notion-list notion-list-disc notion-block-393960973c0d4b27beb8d3d298f678f1"><li>作为数组索引</li><li>作为对象的长度或者大小</li><li>作为数组的边界（如作为循环计数器）</li></ul></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-28f365e81ee3463c9bff54fc03d95889" data-id="28f365e81ee3463c9bff54fc03d95889"><span><div id="28f365e81ee3463c9bff54fc03d95889" class="notion-header-anchor"></div><a class="notion-hash-link" href="#28f365e81ee3463c9bff54fc03d95889" title="1.1.4【必须】make分配长度验证"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.4【必须】make分配长度验证</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-e813ba980b254dcbb4a5216040f52dd1"><li>在进行make分配内存时，需要对外部可控的长度进行校验，防止程序panic。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-cf6e64f133f54b719991f4dd8a8625c3" data-id="cf6e64f133f54b719991f4dd8a8625c3"><span><div id="cf6e64f133f54b719991f4dd8a8625c3" class="notion-header-anchor"></div><a class="notion-hash-link" href="#cf6e64f133f54b719991f4dd8a8625c3" title="1.1.5【必须】禁止SetFinalizer和指针循环引用同时使用"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.5【必须】禁止SetFinalizer和指针循环引用同时使用</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-7cc501aa27d64f65bb9674c8c45e9992"><li>当一个对象从被GC选中到移除内存之前，runtime.SetFinalizer()都不会执行，即使程序正常结束或者发生错误。由指针构成的“循环引用”虽然能被GC正确处理，但由于无法确定Finalizer依赖顺序，从而无法调用runtime.SetFinalizer()，导致目标对象无法变成可达状态，从而造成内存无法被回收。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-32d60144cb2d44e6b6ea16b0b2e58fca" data-id="32d60144cb2d44e6b6ea16b0b2e58fca"><span><div id="32d60144cb2d44e6b6ea16b0b2e58fca" class="notion-header-anchor"></div><a class="notion-hash-link" href="#32d60144cb2d44e6b6ea16b0b2e58fca" title="1.1.6【必须】禁止重复释放channel"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.6【必须】禁止重复释放channel</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-a0a64d4b78724b5e9b2e387b8bc17670"><li>重复释放一般存在于异常流程判断中，如果恶意攻击者构造出异常条件使程序重复释放channel，则会触发运行时panic，从而造成DoS攻击。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-44dbb2c07a524962a2cd50894de0577b" data-id="44dbb2c07a524962a2cd50894de0577b"><span><div id="44dbb2c07a524962a2cd50894de0577b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#44dbb2c07a524962a2cd50894de0577b" title="1.1.7【必须】确保每个协程都能退出"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.7【必须】确保每个协程都能退出</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-6646726c390f44de8988fc46917361d7"><li>启动一个协程就会做一个入栈操作，在系统不退出的情况下，协程也没有设置退出条件，则相当于协程失去了控制，它占用的资源无法回收，可能会导致内存泄露。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-7614c426abbd4d4fb239552b467eca56" data-id="7614c426abbd4d4fb239552b467eca56"><span><div id="7614c426abbd4d4fb239552b467eca56" class="notion-header-anchor"></div><a class="notion-hash-link" href="#7614c426abbd4d4fb239552b467eca56" title="1.1.8【推荐】不使用unsafe包"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.8【推荐】不使用unsafe包</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-78858c49672d4f3c82c08f4402e5af81"><li>由于unsafe包绕过了 Golang 的内存安全原则，一般来说使用该库是不安全的，可导致内存破坏，尽量避免使用该包。若必须要使用unsafe操作指针，必须做好安全校验。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-9cacdd3b31db4d6a8336c177fe0593c7" data-id="9cacdd3b31db4d6a8336c177fe0593c7"><span><div id="9cacdd3b31db4d6a8336c177fe0593c7" class="notion-header-anchor"></div><a class="notion-hash-link" href="#9cacdd3b31db4d6a8336c177fe0593c7" title="1.1.9【推荐】不使用slice作为函数入参"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.9【推荐】不使用slice作为函数入参</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-6257970e8d2c42e99b903ce4218c68c1"><li>slice在作为函数入参时，函数内对slice的修改可能会影响原始数据</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-3faaccb153d64fa6a1b89cf5686f50ae" data-id="3faaccb153d64fa6a1b89cf5686f50ae"><span><div id="3faaccb153d64fa6a1b89cf5686f50ae" class="notion-header-anchor"></div><a class="notion-hash-link" href="#3faaccb153d64fa6a1b89cf5686f50ae" title="1.2 文件操作"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.2 文件操作</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-8b514ef5c2bf476db420bba2a586a24d" data-id="8b514ef5c2bf476db420bba2a586a24d"><span><div id="8b514ef5c2bf476db420bba2a586a24d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#8b514ef5c2bf476db420bba2a586a24d" title="1.2.1【必须】 路径穿越检查"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.2.1【必须】 路径穿越检查</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-bf77e3894eee4723ba490dd512814d71"><li>在进行文件操作时，如果对外部传入的文件名未做限制，可能导致任意文件读取或者任意文件写入，严重可能导致代码执行。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-d6fc3b2eeffc4d979d116b432e95d58a" data-id="d6fc3b2eeffc4d979d116b432e95d58a"><span><div id="d6fc3b2eeffc4d979d116b432e95d58a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#d6fc3b2eeffc4d979d116b432e95d58a" title="1.2.2【必须】 文件访问权限"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.2.2【必须】 文件访问权限</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-546d940c1be94bfe9e9b9dc1af2957f5"><li>根据创建文件的敏感性设置不同级别的访问权限，以防止敏感数据被任意权限用户读取。例如，设置文件权限为：<code class="notion-inline-code">rw-r-----</code></li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-5dd3a14a403040b7bab9ad3286bd9d7c" data-id="5dd3a14a403040b7bab9ad3286bd9d7c"><span><div id="5dd3a14a403040b7bab9ad3286bd9d7c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#5dd3a14a403040b7bab9ad3286bd9d7c" title="1.3 系统接口"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.3 系统接口</b></span></span></h4><div class="notion-text notion-block-2fe90e0e5ac3423dbf732555b7ab5802"><b>1.3.1【必须】命令执行检查</b></div><ul class="notion-list notion-list-disc notion-block-e96a9323d031455f9a547a807c5bffd6"><li>使用<code class="notion-inline-code">exec.Command</code>、<code class="notion-inline-code">exec.CommandContext</code>、<code class="notion-inline-code">syscall.StartProcess</code>、<code class="notion-inline-code">os.StartProcess</code>等函数时，第一个参数（path）直接取外部输入值时，应使用白名单限定可执行的命令范围，不允许传入<code class="notion-inline-code">bash</code>、<code class="notion-inline-code">cmd</code>、<code class="notion-inline-code">sh</code>等命令；</li></ul><ul class="notion-list notion-list-disc notion-block-ff387fd24aa44e268b7582a13d6ecc03"><li>使用<code class="notion-inline-code">exec.Command</code>、<code class="notion-inline-code">exec.CommandContext</code>等函数时，通过<code class="notion-inline-code">bash</code>、<code class="notion-inline-code">cmd</code>、<code class="notion-inline-code">sh</code>等创建shell，-c后的参数（arg）拼接外部输入，应过滤\n $ &amp; ; | &#x27; &quot; ( ) `等潜在恶意字符；</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-679eb2b4f85245f8844225fe97104271" data-id="679eb2b4f85245f8844225fe97104271"><span><div id="679eb2b4f85245f8844225fe97104271" class="notion-header-anchor"></div><a class="notion-hash-link" href="#679eb2b4f85245f8844225fe97104271" title="1.4 通信安全"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.4 通信安全</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-5362c236de7842c39d3feeb32572702d" data-id="5362c236de7842c39d3feeb32572702d"><span><div id="5362c236de7842c39d3feeb32572702d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#5362c236de7842c39d3feeb32572702d" title="1.4.1【必须】网络通信采用TLS方式"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.4.1【必须】网络通信采用TLS方式</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-acdf75a4d8c94beaa9d1236ed40c6759"><li>明文传输的通信协议目前已被验证存在较大安全风险，被中间人劫持后可能导致许多安全风险，因此必须采用至少TLS的安全通信方式保证通信安全，例如gRPC/Websocket都使用TLS1.3。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-b72991e00f6b479d94de7f963620a228" data-id="b72991e00f6b479d94de7f963620a228"><span><div id="b72991e00f6b479d94de7f963620a228" class="notion-header-anchor"></div><a class="notion-hash-link" href="#b72991e00f6b479d94de7f963620a228" title="1.4.2【推荐】TLS启用证书验证"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.4.2【推荐】TLS启用证书验证</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-ccb552cfb3d74dbd84b253470a411e76"><li>TLS证书应当是有效的、未过期的，且配置正确的域名，生产环境的服务端应启用证书验证。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-77624f3ffcdf4e77adbedd16c4b733fc" data-id="77624f3ffcdf4e77adbedd16c4b733fc"><span><div id="77624f3ffcdf4e77adbedd16c4b733fc" class="notion-header-anchor"></div><a class="notion-hash-link" href="#77624f3ffcdf4e77adbedd16c4b733fc" title="1.5 敏感数据保护"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.5 敏感数据保护</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-b2339f41f2b54b4f88e3ea5610762fce" data-id="b2339f41f2b54b4f88e3ea5610762fce"><span><div id="b2339f41f2b54b4f88e3ea5610762fce" class="notion-header-anchor"></div><a class="notion-hash-link" href="#b2339f41f2b54b4f88e3ea5610762fce" title="1.5.1【必须】敏感信息访问"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.5.1【必须】敏感信息访问</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-f8a6942048894450a050361babe01190"><li>禁止将敏感信息硬编码在程序中，既可能会将敏感信息暴露给攻击者，也会增加代码管理和维护的难度</li></ul><ul class="notion-list notion-list-disc notion-block-ecb625e57dd0464fb6f0c7f9404ab8d1"><li>使用配置中心系统统一托管密钥等敏感信息</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-0e852f708fec4a739247ff537facc6ea" data-id="0e852f708fec4a739247ff537facc6ea"><span><div id="0e852f708fec4a739247ff537facc6ea" class="notion-header-anchor"></div><a class="notion-hash-link" href="#0e852f708fec4a739247ff537facc6ea" title="1.5.2【必须】敏感数据输出"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.5.2【必须】敏感数据输出</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-31227d335f504cdd8e773def68b84a9a"><li>只输出必要的最小数据集，避免多余字段暴露引起敏感信息泄露</li></ul><ul class="notion-list notion-list-disc notion-block-a2e1a804f35a449ca47e50b01d6724a2"><li>不能在日志保存密码（包括明文密码和密文密码）、密钥和其它敏感信息</li></ul><ul class="notion-list notion-list-disc notion-block-83ecd7a1252f467a864b85b4bdbc8313"><li>对于必须输出的敏感信息，必须进行合理脱敏展示</li></ul><ul class="notion-list notion-list-disc notion-block-3de7aa9e94ef48ffb3dd0abbbdd10175"><li>避免通过GET方法、代码注释、自动填充、缓存等方式泄露敏感信息</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-57c0e31c98724477b8bbf8cc11da1874" data-id="57c0e31c98724477b8bbf8cc11da1874"><span><div id="57c0e31c98724477b8bbf8cc11da1874" class="notion-header-anchor"></div><a class="notion-hash-link" href="#57c0e31c98724477b8bbf8cc11da1874" title="1.5.3【必须】敏感数据存储"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.5.3【必须】敏感数据存储</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-2c8389561bc64a0fb2784ec1b4e8cbbc"><li>敏感数据应使用SHA2、RSA等算法进行加密存储</li></ul><ul class="notion-list notion-list-disc notion-block-ce6c3fc2868d4a48b318fdfba769dadc"><li>敏感数据应使用独立的存储层，并在访问层开启访问控制</li></ul><ul class="notion-list notion-list-disc notion-block-cfdac5da68624e64b76c157891786dff"><li>包含敏感信息的临时文件或缓存一旦不再需要应立刻删除</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-e0e91c11b74a4df3b066d7db2bc8f653" data-id="e0e91c11b74a4df3b066d7db2bc8f653"><span><div id="e0e91c11b74a4df3b066d7db2bc8f653" class="notion-header-anchor"></div><a class="notion-hash-link" href="#e0e91c11b74a4df3b066d7db2bc8f653" title="1.5.4【必须】异常处理和日志记录"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.5.4【必须】异常处理和日志记录</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-9e7407b52ff94647a8a1442a9c5a5494"><li>应合理使用panic、recover、defer处理系统异常，避免出错信息输出到前端</li></ul><ul class="notion-list notion-list-disc notion-block-f111ffc196634f87aa9aa8f1ffb14b95"><li>对外环境禁止开启debug模式，或将程序运行日志输出到前端</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-a9de005d85e843b98d943f993914605a" data-id="a9de005d85e843b98d943f993914605a"><span><div id="a9de005d85e843b98d943f993914605a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#a9de005d85e843b98d943f993914605a" title="1.6 加密解密"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6 加密解密</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-a47ce43f8b6f459cb929d5fb1ced7750" data-id="a47ce43f8b6f459cb929d5fb1ced7750"><span><div id="a47ce43f8b6f459cb929d5fb1ced7750" class="notion-header-anchor"></div><a class="notion-hash-link" href="#a47ce43f8b6f459cb929d5fb1ced7750" title="1.6.1【必须】不得硬编码密码/密钥"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6.1【必须】不得硬编码密码/密钥</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-7eaca9527c90459ea0ed9ad67c2fd7ed"><li>在进行用户登陆，加解密算法等操作时，不得在代码里硬编码密钥或密码，可通过变换算法或者配置等方式设置密码或者密钥。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-3547fdf3864c44a188d60dc9c38b4933" data-id="3547fdf3864c44a188d60dc9c38b4933"><span><div id="3547fdf3864c44a188d60dc9c38b4933" class="notion-header-anchor"></div><a class="notion-hash-link" href="#3547fdf3864c44a188d60dc9c38b4933" title="1.6.2【必须】密钥存储安全"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6.2【必须】密钥存储安全</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-a68468b0f4c9409ab786b0e109121626"><li>在使用对称密码算法时，需要保护好加密密钥。当算法涉及敏感、业务数据时，可通过非对称算法协商加密密钥。其他较为不敏感的数据加密，可以通过变换算法等方式保护密钥。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-86c646fa81f44d23abb8edafbb16ff8a" data-id="86c646fa81f44d23abb8edafbb16ff8a"><span><div id="86c646fa81f44d23abb8edafbb16ff8a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#86c646fa81f44d23abb8edafbb16ff8a" title="1.6.3【推荐】不使用弱密码算法"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6.3【推荐】不使用弱密码算法</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-2df160c058af484895ee7e35eb5016f8"><li>在使用加密算法时，不建议使用加密强度较弱的算法。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-79e0013313f34a8bb6442be662fcff2c" data-id="79e0013313f34a8bb6442be662fcff2c"><span><div id="79e0013313f34a8bb6442be662fcff2c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#79e0013313f34a8bb6442be662fcff2c" title="1.7 正则表达式"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.7 正则表达式</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-842fa45ccf61407989ad2539487848cc" data-id="842fa45ccf61407989ad2539487848cc"><span><div id="842fa45ccf61407989ad2539487848cc" class="notion-header-anchor"></div><a class="notion-hash-link" href="#842fa45ccf61407989ad2539487848cc" title="1.7.1【推荐】使用regexp进行正则表达式匹配"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.7.1【推荐】使用regexp进行正则表达式匹配</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-7d30bac656a34b638f6b8f2b75d0f932"><li>正则表达式编写不恰当可被用于DoS攻击，造成服务不可用，推荐使用regexp包进行正则表达式匹配。regexp保证了线性时间性能和优雅的失败：对解析器、编译器和执行引擎都进行了内存限制。但regexp不支持以下正则表达式特性，如业务依赖这些特性，则regexp不适合使用。</li><ul class="notion-list notion-list-disc notion-block-7d30bac656a34b638f6b8f2b75d0f932"><li>回溯引用<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://www.regular-expressions.info/backref.html">Backreferences</a></li><li>查看<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://www.regular-expressions.info/lookaround.html">Lookaround</a></li></ul></ul><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-d09caa631115413da17c318254bb1766" data-id="d09caa631115413da17c318254bb1766"><span><div id="d09caa631115413da17c318254bb1766" class="notion-header-anchor"></div><a class="notion-hash-link" href="#d09caa631115413da17c318254bb1766" title="后台类"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>后台类</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-d27148c834564cc3b222219445b5771a" data-id="d27148c834564cc3b222219445b5771a"><span><div id="d27148c834564cc3b222219445b5771a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#d27148c834564cc3b222219445b5771a" title="1 代码实现类"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1 代码实现类</b></span></span></h3><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-740d9bbc35294e8ab91765103833c191" data-id="740d9bbc35294e8ab91765103833c191"><span><div id="740d9bbc35294e8ab91765103833c191" class="notion-header-anchor"></div><a class="notion-hash-link" href="#740d9bbc35294e8ab91765103833c191" title="1.1 输入校验"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1 输入校验</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-bf8a980dfed444b98ae5bd088cdc51e4" data-id="bf8a980dfed444b98ae5bd088cdc51e4"><span><div id="bf8a980dfed444b98ae5bd088cdc51e4" class="notion-header-anchor"></div><a class="notion-hash-link" href="#bf8a980dfed444b98ae5bd088cdc51e4" title="1.1.1【必须】按类型进行数据校验"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.1.1【必须】按类型进行数据校验</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-996a7da4b1dc4a47815e03322002e678"><li>所有外部输入的参数，应使用<code class="notion-inline-code">validator</code>进行白名单校验，校验内容包括但不限于数据长度、数据范围、数据类型与格式，校验不通过的应当拒绝</li></ul><ul class="notion-list notion-list-disc notion-block-eed2a5a542154f38be3f1ed76890ec59"><li>无法通过白名单校验的应使用<code class="notion-inline-code">html.EscapeString</code>、<code class="notion-inline-code">text/template</code>或<code class="notion-inline-code">bluemonday</code>对<code class="notion-inline-code">&lt;, &gt;, &amp;, &#x27;,&quot;</code>等字符进行过滤或编码</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-0a292090b7a9442cab2a350fd8f9cee7" data-id="0a292090b7a9442cab2a350fd8f9cee7"><span><div id="0a292090b7a9442cab2a350fd8f9cee7" class="notion-header-anchor"></div><a class="notion-hash-link" href="#0a292090b7a9442cab2a350fd8f9cee7" title="1.2 SQL操作"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.2 SQL操作</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2cb60eceb1124b508d271aecad07398b" data-id="2cb60eceb1124b508d271aecad07398b"><span><div id="2cb60eceb1124b508d271aecad07398b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2cb60eceb1124b508d271aecad07398b" title="1.2.1【必须】SQL语句默认使用预编译并绑定变量"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.2.1【必须】SQL语句默认使用预编译并绑定变量</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-538ea624a710406f971900b9815aeac9"><li>使用<code class="notion-inline-code">database/sql</code>的prepare、Query或使用GORM等ORM执行SQL操作</li></ul><ul class="notion-list notion-list-disc notion-block-9eb90a8083f546938204d75572791efd"><li>使用参数化查询，禁止拼接SQL语句，另外对于传入参数用于order by或表名的需要通过校验</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-66f0c2cca8eb41b1973782095bc54e4e" data-id="66f0c2cca8eb41b1973782095bc54e4e"><span><div id="66f0c2cca8eb41b1973782095bc54e4e" class="notion-header-anchor"></div><a class="notion-hash-link" href="#66f0c2cca8eb41b1973782095bc54e4e" title="1.3 网络请求"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.3 网络请求</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-b6e3e656ba2740e5b0d9d7ae8a32182b" data-id="b6e3e656ba2740e5b0d9d7ae8a32182b"><span><div id="b6e3e656ba2740e5b0d9d7ae8a32182b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#b6e3e656ba2740e5b0d9d7ae8a32182b" title="1.3.1【必须】资源请求过滤验证"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.3.1【必须】资源请求过滤验证</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-ea11adc0a2094646bec54cdb29c73df7"><li>使用<code class="notion-inline-code">&quot;net/http&quot;</code>下的方法<code class="notion-inline-code">http.Get(url)</code>、<code class="notion-inline-code">http.Post(url, contentType, body)</code>、<code class="notion-inline-code">http.Head(url)</code>、<code class="notion-inline-code">http.PostForm(url, data)</code>、<code class="notion-inline-code">http.Do(req)</code>时，如变量值外部可控（指从参数中动态获取），应对请求目标进行严格的安全校验。</li></ul><ul class="notion-list notion-list-disc notion-block-05df75951f6443e5be42ad0b14c07db1"><li>如请求资源域名归属固定的范围，如只允许<code class="notion-inline-code">a.qq.com</code>和<code class="notion-inline-code">b.qq.com</code>，应做白名单限制。如不适用白名单，则推荐的校验逻辑步骤是：</li><ul class="notion-list notion-list-disc notion-block-05df75951f6443e5be42ad0b14c07db1"><li>第 1 步、只允许HTTP或HTTPS协议</li><li>第 2 步、解析目标URL，获取其HOST</li><li>第 3 步、解析HOST，获取HOST指向的IP地址转换成Long型</li><li>第 4 步、检查IP地址是否为内网IP，网段有：</li><ul class="notion-list notion-list-disc notion-block-19d7364ddfbe4c2191a64ab61b892a44"></ul><li>第 5 步、请求URL</li><li>第 6 步、如有跳转，跳转后执行1，否则绑定经校验的ip和域名，对URL发起请求</li></ul></ul><ul class="notion-list notion-list-disc notion-block-328cfc6ff52f4e4380df6242558948d4"><li>官方库<code class="notion-inline-code">encoding/xml</code>不支持外部实体引用，使用该库可避免xxe漏洞</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-3d1d1ad992fa407ca0ab81e4dcde22e1" data-id="3d1d1ad992fa407ca0ab81e4dcde22e1"><span><div id="3d1d1ad992fa407ca0ab81e4dcde22e1" class="notion-header-anchor"></div><a class="notion-hash-link" href="#3d1d1ad992fa407ca0ab81e4dcde22e1" title="1.4 服务器端渲染"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.4 服务器端渲染</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-4e314d585f564efa917414d8f71f84e1" data-id="4e314d585f564efa917414d8f71f84e1"><span><div id="4e314d585f564efa917414d8f71f84e1" class="notion-header-anchor"></div><a class="notion-hash-link" href="#4e314d585f564efa917414d8f71f84e1" title="1.4.1【必须】模板渲染过滤验证"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.4.1【必须】模板渲染过滤验证</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-ce05dd5b4daa4af78863962fa6a72c48"><li>使用<code class="notion-inline-code">text/template</code>或者<code class="notion-inline-code">html/template</code>渲染模板时禁止将外部输入参数引入模板，或仅允许引入白名单内字符。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-de1413b2f7df4eeaa366338171e0d620" data-id="de1413b2f7df4eeaa366338171e0d620"><span><div id="de1413b2f7df4eeaa366338171e0d620" class="notion-header-anchor"></div><a class="notion-hash-link" href="#de1413b2f7df4eeaa366338171e0d620" title="1.5 Web跨域"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.5 Web跨域</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-e1983f5be418434f9270a2ef24bbc124" data-id="e1983f5be418434f9270a2ef24bbc124"><span><div id="e1983f5be418434f9270a2ef24bbc124" class="notion-header-anchor"></div><a class="notion-hash-link" href="#e1983f5be418434f9270a2ef24bbc124" title="1.5.1【必须】跨域资源共享CORS限制请求来源"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.5.1【必须】跨域资源共享CORS限制请求来源</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-056e444281a34212bb1eaac1e4ce9222"><li>CORS请求保护不当可导致敏感信息泄漏，因此应当严格设置Access-Control-Allow-Origin使用同源策略进行保护。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-5e8c856983af44f79f4d94c1217a1fd7" data-id="5e8c856983af44f79f4d94c1217a1fd7"><span><div id="5e8c856983af44f79f4d94c1217a1fd7" class="notion-header-anchor"></div><a class="notion-hash-link" href="#5e8c856983af44f79f4d94c1217a1fd7" title="1.6 响应输出"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6 响应输出</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-ecbb10ff7eef405cbffa43b848edd454" data-id="ecbb10ff7eef405cbffa43b848edd454"><span><div id="ecbb10ff7eef405cbffa43b848edd454" class="notion-header-anchor"></div><a class="notion-hash-link" href="#ecbb10ff7eef405cbffa43b848edd454" title="1.6.1 【必须】设置正确的HTTP响应包类型"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6.1 【必须】设置正确的HTTP响应包类型</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-b86de220dcdc4c2d8decf1e8d9b073cb"><li>响应头Content-Type与实际响应内容，应保持一致。如：API响应数据类型是json，则响应头使用<code class="notion-inline-code">application/json</code>；若为xml，则设置为<code class="notion-inline-code">text/xml</code>。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-673fb0022f2645a3b94660e172fecb1b" data-id="673fb0022f2645a3b94660e172fecb1b"><span><div id="673fb0022f2645a3b94660e172fecb1b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#673fb0022f2645a3b94660e172fecb1b" title="1.6.2 【必须】添加安全响应头"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6.2 【必须】添加安全响应头</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-7d69f1aafcc141318fb65da6667f7bb0"><li>所有接口、页面，添加响应头 <code class="notion-inline-code">X-Content-Type-Options: nosniff</code>。</li></ul><ul class="notion-list notion-list-disc notion-block-ef8d9e1f559e4aac8a09ff46f6baa313"><li>所有接口、页面，添加响应头<code class="notion-inline-code">X-Frame-Options</code>。按需合理设置其允许范围，包括：<code class="notion-inline-code">DENY</code>、<code class="notion-inline-code">SAMEORIGIN</code>、<code class="notion-inline-code">ALLOW-FROM origin</code>。用法参考：<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/X-Frame-Options">MDN文档</a></li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-fc9d556fe613491c987e2829a7505e9a" data-id="fc9d556fe613491c987e2829a7505e9a"><span><div id="fc9d556fe613491c987e2829a7505e9a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#fc9d556fe613491c987e2829a7505e9a" title="1.6.3【必须】外部输入拼接到HTTP响应头中需进行过滤"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6.3【必须】外部输入拼接到HTTP响应头中需进行过滤</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-be90000091e7458fa47e80d07e2e5591"><li>应尽量避免外部可控参数拼接到HTTP响应头中，如业务需要则需要过滤掉<code class="notion-inline-code">\r</code>、<code class="notion-inline-code">\n</code>等换行符，或者拒绝携带换行符号的外部输入。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-29be614f35ea490eb3ec536608750873" data-id="29be614f35ea490eb3ec536608750873"><span><div id="29be614f35ea490eb3ec536608750873" class="notion-header-anchor"></div><a class="notion-hash-link" href="#29be614f35ea490eb3ec536608750873" title="1.6.4【必须】外部输入拼接到response页面前进行编码处理"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.6.4【必须】外部输入拼接到response页面前进行编码处理</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-b64d1aacd03f4f6f98d547518e1673e1"><li>直出html页面或使用模板生成html页面的，推荐使用<code class="notion-inline-code">text/template</code>自动编码，或者使用<code class="notion-inline-code">html.EscapeString</code>或<code class="notion-inline-code">text/template</code>对<code class="notion-inline-code">&lt;, &gt;, &amp;, &#x27;,&quot;</code>等字符进行编码。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-d87ae0c4c14646278b7aaccb44b071e0" data-id="d87ae0c4c14646278b7aaccb44b071e0"><span><div id="d87ae0c4c14646278b7aaccb44b071e0" class="notion-header-anchor"></div><a class="notion-hash-link" href="#d87ae0c4c14646278b7aaccb44b071e0" title="1.7 会话管理"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.7 会话管理</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-87928013aa3c4745ad2120338d5bae1a" data-id="87928013aa3c4745ad2120338d5bae1a"><span><div id="87928013aa3c4745ad2120338d5bae1a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#87928013aa3c4745ad2120338d5bae1a" title="1.7.1【必须】安全维护session信息"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.7.1【必须】安全维护session信息</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-da7b4a4c8c704588ae3a114cc9fbe444"><li>用户登录时应重新生成session，退出登录后应清理session。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-5bae438b4da144448729c2af75931c0b" data-id="5bae438b4da144448729c2af75931c0b"><span><div id="5bae438b4da144448729c2af75931c0b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#5bae438b4da144448729c2af75931c0b" title="1.7.2【必须】CSRF防护"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.7.2【必须】CSRF防护</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-33df5a32c5a343bf8c492f5d81e448e2"><li>涉及系统敏感操作或可读取敏感信息的接口应校验<code class="notion-inline-code">Referer</code>或添加<code class="notion-inline-code">csrf_token</code>。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-1f7a8037459a4d508333d15d9b24de32" data-id="1f7a8037459a4d508333d15d9b24de32"><span><div id="1f7a8037459a4d508333d15d9b24de32" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1f7a8037459a4d508333d15d9b24de32" title="1.8 访问控制"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.8 访问控制</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-72984f8753634bec88cec6fcd02b3cd9" data-id="72984f8753634bec88cec6fcd02b3cd9"><span><div id="72984f8753634bec88cec6fcd02b3cd9" class="notion-header-anchor"></div><a class="notion-hash-link" href="#72984f8753634bec88cec6fcd02b3cd9" title="1.8.1【必须】默认鉴权"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.8.1【必须】默认鉴权</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-a2909975387f4c9b843d74ed315426ae"><li>除非资源完全可对外开放，否则系统默认进行身份认证，使用白名单的方式放开不需要认证的接口或页面。</li></ul><ul class="notion-list notion-list-disc notion-block-03c1088fe60042eb8b87ac0c8f95bf46"><li>根据资源的机密程度和用户角色，以最小权限原则，设置不同级别的权限，如完全公开、登录可读、登录可写、特定用户可读、特定用户可写等</li></ul><ul class="notion-list notion-list-disc notion-block-2afcbf252ace4bd0aa105819de4a9176"><li>涉及用户自身相关的数据的读写必须验证登录态用户身份及其权限，避免越权操作</li><ul class="notion-list notion-list-disc notion-block-2afcbf252ace4bd0aa105819de4a9176"></ul></ul><ul class="notion-list notion-list-disc notion-block-7a9ea7097c9e43d39563d26e29d5f960"><li>没有独立账号体系的外网服务使用<code class="notion-inline-code">QQ</code>或<code class="notion-inline-code">微信</code>登录，内网服务使用<code class="notion-inline-code">统一登录服务</code>登录，其他使用账号密码登录的服务需要增加验证码等二次验证</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-8127acdeea2b409686d40c78601dac30" data-id="8127acdeea2b409686d40c78601dac30"><span><div id="8127acdeea2b409686d40c78601dac30" class="notion-header-anchor"></div><a class="notion-hash-link" href="#8127acdeea2b409686d40c78601dac30" title="1.9 并发保护"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.9 并发保护</b></span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-fc1c66391214471a82df7acedca3c6d3" data-id="fc1c66391214471a82df7acedca3c6d3"><span><div id="fc1c66391214471a82df7acedca3c6d3" class="notion-header-anchor"></div><a class="notion-hash-link" href="#fc1c66391214471a82df7acedca3c6d3" title="1.9.1【必须】禁止在闭包中直接调用循环变量"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.9.1【必须】禁止在闭包中直接调用循环变量</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-adda5369589142e6a2c2c2759d7642e8"><li>在循环中启动协程，当协程中使用到了循环的索引值，由于多个协程同时使用同一个变量会产生数据竞争，造成执行结果异常。</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-ae5f50f369a24c29a6e67c650eca61c3" data-id="ae5f50f369a24c29a6e67c650eca61c3"><span><div id="ae5f50f369a24c29a6e67c650eca61c3" class="notion-header-anchor"></div><a class="notion-hash-link" href="#ae5f50f369a24c29a6e67c650eca61c3" title="1.9.2【必须】禁止并发写map"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.9.2【必须】禁止并发写map</b></span></span></h4><ul class="notion-list notion-list-disc notion-block-bc223da1b6f34857b3ca744faae6b6fe"><li>并发写map容易造成程序崩溃并异常退出，建议加锁保护</li></ul><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-04ecf62a8dce470681b419f47e1c1100" data-id="04ecf62a8dce470681b419f47e1c1100"><span><div id="04ecf62a8dce470681b419f47e1c1100" class="notion-header-anchor"></div><a class="notion-hash-link" href="#04ecf62a8dce470681b419f47e1c1100" title="1.9.3【必须】确保并发安全"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1.9.3【必须】确保并发安全</b></span></span></h4><div class="notion-text notion-block-917da74ef1e0415b8e6deec06c401d39">敏感操作如果未作并发安全限制，可导致数据读写异常，造成业务逻辑限制被绕过。可通过同步锁或者原子操作进行防护。</div><div class="notion-text notion-block-2b94517e7dc04e08b3490678e9201ae1">通过同步锁共享内存</div><ul class="notion-list notion-list-disc notion-block-affc1c87509149bbbddab29803d06c36"><li>使用<code class="notion-inline-code">sync/atomic</code>执行原子操作</li></ul></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[编程语言多版本管理]]></title>
            <link>https://blg.milkcoff.com/article/8a4d6c10-ce54-49d5-8d70-117c761c21e6</link>
            <guid>https://blg.milkcoff.com/article/8a4d6c10-ce54-49d5-8d70-117c761c21e6</guid>
            <pubDate>Tue, 20 Feb 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-8a4d6c10ce5449d58d70117c761c21e6"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><blockquote class="notion-quote notion-block-348842afe182416986b50fbdb21239d6"><div>对于编程语言，有时对多个版本的管理，是一个痛点，那么使用多版本管理工具是一种有效的解决方案。多版本管理工具可以帮助我们在同一台机器上安装和使用多个版本的编程语言，同时可以轻松地在不同版本之间切换。这样，无论是为了兼容旧版本的代码，还是为了尝试新版本的特性，都能得到很好的支持。</div></blockquote><div class="notion-blank notion-block-db7fc3fbffd1478f87a971e8f50781da"> </div><div class="notion-text notion-block-95efac0497aa4a749142f1ebb3c1b43d">👨‍💻 Golang<div class="notion-text-children"><ul class="notion-list notion-list-disc notion-block-800161cc67eb4a7889b8d4763606f94d"><li>g</li><ul class="notion-list notion-list-disc notion-block-800161cc67eb4a7889b8d4763606f94d"><div class="notion-text notion-block-4a4ff35dba6f4795807fc636e7497d58"><b>g安装</b></div><div class="notion-text notion-block-782752fd0b084bc7b57df603289746fa">1. 下载 <a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://github.com/voidint/g/releases">https://github.com/voidint/g/releases</a></div><div class="notion-text notion-block-9f86254307824eac8fb535e7e13557aa"><b>配置流程：</b></div><div class="notion-text notion-block-00cdab06f6ce4e33909894c7b01f955d">1.创建目录在D盘新建目录G（可根据自己的情况设置新建目录，只要配置的目录地址正确就可以）</div><div class="notion-text notion-block-ffe6c07137fe4770b9ec4660ebaf3ee9">（1）在G下面新建bin文件夹</div><div class="notion-text notion-block-f9d3edcc898d4d5fad766b9169ec6dbb">（2）在G下面新建go文件夹</div><div class="notion-text notion-block-21dd5a9e66ba4f75ad87f773f7bbe6b2">（3）解压文件将exe文件放到bin目录下</div><div class="notion-text notion-block-a31160c875984cd795170e306e152b63">（4）新建gowww文件夹用来存放代码</div><div class="notion-text notion-block-52457b348c954c139fcdaa7506ca4028">（5）在gowww下新建bin(编译文件存放位置)、pkg(包存放位置)、src目录(项目存放的位置)</div><div class="notion-text notion-block-f4593990b47f4b1f96cbba6c8c4fd1c8">2.配置环境变量</div><div class="notion-text notion-block-69066055ae3e42419797c940854413a1">（1）配置g的环境变量 path D:\G\bin</div><div class="notion-text notion-block-2860b47b8e99446888a6aadeae6abe18">（2）配置g安装目录环境变量 G_HOME = D:\G</div><div class="notion-text notion-block-f7e152243569496fbbe5b3badb0b0d68">（3）配置GOBIN D:\G\go\bin</div><div class="notion-text notion-block-0eae5c97486d4c0f902aa2446dbb26ed">（4）配置GOPATH （你代码的位置）</div><div class="notion-text notion-block-8a9dc100a16a4a43a9abd85325df9844">（5）配置GOROOT D:\G\go</div><div class="notion-text notion-block-605643c084b14b419ab653c081012e1b">（6）配置g默认目录生效 G_EXPERIMENTAL true</div><div class="notion-text notion-block-b6868fd00eba4b85a8e1566682b9503c">3.g基本命令</div></ul></ul></div></div><div class="notion-blank notion-block-b7d2c164fb8243569cbf405f2c18251a"> </div><div class="notion-text notion-block-39468b8d9ff44887bbb2132531312df6">👨‍💻 Node.js<div class="notion-text-children"><ul class="notion-list notion-list-disc notion-block-3a75b26352644fbe925bcee7d389560a"><li>nvm</li></ul></div></div><div class="notion-blank notion-block-c4de33f0e1404d14b56dc3df42230e51"> </div><div class="notion-text notion-block-6d9100a217bb46cc924c75397426a243">👨‍💻 Python<div class="notion-text-children"><ul class="notion-list notion-list-disc notion-block-6047618f777a4379b444ac7ddeae0f1a"><li>pyenv-win</li></ul></div></div></main></div>]]></content:encoded>
        </item>
    </channel>
</rss>