-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.json
1 lines (1 loc) · 354 KB
/
search.json
1
[{"title":"我的2020年终总结","url":"/1.Growth/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/%E6%88%91%E7%9A%842020%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/","content":"","categories":["1.Growth","总结"],"tags":["总结"]},{"title":"MySQL存储关联数组","url":"/2.Programming/3.MySQL/MySQL%E5%AD%98%E5%82%A8%E5%85%B3%E8%81%94%E6%95%B0%E7%BB%84/","content":"<p>关联数组:</p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"variable\">$fruits</span>= <span class=\"keyword\">array</span>(<span class=\"string\">"apple"</span> => <span class=\"string\">"苹果"</span>, <span class=\"string\">"banana"</span> => <span class=\"string\">"香蕉"</span>,<span class=\"string\">"oriange"</span> => <span class=\"string\">"橘子"</span>);</span><br></pre></td></tr></table></figure>\n\n<p>对于这样的数据,MySQL数据库因存储类型是无法直接写入的,那有什么办法呢?</p>\n<p><strong>解决方案:使用PHP自带的serialize()或者json_encode()函数序列化数据成字符串,之后从数据库里面读出来的数据还是字符串格式的,用unserialize()和json_decode()函数转换成数组就可以了</strong></p>\n<p><strong>写入数据库之前</strong></p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"variable\">$fruits_serialize</span> = serialize(<span class=\"variable\">$fruits</span>); <span class=\"comment\">// 序列化成字符串</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"variable\">$fruits_json</span> = json_encode(<span class=\"variable\">$fruits</span>); <span class=\"comment\">// JSON编码数组成字符串</span></span><br></pre></td></tr></table></figure>\n\n\n\n<p><strong>读取数据库后</strong></p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"variable\">$fruits</span> _restore = unserialize(<span class=\"variable\">$fruits_serialize</span>); <span class=\"comment\">// 反序列化成数组</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"variable\">$fruits</span> _dejson = json_decode(<span class=\"variable\">$fruits_json</span>, <span class=\"literal\">true</span>); <span class=\"comment\">// JSON解码成数组</span></span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","MySQL"],"tags":["MySQL"]},{"title":"关系型数据库和非关系型数据及其区别","url":"/2.Programming/3.MySQL/%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E5%92%8C%E9%9D%9E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%8F%8A%E5%85%B6%E5%8C%BA%E5%88%AB/","content":"<p><a href=\"https://www.cnblogs.com/aaronthon/p/9459353.html\">原文参考</a></p>\n<h2 id=\"关系型数据库\"><a href=\"#关系型数据库\" class=\"headerlink\" title=\"关系型数据库\"></a>关系型数据库</h2><p>\u000b<img src=\"/images/20200107-1.png\" alt=\"mysql\"></p>\n<p>关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织</p>\n<table>\n<thead>\n<tr>\n<th>优点</th>\n<th>1、易于维护:都是使用表结构,格式一致;</th>\n</tr>\n</thead>\n<tbody><tr>\n<td></td>\n<td>2、使用方便:SQL语言通用,可用于复杂查询;</td>\n</tr>\n<tr>\n<td></td>\n<td>3、复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。</td>\n</tr>\n<tr>\n<td>缺点</td>\n<td>1、读写性能比较差,尤其是海量数据的高效率读写;</td>\n</tr>\n<tr>\n<td></td>\n<td>2、固定的表结构,灵活度稍欠;</td>\n</tr>\n<tr>\n<td></td>\n<td>3、高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。</td>\n</tr>\n</tbody></table>\n<h2 id=\"非关系型数据库\"><a href=\"#非关系型数据库\" class=\"headerlink\" title=\"非关系型数据库\"></a>非关系型数据库</h2><p>\u000b<img src=\"/images/20200107-2.png\" alt=\"mysql\"></p>\n<p>非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。</p>\n<table>\n<thead>\n<tr>\n<th>优点</th>\n<th>1、格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。</th>\n</tr>\n</thead>\n<tbody><tr>\n<td></td>\n<td>2、速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;</td>\n</tr>\n<tr>\n<td></td>\n<td>3、高扩展性;</td>\n</tr>\n<tr>\n<td></td>\n<td>4、成本低:nosql数据库部署简单,基本都是开源软件。</td>\n</tr>\n<tr>\n<td>缺点</td>\n<td>1、不提供sql支持,学习和使用成本较高;</td>\n</tr>\n<tr>\n<td></td>\n<td>2、无事务处理;</td>\n</tr>\n<tr>\n<td></td>\n<td>3、数据结构相对复杂,复杂查询方面稍欠。</td>\n</tr>\n<tr>\n<td></td>\n<td>非关系型数据库的分类和比较:<br/>1、文档型<br/>2、key-value型<br/>3、列式数据库<br/>4、图形数据库</td>\n</tr>\n</tbody></table>\n<p>\u000b<img src=\"/images/20200107-3.png\" alt=\"mysql\"></p>\n<p>\u000b<img src=\"/images/20200107-4.png\" alt=\"mysql\"></p>\n<p>\u000b<img src=\"/images/20200107-5.png\" alt=\"mysql\"></p>\n<p>\u000b<img src=\"/images/20200107-6.png\" alt=\"mysql\"></p>\n","categories":["2.Programming","MySQL"],"tags":["MySQL"]},{"title":"Django三件套","url":"/2.Programming/1.Python/Django%E4%B8%89%E4%BB%B6%E5%A5%97/","content":"<h4 id=\"Django基础必备三件套\"><a href=\"#Django基础必备三件套\" class=\"headerlink\" title=\"Django基础必备三件套:\"></a>Django基础必备三件套:</h4><p><strong>1、HttpResponse 内部传入一个字符串参数,返回给浏览器</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> django.shortcuts <span class=\"keyword\">import</span> HttpResponse</span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">index</span>(<span class=\"params\">request</span>):</span></span><br><span class=\"line\"> <span class=\"comment\"># 业务逻辑代码</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> HttpResponse(<span class=\"string\">"OK"</span>)</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、render除request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数。</strong></p>\n<p><strong>将数据填充进模板文件,最后把结果返回给浏览器。</strong> </p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> django.shortcuts <span class=\"keyword\">import</span> render</span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">index</span>(<span class=\"params\">request</span>):</span></span><br><span class=\"line\"> <span class=\"comment\"># 业务逻辑代码</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> render(request, <span class=\"string\">"index.html"</span>, {<span class=\"string\">"name"</span>: <span class=\"string\">"alex"</span>, <span class=\"string\">"hobby"</span>: [<span class=\"string\">"烫头"</span>, <span class=\"string\">"泡吧"</span>]})</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、redirect接受一个URL参数,表示跳转到指定的URL</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> django.shortcuts <span class=\"keyword\">import</span> redirect</span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">index</span>(<span class=\"params\">request</span>):</span></span><br><span class=\"line\"> <span class=\"comment\"># 业务逻辑代码</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> redirect(<span class=\"string\">"/home/"</span>)</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Python"],"tags":["Python","接口"]},{"title":"Django常用的第三方包","url":"/2.Programming/1.Python/Django%E5%B8%B8%E7%94%A8%E7%9A%84%E7%AC%AC%E4%B8%89%E6%96%B9%E5%8C%85/","content":"<h3 id=\"API开发\"><a href=\"#API开发\" class=\"headerlink\" title=\"API开发\"></a>API开发</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">djangorestframework #https://www.django-rest-framework.org/</span><br><span class=\"line\">django-rest-multiple-models #model层返回多个库信息</span><br><span class=\"line\">django-cors-headers #跨域</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"查询\"><a href=\"#查询\" class=\"headerlink\" title=\"查询\"></a>查询</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">django-filter</span><br><span class=\"line\">django-haystack</span><br><span class=\"line\">drf-haystack</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"后台界面\"><a href=\"#后台界面\" class=\"headerlink\" title=\"后台界面\"></a>后台界面</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">bootstrap_admin #推荐</span><br><span class=\"line\">django-jet</span><br><span class=\"line\">xadmin</span><br><span class=\"line\">django-simpleui</span><br><span class=\"line\">django-suit</span><br><span class=\"line\">django-grappelli</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"调试\"><a href=\"#调试\" class=\"headerlink\" title=\"调试\"></a>调试</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">django-debug-toolbar #推荐</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"对象级权限\"><a href=\"#对象级权限\" class=\"headerlink\" title=\"对象级权限\"></a>对象级权限</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">django-guardian</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"异步\"><a href=\"#异步\" class=\"headerlink\" title=\"异步\"></a>异步</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">celery </span><br></pre></td></tr></table></figure>\n\n<h3 id=\"富文本编辑器\"><a href=\"#富文本编辑器\" class=\"headerlink\" title=\"富文本编辑器\"></a>富文本编辑器</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">django-ckeditor</span><br><span class=\"line\">django-tinymce</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Python"],"tags":["Python"]},{"title":"Django实现列表分页功能","url":"/2.Programming/1.Python/Django%E5%AE%9E%E7%8E%B0%E5%88%97%E8%A1%A8%E5%88%86%E9%A1%B5%E5%8A%9F%E8%83%BD/","content":"<h5 id=\"在view-py里添加分页查询方法\"><a href=\"#在view-py里添加分页查询方法\" class=\"headerlink\" title=\"在view.py里添加分页查询方法:\"></a>在view.py里添加分页查询方法:</h5><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> django.http <span class=\"keyword\">import</span> JsonResponse</span><br><span class=\"line\"><span class=\"keyword\">from</span> django.views.decorators.http <span class=\"keyword\">import</span> require_http_methods</span><br><span class=\"line\"><span class=\"keyword\">from</span> django.core <span class=\"keyword\">import</span> serializers</span><br><span class=\"line\"><span class=\"keyword\">from</span> django.core.paginator <span class=\"keyword\">import</span> Paginator, EmptyPage, PageNotAnInteger</span><br><span class=\"line\"><span class=\"keyword\">import</span> json</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># 分页查询</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">show_page</span>(<span class=\"params\">request</span>):</span></span><br><span class=\"line\"> page = request.GET.get(<span class=\"string\">'page'</span>)</span><br><span class=\"line\"> pageSize = <span class=\"built_in\">int</span>(request.GET.get(<span class=\"string\">'pageSize'</span>))</span><br><span class=\"line\"> response = {}</span><br><span class=\"line\"> book_list = Book.objects.<span class=\"built_in\">all</span>()</span><br><span class=\"line\"> paginator = Paginator(book_list, pageSize)</span><br><span class=\"line\"> response[<span class=\"string\">'total'</span>] = paginator.count</span><br><span class=\"line\"> <span class=\"keyword\">try</span>:</span><br><span class=\"line\"> books = paginator.page(page)</span><br><span class=\"line\"> <span class=\"keyword\">except</span> PageNotAnInteger:</span><br><span class=\"line\"> books = paginator.page(<span class=\"number\">1</span>)</span><br><span class=\"line\"> <span class=\"keyword\">except</span> EmptyPage:</span><br><span class=\"line\"> books = paginator.page(paginator.num_pages)</span><br><span class=\"line\"> response[<span class=\"string\">'list'</span>] = json.loads(serializers.serialize(<span class=\"string\">"json"</span>, books))</span><br><span class=\"line\"> <span class=\"keyword\">return</span> JsonResponse(response)</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Python"],"tags":["Python","接口"]},{"title":"Django总结","url":"/2.Programming/1.Python/Django%E6%80%BB%E7%BB%93/","content":"<p><a href=\"https://www.cnblogs.com/djangocn/p/9538551.html\">centos7下部署django详细步骤</a></p>\n<p><a href=\"https://www.cnblogs.com/zengjielin/p/8487077.html\">快速入门</a></p>\n<p><a href=\"%5Bhttps://cnblogs.com/aylin/p/5608175.html\">基础知识</a></p>\n<p><a href=\"https://www.cnblogs.com/gaosai/p/10322924.html\">日志总结</a></p>\n","categories":["2.Programming","Python"],"tags":["Python","接口"]},{"title":"Django问题总结","url":"/2.Programming/1.Python/Django%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/","content":"<p><strong>1、python manage.py makemigrations No changes detected</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">在修改了models.py后,有些用户会喜欢用python manage.py makemigrations生成对应的py代码。</span><br><span class=\"line\"></span><br><span class=\"line\">但有时执行python manage.py makemigrations命令(也可能人比较皮,把migrations文件夹给删了),会提示"Nochangesdetected."可能有用的解决方式如下:</span><br><span class=\"line\"></span><br><span class=\"line\">先python manage.py makemigrations --empty yourappname生成一个空的initial.py</span><br><span class=\"line\"></span><br><span class=\"line\">再python manage.py makemigrations生成原先的model对应的migrationfile</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、Django使用migrations迁移版本和数据库中报错解决方案</strong></p>\n<p><a href=\"https://blog.csdn.net/a599174211/article/details/82795206\">参考</a></p>\n<p><strong>3、Django-关于manage.py migrate无效的问题</strong></p>\n<p><a href=\"https://blog.csdn.net/qq_25730711/article/details/60327344\">参考</a></p>\n<p><strong>4、解决在vscode中用python操作数据库模型时出现的Class “xxx” has no ‘objects’ member错误提示</strong></p>\n<p><a href=\"https://blog.csdn.net/qq_36272282/article/details/89416663\">参考</a></p>\n<p><strong>5、关于线上部署admin后台样式没有生效的问题</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">1、在settings.py尾部:</span><br><span class=\"line\">STATIC_ROOT = os.path.join(BASE_DIR, 'static')#指定样式收集目录</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">或</span></span><br><span class=\"line\">STATIC_ROOT = '/www/mysite/mysite/static' #指定样式收集目录</span><br><span class=\"line\"></span><br><span class=\"line\">2、收集CSS样式,在终端输入:</span><br><span class=\"line\">python manage.py collectstatic</span><br><span class=\"line\">运行这个命令之后,就会自动把后台CSS样式收集到/static/目录下。刷新页面就能恢复样式!</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Python"],"tags":["Python","接口"]},{"title":"Django数据Model层总结","url":"/2.Programming/1.Python/Django%E6%95%B0%E6%8D%AEModel%E5%B1%82%E6%80%BB%E7%BB%93/","content":"<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">vlaues:</span><br><span class=\"line\">单条记录 - <<span class=\"class\"><span class=\"keyword\">class</span> '<span class=\"title\">dict</span>'></span></span><br><span class=\"line\"><span class=\"class\">多条记录 - <<span class=\"title\">class</span> '<span class=\"title\">django</span>.<span class=\"title\">db</span>.<span class=\"title\">models</span>.<span class=\"title\">query</span>.<span class=\"title\">QuerySet</span>'></span></span><br><span class=\"line\"><span class=\"class\"><span class=\"title\">vlaues_list</span>:</span></span><br><span class=\"line\">单条记录 - <<span class=\"class\"><span class=\"keyword\">class</span> '<span class=\"title\">tuple</span>'></span></span><br><span class=\"line\"><span class=\"class\">多条记录 - <<span class=\"title\">class</span> '<span class=\"title\">django</span>.<span class=\"title\">db</span>.<span class=\"title\">models</span>.<span class=\"title\">query</span>.<span class=\"title\">QuerySet</span>'></span></span><br></pre></td></tr></table></figure>\n\n<p>Django的抽象模型Models可以直接对数据库进行增删改查,不需要你自己写SQL语言来进行相关数据库操作。今天我们就以博客blog为例,看下Django是如何对数据库进行增删改查的。</p>\n<p>我们将会用到如下这个简单的Article模型: </p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> django.db <span class=\"keyword\">import</span> models</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Article</span>(<span class=\"params\">models.Model</span>):</span></span><br><span class=\"line\"> title = models.CharField(<span class=\"string\">'标题'</span>, max_length=<span class=\"number\">200</span>, unique=<span class=\"literal\">True</span>)</span><br><span class=\"line\"> body = models.TextField(<span class=\"string\">'正文'</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">__str__</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> self.title</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"增\"><a href=\"#增\" class=\"headerlink\" title=\"增\"></a>增</h2><p>增即创建新的对象或添加新的条目。如果我们要给数据库添加一篇新的文章,Django提供了2种常见操作方式。</p>\n<p><strong>1、传统save方法</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">obj = Article(title=<span class=\"string\">"My first article"</span>, body=<span class=\"string\">"My first article body"</span>)</span><br><span class=\"line\">obj.save()</span><br></pre></td></tr></table></figure>\n\n<p>注意: 该方法如果不选择save(), 创建的对象将不会保存到数据库中去。正因为如此,Django还提供了更便捷的create方法。</p>\n<p><strong>2、快捷的create方法</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.create(title=<span class=\"string\">"My first article"</span>, body=<span class=\"string\">"My first article body"</span>)</span><br></pre></td></tr></table></figure>\n\n<p>注意: 对Django自带auth模块中的User模型操作,比如创建新的用户时,请用create_user方法。该方法会将密码自动加Hash存储到数据库中。</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> django.contrib.auth.models <span class=\"keyword\">import</span> User</span><br><span class=\"line\">user = User.objects.create_user(username=<span class=\"string\">'john'</span>,</span><br><span class=\"line\"> email=<span class=\"string\">'john@gmail.com'</span>,</span><br><span class=\"line\"> password=<span class=\"string\">'somepwd'</span>)</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"删\"><a href=\"#删\" class=\"headerlink\" title=\"删\"></a>删</h2><p>删即删除一个已有对象或从表中删除一个已有条目。Django也允许同时删除多个对象或条目。</p>\n<p><strong>1、删除所有文章 (请慎用!!)</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.<span class=\"built_in\">all</span>().delete()</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、删除标题里含有python的所有文章(不区分大小写)</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.<span class=\"built_in\">filter</span>(title__icontains=<span class=\"string\">"python"</span>).delete()</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"改\"><a href=\"#改\" class=\"headerlink\" title=\"改\"></a>改</h2><p>改既可以用save方法,也可以用update方法。其区别在于save方法不仅可以更新数据中现有对象数据,还可以创建新的对象。而update方法只能用于更新已有对象数据。一般来说,如果要同时更新多个对象数据,用update方法更合适。</p>\n<p><strong>1、利用save方法更新某一文章标题</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">article = Article.objects.get(<span class=\"built_in\">id</span>=<span class=\"number\">1</span>)</span><br><span class=\"line\">article.title = <span class=\"string\">"New article title"</span></span><br><span class=\"line\">article.save()</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、利用update方法更新某一文章标题</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">article = Article.objects.get(<span class=\"built_in\">id</span>=<span class=\"number\">1</span>).update(title=<span class=\"string\">'new title'</span>)</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、利用update方法更新多篇文章标题</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">article = Article.objects.<span class=\"built_in\">filter</span>(title__icontains=<span class=\"string\">'python'</span>).update(title=<span class=\"string\">'Django'</span>)</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"查\"><a href=\"#查\" class=\"headerlink\" title=\"查\"></a>查</h2><p>Django对于数据库的查询主要是get和filter等方法。我们来看几个案例。</p>\n<p><strong>1、查询所有数据</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.<span class=\"built_in\">all</span>()</span><br><span class=\"line\">Article.objects.<span class=\"built_in\">all</span>().values()</span><br></pre></td></tr></table></figure>\n\n<p># 只获取title列表-字典形式</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.<span class=\"built_in\">all</span>().values(<span class=\"string\">'title'</span>)</span><br></pre></td></tr></table></figure>\n\n<p># 只获取title列表- 元组形式,只有value,没有key</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.<span class=\"built_in\">all</span>().values_list(<span class=\"string\">'title'</span>)</span><br></pre></td></tr></table></figure>\n\n<p>注意:使用values和values_list可以减少数据库查询工作量。如果只需要在模板中使用某些字段,而不是全部字段,建议使用values和values_list。</p>\n<p><strong>2、查询某一条数据</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.get(<span class=\"built_in\">id</span>=<span class=\"number\">1</span>)</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、模糊查询返回数据集, 并去重</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">Article.objects.<span class=\"built_in\">filter</span>(title__icontains=<span class=\"string\">'python'</span>).distinct()</span><br></pre></td></tr></table></figure>","categories":["2.Programming","Python"],"tags":["Python","接口"]},{"title":"Python-Jenkins信息","url":"/2.Programming/1.Python/Python-Jenkins%E4%BF%A1%E6%81%AF/","content":"<p><a href=\"https://python-jenkins.readthedocs.io/en/latest/examples.html#example-1-get-version-of-jenkins\">1、官方文档</a></p>\n<p><a href=\"https://www.jianshu.com/p/8fda9e96addd\">2、Python-jenkins-api</a></p>\n<p><a href=\"https://www.cnblogs.com/znicy/p/5498609.html\">3、Python调用Jenkins</a></p>\n<p><a href=\"https://juejin.im/post/5c70de3b6fb9a049c2330e2d\">4、Jenkins常用rest-api</a></p>\n<p><a href=\"https://blog.csdn.net/seeeees/article/details/79388684\">5、Python-jenkins模块之job相关操作</a></p>\n","categories":["2.Programming","Python"],"tags":["Python","Jenkins"]},{"title":"HttprunnerManager接口测试平台","url":"/2.Programming/1.Python/HttprunnerManager%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0/","content":"<h2 id=\"说名\"><a href=\"#说名\" class=\"headerlink\" title=\"说名\"></a>说名</h2><p>部门业务成立之初,便开始使用HttpRunner进行接口自动化的维护;根据平台维护用例较通过xml维护用例的好处是可以查看当前模块对应的用例个数、负责人和历史报告等信息,且使用数据库维护,所以在业务测试空隙进行了用例迁移。</p>\n<h2 id=\"HttpRunner\"><a href=\"#HttpRunner\" class=\"headerlink\" title=\"HttpRunner\"></a>HttpRunner</h2><h3 id=\"简介\"><a href=\"#简介\" class=\"headerlink\" title=\"简介\"></a>简介</h3><p>HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 <code>YAML/JSON</code> 脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。</p>\n<p><a href=\"https://github.com/HttpRunner/HttpRunner\">项目地址</a></p>\n<p><a href=\"%5Bhttp://cn.httprunner.org\">中文手册</a></p>\n<h2 id=\"HttpRunnerManager\"><a href=\"#HttpRunnerManager\" class=\"headerlink\" title=\"HttpRunnerManager\"></a>HttpRunnerManager</h2><h3 id=\"简介-1\"><a href=\"#简介-1\" class=\"headerlink\" title=\"简介\"></a>简介</h3><p>HttpRunnerManager是基于<code>HttpRunner</code>的接口自动化测试平台,该工具是对 <code>HttpRunner</code>的包装和Web图形化, 另外还增加了一些新概念(项目/模块)用来组织用例。<br>如果对yaml语法格式不熟悉,以及对于httprunner命令不熟悉的可以使用该平台执行接口自动化测试。</p>\n<p><a href=\"https://github.com/HttpRunner/HttpRunnerManager\">项目地址</a></p>\n<h3 id=\"核心特性\"><a href=\"#核心特性\" class=\"headerlink\" title=\"核心特性\"></a>核心特性</h3><ol>\n<li><p>项目管理:新增项目、列表展示及相关操作,支持用例批量上传(标准化的HttpRunner json和yaml用例脚本)</p>\n</li>\n<li><p>模块管理:为项目新增模块,用例和配置都归属于module,module和project支持同步和异步方式</p>\n</li>\n<li><p>用例管理:分为添加config与test子功能,config定义全部变量和request等相关信息 request可以为公共参数和请求头,也可定义全部变量</p>\n</li>\n<li><p>场景管理:可以动态加载可引用的用例,跨项目、跨模块,依赖用例列表支持拖拽排序和删除</p>\n</li>\n<li><p>运行方式:可单个test,单个module,单个project,也可选择多个批量运行,支持自定义测试计划,运行时可以灵活选择配置和环境</p>\n</li>\n<li><p>分布执行:单个用例和批量执行结果会直接在前端展示,模块和项目执行可选择为同步或者异步方式,</p>\n</li>\n<li><p>环境管理:可添加运行环境,运行用例时可以一键切换环境</p>\n</li>\n<li><p>报告查看:所有异步执行的用例均可在线查看报告,可自主命名,为空默认时间戳保存,</p>\n</li>\n<li><p>定时任务:可设置定时任务,遵循<code>crontab</code>表达式,可在线开启、关闭,完毕后支持邮件通知</p>\n</li>\n<li><p>持续集成:jenkins对接,开发中。。。</p>\n</li>\n</ol>\n<h3 id=\"环境安装\"><a href=\"#环境安装\" class=\"headerlink\" title=\"环境安装\"></a>环境安装</h3><p><strong>1、安装docker、mysql、rabbitmq并启动</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">docker search mysql</span><br><span class=\"line\"></span><br><span class=\"line\">docker pull mysql:5.7</span><br><span class=\"line\"></span><br><span class=\"line\">docker images |grep mysql</span><br><span class=\"line\"></span><br><span class=\"line\">docker run -p 3306:3306 --name bj_qa_mysql -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7</span><br><span class=\"line\"></span><br><span class=\"line\">docker ps</span><br><span class=\"line\"></span><br><span class=\"line\">sudo docker exec -it bj_qa_mysql bash</span><br><span class=\"line\"></span><br><span class=\"line\">mysql -h 127.0.0.1 -u root -p #密码123456</span><br><span class=\"line\"></span><br><span class=\"line\">CREATE DATABASE HttpRunner DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;</span><br><span class=\"line\"> </span><br><span class=\"line\"></span><br><span class=\"line\">docker search rabbitMq</span><br><span class=\"line\"></span><br><span class=\"line\">docker pull rabbitmq:3.7-management</span><br><span class=\"line\"></span><br><span class=\"line\">docker run -d --name rabbitmq -e RABBITMQ_DEFAULT_USER=user -e RABBITMQ_DEFAULT_PASS=password -p 15672:15672 -p 5672:5672 rabbitmq:3.7-management</span><br><span class=\"line\"></span><br><span class=\"line\">cd /var/lib/docker</span><br><span class=\"line\"></span><br><span class=\"line\">sudo docker exec -it rabbitmq bash</span><br><span class=\"line\"></span><br><span class=\"line\">rabbitmqctl add_user admin 123456</span><br><span class=\"line\"></span><br><span class=\"line\">rabbitmqctl set_permissions -p / admin '.*' '.*' '.*'</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、安装git,拉取代码</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">git clone https://github.com/HttpRunner/HttpRunnerManager.git</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、修改配置</strong></p>\n<ul>\n<li> 修改:HttpRunnerManager/HttpRunnerManager/settings.py里DATABASES字典和邮件发送账号相关配置</li>\n</ul>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\"> DATABASES = {</span><br><span class=\"line\"> 'default': {</span><br><span class=\"line\"> 'ENGINE': 'django.db.backends.mysql',</span><br><span class=\"line\"> 'NAME': 'HttpRunner', # 新建数据库名</span><br><span class=\"line\"> 'USER': 'root', # 数据库登录名</span><br><span class=\"line\"> 'PASSWORD': 'lcc123456', # 数据库登录密码</span><br><span class=\"line\"> 'HOST': '127.0.0.1', # 数据库所在服务器ip地址</span><br><span class=\"line\"> 'PORT': '3306', # 监听端口 默认3306即可</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\">EMAIL_SEND_USERNAME = 'username@163.com' # 定时任务报告发送邮箱,支持163,qq,sina,企业qq邮箱等,注意需要开通smtp服务</span><br><span class=\"line\">EMAIL_SEND_PASSWORD = 'password' # 邮箱密码</span><br></pre></td></tr></table></figure>\n\n<ul>\n<li> 修改:HttpRunnerManager/HttpRunnerManager/settings.py里worker相关配置</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"> djcelery.setup_loader()</span><br><span class=\"line\"> CELERY_ENABLE_UTC = True</span><br><span class=\"line\"> CELERY_TIMEZONE = 'Asia/Shanghai'</span><br><span class=\"line\"> BROKER_URL = 'amqp://guest:guest@127.0.0.1:5672//' # 127.0.0.1即为rabbitmq-server所在服务器ip地址</span><br><span class=\"line\"> CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'</span><br><span class=\"line\"> CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend'</span><br><span class=\"line\"> CELERY_ACCEPT_CONTENT = ['application/json']</span><br><span class=\"line\"> CELERY_TASK_SERIALIZER = 'json'</span><br><span class=\"line\"> CELERY_RESULT_SERIALIZER = 'json'</span><br><span class=\"line\"></span><br><span class=\"line\"> CELERY_TASK_RESULT_EXPIRES = 7200 # celery任务执行结果的超时时间,</span><br><span class=\"line\"> CELERYD_CONCURRENCY = 10 # celery worker的并发数 也是命令行-c指定的数目 根据服务器配置实际更改 默认10</span><br><span class=\"line\"> CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker执行了多少任务就会死掉,我建议数量可以大一些,默认100</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\">4、执行pip install -r requirements.txt 安装工程所依赖的库文件</span><br><span class=\"line\">5、切换到HttpRunnerManager目录(cd /home/HttpRunnerManager) 生成数据库迁移脚本,并生成表结构</span><br><span class=\"line\"> python manage.py makemigrations ApiManager #生成数据迁移脚本</span><br><span class=\"line\"> python manage.py migrate #应用到db生成数据表</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\">6、创建超级用户,用户后台管理数据库,并按提示输入相应用户名,密码,邮箱。 如不需用,可跳过此步骤</span><br><span class=\"line\"> python manage.py createsuperuser</span><br><span class=\"line\">7、启动服务</span><br><span class=\"line\"> python manage.py runserver </span><br><span class=\"line\"> python manage.py runserver & &作用:回到linux控制台服务不会停掉</span><br><span class=\"line\"></span><br><span class=\"line\"> </span><br><span class=\"line\">8、访问并使用</span><br><span class=\"line\"></span><br><span class=\"line\">浏览器输入:http://192.168.3.143:8000/api/register/ 注册用户,开始尽情享用平台</span><br><span class=\"line\"></span><br><span class=\"line\">浏览器输入:http://192.168.3.143:8000/admin/ 输入步骤6设置的用户名、密码,登录后台运维管理系统,可后台管理数据</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"异步生成测试报告\"><a href=\"#异步生成测试报告\" class=\"headerlink\" title=\"异步生成测试报告\"></a>异步生成测试报告</h2><p><strong>1、RebbitMQ信息</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">浏览器输入:http://192.168.3.143:15672 默认的登陆账号为:guest,密码为:guest </span><br></pre></td></tr></table></figure>\n\n<p><strong>2、进入到HttpRunnerManager目录,启动worker</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">python manage.py celery -A HttpRunnerManager worker --loglevel=info</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、启动任务监控后台</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">celery flower</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Python"],"tags":["Python","接口"]},{"title":"Python中装饰器的理解","url":"/2.Programming/1.Python/Python%E4%B8%AD%E8%A3%85%E9%A5%B0%E5%99%A8%E7%9A%84%E7%90%86%E8%A7%A3/","content":"<h2 id=\"说明\"><a href=\"#说明\" class=\"headerlink\" title=\"说明\"></a>说明</h2><p>装饰器的本质是函数,主要用来修饰其他函数,也就是为其他函数添加附加功能。可以让其他函数在不增加代码的前提下增加额外功能,其返回值也是一个函数对象。常用于有切面需求的场景,如:插入日志、事务处理、缓存、权限校验等。</p>\n<h3 id=\"参考\"><a href=\"#参考\" class=\"headerlink\" title=\"参考\"></a>参考</h3><p><a href=\"https://blog.csdn.net/weixin_44141532/article/details/87211683?spm=1001.2014.3001.5501\">Python装饰器</a></p>\n<p><a href=\"https://blog.csdn.net/weixin_44141532/article/details/87116038?spm=1001.2014.3001.5501\">Python中的闭包</a></p>\n<h2 id=\"闭包\"><a href=\"#闭包\" class=\"headerlink\" title=\"闭包\"></a>闭包</h2><h3 id=\"理解\"><a href=\"#理解\" class=\"headerlink\" title=\"理解\"></a>理解</h3><p>我们可以将闭包理解为一种特殊的函数,这种函数由两个函数的嵌套组成,且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。</p>\n<h3 id=\"格式\"><a href=\"#格式\" class=\"headerlink\" title=\"格式\"></a>格式</h3><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> 外层函数(<span class=\"params\">参数</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> 内层函数():</span></span><br><span class=\"line\"> print(<span class=\"string\">"内层函数执行"</span>, 参数)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> 内层函数</span><br><span class=\"line\"></span><br><span class=\"line\">内层函数的引用 = 外层函数(<span class=\"string\">"传入参数"</span>)</span><br><span class=\"line\">内层函数的引用()</span><br></pre></td></tr></table></figure>\n\n<p>外层函数中的参数,不一定要有,据情况而定,但是一般情况下都会有并在内函数中使用到。</p>\n<h3 id=\"案例\"><a href=\"#案例\" class=\"headerlink\" title=\"案例\"></a>案例</h3><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func</span>(<span class=\"params\">a, b</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">line</span>(<span class=\"params\">x</span>):</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> a * x - b</span><br><span class=\"line\"> <span class=\"keyword\">return</span> line</span><br><span class=\"line\"></span><br><span class=\"line\">line = func(<span class=\"number\">2</span>, <span class=\"number\">3</span>)</span><br><span class=\"line\">print(line(<span class=\"number\">5</span>))</span><br></pre></td></tr></table></figure>\n\n<p>结果得到 7<br>在这个案例中,外函数func有接收参数 a=2,b=3,内函数line接收参数x=5,在内函数体中计算了a*x-b 即 2×5-3的值作为返回值,外函数返回内函数的引用,这里的引用指的是内函数line在内存中的起始地址,最终调用内函数line()得到返回值7</p>\n<h3 id=\"内函数中修改外函数的值\"><a href=\"#内函数中修改外函数的值\" class=\"headerlink\" title=\"内函数中修改外函数的值\"></a>内函数中修改外函数的值</h3><p>一般在函数结束时,会释放临时变量,但在闭包中,由于外函数的临时变量在内函数中用到,此时外函数会把临时变量与内函数绑定到一起,这样虽然外函数结束了,但调用内函数时依旧能够使用临时变量,即闭包外层的参数可以在内存中进行保留<br>如果想要在内函数中修改外函数的值,需要使用 nonlocal 关键字声明变量</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func</span>(<span class=\"params\">a, b</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">line</span>(<span class=\"params\">x</span>):</span></span><br><span class=\"line\"> <span class=\"keyword\">nonlocal</span> a</span><br><span class=\"line\"> a = <span class=\"number\">3</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> a * x - b</span><br><span class=\"line\"> <span class=\"keyword\">return</span> line</span><br><span class=\"line\"></span><br><span class=\"line\">line = func(<span class=\"number\">2</span>, <span class=\"number\">3</span>)</span><br><span class=\"line\">print(line(<span class=\"number\">5</span>))</span><br></pre></td></tr></table></figure>\n\n<p>此时运行结果为:12</p>\n<h2 id=\"装饰器\"><a href=\"#装饰器\" class=\"headerlink\" title=\"装饰器\"></a>装饰器</h2><h3 id=\"装包-拆包\"><a href=\"#装包-拆包\" class=\"headerlink\" title=\"装包/拆包\"></a>装包/拆包</h3><p>装包:把位置参数放到元组中,把关键字参数放到字典中<br>拆包:还原到最初的数据样貌</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func1</span>(<span class=\"params\">*args, **kwargs</span>):</span> <span class=\"comment\"># 装包</span></span><br><span class=\"line\"> print(<span class=\"string\">"args:"</span>, args)</span><br><span class=\"line\"> print(<span class=\"string\">"kwargs:"</span>, kwargs)</span><br><span class=\"line\"></span><br><span class=\"line\"> print(<span class=\"string\">"拆包:"</span>, *args)</span><br><span class=\"line\"> func2(**kwargs) <span class=\"comment\"># **kwargs无法直接打印出来</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func2</span>(<span class=\"params\">**kwargs</span>):</span> <span class=\"comment\"># func2(a=1)再次装包 得到字典</span></span><br><span class=\"line\"> print(<span class=\"string\">"字典:"</span>, kwargs)</span><br><span class=\"line\"></span><br><span class=\"line\">func1(<span class=\"number\">1</span>, <span class=\"number\">2</span>, <span class=\"number\">3</span>, a=<span class=\"number\">1</span>)</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"装饰器导入\"><a href=\"#装饰器导入\" class=\"headerlink\" title=\"装饰器导入\"></a>装饰器导入</h3><p>装饰器可以用闭包和类来实现,首先介绍使用闭包完成装饰器。<br>我们装饰的函数有四种:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">1. 无参数,无返回值</span><br><span class=\"line\">2. 有参数,无返回值</span><br><span class=\"line\">3. 无参数,有返回值</span><br><span class=\"line\">4. 有参数,有返回值</span><br></pre></td></tr></table></figure>\n\n<h4 id=\"1、无参数,无返回值\"><a href=\"#1、无参数,无返回值\" class=\"headerlink\" title=\"1、无参数,无返回值\"></a>1、无参数,无返回值</h4><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func1</span>(<span class=\"params\">func</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func2</span>():</span> <span class=\"comment\"># 内函数中,完成对额外功能的添加,调用原来的函数</span></span><br><span class=\"line\"> print(<span class=\"string\">"无参,无返回值"</span>)</span><br><span class=\"line\"> func()</span><br><span class=\"line\"> <span class=\"keyword\">return</span> func2</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">@func1</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">test</span>():</span></span><br><span class=\"line\"> print(<span class=\"string\">"test"</span>)</span><br><span class=\"line\"></span><br><span class=\"line\">test()</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># --- 输出结果--- #</span></span><br><span class=\"line\">无参,无返回值</span><br><span class=\"line\">test</span><br></pre></td></tr></table></figure>\n\n<h4 id=\"2、有参数,无返回值\"><a href=\"#2、有参数,无返回值\" class=\"headerlink\" title=\"2、有参数,无返回值\"></a>2、有参数,无返回值</h4><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func1</span>(<span class=\"params\">func</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func2</span>(<span class=\"params\">args</span>):</span></span><br><span class=\"line\"> print(<span class=\"string\">"有参,无返回"</span>)</span><br><span class=\"line\"> func(args) <span class=\"comment\"># 返回用户传的参数</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> func2</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">@func1</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">test</span>(<span class=\"params\">args</span>):</span></span><br><span class=\"line\"> print(args)</span><br><span class=\"line\"></span><br><span class=\"line\">test(<span class=\"number\">123</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># --- 输出结果--- #</span></span><br><span class=\"line\">有参,无返回</span><br><span class=\"line\"><span class=\"number\">123</span></span><br></pre></td></tr></table></figure>\n\n<h4 id=\"3、无参数,有返回值\"><a href=\"#3、无参数,有返回值\" class=\"headerlink\" title=\"3、无参数,有返回值\"></a>3、无参数,有返回值</h4><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func1</span>(<span class=\"params\">func</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func2</span>():</span></span><br><span class=\"line\"> print(<span class=\"string\">"无参,有返回值"</span>)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> func() <span class=\"comment\"># return返回函数的返回值</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> func2</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">@func1</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">test</span>():</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">1</span></span><br><span class=\"line\"></span><br><span class=\"line\">print(test())</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># --- 输出结果--- #</span></span><br><span class=\"line\">无参,有返回值</span><br><span class=\"line\"><span class=\"number\">1</span></span><br></pre></td></tr></table></figure>\n\n<h4 id=\"4、有参数,有返回值\"><a href=\"#4、有参数,有返回值\" class=\"headerlink\" title=\"4、有参数,有返回值\"></a>4、有参数,有返回值</h4><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func1</span>(<span class=\"params\">func</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">func2</span>(<span class=\"params\">args</span>):</span></span><br><span class=\"line\"> print(<span class=\"string\">"有参,有返回"</span>)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> func(args)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> func2</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">@func1</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">test</span>(<span class=\"params\">args</span>):</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> args</span><br><span class=\"line\"></span><br><span class=\"line\">print(test(<span class=\"number\">45</span>))</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># --- 输出结果--- #</span></span><br><span class=\"line\">有参,有返回</span><br><span class=\"line\"><span class=\"number\">45</span></span><br></pre></td></tr></table></figure>\n\n<h4 id=\"5、参数不定长\"><a href=\"#5、参数不定长\" class=\"headerlink\" title=\"5、参数不定长\"></a>5、参数不定长</h4><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">set_fun</span>(<span class=\"params\">func</span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">call_fun</span>(<span class=\"params\">*args, **kwargs</span>):</span></span><br><span class=\"line\"> print(<span class=\"string\">"添加额外功能"</span>)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> func(*args, **kwargs)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> call_fun</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">@set_fun</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">test</span>(<span class=\"params\">*args, **kwargs</span>):</span></span><br><span class=\"line\"> print(args)</span><br><span class=\"line\"> print(kwargs)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"number\">100</span></span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\">print(test(<span class=\"number\">1</span>, <span class=\"number\">2</span>, <span class=\"number\">3</span>, m=<span class=\"number\">10</span>, n=<span class=\"number\">20</span>))</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># --- 输出结果--- #</span></span><br><span class=\"line\">添加额外功能</span><br><span class=\"line\">(<span class=\"number\">1</span>,<span class=\"number\">2</span>,<span class=\"number\">3</span>)</span><br><span class=\"line\">{<span class=\"string\">'n'</span>:<span class=\"number\">20</span>,<span class=\"string\">'m'</span>:<span class=\"number\">10</span>}</span><br><span class=\"line\"><span class=\"number\">100</span></span><br></pre></td></tr></table></figure>\n\n<p>这种格式的装饰器,是万能的,即它适用于不同的函数(有无参数,返回值都适用)<br>在上面的装饰器中,@set_fun 是Python中的一种语法糖,当程序执行到这里时,其实底层做了 test = set_fun(test) 这样的转化,所以我们的func指向test的引用,于是当我们在内函数中调用函数func时,实际上是在调用函数test,此时我们便可以做到在不更改原代码的情况下,给我们的代码添加其他的功能!</p>\n<h3 id=\"类装饰器\"><a href=\"#类装饰器\" class=\"headerlink\" title=\"类装饰器\"></a>类装饰器</h3><p>其实使用我们的类也可以实现装饰器的效果,当你理解了使用闭包完成装饰器时,类装饰器会非常好理解,它们的原理是相似的,只不过类有它自己的操作~</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">MyObject</span>(<span class=\"params\"><span class=\"built_in\">object</span></span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">__init__</span>(<span class=\"params\">self, func</span>):</span></span><br><span class=\"line\"> self.func = func</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">__call__</span>(<span class=\"params\">self, *args, **kwargs</span>):</span></span><br><span class=\"line\"> <span class=\"comment\"># 在这里完成额外功能的添加以及调用原函数</span></span><br><span class=\"line\"> print(<span class=\"string\">"添加额外的功能"</span>)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> self.func(*args, **kwargs) <span class=\"comment\"># 拆包</span></span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">@MyObject </span><span class=\"comment\"># test = MyObject(test) 创建实例对象调用魔法方法__init__</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">test</span>(<span class=\"params\">*args, **kwargs</span>):</span></span><br><span class=\"line\"> print(<span class=\"string\">"test"</span>, args)</span><br><span class=\"line\"> print(<span class=\"string\">"test"</span>, kwargs)</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\">test(<span class=\"number\">1</span>, <span class=\"number\">2</span>, <span class=\"number\">3</span>, <span class=\"number\">4</span>, a=<span class=\"number\">3</span>) <span class=\"comment\"># 实例对象() 调用魔法方法__call__</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># --- 输出结果--- #</span></span><br><span class=\"line\">添加额外功能</span><br><span class=\"line\">test(<span class=\"number\">1</span>,<span class=\"number\">2</span>,<span class=\"number\">3</span>,<span class=\"number\">4</span>)</span><br><span class=\"line\">test{<span class=\"string\">'a'</span>:<span class=\"number\">3</span>}</span><br></pre></td></tr></table></figure>\n\n<p>在@MyObject时,底层同样做了转化,test = MyObject(test),这时创建了实例对象test ,并传入参数test,所以会执行我们类中的__init__魔法方法时,此时test(1, 2, 3, 4, a=3)就等于是我们创建的实例对象test(),这时会执行我们类中的__call__方法,在__call__方法中实现我们对功能的添加,以及原函数的调用,是不是与闭包非常相似呢 ˙ ω ˙</p>\n","categories":["2.Programming","Python"],"tags":["Python"]},{"title":"Python基础知识","url":"/2.Programming/1.Python/Python%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/","content":"<h2 id=\"Python垃圾回收机制\"><a href=\"#Python垃圾回收机制\" class=\"headerlink\" title=\"Python垃圾回收机制\"></a>Python垃圾回收机制</h2><ol>\n<li>引用计数:在每次分配和释放内存的时候,加入引用计数的动作;当引用计数为0时,该内存就会被销毁</li>\n<li>标记清除:标记活动对象,回收非活动对象</li>\n<li>分带收集:Python将内存根据对象的存活时间分为不同的集合,每个集合成为一个代,共有3代,他们各对应一个链表,当年轻链表的总数达到上限时,垃圾回收机制就会被触发,把可以回收的对象回收掉,不可回收的对象则移到中年代去,以此类推。</li>\n</ol>\n<h2 id=\"Python缓冲池\"><a href=\"#Python缓冲池\" class=\"headerlink\" title=\"Python缓冲池\"></a>Python缓冲池</h2><p>用于存储高频使用的对象,降低内存的使用;主要对象是不可变对象;</p>\n<ol>\n<li>字符串和整型对象都是不可变对象,因此Python会很高效的缓存它们</li>\n<li>元组tuple是不可变累类型,但是元组不支持缓存</li>\n</ol>\n<h2 id=\"Python中的可变参数和关键字参数\"><a href=\"#Python中的可变参数和关键字参数\" class=\"headerlink\" title=\"Python中的可变参数和关键字参数\"></a>Python中的可变参数和关键字参数</h2><p>func(*args,**kw)</p>\n<ol>\n<li>*args是可变参数,args接收的是一个tuple;既可以直接传入func(1,2,3),又可以先组装成list或tuple,在通过args传入</li>\n<li>**kw是关键字参数,kw接收的是一个dict;既可以直接传入func(a=1,b=2),又可以先组装成dict,再通过kw传入</li>\n</ol>\n<h2 id=\"Python的匿名函数\"><a href=\"#Python的匿名函数\" class=\"headerlink\" title=\"Python的匿名函数\"></a>Python的匿名函数</h2><p>关键字lambda表示匿名函数,只有一个表达式,不用写return,返回值就是该表达式的结果。</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">匿名表达式:</span><br><span class=\"line\"><span class=\"keyword\">lambda</span> x: x*x</span><br><span class=\"line\"></span><br><span class=\"line\">函数式:</span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">f</span>(<span class=\"params\">x</span>):</span></span><br><span class=\"line\">\t<span class=\"keyword\">return</span> x*x</span><br></pre></td></tr></table></figure>\n\n\n\n<h2 id=\"Python装饰器\"><a href=\"#Python装饰器\" class=\"headerlink\" title=\"Python装饰器\"></a>Python装饰器</h2><p>本质是函数,主要用来修饰其他函数,也就是为其他函数添加附加功能。</p>\n<p>可以让其他函数在不增加代码的前提下增加额外功能,其返回值也是一个函数对象。</p>\n<p>原则:</p>\n<ol>\n<li>装饰器不能修改被装饰的函数的源代码</li>\n<li>装饰器不能修改被装饰的函数的调用方式</li>\n</ol>\n<p>常用于有切面需求的场景,如:插入日志、事务处理、缓存、权限校验等</p>\n<h2 id=\"Python的深拷贝和浅拷贝\"><a href=\"#Python的深拷贝和浅拷贝\" class=\"headerlink\" title=\"Python的深拷贝和浅拷贝\"></a>Python的深拷贝和浅拷贝</h2><ol>\n<li>深拷贝是将对象本身复制给另一个对象,意味着对对象的副本进行修改不会影响原对象;在Python中,使用deepcopy()函数实现</li>\n<li>浅拷贝是将对象的引用复制给另一个对象,则对对象的副本进行修改会影响原对象;在Python中,使用copy()函数实现</li>\n</ol>\n<h2 id=\"Python的进程和线程理解\"><a href=\"#Python的进程和线程理解\" class=\"headerlink\" title=\"Python的进程和线程理解\"></a>Python的进程和线程理解</h2><table>\n<thead>\n<tr>\n<th>进程</th>\n<th>Linux/Unix:fork()</th>\n</tr>\n</thead>\n<tbody><tr>\n<td></td>\n<td>跨平台:multiprocessing() POOL(大量)</td>\n</tr>\n<tr>\n<td>线程</td>\n<td>threading</td>\n</tr>\n</tbody></table>\n<p>Thread类中的 start()和run()方法的区别:</p>\n<ol>\n<li>通过调用线程类的start()方法可以直接启动一个线程,是线程处于就绪状态;JVM通过调用线程类的run()方法来完成实际的业务逻辑,当run()方法结束后,此线程就会终止;</li>\n<li>直接调用线程的run()方法,则会被当成是一个普通的函数调用,程序中仍然只有主线程这一个线程</li>\n</ol>\n<p>即start()方法可以异步的调用run()方法;直接调用run()方法是同步的,无法达到多线程的目的</p>\n<h2 id=\"进程和线程的区别\"><a href=\"#进程和线程的区别\" class=\"headerlink\" title=\"进程和线程的区别\"></a>进程和线程的区别</h2><ol>\n<li>进程是资源分配的最小单位,线程是程序执行的最小单位</li>\n<li>进程有自己独立的地址空间,而线程是共享进程中的数据的,使用相同的地址空间;因此CPU切换一个线程的花费比进程要小很多,同时创建一个线程的开销也比进程小很多</li>\n<li>线程之间通信更方便,同一进程下的线程共享全局变量静态变量等,而进程之间的通信需要以通信(IPC)的方式进行</li>\n<li>多进程程序更健壮,多线程程序只要有一个死掉,整个进程就死掉了,而一个进程死掉不会对另一个进程造成影响</li>\n</ol>\n<p>多进程的去掉就是创建进程的代价大,操作系统能同时运行的进程数是有限的;在内存和CPU的限制下,如果进程数较多,操作系统的调度会有问题</p>\n<h2 id=\"同步和异步\"><a href=\"#同步和异步\" class=\"headerlink\" title=\"同步和异步\"></a>同步和异步</h2><p>所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。</p>\n<p>所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。</p>\n","categories":["2.Programming","Python"],"tags":["Python"]},{"title":"Python异步编程之asyncio","url":"/2.Programming/1.Python/Python%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Basyncio/","content":"<h2 id=\"同步异步概念\"><a href=\"#同步异步概念\" class=\"headerlink\" title=\"同步异步概念\"></a>同步异步概念</h2><p><strong>同步:</strong>是指完成事务的逻辑,顺序执行。</p>\n<p><strong>异步:</strong>是和同步相对的,异步是指在处理调用这个事务的之后,不会等待这个事务的处理结果,直接处理第二个事务去了,通过状态、通知、回调来通知调用者处理结果。</p>\n<p>Python中使用asyncio进行异步IO的操作。</p>\n<h2 id=\"说明\"><a href=\"#说明\" class=\"headerlink\" title=\"说明\"></a>说明</h2><p><strong>参考:</strong><a href=\"https://www.liaoxuefeng.com/wiki/1016959663602400/1017970488768640\">asyncio</a> , <a href=\"https://www.cnblogs.com/shenh/p/9090586.html\">Python异步编程</a></p>\n<p>每个线程有一个事件循环,主线程调用asyncio.get_event_loop()时会创建事件循环,你需要把异步的任务丢给这个循环的run_until_complete()方法,事件循环会安排协同程序的执行。</p>\n<h2 id=\"Python3-4实例\"><a href=\"#Python3-4实例\" class=\"headerlink\" title=\"Python3.4实例\"></a>Python3.4实例</h2><figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">import</span> asyncio</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">@asyncio.coroutine</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">hello</span>():</span></span><br><span class=\"line\"> print(<span class=\"string\">"Hello world!"</span>)</span><br><span class=\"line\"> <span class=\"comment\"># 异步调用asyncio.sleep(1):</span></span><br><span class=\"line\"> r = <span class=\"keyword\">yield</span> <span class=\"keyword\">from</span> asyncio.sleep(<span class=\"number\">1</span>)</span><br><span class=\"line\"> print(<span class=\"string\">"Hello again!"</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># 获取EventLoop:</span></span><br><span class=\"line\">loop = asyncio.get_event_loop()</span><br><span class=\"line\"><span class=\"comment\"># 执行coroutine</span></span><br><span class=\"line\">loop.run_until_complete(hello())</span><br><span class=\"line\">loop.close()</span><br></pre></td></tr></table></figure>\n\n<p><code>@asyncio.coroutine</code>把一个generator标记为coroutine类型,然后,我们就把这个<code>coroutine</code>扔到<code>EventLoop</code>中执行。</p>\n<p><code>hello()</code>会首先打印出<code>Hello world!</code>,然后,<code>yield from</code>语法可以让我们方便地调用另一个<code>generator</code>。由于<code>asyncio.sleep()</code>也是一个<code>coroutine</code>,所以线程不会等待<code>asyncio.sleep()</code>,而是直接中断并执行下一个消息循环。当<code>asyncio.sleep()</code>返回时,线程就可以从<code>yield from</code>拿到返回值(此处是<code>None</code>),然后接着执行下一行语句。</p>\n<p><strong>异步操作需要在<code>coroutine</code>中通过<code>yield from</code>完成。</strong></p>\n<h2 id=\"Python3-5实例\"><a href=\"#Python3-5实例\" class=\"headerlink\" title=\"Python3.5实例\"></a>Python3.5实例</h2><p><code>async</code>和<code>await</code>是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:</p>\n<ol>\n<li>把<code>@asyncio.coroutine</code>替换为<code>async</code>;</li>\n<li>把<code>yield from</code>替换为<code>await</code>。</li>\n</ol>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">import</span> asyncio </span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">async</span> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">hello</span>():</span></span><br><span class=\"line\"> print(<span class=\"string\">"Hello world!"</span>)</span><br><span class=\"line\"> r = <span class=\"keyword\">await</span> asyncio.sleep(<span class=\"number\">1</span>)</span><br><span class=\"line\"> print(<span class=\"string\">"Hello again!"</span>)</span><br><span class=\"line\"> </span><br><span class=\"line\"><span class=\"comment\"># 获取EventLoop:</span></span><br><span class=\"line\">loop = asyncio.get_event_loop()</span><br><span class=\"line\"><span class=\"comment\"># 执行coroutine</span></span><br><span class=\"line\">loop.run_until_complete(hello())</span><br><span class=\"line\">loop.close()</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"并发HTTP实例\"><a href=\"#并发HTTP实例\" class=\"headerlink\" title=\"并发HTTP实例\"></a>并发HTTP实例</h2><p>如果需要并发http通常是用requests,但requests是同步的库,如果想异步的话需要引入aiohttp。</p>\n<p><strong>这里引入一个类,from aiohttp import ClientSession,首先要建立一个session对象,然后用session对象去打开网页</strong>。session可以进行多项操作,比如post, get, put, head等。基本用法:</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">async</span> <span class=\"keyword\">with</span> ClientSession() <span class=\"keyword\">as</span> session:</span><br><span class=\"line\"> <span class=\"keyword\">async</span> <span class=\"keyword\">with</span> session.get(url) <span class=\"keyword\">as</span> response:</span><br></pre></td></tr></table></figure>\n\n<p><strong>aiohttp异步实现的例子:</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">import</span> asyncio</span><br><span class=\"line\"><span class=\"keyword\">from</span> aiohttp <span class=\"keyword\">import</span> ClientSession</span><br><span class=\"line\"></span><br><span class=\"line\">tasks = []</span><br><span class=\"line\">url = <span class=\"string\">"https://www.baidu.com/{}"</span></span><br><span class=\"line\"><span class=\"keyword\">async</span> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">hello</span>(<span class=\"params\">url</span>):</span></span><br><span class=\"line\"> <span class=\"keyword\">async</span> <span class=\"keyword\">with</span> ClientSession() <span class=\"keyword\">as</span> session:</span><br><span class=\"line\"> <span class=\"keyword\">async</span> <span class=\"keyword\">with</span> session.get(url) <span class=\"keyword\">as</span> response:</span><br><span class=\"line\"> response = <span class=\"keyword\">await</span> response.read()</span><br><span class=\"line\"> print(response)</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">if</span> __name__ == <span class=\"string\">'__main__'</span>:</span><br><span class=\"line\"> loop = asyncio.get_event_loop()</span><br><span class=\"line\"> loop.run_until_complete(hello(url))</span><br></pre></td></tr></table></figure>\n\n<p>首先<code>async def</code> 关键字定义了这是个异步函数,<code>await</code> 关键字加在需要等待的操作前面,<code>response.read()</code>等待<code>request</code>响应,是个耗IO操作。然后使用ClientSession类发起http请求。</p>\n","categories":["2.Programming","Python"],"tags":["Python"]},{"title":"Python异步编程之celery","url":"/2.Programming/1.Python/Python%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bcelery/","content":"<h2 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h2><p>最近测试的需求里有一个既要满足异步又要满足定时的功能,第一实现想法的是使用asyncio和crontab;服务端的Yago框架中有相关插件可以同时满足两个需求,不禁思考Python中是否也有相关模块,于是乎调研了一下Celery。<br>参考:<br><a href=\"https://www.cnblogs.com/Stitchez/p/10240387.html#top\">https://www.cnblogs.com/Stitchez/p/10240387.html#top</a><br><a href=\"https://www.cnblogs.com/skyflask/p/9865378.html\">https://www.cnblogs.com/skyflask/p/9865378.html</a></p>\n<h2 id=\"原理\"><a href=\"#原理\" class=\"headerlink\" title=\"原理\"></a>原理</h2><p>\u000f<img src=\"/images/20210318-1.png\" alt=\"images\"></p>\n<p>Celery中,以上组件具体功能如下:</p>\n<ol>\n<li><code>任务模块 Task</code>:包含异步任务和定时任务。其中,异步任务通常在业务逻辑中被触发并发往任务队列,而定时任务由 Celery Beat 进程周期性地将任务发往任务队列。</li>\n<li><code>消息中间件 Broker</code>:即为任务调度队列,接收任务生产者发来的消息(即任务),将任务存入队列。Celery 本身不提供队列服务,官方推荐使用 RabbitMQ 和 Redis 等。</li>\n<li><code>任务执行单元 Worker</code>:是执行任务的处理单元,它实时监控消息队列,获取队列中调度的任务,并执行它。</li>\n<li><code>任务结果存储 Backend </code>:用于存储任务的执行结果,以供查询。同消息中间件一样,存储也可使用 RabbitMQ, Redis 和 MongoDB 等。</li>\n</ol>\n<h2 id=\"操作步骤\"><a href=\"#操作步骤\" class=\"headerlink\" title=\"操作步骤\"></a>操作步骤</h2><p>现就Win10环境下载相关模块和中间件:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">redis 3.2.100</span><br><span class=\"line\">Python 3.9.0</span><br><span class=\"line\">celery 4.4.7</span><br><span class=\"line\">celery-with-redis 3.0</span><br><span class=\"line\">celery-with-redis 3.0</span><br><span class=\"line\">eventlet 0.22.1</span><br></pre></td></tr></table></figure>\n\n<p>主要的代码层面来了,我们通过流程图知道,我们需要生产任务,目录结构如下图:</p>\n<p><img src=\"/images/20210318-2.png\" alt=\"images\"></p>\n<p> <strong>1、其中<code>__init__.py</code>是通过启动项目时,选择的配置文件</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> celery <span class=\"keyword\">import</span> Celery</span><br><span class=\"line\"></span><br><span class=\"line\">app = Celery(<span class=\"string\">'demo'</span>)</span><br><span class=\"line\">app.config_from_object(<span class=\"string\">'celery_app.celeryconfig'</span>)</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、celeryconfig.py里面主要是celery的配置</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">from</span> datetime <span class=\"keyword\">import</span> timedelta</span><br><span class=\"line\"><span class=\"keyword\">from</span> celery.schedules <span class=\"keyword\">import</span> crontab</span><br><span class=\"line\">BROKER_URL = <span class=\"string\">'redis://localhost:6379/1'</span> <span class=\"comment\"># 配置broker为redis</span></span><br><span class=\"line\">CELERY_RESULT_BACKEND = <span class=\"string\">'redis://localhost:6379/2'</span> <span class=\"comment\"># 配置结果存储至redis</span></span><br><span class=\"line\">CELERY_TIMEZONE=<span class=\"string\">'Asia/Shanghai'</span> <span class=\"comment\"># 时区设置</span></span><br><span class=\"line\"><span class=\"comment\"># 导入任务</span></span><br><span class=\"line\">CELERY_IMPORTS = (</span><br><span class=\"line\"> <span class=\"string\">'celery_app.task1'</span>,</span><br><span class=\"line\"> <span class=\"string\">'celery_app.task2'</span>,</span><br><span class=\"line\"> )</span><br><span class=\"line\"><span class=\"comment\"># 配置定时任务的调度器</span></span><br><span class=\"line\">CELERYBEAT_SCHEDULE={</span><br><span class=\"line\"> <span class=\"comment\"># 任务名字</span></span><br><span class=\"line\"> <span class=\"string\">'task1'</span>:{ </span><br><span class=\"line\"> <span class=\"string\">'task'</span>:<span class=\"string\">'celery_app.task1.add'</span>, <span class=\"comment\"># 任务启动的函数</span></span><br><span class=\"line\"> <span class=\"string\">'schedule'</span>:timedelta(seconds=<span class=\"number\">10</span>), <span class=\"comment\"># 定时时间设置,每10秒一次</span></span><br><span class=\"line\"> <span class=\"string\">'args'</span>:(<span class=\"number\">1</span>,<span class=\"number\">4</span>) <span class=\"comment\"># 传递的参数</span></span><br><span class=\"line\"> },</span><br><span class=\"line\"> <span class=\"string\">'task2'</span>:{</span><br><span class=\"line\"> <span class=\"string\">'task'</span>:<span class=\"string\">'celery_app.task2.mul'</span>, </span><br><span class=\"line\"> <span class=\"string\">'schedule'</span>:crontab(hour=<span class=\"number\">11</span>,minute=<span class=\"number\">10</span>), <span class=\"comment\"># 定时时间设置,11:10</span></span><br><span class=\"line\"> <span class=\"string\">'args'</span>:(<span class=\"number\">2</span>,<span class=\"number\">5</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、task1的任务</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">import</span> time</span><br><span class=\"line\"><span class=\"keyword\">from</span> celery_app <span class=\"keyword\">import</span> app</span><br><span class=\"line\"><span class=\"meta\">@app.task</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">add</span>(<span class=\"params\">x, y</span>):</span></span><br><span class=\"line\"> time.sleep(<span class=\"number\">3</span>) <span class=\"comment\"># 阻塞测试</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> x + y</span><br></pre></td></tr></table></figure>\n\n<p><strong>4、task2的任务</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">import</span> time</span><br><span class=\"line\"><span class=\"keyword\">from</span> celery_app <span class=\"keyword\">import</span> app</span><br><span class=\"line\"><span class=\"meta\">@app.task</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">mul</span>(<span class=\"params\">x, y</span>):</span></span><br><span class=\"line\"> time.sleep(<span class=\"number\">3</span>)</span><br><span class=\"line\"> <span class=\"keyword\">return</span> x * y</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"运行任务\"><a href=\"#运行任务\" class=\"headerlink\" title=\"运行任务\"></a><strong>运行任务</strong></h2><p>1、启动redis服务器</p>\n<p>2、在celery_app文件的上一级 shift+右键 打开命令行窗口,win10打开powershell</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">$ celery worker -A celery_app --pool=solo -l INFO</span><br></pre></td></tr></table></figure>\n\n<p>3、然后打开celery beat 启动定时任务,另开一个命令行窗口</p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\">$ celery beat -A celery_app -l INFO</span><br></pre></td></tr></table></figure>\n\n<p>4、结果如下,可以看见celery beat一直在隔10秒发送任务;至11:10处执行定时任务</p>\n<p><img src=\"/images/20210318-3.png\" alt=\"images\"></p>\n<p>5、再来看worker</p>\n<p><img src=\"/images/20210318-4.png\" alt=\"images\"></p>\n<h2 id=\"其他\"><a href=\"#其他\" class=\"headerlink\" title=\"其他\"></a>其他</h2><p>如使用Django执行celery操作步骤可查看 <a href=\"%C2%91http://docs.jinkan.org/docs/celery/django/first-steps-with-django.html\">官网</a></p>\n","categories":["2.Programming","Python"],"tags":["Python"]},{"title":"教你怎么调用GitlabAPI","url":"/2.Programming/1.Python/%E6%95%99%E4%BD%A0%E6%80%8E%E4%B9%88%E8%B0%83%E7%94%A8GitlabAPI/","content":"<h2 id=\"官方文档:\"><a href=\"#官方文档:\" class=\"headerlink\" title=\"官方文档:\"></a><strong>官方文档:</strong></h2><p><a href=\"https://docs.gitlab.com/ce/api/\">参考1</a></p>\n<p><a href=\"https://docs.gitlab.com/ee/api/branches.html#list-repository-branches\">参考2</a></p>\n<h2 id=\"生成Personal-Access-Tokens\"><a href=\"#生成Personal-Access-Tokens\" class=\"headerlink\" title=\"生成Personal Access Tokens\"></a><strong>生成Personal Access Tokens</strong></h2><p> 选择右上角用户信息setting—>Access Tokens</p>\n<h2 id=\"常用Gitlab-API\"><a href=\"#常用Gitlab-API\" class=\"headerlink\" title=\"常用Gitlab API\"></a><strong>常用Gitlab API</strong></h2><p><strong>1、获取所有的项目信息</strong></p>\n<p><a href=\"http://192.168.199.184/api/v3/projects?private_token=gqv1hvjbGCLs6uAUmBV8&per_page=10\">private_token来自Access Tokens</a></p>\n<p><strong>2、获取项目信息</strong></p>\n<p><a href=\"http://192.168.199.184/api/v3/projects/15\">15 为项目ID,来自所有的项目信息</a></p>\n<p><strong>3、查看用户信息</strong></p>\n<p><a href=\"http://192.168.199.184/api/v3/projects/15/users?private_token=gqv1hvjbGCLs6uAUmBV8&per_page=10\">http://192.168.199.184/api/v3/projects/15/users?private_token=gqv1hvjbGCLs6uAUmBV8&per_page=10</a></p>\n<p><strong>4、获取commits提交信息</strong>:</p>\n<p><a href=\"http://192.168.199.184/api/v3/projects/15/repository/commits/master?private_token=gqv1hvjbGCLs6uAUmBV8&per_page=10\">15 为项目ID,来自所有的项目信息</a></p>\n<h2 id=\"实战案例\"><a href=\"#实战案例\" class=\"headerlink\" title=\"实战案例\"></a><strong>实战案例</strong></h2><p><strong>1、获取项目信息</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">#!/usr/bin/env python</span></span><br><span class=\"line\"><span class=\"comment\">#-*-coding:utf-8-*-</span></span><br><span class=\"line\"><span class=\"keyword\">import</span> requests</span><br><span class=\"line\">url = <span class=\"string\">'http://192.168.199.184/api/v3/projects?private_token=oMJwN5ErC8_n1QvTsyDR&per_page=50'</span> </span><br><span class=\"line\">user_url= <span class=\"string\">'http://192.168.199.184/api/v3/projects/15/users?private_token=oMJwN5ErC8_n1QvTsyDR&per_page=10'</span> </span><br><span class=\"line\"><span class=\"comment\">#获取项目id和项目名称</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">GetProject_id</span>(<span class=\"params\">project_url</span>):</span> </span><br><span class=\"line\"> r = requests.get(project_url)</span><br><span class=\"line\"> data = r.json()</span><br><span class=\"line\"> ProjectId_list = []</span><br><span class=\"line\"> ProjectName_list = []</span><br><span class=\"line\"> <span class=\"keyword\">for</span> i <span class=\"keyword\">in</span> data:</span><br><span class=\"line\"> ProjectId_list.append(i[<span class=\"string\">'id'</span>])</span><br><span class=\"line\"> ProjectName_list.append(i[<span class=\"string\">'name'</span>])</span><br><span class=\"line\"> <span class=\"keyword\">return</span> ProjectId_list,ProjectName_list</span><br><span class=\"line\"><span class=\"comment\">#根据项目id获取项目下的用户信息</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">GetProject_userlist</span>():</span></span><br><span class=\"line\"> IdList = GetProject_id(url)</span><br><span class=\"line\"> project_id = IdList[<span class=\"number\">0</span>]</span><br><span class=\"line\"> project_name = IdList[<span class=\"number\">1</span>]</span><br><span class=\"line\"> <span class=\"keyword\">for</span> <span class=\"built_in\">id</span> <span class=\"keyword\">in</span> project_id:</span><br><span class=\"line\"> l = []</span><br><span class=\"line\"> project_user = requests.get(user_url.<span class=\"built_in\">format</span>(<span class=\"built_in\">id</span>)) <span class=\"comment\">#生成完整的用于显示项目下所有user的连接</span></span><br><span class=\"line\"> req_data = project_user.json()</span><br><span class=\"line\"> <span class=\"keyword\">for</span> i <span class=\"keyword\">in</span> req_data:</span><br><span class=\"line\"> l.append(i[<span class=\"string\">'name'</span>])</span><br><span class=\"line\"> <span class=\"built_in\">print</span> (project_name[project_id.index(<span class=\"built_in\">id</span>)],l)</span><br><span class=\"line\">GetProject_userlist()</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、获取项目提交信息</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">#-*-coding:utf-8-*-</span></span><br><span class=\"line\"><span class=\"keyword\">import</span> requests</span><br><span class=\"line\"><span class=\"keyword\">import</span> re</span><br><span class=\"line\">url = <span class=\"string\">'http://192.168.199.184/api/v3/projects?private_token=oMJwN5ErC8_n1QvTsyDR&per_page=10'</span></span><br><span class=\"line\">r =requests.get(url)</span><br><span class=\"line\">p_group = [<span class=\"string\">'HJ'</span>]</span><br><span class=\"line\">data = r.json()</span><br><span class=\"line\"><span class=\"built_in\">print</span> (<span class=\"string\">"项目名称"</span>,<span class=\"string\">' '</span>*<span class=\"number\">20</span>,<span class=\"string\">'最近提交时间'</span>)</span><br><span class=\"line\"><span class=\"keyword\">for</span> i <span class=\"keyword\">in</span> data:</span><br><span class=\"line\"> <span class=\"keyword\">if</span> i[<span class=\"string\">'ssh_url_to_repo'</span>].split(<span class=\"string\">':'</span>)[<span class=\"number\">1</span>].split(<span class=\"string\">'/'</span>)[<span class=\"number\">0</span>] <span class=\"keyword\">in</span> p_group:</span><br><span class=\"line\"> r1 = requests.get(<span class=\"string\">'http://192.168.199.184/api/v3/projects/15/repository/commits/master?private_token=gqv1hvjbGCLs6uAUmBV8&per_page=10'</span></span><br><span class=\"line\"> % i[<span class=\"string\">'id'</span>])</span><br><span class=\"line\"> data2 = r1.json()</span><br><span class=\"line\"> <span class=\"keyword\">if</span> data2[<span class=\"string\">'message'</span>].strip() == <span class=\"string\">'404 Commit Not Found'</span>:</span><br><span class=\"line\"> <span class=\"built_in\">print</span> (i[<span class=\"string\">'ssh_url_to_repo'</span>].split(<span class=\"string\">':'</span>)[<span class=\"number\">1</span>],<span class=\"string\">' '</span>*<span class=\"number\">11</span>,<span class=\"string\">'未提交任何代码'</span>)</span><br><span class=\"line\"> <span class=\"keyword\">else</span>:</span><br><span class=\"line\"> print(i[<span class=\"string\">'ssh_url_to_repo'</span>].split(<span class=\"string\">':'</span>)[<span class=\"number\">1</span>], <span class=\"string\">' '</span> * <span class=\"number\">11</span>, data2[<span class=\"string\">'committed_date'</span>][:<span class=\"number\">10</span>])</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Python"],"tags":["Python","Git"]},{"title":"uWSGI启动Django项目","url":"/2.Programming/1.Python/uWSGI%E5%90%AF%E5%8A%A8Django%E9%A1%B9%E7%9B%AE/","content":"<p>\u000b\f\f\u000b<img src=\"/images/20200811-1.png\" alt=\"uwsgi\"></p>\n<h4 id=\"安装\"><a href=\"#安装\" class=\"headerlink\" title=\"安装\"></a>安装</h4><figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">pip install uwsgi</span><br></pre></td></tr></table></figure>\n\n\n\n<p><strong>新增文件uwsgi.ini;跟manage.py 同一级目录</strong></p>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\"> 1 [uwsgi]</span><br><span class=\"line\"> 2 ; 监听的端口</span><br><span class=\"line\"> 3 http = :8000</span><br><span class=\"line\"> 4 </span><br><span class=\"line\"> 5 ; 指定和nginx进行套接字通信的方式:端口或文件</span><br><span class=\"line\"> 6 ; socket = 127.0.0.1:8001</span><br><span class=\"line\"> 7 ; socket = /home/kzzf/project/OfferHelp/OfferHelp.sock</span><br><span class=\"line\"> 8 </span><br><span class=\"line\"> 9 ; 项目所在目录,和manage.py同级</span><br><span class=\"line\">10 chdir = /home/kzzf/project/OfferHelp</span><br><span class=\"line\">11 </span><br><span class=\"line\">12 ; 虚拟环境所在目录</span><br><span class=\"line\">13 home=/home/kzzf/env/OfferHelp-env</span><br><span class=\"line\">14 PYTHONHOME = /home/kzzf/env/OfferHelp-env/bin/</span><br><span class=\"line\">15 </span><br><span class=\"line\">16 ; 主应用中的wsgi文件</span><br><span class=\"line\">17 wsgi-file = OfferHelp/wsgi.py</span><br><span class=\"line\">18 </span><br><span class=\"line\">19 ; 使用路由代理静态资源,但失败了</span><br><span class=\"line\">20 ; static-safe=/home/kzzf/project/OfferHelp/static/</span><br><span class=\"line\">21 ; route = /static/(.*) static:/home/kzzf/project/OfferHelp/static/$1</span><br><span class=\"line\">22 </span><br><span class=\"line\">23 ; 代理静态资源:路径映射</span><br><span class=\"line\">24 static-map = /static=/home/kzzf/project/OfferHelp/collect_static</span><br><span class=\"line\">25 </span><br><span class=\"line\">26 ; 启动一个master进程,来管理其余的子进程</span><br><span class=\"line\">27 master=True</span><br><span class=\"line\">28 processes = 4</span><br><span class=\"line\">29 threads = 2</span><br><span class=\"line\">30 </span><br><span class=\"line\">31 ; 保存主进程的pid,用来控制uwsgi服务</span><br><span class=\"line\">32 pidfile=/home/kzzf/project/OfferHelp/uwsgi.pid</span><br><span class=\"line\">33 ; 启动项目 uwsgi uwsgi.ini</span><br><span class=\"line\">34 ; uwsgi --stop/reload xxx.pid 停止/重启uwsgi</span><br><span class=\"line\">35 </span><br><span class=\"line\">36 ; 设置后台运行,保存日志</span><br><span class=\"line\">37 daemonize=/home/kzzf/project/OfferHelp/log/uwsgi.log</span><br><span class=\"line\">38 ; deamonize=1 ; 用来配置background运行</span><br><span class=\"line\">39 </span><br><span class=\"line\">40 ; 设置每个工作进程处理请求的上限,达到上限时,将回收(重启)该进程。可以预防内存泄漏</span><br><span class=\"line\">41 max-requests=5000</span><br><span class=\"line\">42 </span><br><span class=\"line\">43 # 服务停止时自动移除unix Socket和pid文件</span><br><span class=\"line\">44 vacuum=true</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"启动项目\"><a href=\"#启动项目\" class=\"headerlink\" title=\"启动项目\"></a>启动项目</h4><figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">1 uwsgi uwsgi.ini</span><br><span class=\"line\">2 </span><br><span class=\"line\">3 # 停止</span><br><span class=\"line\">4 uwsgi --stop uwsgi.pid</span><br><span class=\"line\">5 pkill -f uwsgi -9</span><br></pre></td></tr></table></figure>","categories":["2.Programming","Python"],"tags":["Python","接口"]},{"title":"解决pip install太慢的问题","url":"/2.Programming/1.Python/%E8%A7%A3%E5%86%B3pip%20install%E5%A4%AA%E6%85%A2%E7%9A%84%E9%97%AE%E9%A2%98/","content":"<p>将pip的源换为国内的。</p>\n<p>1.新建目录及文件~/.pip/pip.conf</p>\n<p>2.内容为:</p>\n<p>[global]<br>index-url = <a href=\"https://pypi.tuna.tsinghua.edu.cn/simple\">https://pypi.tuna.tsinghua.edu.cn/simple</a></p>\n<p>[install]<br>trusted-host=mirrors.aliyun.com</p>\n","categories":["2.Programming","Python"],"tags":["Python","Tool"]},{"title":"通过Python调用Jenkins 常用api操作","url":"/2.Programming/1.Python/%E9%80%9A%E8%BF%87Python%E8%B0%83%E7%94%A8Jenkins%E5%B8%B8%E7%94%A8api%E6%93%8D%E4%BD%9C/","content":"<p><a href=\"https://www.cnblogs.com/L-O-N/p/11608220.html\">原文参考</a></p>\n<figure class=\"highlight python\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\"># -*- coding: utf-8 -*-</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">import</span> jenkins</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">TestJenkins</span>(<span class=\"params\"><span class=\"built_in\">object</span></span>):</span></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">__new__</span>(<span class=\"params\">cls, *args, **kwargs</span>):</span></span><br><span class=\"line\"> server = <span class=\"string\">'http://1.1.1.1:8080/jenkins'</span></span><br><span class=\"line\"> username = <span class=\"string\">'admin'</span></span><br><span class=\"line\"> <span class=\"comment\"># 对应用户的token信息,不是明文的密码信息</span></span><br><span class=\"line\"> password = <span class=\"string\">'fljljdfladoweurojlsjdfasd123'</span></span><br><span class=\"line\"> server = jenkins.Jenkins(url=server, username=username, password=password)</span><br><span class=\"line\"> instance = <span class=\"built_in\">super</span>(TestJenkins, cls).__new__(cls, *args, **kwargs)</span><br><span class=\"line\"> instance.server = server</span><br><span class=\"line\"> <span class=\"keyword\">return</span> instance</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">__init__</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> <span class=\"comment\">#这里的api_token是针对远程执行任务时,jenkins要验证的token的信息</span></span><br><span class=\"line\"> self.api_token = <span class=\"string\">'okfine'</span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">jobs_count</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> print(self.server.jobs_count())</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">server_info</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> print(self.server.server)</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">get_jobs_info</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> item <span class=\"keyword\">in</span> self.server.get_all_jobs():</span><br><span class=\"line\"> print(<span class=\"string\">'name: %s'</span> % item[<span class=\"string\">'name'</span>], <span class=\"string\">'URL: '</span>, item[<span class=\"string\">'url'</span>])</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">get_whoami</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> print(self.server.get_whoami(depth=<span class=\"number\">10</span>))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">get_auth</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> print(self.server.auth)</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">get_debug_job_info</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> print(self.server.debug_job_info(name))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">check_job_exists</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> print(self.server.job_exists(name))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">get_all_jobs</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> print(self.server.get_all_jobs())</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">create_job</span>(<span class=\"params\">self</span>):</span></span><br><span class=\"line\"> print(self.server.create_job(<span class=\"string\">'API-1'</span>, jenkins.RECONFIG_XML))</span><br><span class=\"line\"> print(self.server.create_job(<span class=\"string\">'API-2'</span>, jenkins.RECONFIG_XML))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">delete_job</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> print(self.server.delete_job(name))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">copy_job</span>(<span class=\"params\">self, name, new_name</span>):</span></span><br><span class=\"line\"> print(self.server.copy_job(name, new_name))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">enable_job</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> print(self.server.enable_job(name))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">disable_job</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> print(self.server.disable_job(name))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">reconfig_job</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> print(self.server.reconfig_job(name, jenkins.RECONFIG_XML))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">rename_job</span>(<span class=\"params\">self, name, new_name</span>):</span></span><br><span class=\"line\"> print(self.server.rename_job(name, new_name))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">build_job</span>(<span class=\"params\">self, name, parameters</span>):</span></span><br><span class=\"line\"> print(self.server.build_job(name, parameters, token=self.api_token))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">get_job_info</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> <span class=\"comment\"># 主要是通过任务的信息,来得到需要传入的参数信息,jenkins 各种自定义选项信息,单凭肉眼是很难辨别出参数信息的,</span></span><br><span class=\"line\"> <span class=\"comment\"># 任务相关参数信息都是在property这个参数里面</span></span><br><span class=\"line\"> build_arg = self.server.get_job_info(name)[<span class=\"string\">"property"</span>]</span><br><span class=\"line\"> <span class=\"keyword\">for</span> parameter_definitions <span class=\"keyword\">in</span> build_arg:</span><br><span class=\"line\"> <span class=\"keyword\">if</span> <span class=\"built_in\">len</span>(parameter_definitions) > <span class=\"number\">1</span>:</span><br><span class=\"line\"> <span class=\"keyword\">for</span> parameter <span class=\"keyword\">in</span> parameter_definitions[<span class=\"string\">"parameterDefinitions"</span>]:</span><br><span class=\"line\"> print(<span class=\"string\">'----------------------------------'</span>)</span><br><span class=\"line\"> print(<span class=\"string\">'name: %s'</span> % parameter[<span class=\"string\">"name"</span>])</span><br><span class=\"line\"> print(<span class=\"string\">'class: %s'</span> % parameter[<span class=\"string\">"_class"</span>])</span><br><span class=\"line\"> print(<span class=\"string\">'type: %s'</span> % parameter[<span class=\"string\">"type"</span>])</span><br><span class=\"line\"> print(<span class=\"string\">'description: %s'</span> % parameter[<span class=\"string\">"description"</span>])</span><br><span class=\"line\"> print(<span class=\"string\">'jenkins_arg: %s'</span> % parameter[<span class=\"string\">"defaultParameterValue"</span>][<span class=\"string\">"name"</span>])</span><br><span class=\"line\"> print(<span class=\"string\">'default_value: %s'</span> % parameter[<span class=\"string\">"defaultParameterValue"</span>][<span class=\"string\">"value"</span>])</span><br><span class=\"line\"> <span class=\"keyword\">if</span> parameter[<span class=\"string\">"_class"</span>] == <span class=\"string\">'hudson.model.ChoiceParameterDefinition'</span>:</span><br><span class=\"line\"> print(<span class=\"string\">'can_choices: %s'</span> % parameter[<span class=\"string\">"choices"</span>])</span><br><span class=\"line\"> print(<span class=\"string\">'----------------------------------'</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">get_build_log</span>(<span class=\"params\">self, name</span>):</span></span><br><span class=\"line\"> last_build_number = self.server.get_job_info(name)[<span class=\"string\">'lastCompletedBuild'</span>][<span class=\"string\">'number'</span>]</span><br><span class=\"line\"> print(<span class=\"string\">'last_build_number'</span>, last_build_number)</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"># 查看指定构建编号的输出</span></span><br><span class=\"line\"> print(self.server.get_build_console_output(name, last_build_number))</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"function\"><span class=\"keyword\">def</span> <span class=\"title\">__call__</span>(<span class=\"params\">self, *args, **kwargs</span>):</span></span><br><span class=\"line\"> self.get_job_info(<span class=\"string\">'shop'</span>)</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"># 通过特定任务的信息来得到要传入的参数信息,然后再来执行构建任务</span></span><br><span class=\"line\"> <span class=\"comment\"># build new job, nice operation</span></span><br><span class=\"line\"> <span class=\"comment\"># 如下列所示的5个参数,就是此次构建必须提供的参数</span></span><br><span class=\"line\"> param_dict = {<span class=\"string\">'repository'</span>: <span class=\"string\">'ssh://git@xxxxx.com/xx/xxxx.git'</span>,</span><br><span class=\"line\"> <span class=\"string\">'profile'</span>: <span class=\"string\">'xxxx-xxx'</span>,</span><br><span class=\"line\"> <span class=\"string\">'branch'</span>: <span class=\"string\">'master'</span>,</span><br><span class=\"line\"> <span class=\"string\">'upload_nexus'</span>: <span class=\"literal\">False</span>,</span><br><span class=\"line\"> <span class=\"string\">'deploy_app'</span>: <span class=\"literal\">False</span>}</span><br><span class=\"line\"></span><br><span class=\"line\"> self.build_job(<span class=\"string\">'xxxxx'</span>, parameters=param_dict)</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\">TestJenkins()()</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Python"],"tags":["Python","Jenkins"]},{"title":"PHP之Pchart生产图片","url":"/2.Programming/2.PHP/PHP%E4%B9%8BPchart%E7%94%9F%E4%BA%A7%E5%9B%BE%E7%89%87/","content":"<p><a href=\"http://wiki.pchart.net/doc.introduction.html\">pChart online documentation</a></p>\n<p><a href=\"http://pchart.sourceforge.net/index.php\">实例</a></p>\n","categories":["2.Programming","PHP"],"tags":["PHP"]},{"title":"PHP之SMTP发送邮件","url":"/2.Programming/2.PHP/PHP%E4%B9%8BSMTP%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6/","content":"<h2 id=\"下载相关库\"><a href=\"#下载相关库\" class=\"headerlink\" title=\"下载相关库\"></a>下载相关库</h2><p>class.phpmailer.php和class.smtp.php至公共库</p>\n<h2 id=\"编写公共函数\"><a href=\"#编写公共函数\" class=\"headerlink\" title=\"编写公共函数\"></a>编写公共函数</h2><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">sendMail</span>(<span class=\"params\"><span class=\"variable\">$param</span></span>) </span>{</span><br><span class=\"line\"> <span class=\"variable\">$config</span> = C(<span class=\"string\">'THINK_EMAIL'</span>);</span><br><span class=\"line\"> vendor(<span class=\"string\">'PHPMailer.class#phpmailer'</span>); <span class=\"comment\">//从PHPMailer目录导class.phpmailer.php类文件</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span> = <span class=\"keyword\">new</span> PHPMailer(); <span class=\"comment\">//PHPMailer对象</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->CharSet = <span class=\"variable\">$config</span>[<span class=\"string\">'EMAIL_CHARSET'</span>]; <span class=\"comment\">//设定邮件编码,默认ISO-8859-1,如果发中文此项必须设置,否则乱码</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->IsSMTP(); <span class=\"comment\">// 设定使用SMTP服务</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->SMTPDebug = <span class=\"number\">0</span>; <span class=\"comment\">// 关闭SMTP调试功能</span></span><br><span class=\"line\"> <span class=\"comment\">// 1 = errors and messages</span></span><br><span class=\"line\"> <span class=\"comment\">// 2 = messages only</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->SMTPAuth = <span class=\"variable\">$config</span>[<span class=\"string\">'EMAIL_SMTPAUTH'</span>]; <span class=\"comment\">// 启用 SMTP 验证功能</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->Host = <span class=\"variable\">$config</span>[<span class=\"string\">'SMTP_HOST'</span>]; <span class=\"comment\">// SMTP 服务器</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->Port = <span class=\"variable\">$config</span>[<span class=\"string\">'SMTP_PORT'</span>]; <span class=\"comment\">// SMTP服务器的端口号</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->Username = <span class=\"variable\">$config</span>[<span class=\"string\">'SMTP_USER'</span>]; <span class=\"comment\">// SMTP服务器用户名</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->Password = <span class=\"variable\">$config</span>[<span class=\"string\">'SMTP_PASS'</span>]; <span class=\"comment\">// SMTP服务器密码</span></span><br><span class=\"line\"> <span class=\"comment\">//$mail->SetFrom($config['FROM_EMAIL'], $config['FROM_NAME']);</span></span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->SetFrom(<span class=\"variable\">$param</span>[<span class=\"string\">'mail_from'</span>], <span class=\"variable\">$param</span>[<span class=\"string\">'mail_name'</span>]);</span><br><span class=\"line\"> <span class=\"variable\">$replyEmail</span> = <span class=\"variable\">$config</span>[<span class=\"string\">'REPLY_EMAIL'</span>] ? <span class=\"variable\">$config</span>[<span class=\"string\">'REPLY_EMAIL'</span>] : <span class=\"variable\">$param</span>[<span class=\"string\">'mail_from'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$replyName</span> = <span class=\"variable\">$config</span>[<span class=\"string\">'REPLY_NAME'</span>] ? <span class=\"variable\">$config</span>[<span class=\"string\">'REPLY_NAME'</span>] : <span class=\"variable\">$param</span>[<span class=\"string\">'mail_name'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->AddReplyTo(<span class=\"variable\">$replyEmail</span>, <span class=\"variable\">$replyName</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"keyword\">empty</span>(<span class=\"variable\">$param</span>[<span class=\"string\">'to'</span>])) {</span><br><span class=\"line\"> <span class=\"keyword\">foreach</span> (<span class=\"variable\">$param</span>[<span class=\"string\">'to'</span>] <span class=\"keyword\">as</span> <span class=\"variable\">$to</span>) {</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->AddAddress(<span class=\"variable\">$to</span>[<span class=\"string\">'address'</span>], <span class=\"variable\">$to</span>[<span class=\"string\">'name'</span>]);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"keyword\">empty</span>(<span class=\"variable\">$param</span>[<span class=\"string\">'cc'</span>])) {</span><br><span class=\"line\"> <span class=\"keyword\">foreach</span> (<span class=\"variable\">$param</span>[<span class=\"string\">'cc'</span>] <span class=\"keyword\">as</span> <span class=\"variable\">$cc</span>) {</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->addCC(<span class=\"variable\">$cc</span>[<span class=\"string\">'address'</span>], <span class=\"variable\">$cc</span>[<span class=\"string\">'name'</span>]);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"><span class=\"comment\">// if (!empty($param['bcc'])) {</span></span><br><span class=\"line\"><span class=\"comment\">// foreach ($param['bcc'] as $bcc) {</span></span><br><span class=\"line\"><span class=\"comment\">// $mail->addBCC($bcc['address'], $bcc['name']);</span></span><br><span class=\"line\"><span class=\"comment\">// }</span></span><br><span class=\"line\"><span class=\"comment\">// }</span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"variable\">$param</span>[<span class=\"string\">'body'</span>] = <span class=\"variable\">$mail</span>->WrapText(<span class=\"variable\">$param</span>[<span class=\"string\">'body'</span>], <span class=\"number\">900</span>);</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->Subject = <span class=\"variable\">$param</span>[<span class=\"string\">'subject'</span>];</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"keyword\">empty</span>(<span class=\"variable\">$param</span>[<span class=\"string\">'body'</span>])) {</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->MsgHTML(<span class=\"variable\">$param</span>[<span class=\"string\">'body'</span>]);</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->IsHTML(<span class=\"variable\">$config</span>[<span class=\"string\">'EMAIL_ISHTML'</span>]);</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->Body = <span class=\"variable\">$param</span>[<span class=\"string\">'body'</span>];</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">// if (!empty($param['attachment'])) { // 添加附件</span></span><br><span class=\"line\"><span class=\"comment\">// foreach ($param['attachment'] as $file) {</span></span><br><span class=\"line\"><span class=\"comment\">// if (is_file($file['path'])) {</span></span><br><span class=\"line\"><span class=\"comment\">// $mail->AddAttachment($file['path'], $file['name']);</span></span><br><span class=\"line\"><span class=\"comment\">// }</span></span><br><span class=\"line\"><span class=\"comment\">// }</span></span><br><span class=\"line\"><span class=\"comment\">// }</span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">for</span>(<span class=\"variable\">$i</span>=<span class=\"number\">0</span>;<span class=\"variable\">$i</span><(count(<span class=\"variable\">$param</span>[<span class=\"string\">'attachment'</span>]));<span class=\"variable\">$i</span>++){</span><br><span class=\"line\"> <span class=\"variable\">$img</span>=substr(<span class=\"variable\">$param</span>[<span class=\"string\">'attachment'</span>][<span class=\"variable\">$i</span>], strpos(<span class=\"variable\">$param</span>[<span class=\"string\">'attachment'</span>][<span class=\"variable\">$i</span>], <span class=\"string\">","</span>));</span><br><span class=\"line\"> <span class=\"variable\">$mail</span>->AddStringAttachment(base64_decode(<span class=\"variable\">$img</span>),<span class=\"string\">"attach"</span>.<span class=\"variable\">$i</span>.<span class=\"string\">".png"</span>,<span class=\"string\">"base64"</span>,<span class=\"string\">"image/png"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//重发机制</span></span><br><span class=\"line\"> <span class=\"variable\">$ret</span>[<span class=\"string\">'errno'</span>] = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"variable\">$ret</span>[<span class=\"string\">'msg'</span>] = <span class=\"string\">''</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"variable\">$mail</span>->Send()) {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"variable\">$ret</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"variable\">$mail</span>->Send()) {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"variable\">$ret</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"variable\">$ret</span>[<span class=\"string\">'errno'</span>] = <span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"variable\">$ret</span>[<span class=\"string\">'msg'</span>] = <span class=\"variable\">$mail</span>->ErrorInfo;</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"variable\">$ret</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"comment\">// return $mail->Send() ? true : $mail->ErrorInfo;</span></span><br><span class=\"line\"> }</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"SMTP配置函数\"><a href=\"#SMTP配置函数\" class=\"headerlink\" title=\"SMTP配置函数\"></a>SMTP配置函数</h2><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">// 配置邮件发送服务器</span></span><br><span class=\"line\"><span class=\"string\">'THINK_EMAIL'</span>=><span class=\"keyword\">array</span>(</span><br><span class=\"line\"> <span class=\"string\">'SMTP_HOST'</span> => <span class=\"string\">'localhost'</span>, <span class=\"comment\">//邮件发送SMTP服务器</span></span><br><span class=\"line\"> <span class=\"string\">'SMTP_PORT'</span> => <span class=\"string\">'25'</span>,<span class=\"comment\">//SMTP服务器端口 </span></span><br><span class=\"line\"> <span class=\"string\">'SMTP_USER'</span> => <span class=\"string\">'admin'</span>, <span class=\"comment\">//SMTP服务器登陆用户名</span></span><br><span class=\"line\"> <span class=\"string\">'SMTP_PASS'</span> => <span class=\"string\">'admin'</span>, <span class=\"comment\">//SMTP服务器登陆密码 </span></span><br><span class=\"line\"> <span class=\"string\">'FROM_EMAIL'</span> =><span class=\"string\">'发件箱@XX.com'</span>,</span><br><span class=\"line\"> <span class=\"string\">'FROM_NAME'</span> =><span class=\"string\">'发件人姓名'</span>,</span><br><span class=\"line\"> <span class=\"string\">'REPLY_EMAIL'</span> =><span class=\"string\">''</span>,</span><br><span class=\"line\"> <span class=\"string\">'REPLY_NAME'</span> =><span class=\"string\">''</span>,</span><br><span class=\"line\"> <span class=\"string\">'EMAIL_CHARSET'</span> =><span class=\"string\">'utf-8'</span>,</span><br><span class=\"line\"> <span class=\"string\">'EMAIL_ISHTML'</span> => <span class=\"string\">'TRUE'</span>,</span><br><span class=\"line\"> <span class=\"string\">'EMAIL_SMTPAUTH'</span> => <span class=\"string\">'0'</span>,</span><br><span class=\"line\"> ),</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"根据库中存取的base64获取图片信息,实际调用为一个url\"><a href=\"#根据库中存取的base64获取图片信息,实际调用为一个url\" class=\"headerlink\" title=\"根据库中存取的base64获取图片信息,实际调用为一个url\"></a>根据库中存取的base64获取图片信息,实际调用为一个url</h2><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">getImage</span>(<span class=\"params\"></span>) </span>{</span><br><span class=\"line\"> <span class=\"variable\">$reportId</span> = I(<span class=\"string\">'request.id'</span>);</span><br><span class=\"line\"> <span class=\"variable\">$imgInfos</span> = I(<span class=\"string\">'request.img'</span>);</span><br><span class=\"line\"> header(<span class=\"string\">'Content-Type: image/png'</span>);</span><br><span class=\"line\"> <span class=\"variable\">$repotModel</span> = M(<span class=\"string\">'XXX'</span>);</span><br><span class=\"line\"> <span class=\"variable\">$report</span> = <span class=\"variable\">$repotModel</span>->where([<span class=\"string\">'id'</span>=><span class=\"variable\">$reportId</span>])->find();</span><br><span class=\"line\"> <span class=\"variable\">$base</span> = explode(<span class=\"string\">','</span>, <span class=\"variable\">$report</span>[<span class=\"variable\">$imgInfos</span>])[<span class=\"number\">1</span>];</span><br><span class=\"line\"> <span class=\"variable\">$base</span> = base64_decode(<span class=\"variable\">$base</span>);</span><br><span class=\"line\"> <span class=\"keyword\">echo</span> <span class=\"variable\">$base</span>;</span><br><span class=\"line\"> <span class=\"keyword\">die</span>();</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","PHP"],"tags":["PHP"]},{"title":"PHP代码覆盖率实践","url":"/2.Programming/2.PHP/PHP%E4%BB%A3%E7%A0%81%E8%A6%86%E7%9B%96%E7%8E%87%E5%AE%9E%E8%B7%B5/","content":"<h2 id=\"前言\"><a href=\"#前言\" class=\"headerlink\" title=\"前言\"></a><strong>前言</strong></h2><p>代码覆盖率作为一个指导性指标,可以一定程度上反应测试的完备程度,虽然100%覆盖的代码并不意味着100%无bug的应用,但是较高的覆盖率一般情况下也意味着更少的bug。</p>\n<h2 id=\"实现说明\"><a href=\"#实现说明\" class=\"headerlink\" title=\"实现说明\"></a><strong>实现说明</strong></h2><h3 id=\"环境依赖\"><a href=\"#环境依赖\" class=\"headerlink\" title=\"环境依赖\"></a>环境依赖</h3><ol>\n<li>xdebug:php插件,用于收集覆盖率信息</li>\n<li>php-code-coverage:phpunit下的一个库,用于从xdebug收集的覆盖率信息中生成覆盖率统计报告,支持xml、html等多种格式</li>\n</ol>\n<h3 id=\"具体实现\"><a href=\"#具体实现\" class=\"headerlink\" title=\"具体实现\"></a>具体实现</h3><p>脚本和报告生成路径:/usr/local/project/config/coverage/prepend.php</p>\n<p>单测:<a href=\"http://xxx.xxx.xxx.xxx:8888/html/\">http://XXX.XXX.XXX.XXX:8888/html/</a></p>\n<p>PCC:<a href=\"http://xxx.xxx.xxx.xxx:8888/report/\">http://XXX.XXX.XXX.XXX:8888/report/</a></p>\n<h4 id=\"单测脚本\"><a href=\"#单测脚本\" class=\"headerlink\" title=\"单测脚本\"></a>单测脚本</h4><p> 确认生成存在phpcov模块:php72 -m 查看(如无,则 #php72 /usr/local/bin/composer require “phpunit/phpcov”:”*” -vvv)</p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@dev01 /usr/local/project/honghan-api]<span class=\"comment\"># php72 ./vendor/bin/phpunit --coverage-html /usr/local/project/config/coverage/html/ ./tests/EventsLogicTest.php</span></span><br><span class=\"line\"></span><br><span class=\"line\">[root@dev01 /usr/local/project/honghan-api]<span class=\"comment\"># php72 ./vendor/bin/phpunit --coverage-html /usr/local/project/config/coverage/html/ ./tests</span></span><br></pre></td></tr></table></figure>\n\n\n<h4 id=\"代码全量统计\"><a href=\"#代码全量统计\" class=\"headerlink\" title=\"代码全量统计\"></a>代码全量统计</h4><p><strong>1、PCC依靠xdebug插件,主要在php.ini文件中增加xdebug相关配置:</strong></p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@dev01 /etc/opt/remi/php72]<span class=\"comment\"># vim php.ini</span></span><br><span class=\"line\">[Xdebug]</span><br><span class=\"line\">zend_extension =<span class=\"string\">"/usr/lib64/php/modules/xdebug.so"</span></span><br><span class=\"line\">xdebug.collect_params=on</span><br><span class=\"line\">xdebug.collect_return=on</span><br><span class=\"line\">xdebug.remote_autostart=on</span><br><span class=\"line\">;xdebug.remote_enable=off</span><br><span class=\"line\">;xdebug.profiler_enable = off</span><br><span class=\"line\">;xdebug.profiler_enable_trigger = off</span><br><span class=\"line\">;xdebug.profiler_output_name = cachegrind.out.%t</span><br><span class=\"line\">;xdebug.profiler_output_dir =<span class=\"string\">"/home/hhzl/tmp"</span></span><br><span class=\"line\">;xdebug.show_local_vars=<span class=\"number\">0</span></span><br><span class=\"line\">;xdebug.profiler_enable = on</span><br><span class=\"line\">;xdebug.trace_enable_trigger=<span class=\"number\">1</span></span><br><span class=\"line\">;xdebug.trace_output_dir=<span class=\"string\">"/home/hhzl/tmp"</span></span><br><span class=\"line\">;xdebug.trace_output_name=trace.%R.%u</span><br><span class=\"line\">;xdebug.coverage_enable = <span class=\"number\">1</span></span><br></pre></td></tr></table></figure>\n\n<p><strong>2、[root@dev01 /usr/local/project/config/coverage]# vim prepend.php 收集全量代码覆盖率脚本</strong></p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@dev01 /usr/local/project/config/coverage]<span class=\"comment\"># vim prepend.php</span></span><br><span class=\"line\"><span class=\"meta\"><?php</span></span><br><span class=\"line\"><span class=\"keyword\">require_once</span> <span class=\"string\">'/usr/local/project/honghan-api/vendor/autoload.php'</span>;</span><br><span class=\"line\"><span class=\"keyword\">use</span> <span class=\"title\">SebastianBergmann</span>\\<span class=\"title\">CodeCoverage</span>\\<span class=\"title\">CodeCoverage</span>;</span><br><span class=\"line\"> </span><br><span class=\"line\"><span class=\"variable\">$coverage</span> = <span class=\"keyword\">new</span> CodeCoverage;</span><br><span class=\"line\"><span class=\"variable\">$coverage</span>->filter()->addDirectoryToWhitelist(<span class=\"string\">'/usr/local/project/honghan-api/tests/'</span>);</span><br><span class=\"line\"><span class=\"variable\">$coverage</span>->filter()->addDirectoryToWhitelist(<span class=\"string\">'/usr/local/project/honghan-api/app/'</span>);</span><br><span class=\"line\"><span class=\"variable\">$coverage</span>->filter()->addDirectoryToWhitelist(<span class=\"string\">'/usr/local/project/honghan-api/public/'</span>);</span><br><span class=\"line\"><span class=\"variable\">$coverage</span>->start(<span class=\"string\">'<Site coverage>'</span>);<span class=\"comment\">#开始统计</span></span><br><span class=\"line\">register_shutdown_function(<span class=\"string\">'__coverage_stop'</span>,<span class=\"variable\">$coverage</span>);<span class=\"comment\">#注册关闭方法</span></span><br><span class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">__coverage_stop</span>(<span class=\"params\">CodeCoverage <span class=\"variable\">$coverage</span></span>)</span>{</span><br><span class=\"line\"> <span class=\"variable\">$coverage</span>->stop();</span><br><span class=\"line\"> </span><br><span class=\"line\"> ini_set(<span class=\"string\">'date.timezone'</span>, <span class=\"string\">'Asia/Shanghai'</span>);</span><br><span class=\"line\"> writer = <span class=\"keyword\">new</span> \\SebastianBergmann\\CodeCoverage\\Report\\Html\\Facade;</span><br><span class=\"line\"> writer->process(<span class=\"variable\">$coverage</span>,<span class=\"string\">'/usr/local/project/config/coverage/html'</span>.date(<span class=\"string\">'Y_m_d_H_i_s'</span>));</span><br><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"variable\">$htmlWriter</span>->process(<span class=\"variable\">$coverage</span>, <span class=\"string\">'/usr/local/project/honghan-api/coverage_html/'</span> . date(<span class=\"string\">'Y_m_d_H_i_s'</span>));</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、index.php文件中引用</strong></p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@dev01 /usr/local/project/honghan-api/<span class=\"keyword\">public</span>]<span class=\"comment\"># cat index.php</span></span><br><span class=\"line\"><span class=\"meta\"><?php</span></span><br><span class=\"line\">ini_set(<span class=\"string\">'memory_limit'</span>, <span class=\"string\">'1024M'</span>);</span><br><span class=\"line\">ini_set(<span class=\"string\">'date.timezone'</span>,<span class=\"string\">'Asia/Shanghai'</span>);</span><br><span class=\"line\"><span class=\"variable\">$app</span> = <span class=\"keyword\">require</span> <span class=\"keyword\">__DIR__</span>.<span class=\"string\">'/../bootstrap/app.php'</span>;</span><br><span class=\"line\"> </span><br><span class=\"line\"><span class=\"comment\">#require '/usr/local/project/config/coverage/prepend.php';</span></span><br><span class=\"line\"> </span><br><span class=\"line\"><span class=\"variable\">$app</span>->run();</span><br></pre></td></tr></table></figure>\n\n<p><strong>4、执行php72 index.php即可</strong></p>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@dev01 /usr/local/project/honghan-api/<span class=\"keyword\">public</span>]<span class=\"comment\"># php72 index.php</span></span><br><span class=\"line\">Lumen (<span class=\"number\">5.8</span><span class=\"number\">.4</span>) (Laravel Components <span class=\"number\">5.8</span>.*)</span><br></pre></td></tr></table></figure>\n\n<p><strong>5、配置nginx访问即可</strong></p>\n<h2 id=\"注意\"><a href=\"#注意\" class=\"headerlink\" title=\"注意\"></a><strong>注意</strong></h2><ol>\n<li>执行# php72 index.php 文件的用户非apache,php-fpm的启动用户和组为apache,会存在统计数据写不到报告的情况;更新执行脚本用户或php-fpm的用户组</li>\n</ol>\n","categories":["2.Programming","PHP"],"tags":["PHP"]},{"title":"PHP导出Excel","url":"/2.Programming/2.PHP/PHP%E5%AF%BC%E5%87%BAExcel/","content":"<h2 id=\"引入相关公共库PHPExcel\"><a href=\"#引入相关公共库PHPExcel\" class=\"headerlink\" title=\"引入相关公共库PHPExcel\"></a>引入相关公共库PHPExcel</h2><h2 id=\"编写公共函数\"><a href=\"#编写公共函数\" class=\"headerlink\" title=\"编写公共函数\"></a>编写公共函数</h2><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">exportExcel</span>(<span class=\"params\"><span class=\"variable\">$excelTitle</span>,<span class=\"variable\">$data</span>,<span class=\"variable\">$filename</span>=<span class=\"string\">''</span>,<span class=\"variable\">$column_width</span>=<span class=\"string\">''</span></span>)</span>{</span><br><span class=\"line\"> ini_set(<span class=\"string\">'max_execution_time'</span>, <span class=\"string\">'0'</span>);</span><br><span class=\"line\"> header(<span class=\"string\">"Content-Type:application/force-download"</span>);</span><br><span class=\"line\"> header(<span class=\"string\">"Content-Type:application/vnd.ms-execl"</span>);</span><br><span class=\"line\"> header(<span class=\"string\">"Content-Type:application/download"</span>);</span><br><span class=\"line\"> <span class=\"variable\">$filename</span>=str_replace(<span class=\"string\">'.xls'</span>, <span class=\"string\">''</span>, <span class=\"variable\">$filename</span>).<span class=\"string\">'.xls'</span>;</span><br><span class=\"line\"> header(<span class=\"string\">'Content-Disposition: attachment;filename='</span>.<span class=\"variable\">$filename</span>);</span><br><span class=\"line\"> Vendor(<span class=\"string\">'PHPExcel.PHPExcel'</span>);</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span> = <span class=\"keyword\">new</span> PHPExcel();</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getActiveSheet()->setTitle(<span class=\"string\">'Sheet1'</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"variable\">$key</span> = <span class=\"number\">0</span>; <span class=\"comment\">//设置表头</span></span><br><span class=\"line\"> <span class=\"keyword\">foreach</span>(<span class=\"variable\">$excelTitle</span> <span class=\"keyword\">as</span> <span class=\"variable\">$v</span>){</span><br><span class=\"line\"> <span class=\"variable\">$colum</span> = \\PHPExcel_Cell::stringFromColumnIndex(<span class=\"variable\">$key</span>);</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->setActiveSheetIndex(<span class=\"number\">0</span>) ->setCellValue(<span class=\"variable\">$colum</span>.<span class=\"string\">'1'</span>, <span class=\"variable\">$v</span>);</span><br><span class=\"line\"> <span class=\"variable\">$key</span> += <span class=\"number\">1</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"variable\">$column</span> = <span class=\"number\">2</span>;</span><br><span class=\"line\"> <span class=\"variable\">$objActSheet</span> = <span class=\"variable\">$phpexcel</span>->getActiveSheet();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">foreach</span>(<span class=\"variable\">$data</span> <span class=\"keyword\">as</span> <span class=\"variable\">$key</span> => <span class=\"variable\">$rows</span>){ <span class=\"comment\">//行写入</span></span><br><span class=\"line\"> <span class=\"variable\">$span</span> = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">foreach</span>(<span class=\"variable\">$rows</span> <span class=\"keyword\">as</span> <span class=\"variable\">$keyName</span>=><span class=\"variable\">$value</span>){<span class=\"comment\">// 列写入</span></span><br><span class=\"line\"> <span class=\"variable\">$j</span> = \\PHPExcel_Cell::stringFromColumnIndex(<span class=\"variable\">$span</span>);</span><br><span class=\"line\"> <span class=\"variable\">$objActSheet</span>->setCellValue(<span class=\"variable\">$j</span>.<span class=\"variable\">$column</span>, <span class=\"variable\">$value</span>);</span><br><span class=\"line\"> <span class=\"variable\">$span</span>++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"variable\">$column</span>++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//设置字体格式及大小</span></span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getDefaultStyle()->getFont()->setName( <span class=\"string\">'微软雅黑'</span>);</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getDefaultStyle()->getFont()->setSize(<span class=\"number\">10</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//第一行设置填充的样式和背景色</span></span><br><span class=\"line\"> <span class=\"variable\">$currentColumn</span> = <span class=\"string\">'A'</span>;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"variable\">$i</span> = <span class=\"number\">1</span>; <span class=\"variable\">$i</span> <= count(<span class=\"variable\">$excelTitle</span>); <span class=\"variable\">$i</span>++) {</span><br><span class=\"line\"> <span class=\"variable\">$a</span>[] = <span class=\"variable\">$currentColumn</span>++;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"variable\">$last</span> = <span class=\"variable\">$a</span>[(count(<span class=\"variable\">$a</span>) <span class=\"number\">-1</span>)].<span class=\"string\">"1"</span>;</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getActiveSheet()->getStyle( <span class=\"string\">"A1:<span class=\"subst\">$last</span>"</span>)->getFill()->setFillType(\\PHPExcel_Style_Fill::FILL_SOLID);</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getActiveSheet()->getStyle( <span class=\"string\">"A1:<span class=\"subst\">$last</span>"</span>)->getFill()->getStartColor()->setARGB(<span class=\"string\">'#458B00'</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//设置单元格内容居左显示</span></span><br><span class=\"line\"> <span class=\"comment\">//$phpexcel->getActiveSheet()->getStyle('A')->getAlignment()->setHorizontal(\\PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);</span></span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getDefaultStyle()->getAlignment()->setHorizontal(\\PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getDefaultStyle()->getAlignment()->setVertical(\\PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//设置列宽度</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span>(!<span class=\"keyword\">empty</span>(<span class=\"variable\">$column_width</span>)){</span><br><span class=\"line\"> <span class=\"keyword\">foreach</span>(<span class=\"variable\">$column_width</span> <span class=\"keyword\">as</span> <span class=\"variable\">$key</span> => <span class=\"variable\">$value</span>){</span><br><span class=\"line\"> <span class=\"variable\">$phpexcel</span>->getActiveSheet()->getColumnDimension(<span class=\"variable\">$key</span>)->setWidth(<span class=\"variable\">$value</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"variable\">$objwriter</span> = PHPExcel_IOFactory::createWriter(<span class=\"variable\">$phpexcel</span>, <span class=\"string\">'Excel5'</span>);</span><br><span class=\"line\"> <span class=\"variable\">$objwriter</span>->save(<span class=\"string\">'php://output'</span>);</span><br><span class=\"line\"> <span class=\"keyword\">exit</span>;</span><br><span class=\"line\"> }</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"调用公共函数\"><a href=\"#调用公共函数\" class=\"headerlink\" title=\"调用公共函数\"></a>调用公共函数</h2><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"variable\">$excelTitle</span> = <span class=\"keyword\">array</span>(<span class=\"string\">"提测单名称"</span>,<span class=\"string\">"BUG统计周期"</span>,<span class=\"string\">"BUG_TOTAL"</span>,<span class=\"string\">"ASSIGNED"</span>,<span class=\"string\">"REOPENED"</span>,<span class=\"string\">"RESOLVED"</span>,<span class=\"string\">"VERIFIED"</span>,<span class=\"string\">"CLOSED"</span>);</span><br><span class=\"line\"><span class=\"keyword\">foreach</span> (<span class=\"variable\">$retSearchStatusList</span> <span class=\"keyword\">as</span> <span class=\"variable\">$excelExport</span>){</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'A'</span>] = <span class=\"variable\">$excelExport</span>[<span class=\"string\">'A'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'B'</span>] = <span class=\"variable\">$dateFrom</span>.<span class=\"string\">"至"</span>.<span class=\"variable\">$dateTo</span>;</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'C'</span>] = <span class=\"variable\">$excelExport</span>[<span class=\"string\">'C'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'D'</span>] = <span class=\"variable\">$excelExport</span>[<span class=\"string\">'D'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'E'</span>] = <span class=\"variable\">$excelExport</span>[<span class=\"string\">'E'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'F'</span>] = <span class=\"variable\">$excelExport</span>[<span class=\"string\">'F'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'G'</span>] = <span class=\"variable\">$excelExport</span>[<span class=\"string\">'G'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$excelExports</span>[<span class=\"string\">'H'</span>] = <span class=\"variable\">$excelExport</span>[<span class=\"string\">'H'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$list</span>[] = <span class=\"variable\">$excelExports</span>;</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"variable\">$filename</span> = <span class=\"string\">"文件名称-"</span>.date(<span class=\"string\">'Y-m-d H-i-s'</span>);</span><br><span class=\"line\"><span class=\"variable\">$column_width</span> = <span class=\"keyword\">array</span>(<span class=\"string\">"A"</span>=><span class=\"number\">50</span>,<span class=\"string\">"B"</span>=><span class=\"number\">38</span>);</span><br><span class=\"line\"><span class=\"variable\">$exportExcel</span> = <span class=\"variable\">$excelUtil</span>->exportExcel(<span class=\"variable\">$excelTitle</span>,<span class=\"variable\">$list</span>,<span class=\"variable\">$filename</span>,<span class=\"variable\">$column_width</span>);</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","PHP"],"tags":["PHP"]},{"title":"ThinkPHP修改Redis操作类,支持选择数据库功能及添加其他方法","url":"/2.Programming/2.PHP/ThinkPHP%E4%BF%AE%E6%94%B9Redis%E6%93%8D%E4%BD%9C%E7%B1%BB%EF%BC%8C%E6%94%AF%E6%8C%81%E9%80%89%E6%8B%A9%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8A%9F%E8%83%BD%E5%8F%8A%E6%B7%BB%E5%8A%A0%E5%85%B6%E4%BB%96%E6%96%B9%E6%B3%95/","content":"<h2 id=\"版本\"><a href=\"#版本\" class=\"headerlink\" title=\"版本\"></a>版本</h2><p>ThinkPHP 3.2.2</p>\n<p><strong>官方默认不支持选择数据库功能及,现就可选择数据库功能进行说明</strong></p>\n<ol>\n<li>config.php 配置文件中选择数据库 </li>\n</ol>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"string\">'REDIS_DBINDEX'</span> =><span class=\"number\">1</span>, <span class=\"comment\">// 选择库信息(0~16)</span></span><br></pre></td></tr></table></figure>\n\n<ol start=\"2\">\n<li>Redis.class.php中修改__construct()方法</li>\n</ol>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"string\">'dbindex'</span> => C(<span class=\"string\">'REDIS_DBINDEX'</span>) ? C(<span class=\"string\">'REDIS_DBINDEX'</span>) : <span class=\"number\">0</span>; <span class=\"comment\">//选择存库</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">$this</span>->options[<span class=\"string\">'dbindex'</span>] = <span class=\"keyword\">isset</span>(<span class=\"variable\">$options</span>[<span class=\"string\">'dbindex'</span>])? <span class=\"variable\">$options</span>[<span class=\"string\">'dbindex'</span>] : <span class=\"number\">0</span>; <span class=\"comment\">//选择存库</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">$this</span>->handler->select(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'dbindex'</span>]); <span class=\"comment\">//选择存库</span></span><br></pre></td></tr></table></figure>\n\n\n\n<p><strong>官方默认未实现鉴权功能,现就实现鉴权进行说明</strong></p>\n<ol>\n<li>config.php 配置文件中增加鉴权密码 </li>\n</ol>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">'REDIS_AUTH'=>'123456', //AUTH认证密码</span><br></pre></td></tr></table></figure>\n\n<ol start=\"2\">\n<li>Redis.class.php中修改__construct()方法</li>\n</ol>\n<figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">if</span>(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'auth'</span>]!=<span class=\"literal\">null</span>){</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->handler->auth(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'auth'</span>]); <span class=\"comment\">//说明有配置redis的认证配置密码 需要认证</span></span><br><span class=\"line\"></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n\n\n<h2 id=\"具体代码如下\"><a href=\"#具体代码如下\" class=\"headerlink\" title=\"具体代码如下\"></a>具体代码如下</h2><p><img src=\"/images/20180910-1.png\" alt=\"code\"></p>\n","categories":["2.Programming","PHP"],"tags":["PHP"]},{"title":"ThinkPHP实现存储Session至Redis","url":"/2.Programming/2.PHP/ThinkPHP%E5%AE%9E%E7%8E%B0%E5%AD%98%E5%82%A8Session%E8%87%B3Redis/","content":"<h2 id=\"涉及文件\"><a href=\"#涉及文件\" class=\"headerlink\" title=\"涉及文件\"></a>涉及文件</h2><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\">Thinkphp\\Library\\Think\\Session\\Driver 中新建redis缓存文件:Redis.<span class=\"keyword\">class</span>.php</span><br><span class=\"line\">Thinkphp\\Common\\function.php 中<span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">session</span>(<span class=\"params\"><span class=\"variable\">$name</span>=<span class=\"string\">''</span>,<span class=\"variable\">$value</span>=<span class=\"string\">''</span></span>) //<span class=\"title\">session</span>说明文件</span></span><br></pre></td></tr></table></figure>\n\n<h3 id=\"配置文件\"><a href=\"#配置文件\" class=\"headerlink\" title=\"配置文件\"></a>配置文件</h3><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">//redis操作session</span></span><br><span class=\"line\"><span class=\"string\">'SESSION_AUTO_START'</span> => <span class=\"literal\">true</span>, <span class=\"comment\">// 是否自动开启Session</span></span><br><span class=\"line\"><span class=\"string\">'SESSION_TYPE'</span> => <span class=\"string\">'Redis'</span>, <span class=\"comment\">//session类型</span></span><br><span class=\"line\"><span class=\"string\">'SESSION_PERSISTENT'</span> => <span class=\"number\">1</span>, <span class=\"comment\">//是否长连接(对于php来说0和1都一样)</span></span><br><span class=\"line\"><span class=\"string\">'SESSION_CACHE_TIME'</span> => <span class=\"number\">3000</span>, <span class=\"comment\">//连接超时时间(秒)</span></span><br><span class=\"line\"><span class=\"string\">'SESSION_EXPIRE'</span> => <span class=\"number\">0</span>, <span class=\"comment\">//session有效期(单位:秒) 0表示永久缓存</span></span><br><span class=\"line\"><span class=\"string\">'SESSION_PREFIX'</span> => <span class=\"string\">'sses_'</span>, <span class=\"comment\">//session前缀</span></span><br></pre></td></tr></table></figure>\n\n<h3 id=\"Redis-class-php文件\"><a href=\"#Redis-class-php文件\" class=\"headerlink\" title=\"Redis.class.php文件\"></a>Redis.class.php文件</h3><figure class=\"highlight php\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\"><?php</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">namespace</span> <span class=\"title\">Think</span>\\<span class=\"title\">Session</span>\\<span class=\"title\">Driver</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Redis Session驱动</span></span><br><span class=\"line\"><span class=\"comment\"> * 要求安装phpredis扩展:https://github.com/nicolasff/phpredis</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@category</span> Think</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@package</span> Session</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@subpackage</span> Driver</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@version</span> TP3.2~TP3.2.1</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Redis</span> <span class=\"keyword\">implements</span> \\<span class=\"title\">SessionHandlerInterface</span></span>{</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Redis句柄</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">private</span> <span class=\"variable\">$handler</span>;</span><br><span class=\"line\"> <span class=\"keyword\">private</span> <span class=\"variable\">$get_result</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">__construct</span>(<span class=\"params\"></span>)</span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> ( !extension_loaded(<span class=\"string\">'redis'</span>) ) {</span><br><span class=\"line\"> E(L(<span class=\"string\">'_NOT_SUPPERT_'</span>).<span class=\"string\">':redis'</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(<span class=\"keyword\">empty</span>(<span class=\"variable\">$options</span>)) {</span><br><span class=\"line\"> <span class=\"variable\">$options</span> = <span class=\"keyword\">array</span> (</span><br><span class=\"line\"> <span class=\"string\">'host'</span> => C(<span class=\"string\">'REDIS_HOST'</span>) ? C(<span class=\"string\">'REDIS_HOST'</span>) : <span class=\"string\">'127.0.0.1'</span>,</span><br><span class=\"line\"> <span class=\"string\">'port'</span> => C(<span class=\"string\">'REDIS_PORT'</span>) ? C(<span class=\"string\">'REDIS_PORT'</span>) : <span class=\"number\">6379</span>,</span><br><span class=\"line\"> <span class=\"string\">'timeout'</span> => C(<span class=\"string\">'SESSION_CACHE_TIME'</span>) ? C(<span class=\"string\">'SESSION_CACHE_TIME'</span>) : <span class=\"literal\">false</span>,</span><br><span class=\"line\"> <span class=\"string\">'persistent'</span> => C(<span class=\"string\">'SESSION_PERSISTENT'</span>) ? C(<span class=\"string\">'SESSION_PERSISTENT'</span>) : <span class=\"literal\">false</span>,</span><br><span class=\"line\"> <span class=\"string\">'auth'</span> => C(<span class=\"string\">'REDIS_AUTH'</span>) ? C(<span class=\"string\">'REDIS_AUTH'</span>) : <span class=\"literal\">false</span>,</span><br><span class=\"line\"> <span class=\"string\">'dbindex'</span> => C(<span class=\"string\">'REDIS_DBINDEX'</span>) ? C(<span class=\"string\">'REDIS_DBINDEX'</span>) : <span class=\"number\">0</span>, <span class=\"comment\">//选择存库</span></span><br><span class=\"line\"> );</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"variable\">$options</span>[<span class=\"string\">'host'</span>] = explode(<span class=\"string\">','</span>, <span class=\"variable\">$options</span>[<span class=\"string\">'host'</span>]);</span><br><span class=\"line\"> <span class=\"variable\">$options</span>[<span class=\"string\">'port'</span>] = explode(<span class=\"string\">','</span>, <span class=\"variable\">$options</span>[<span class=\"string\">'port'</span>]);</span><br><span class=\"line\"> <span class=\"variable\">$options</span>[<span class=\"string\">'auth'</span>] = explode(<span class=\"string\">','</span>, <span class=\"variable\">$options</span>[<span class=\"string\">'auth'</span>]);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">foreach</span> (<span class=\"variable\">$options</span>[<span class=\"string\">'host'</span>] <span class=\"keyword\">as</span> <span class=\"variable\">$key</span>=><span class=\"variable\">$value</span>) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"keyword\">isset</span>(<span class=\"variable\">$options</span>[<span class=\"string\">'port'</span>][<span class=\"variable\">$key</span>])) {</span><br><span class=\"line\"> <span class=\"variable\">$options</span>[<span class=\"string\">'port'</span>][<span class=\"variable\">$key</span>] = <span class=\"variable\">$options</span>[<span class=\"string\">'port'</span>][<span class=\"number\">0</span>];</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"keyword\">isset</span>(<span class=\"variable\">$options</span>[<span class=\"string\">'auth'</span>][<span class=\"variable\">$key</span>])) {</span><br><span class=\"line\"> <span class=\"variable\">$options</span>[<span class=\"string\">'auth'</span>][<span class=\"variable\">$key</span>] = <span class=\"variable\">$options</span>[<span class=\"string\">'auth'</span>][<span class=\"number\">0</span>];</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->options = <span class=\"variable\">$options</span>;</span><br><span class=\"line\"> <span class=\"variable\">$expire</span> = C(<span class=\"string\">'SESSION_EXPIRE'</span>);</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->options[<span class=\"string\">'expire'</span>] = <span class=\"keyword\">isset</span>(<span class=\"variable\">$expire</span>) ? (<span class=\"keyword\">int</span>)<span class=\"variable\">$expire</span> : (<span class=\"keyword\">int</span>)ini_get(<span class=\"string\">'session.gc_maxlifetime'</span>);;</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->options[<span class=\"string\">'prefix'</span>] = <span class=\"keyword\">isset</span>(<span class=\"variable\">$options</span>[<span class=\"string\">'prefix'</span>]) ? <span class=\"variable\">$options</span>[<span class=\"string\">'prefix'</span>] : C(<span class=\"string\">'SESSION_PREFIX'</span>);</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->options[<span class=\"string\">'dbindex'</span>] = <span class=\"keyword\">isset</span>(<span class=\"variable\">$options</span>[<span class=\"string\">'dbindex'</span>])? <span class=\"variable\">$options</span>[<span class=\"string\">'dbindex'</span>] : <span class=\"number\">0</span>; <span class=\"comment\">//选择存库</span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->handler = <span class=\"keyword\">new</span> \\Redis;</span><br><span class=\"line\"></span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 连接Redis服务端</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> bool $is_master : 是否连接主服务器</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">connect</span>(<span class=\"params\"><span class=\"variable\">$is_master</span> = <span class=\"literal\">true</span></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"variable\">$is_master</span>) {</span><br><span class=\"line\"> <span class=\"variable\">$i</span> = <span class=\"number\">0</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"variable\">$count</span> = count(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'host'</span>]);</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"variable\">$count</span> == <span class=\"number\">1</span>) {</span><br><span class=\"line\"> <span class=\"variable\">$i</span> = <span class=\"number\">0</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"variable\">$i</span> = rand(<span class=\"number\">1</span>, <span class=\"variable\">$count</span> - <span class=\"number\">1</span>); <span class=\"comment\">//多个从服务器随机选择</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"variable\">$func</span> = <span class=\"keyword\">$this</span>->options[<span class=\"string\">'persistent'</span>] ? <span class=\"string\">'pconnect'</span> : <span class=\"string\">'connect'</span>;</span><br><span class=\"line\"> <span class=\"keyword\">try</span> {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"keyword\">$this</span>->options[<span class=\"string\">'timeout'</span>] === <span class=\"literal\">false</span>) {</span><br><span class=\"line\"> <span class=\"variable\">$result</span> = <span class=\"keyword\">$this</span>->handler-><span class=\"variable\">$func</span>(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'host'</span>][<span class=\"variable\">$i</span>], <span class=\"keyword\">$this</span>->options[<span class=\"string\">'port'</span>][<span class=\"variable\">$i</span>]);</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"variable\">$result</span>)</span><br><span class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> \\Think\\<span class=\"built_in\">Exception</span>(<span class=\"string\">'Redis Error'</span>, <span class=\"number\">100</span>);</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"variable\">$result</span> = <span class=\"keyword\">$this</span>->handler-><span class=\"variable\">$func</span>(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'host'</span>][<span class=\"variable\">$i</span>], <span class=\"keyword\">$this</span>->options[<span class=\"string\">'port'</span>][<span class=\"variable\">$i</span>], <span class=\"keyword\">$this</span>->options[<span class=\"string\">'timeout'</span>]);</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"variable\">$result</span>)</span><br><span class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> \\Think\\<span class=\"built_in\">Exception</span>(<span class=\"string\">'Redis Error'</span>, <span class=\"number\">101</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"keyword\">$this</span>->options[<span class=\"string\">'auth'</span>][<span class=\"variable\">$i</span>]) {</span><br><span class=\"line\"> <span class=\"variable\">$result</span> = <span class=\"keyword\">$this</span>->handler->auth(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'auth'</span>][<span class=\"variable\">$i</span>]);</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"variable\">$result</span>) {</span><br><span class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> \\Think\\<span class=\"built_in\">Exception</span>(<span class=\"string\">'Redis Error'</span>, <span class=\"number\">102</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"comment\">//选择db存库</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"number\">0</span> != <span class=\"keyword\">$this</span>->options[<span class=\"string\">'dbindex'</span>]) {</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->handler->select(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'dbindex'</span>]);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> } <span class=\"keyword\">catch</span> ( \\<span class=\"built_in\">Exception</span> <span class=\"variable\">$e</span> ) {</span><br><span class=\"line\"> <span class=\"keyword\">exit</span>(<span class=\"string\">'Error Message:'</span>.<span class=\"variable\">$e</span>->getMessage().<span class=\"string\">'<br>Error Code:'</span>.<span class=\"variable\">$e</span>->getCode().<span class=\"string\">''</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 打开Session</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> string $savePath</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> mixed $sessName</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">open</span>(<span class=\"params\"><span class=\"variable\">$savePath</span>, <span class=\"variable\">$sessName</span></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 关闭Session</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">close</span>(<span class=\"params\"></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"keyword\">$this</span>->options[<span class=\"string\">'persistent'</span>] == <span class=\"string\">'pconnect'</span>) {</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->handler->close();</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 读取Session</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> string $sessID</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">read</span>(<span class=\"params\"><span class=\"variable\">$sessID</span></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->connect(<span class=\"number\">0</span>);</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->get_result = <span class=\"keyword\">$this</span>->handler->get(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'prefix'</span>].<span class=\"variable\">$sessID</span>);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">$this</span>->get_result;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 写入Session</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> string $sessID</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> String $sessData</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">write</span>(<span class=\"params\"><span class=\"variable\">$sessID</span>, <span class=\"variable\">$sessData</span></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!<span class=\"variable\">$sessData</span> || <span class=\"variable\">$sessData</span> == <span class=\"keyword\">$this</span>->get_result) {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->connect(<span class=\"number\">1</span>);</span><br><span class=\"line\"> <span class=\"variable\">$expire</span> = <span class=\"keyword\">$this</span>->options[<span class=\"string\">'expire'</span>];</span><br><span class=\"line\"> <span class=\"variable\">$sessID</span> = <span class=\"keyword\">$this</span>->options[<span class=\"string\">'prefix'</span>].<span class=\"variable\">$sessID</span>;</span><br><span class=\"line\"> <span class=\"keyword\">if</span>(is_int(<span class=\"variable\">$expire</span>) && <span class=\"variable\">$expire</span> > <span class=\"number\">0</span>) {</span><br><span class=\"line\"> <span class=\"variable\">$result</span> = <span class=\"keyword\">$this</span>->handler->setex(<span class=\"variable\">$sessID</span>, <span class=\"variable\">$expire</span>, <span class=\"variable\">$sessData</span>);</span><br><span class=\"line\"> <span class=\"variable\">$re</span> = <span class=\"variable\">$result</span> ? <span class=\"string\">'true'</span> : <span class=\"string\">'false'</span>;</span><br><span class=\"line\"> }<span class=\"keyword\">else</span>{</span><br><span class=\"line\"> <span class=\"variable\">$result</span> = <span class=\"keyword\">$this</span>->handler->set(<span class=\"variable\">$sessID</span>, <span class=\"variable\">$sessData</span>);</span><br><span class=\"line\"> <span class=\"variable\">$re</span> = <span class=\"variable\">$result</span> ? <span class=\"string\">'true'</span> : <span class=\"string\">'false'</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"variable\">$result</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 删除Session</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> string $sessID</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">destroy</span>(<span class=\"params\"><span class=\"variable\">$sessID</span></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->connect(<span class=\"number\">1</span>);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">$this</span>->handler->delete(<span class=\"keyword\">$this</span>->options[<span class=\"string\">'prefix'</span>].<span class=\"variable\">$sessID</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Session 垃圾回收</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> string $sessMaxLifeTime</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">gc</span>(<span class=\"params\"><span class=\"variable\">$sessMaxLifeTime</span></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"literal\">true</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 打开Session</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@access</span> public</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> string $savePath</span></span><br><span class=\"line\"><span class=\"comment\"> * <span class=\"doctag\">@param</span> mixed $sessName</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">execute</span>(<span class=\"params\"></span>) </span>{</span><br><span class=\"line\"> session_set_save_handler(</span><br><span class=\"line\"> <span class=\"keyword\">array</span>(&<span class=\"keyword\">$this</span>, <span class=\"string\">"open"</span>),</span><br><span class=\"line\"> <span class=\"keyword\">array</span>(&<span class=\"keyword\">$this</span>, <span class=\"string\">"close"</span>),</span><br><span class=\"line\"> <span class=\"keyword\">array</span>(&<span class=\"keyword\">$this</span>, <span class=\"string\">"read"</span>),</span><br><span class=\"line\"> <span class=\"keyword\">array</span>(&<span class=\"keyword\">$this</span>, <span class=\"string\">"write"</span>),</span><br><span class=\"line\"> <span class=\"keyword\">array</span>(&<span class=\"keyword\">$this</span>, <span class=\"string\">"destroy"</span>),</span><br><span class=\"line\"> <span class=\"keyword\">array</span>(&<span class=\"keyword\">$this</span>, <span class=\"string\">"gc"</span>)</span><br><span class=\"line\"> );</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">__destruct</span>(<span class=\"params\"></span>) </span>{</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"keyword\">$this</span>->options[<span class=\"string\">'persistent'</span>] == <span class=\"string\">'pconnect'</span>) {</span><br><span class=\"line\"> <span class=\"keyword\">$this</span>->handler->close();</span><br><span class=\"line\"> }</span><br><span class=\"line\"> session_write_close();</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","PHP"],"tags":["PHP"]},{"title":"Linux两台服务器之间免密登录方法","url":"/2.Programming/4.Shell/Linux%E4%B8%A4%E5%8F%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B9%8B%E9%97%B4%E5%85%8D%E5%AF%86%E7%99%BB%E5%BD%95%E6%96%B9%E6%B3%95/","content":"<p>搭建集群机器192.168.0.100和192.168.0.200里,需要两台机器中间相互拷贝文件:</p>\n<p>方式一:下载192.168.0.100机器文件到本地,再将本地文件拷贝到B机器</p>\n<p>方式二:192.168.0.100#scp -r /home/test <a href=\"mailto:root@192.168.0.200\">root@192.168.0.200</a>:/home/</p>\n<p>linux命令scp可以在两台服务器192.168.0.100和192.168.0.200之间互传文件。第一次会提示授权操作,输入yes后在输入root用户的密码,会将192.168.0.100机器的/home/test文件拷贝到192.168.0.200机器的/home下。</p>\n<p>现每次192.168.0.100和192.168.0.200之间互传文件都要输入密码比较麻烦,现介绍一种采用公钥/私钥认证的方式去掉密码登录。</p>\n<p>注意点:</p>\n<p>1.互传文件为同一登录用户root</p>\n<p>2.秘钥存放位置为当前登录用户下 #cd ~/.ssh 可查看</p>\n<h2 id=\"创建一个ssh-key\"><a href=\"#创建一个ssh-key\" class=\"headerlink\" title=\"创建一个ssh key\"></a>创建一个ssh key</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">192.168.0.100机器执行如下代码:</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh-keygen -t rsa -C <span class=\"string\">"your_email@example.com"</span> -t rsa-test</span></span><br></pre></td></tr></table></figure>\n\n<p>代码中各个参数含义为:</p>\n<p>-t 指定密钥类型,默认是 rsa ,可以省略</p>\n<p>-C 设置注释文字,比如邮箱,可以忽略</p>\n<p>-f 指定密钥文件存储文件名,使用默认文件名(推荐);那么可以看到生成的两个文件 <code>id_rsa</code> <code>id_rsa.pub(id_rsa这个叫私钥;id_rsa.pub这个叫公钥)</code></p>\n<p>接着又会提示你输入两次密码(该密码是你push文件的时候要输入的密码,而不是github管理者的密码),</p>\n<p>当然,你也可以不输入密码,直接按回车。那么push的时候就不需要输入密码,直接提交到github上了,如:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">Enter passphrase (empty for no passphrase): </span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> Enter same passphrase again:</span></span><br></pre></td></tr></table></figure>\n\n<p>接下来,就会显示如下代码提示,如:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">Your identification has been saved in /c/Users/you/.ssh/id_rsa.</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> Your public key has been saved <span class=\"keyword\">in</span> /c/Users/you/.ssh/id_rsa.pub.</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> The key fingerprint is:</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 01:0f:f4:3b:ca:85:d6:17:a1:7d:f0:68:9d:f0:a2:db your_email@example.com</span></span><br></pre></td></tr></table></figure>\n\n<p>当你看到上面这段代码的收,那就说明,你的 SSH key 已经创建成功,你只需要添加到github的SSH key上就可以了。</p>\n<h2 id=\"将机器192-168-0-100上的公钥发送到机器192-168-0-200的-ssh-authorized-keys里\"><a href=\"#将机器192-168-0-100上的公钥发送到机器192-168-0-200的-ssh-authorized-keys里\" class=\"headerlink\" title=\"将机器192.168.0.100上的公钥发送到机器192.168.0.200的~.ssh/authorized_keys里\"></a>将机器192.168.0.100上的公钥发送到机器192.168.0.200的~.ssh/authorized_keys里</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">服务器为:192.168.0.100</span><br><span class=\"line\">192.168.0.100# scp /home/root/.ssh/id_rsa.pub root@192.168.0.200:/home/root/.ssh</span><br><span class=\"line\">服务器为:192.168.0.200</span><br><span class=\"line\">192.168.0.200#cd ~/.ssh</span><br><span class=\"line\">192.168.0.200#cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys</span><br></pre></td></tr></table></figure>\n\n<p>注意:如192.168.0.200机器的/home/root/.ssh下存在id_rsa.pub会将文件内容覆盖,因此我们可以将新公钥进行文件的追加。</p>\n<h2 id=\"\"><a href=\"#\" class=\"headerlink\" title=\"\"></a></h2><h2 id=\"执行复制操作\"><a href=\"#执行复制操作\" class=\"headerlink\" title=\"执行复制操作\"></a>执行复制操作</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">192.168.0.100#scp -r /home/test root@192.168.0.200:/home/</span><br></pre></td></tr></table></figure>\n\n<p>如还需要密码,则在192.168.0.200服务器里的<code>/etc/ssh/sshd_config</code>文件,关键字<code>PubkeyAuthentication</code> 确保这个值是 <code>yes;</code>若这个<code>sshd_config</code>有修改,则需要重启sshd(#service sshd restart)</p>\n<h2 id=\"权限问题\"><a href=\"#权限问题\" class=\"headerlink\" title=\"权限问题\"></a>权限问题</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">192.168.0.200服务器里查看:</span><br><span class=\"line\">/home/root`文件夹的权限为 700,即 显示的权限应该是 `drwx------</span><br><span class=\"line\">/home/root/.ssh`文件夹的权限也为700</span><br><span class=\"line\">`/home/root/.ssh/authorized_keys` 文件权限为600,即,显示的权限应该是 `-rw-------</span><br></pre></td></tr></table></figure>\n\n<p> 完毕之后,退出服务器的登录,再使用ssh登录,你就会发现服务器不会再向你询问密码了.</p>\n<h2 id=\"调试\"><a href=\"#调试\" class=\"headerlink\" title=\"调试\"></a>调试</h2><p>192.168.0.100# ssh <a href=\"mailto:admin@192.168.0.200\">admin@192.168.0.200</a> -vvv</p>\n<h2 id=\"问题总结\"><a href=\"#问题总结\" class=\"headerlink\" title=\"问题总结\"></a><strong>问题总结</strong></h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">目标机器配置SSH</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">vi /etc/ssh/sshd_config</span></span><br><span class=\"line\">//更改为下面行</span><br><span class=\"line\">PermitRootLogin yes</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">systemctl restart sshd</span> </span><br></pre></td></tr></table></figure>\n\n<p><a href=\"https://community.qingcloud.com/topic/1140/%E5%85%B3%E4%BA%8Essh%E6%97%A0%E6%B3%95%E7%99%BB%E9%99%86%E7%9A%84%E6%8E%92%E6%9F%A5%E6%80%9D%E8%B7%AF\">关于ssh无法登陆的排查思路</a></p>\n<p><a href=\"https://blog.csdn.net/menghuanbeike/article/details/78958015\">SSH远程登录配置文件sshd_config详解</a></p>\n","categories":["2.Programming","Shell"],"tags":["Shell"]},{"title":"Linux设置网络延迟丢包操作","url":"/2.Programming/4.Shell/Linux%E8%AE%BE%E7%BD%AE%E7%BD%91%E7%BB%9C%E5%BB%B6%E8%BF%9F%E4%B8%A2%E5%8C%85%E6%93%8D%E4%BD%9C/","content":"<h2 id=\"tc方式\"><a href=\"#tc方式\" class=\"headerlink\" title=\"tc方式\"></a>tc方式</h2><p>* 清除设备策略:tc qdisc del root dev eth2 2>/dev/null<br>* 设置设备策略:tc qdisc add dev eth0 root netem loss 5%</p>\n<p>tc qdisc add dev eth2 root netem loss 5%<br>tc qdisc add dev eth2 root netem delay 200ms<br>tc qdisc add dev eth2 root netem delay 200ms loss 5%<br>tc qdisc add dev eth2 root netem delay 400ms</p>\n<h2 id=\"comcast方式\"><a href=\"#comcast方式\" class=\"headerlink\" title=\"comcast方式\"></a>comcast方式</h2><p><a href=\"https://github.com/tylertreat/comcast\">https://github.com/tylertreat/comcast</a></p>\n<h2 id=\"iptables方式\"><a href=\"#iptables方式\" class=\"headerlink\" title=\"iptables方式\"></a>iptables方式</h2>","categories":["2.Programming","Shell"],"tags":["Shell"]},{"title":"Linux增加开机自启动脚本","url":"/2.Programming/4.Shell/Linux%E5%A2%9E%E5%8A%A0%E5%BC%80%E6%9C%BA%E8%87%AA%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC/","content":"<h3 id=\"在rc-local脚本中添加开机自启动程序\"><a href=\"#在rc-local脚本中添加开机自启动程序\" class=\"headerlink\" title=\"在rc.local脚本中添加开机自启动程序\"></a>在rc.local脚本中添加开机自启动程序</h3><p><img src=\"/images/20191226-1.png\" alt=\"shell\"></p>\n<p><img src=\"/images/20191226-2.png\" alt=\"shell\"></p>\n","categories":["2.Programming","Shell"],"tags":["Shell"]},{"title":"SSH远程执行命令","url":"/2.Programming/4.Shell/SSH%E8%BF%9C%E7%A8%8B%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4/","content":"<h2 id=\"参考\"><a href=\"#参考\" class=\"headerlink\" title=\"参考\"></a>参考</h2><p><a href=\"https://blog.csdn.net/liuxiao723846/article/details/82667482\">SSH远程执行命令</a></p>\n<p>SSH 是 Linux 下进行远程连接的基本工具,不光可以登录,也可以远程操作。接下来我们详细讲解一些常用的情况。</p>\n<h2 id=\"执行简单的命令\"><a href=\"#执行简单的命令\" class=\"headerlink\" title=\"执行简单的命令\"></a>执行简单的命令</h2><p><strong>1、查看某台主机上的磁盘使用情况</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@1.113.195.138 <span class=\"string\">"df -h"</span></span></span><br><span class=\"line\">***************************************************************************</span><br><span class=\"line\">NOTICE TO Users</span><br><span class=\"line\"></span><br><span class=\"line\">This computer system is the private property of ...</span><br><span class=\"line\"></span><br><span class=\"line\">***************************************************************************</span><br><span class=\"line\"></span><br><span class=\"line\">Filesystem Size Used Avail Use% Mounted on</span><br><span class=\"line\">/dev/vda2 36G 3.2G 31G 10% /</span><br><span class=\"line\">tmpfs 25G 0 25G 0% /dev/shm</span><br><span class=\"line\">/dev/vdb 296G 2.0G 279G 1% /data</span><br></pre></td></tr></table></figure>\n\n<p>可以看到会把ssh远程连接的信息,以及远程执行名的返回的信息都输出到了控制台上。</p>\n<p><strong>2、保存远程执行命令结果</strong></p>\n<p>有时我们需要保存远程执行命令的结果,然后进行判断。有两种方法:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">赋值的方式:result=`ssh x@B ~/command.sh`</span><br><span class=\"line\">追加到文件:ssh root@$ip "cmd" >> ./log</span><br></pre></td></tr></table></figure>\n\n<p>详情见:<a href=\"https://blog.csdn.net/liuxiao723846/article/details/55045988\">https://blog.csdn.net/liuxiao723846/article/details/55045988</a></p>\n<p><strong>3、一次执行多个命令</strong></p>\n<p>在shell中单行语句一般要用到分号来区分代码块,多行的话用换行符来区分代码块,则无需用到分号。</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> <span class=\"keyword\">if</span> [ <span class=\"string\">"<span class=\"variable\">$PS1</span>"</span> ]; <span class=\"keyword\">then</span> <span class=\"built_in\">echo</span> <span class=\"built_in\">test</span> is ok; <span class=\"keyword\">fi</span></span></span><br><span class=\"line\">test is ok</span><br><span class=\"line\"></span><br><span class=\"line\">如果换做多行</span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"><span class=\"keyword\">if</span> [ <span class=\"string\">"PS1"</span> ]</span></span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"> <span class=\"keyword\">then</span> <span class=\"built_in\">echo</span> <span class=\"string\">"test is ok"</span></span></span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"> <span class=\"keyword\">fi</span></span></span><br><span class=\"line\">test is ok</span><br></pre></td></tr></table></figure>\n\n<p>所以,我们可以在ssh中用分好拼接多个命令</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">1 ssh root@$IP "if [ -e /lib64/libpcre.so.1 ];then echo 'file exits...';else cd /lib64 && ln -s libpcre.so.0.0.1 libpcre.so.1;fi"</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"执行需要交互的命令\"><a href=\"#执行需要交互的命令\" class=\"headerlink\" title=\"执行需要交互的命令\"></a>执行需要交互的命令</h2><p>有时候我们需要远程执行一些有交互操作的命令,如下:</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"code\"><pre><span class=\"line\">$ ssh nick@xxx.xxx.xxx.xxx <span class=\"string\">"sudo ls /root"</span></span><br><span class=\"line\">$ ssh nick@xxx.xxx.xxx.xxx <span class=\"string\">"top"</span></span><br></pre></td></tr></table></figure>\n\n<p><img src=\"/images/20191016-3.png\" alt=\"images\"></p>\n<p>这两条命令虽然提示的失败原因不同,但它们有一个共同点:都需要与用户交互(需要 TTY)。所以它们失败的原因也是相同的:<br>默认情况下,当你执行不带命令的 ssh 连接时,会为你分配一个 TTY。因为此时你应该是想要运行一个 shell 会话。<br>但是当你通过 ssh 在远程主机上执行命令时,并不会为这个远程会话分配 TTY。此时 ssh 会立即退出远程主机,所以需要交互的命令也随之结束。<br>好在我们可以通过 -t 参数显式的告诉 ssh,我们需要一个 TTY 远程 shell 进行交互!<br>添加 -t 参数后,ssh 会保持登录状态,直到你退出需要交互的命令。</p>\n<h2 id=\"执行本地脚本\"><a href=\"#执行本地脚本\" class=\"headerlink\" title=\"执行本地脚本\"></a>执行本地脚本</h2><p>通常我们遇到的不会是上面那种简单的问题,大多数时候我们需要把若干个命令放到一个脚本里,然后分发到远程去执行。大致有两种思路:</p>\n<p>使用scp将本地脚本文件拷贝到远端,然后再通过ssh执行远端的脚本;(弊端是脚本修改后,每次都需要scp)<br>直接在本地执行脚本到远程;<br>一个scp的例子</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">for IP in ${IP_ARR[@]}</span><br><span class=\"line\">do</span><br><span class=\"line\">ssh root@$IP "rm -rf $MONITOR_TARGET_FILE" </span><br><span class=\"line\">ssh root@$IP "mkdir -p /data/apps/scripts"</span><br><span class=\"line\">scp $MONITOR_SOURCE_FILE root@$IP:$MONITOR_TARGET_FILE</span><br><span class=\"line\">ssh root@$IP 'echo "*/1 * * * * /usr/bin/python /data/apps/scripts/checkStatus.py' $BUSINESS_TYPE '>/dev/null 2>&1" >> /var/spool/cron/root'</span><br><span class=\"line\"> </span><br><span class=\"line\">done</span><br></pre></td></tr></table></figure>\n\n<p>重点我们在如何在本地执行脚本到远程。</p>\n<p><strong>1、执行一个简单的脚本到远程:</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> cat test.sh</span> </span><br><span class=\"line\">ls</span><br><span class=\"line\">pwd</span><br><span class=\"line\"> </span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@10.153.195.138 < test.sh</span> </span><br><span class=\"line\">anaconda-ks.cfg</span><br><span class=\"line\">/root</span><br></pre></td></tr></table></figure>\n\n<p>通过重定向 stdin,本地的脚本 test.sh 在远程服务器上被执行。</p>\n<p><strong>2、为脚本传递参数:</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> cat test.sh</span> </span><br><span class=\"line\">echo $1</span><br><span class=\"line\">echo $2</span><br><span class=\"line\"> </span><br><span class=\"line\">在本地执行结构如下:</span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> sh test.sh a b</span></span><br><span class=\"line\">a</span><br><span class=\"line\">b</span><br><span class=\"line\"></span><br><span class=\"line\">通过重定向远程执行,会报错</span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@10.153.195.138 < test.sh a b</span></span><br><span class=\"line\">bash: a: command not found</span><br></pre></td></tr></table></figure>\n\n<p>看来上面的方法都无法为脚本传递参数。<br>要想在这种情况下(远程执行本地的脚本)执行带有参数的脚本,需要为 bash 指定 -s 参数:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@10.153.195.138 <span class=\"string\">'bash -s'</span> < test.sh a b</span></span><br><span class=\"line\">a</span><br><span class=\"line\">b</span><br></pre></td></tr></table></figure>\n\n<p>除此之外,我们还可以通过替换的方式传参,然后远程执行,例如:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">cat ./rollback_remote.sh | sed -e "s/#module#/${MODULE_NAME}/g" -e "s/#runarg#/${RUN_ARG}/g" | ssh $IP</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"执行远程服务器上的脚本\"><a href=\"#执行远程服务器上的脚本\" class=\"headerlink\" title=\"执行远程服务器上的脚本\"></a>执行远程服务器上的脚本</h2><p>除了执行本地的脚本,还有一种情况是脚本文件存放在远程服务器上,而我们需要远程的执行它!此时在远程服务器上用户 nick 的家目录中有一个脚本 test.sh。文件的内容如下:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">ls</span><br><span class=\"line\">pwd</span><br><span class=\"line\">执行下面的命令即可(注:一定是绝对路径):</span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh nick@xxx.xxx.xxx.xxx <span class=\"string\">"/home/nick/test.sh"</span></span></span><br></pre></td></tr></table></figure>\n\n<p>下面我们也尝试为脚本传递参数。在远程主机上的 test.sh 文件的末尾添加两行:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">echo $0</span><br><span class=\"line\">echo $1</span><br><span class=\"line\">然后尝试执行下面的命令:</span><br><span class=\"line\"> </span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh nick@xxx.xxx.xxx.xxx /home/nick/test.sh helloworld</span></span><br></pre></td></tr></table></figure>\n\n<p>可以正确得到结果。</p>\n<h2 id=\"执行多行命令\"><a href=\"#执行多行命令\" class=\"headerlink\" title=\"执行多行命令\"></a>执行多行命令</h2><p>有时候我们可能需要随手写几行简单的逻辑,这也没有问题,ssh 能轻松搞定!</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@10.153.195.138 <span class=\"string\">"</span></span> </span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"> ls</span></span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"> <span class=\"built_in\">pwd</span></span></span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"> <span class=\"string\">"</span></span></span><br><span class=\"line\">anaconda-ks.cfg</span><br><span class=\"line\">/root</span><br></pre></td></tr></table></figure>\n\n<p>你可以用单引号或双引号开头,然后写上几行命令,最后再用相同的引号来结束。</p>\n<p>当我们在命令中引用了变量时会怎么样呢?</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> name=<span class=\"built_in\">test</span></span></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@10.153.195.138 <span class=\"string\">"</span></span></span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"> <span class=\"built_in\">echo</span> <span class=\"variable\">$name</span></span></span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"> <span class=\"string\">"</span></span></span><br><span class=\"line\">test</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@10.153.195.138 <span class=\"string\">'</span></span></span><br><span class=\"line\">echo $name</span><br><span class=\"line\">'</span><br></pre></td></tr></table></figure>\n\n<p>最后一行,并没有输出我们期望的 test。这里多少有些诡异,因为如果变量没有被解释的话,输出的应该是 $name 才对。但是这里却什么都没有输出。对于引用变量的写法,可以通过bash 指定了 -c 参数方式保证变量被正确解释:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@10.153.195.138 bash -c <span class=\"string\">"'</span></span></span><br><span class=\"line\">echo $name</span><br><span class=\"line\">'"</span><br><span class=\"line\">test</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Shell"],"tags":["Shell"]},{"title":"Shell增加定时任务","url":"/2.Programming/4.Shell/Shell%E5%A2%9E%E5%8A%A0%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/","content":"<h4 id=\"增加定时任务\"><a href=\"#增加定时任务\" class=\"headerlink\" title=\"增加定时任务\"></a>增加定时任务</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">CRON_FILE=<span class=\"string\">"/var/spool/cron/root"</span> (centos系统)</span></span><br><span class=\"line\">CRON_FILE="/var/spool/cron/crontabs/root"(ubantu系统)</span><br><span class=\"line\">grep "cron_one_min.sh" ${CRON_FILE}|| echo "01 * * * * bash /data/server/cron/one_min.sh" >> ${CRON_FILE}</span><br></pre></td></tr></table></figure>\n\n<h4 id=\"查看定时任务\"><a href=\"#查看定时任务\" class=\"headerlink\" title=\"查看定时任务\"></a>查看定时任务</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">crontab -l</span></span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Shell"],"tags":["Shell"]},{"title":"rsync使用","url":"/2.Programming/4.Shell/rsync%E4%BD%BF%E7%94%A8/","content":"<p>在使用jenkins当跳板机的场景下,有使用git pull 代码到jenkins机器后,需要将代码复制到另一台机器上,常用的复制命令有scp和rsync;现就使用到了rsync进行详解:</p>\n<p>rsync是一种快速且通用的文件复制工具,以其Delta传输算法,通过仅发送源文件和目标文件中现有文件之间的差异来减少网络发送的数据量。</p>\n<h3 id=\"常用参数:\"><a href=\"#常用参数:\" class=\"headerlink\" title=\"常用参数:\"></a>常用参数:</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">-z:传输时进行压缩提高效率</span><br><span class=\"line\">-v:显示rsync过程中详细信息。可以使用"-vvvv"获取更详细信息</span><br><span class=\"line\">-P:显示文件传输的进度信息</span><br><span class=\"line\">-a --archive:归档模式,表示递归传输并保持文件属性,等同于"-rtopgDl"</span><br><span class=\"line\">-r --recursive:以递归模式拷贝目录</span><br><span class=\"line\">-R --relative:使用相对路径</span><br><span class=\"line\">-l --links:如果文件是软链接,则拷贝软链接本身而非软链接所指向的文件</span><br><span class=\"line\">-L --copy-links:如果文件是软链接,拷贝软链接指向的文件</span><br><span class=\"line\">-W --whole-file:拷贝文件时不进行增量检测</span><br><span class=\"line\">-t --times:保持 mtime 属性</span><br><span class=\"line\"></span><br><span class=\"line\">rsync 默认用"quick check"算法决定哪些文件需要增量传输。此算法只比较文件的大小和 mtime,即使其它属性不同也会认为它们是完全相同的文件,从而不需要增量传输</span><br><span class=\"line\">建议任何时候都加上"-t",否则目标文件 mtime 会设置为系统时间,导致下次更新检查出 mtime 不同而导致增量传输无效</span><br><span class=\"line\"></span><br><span class=\"line\">实际工作中使用-avz即可 </span><br></pre></td></tr></table></figure>\n\n<h3 id=\"使用(重要):\"><a href=\"#使用(重要):\" class=\"headerlink\" title=\"使用(重要):\"></a>使用(重要):</h3><p>源路径如果为目录,不带斜线表示目录本身和目录中的文件,带斜线表示目录中的文件,不包括本身</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 复制远程计算机 foo 上的 /src/bar/ 目录中的文件到本地 /data/tmp 目录中</span></span><br><span class=\"line\">rsync -avz foo:/src/bar/ /data/tmp</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 复制远程计算机 foo 上的 /src/bar/ 目录到本地 /data/tmp 目录中</span></span><br><span class=\"line\">rsync -avz foo:/src/bar /data/tmp</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 以下命令等效</span></span><br><span class=\"line\">rsync -av /src/foo /dest</span><br><span class=\"line\">rsync -av /src/foo/ /dest/foo</span><br></pre></td></tr></table></figure>\n\n<p>文件名(* .c)中的通配符扩展为文件列表由 shell 在运行 rsync 之前处理,而不是由 rsync 本身处理</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 复制当前路径下所有以 .c 结尾的文件至远程计算机 foo 的 /src 目录中</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 对于远程系统上已存在的文件,会使用 rsync 远程更新协议,通过仅发送数据中的差异来更新文件</span></span><br><span class=\"line\">rsync -t *.c foo:/src/</span><br></pre></td></tr></table></figure>\n\n","categories":["2.Programming","Shell"],"tags":["Shell"]},{"title":"Shell处理MySQL增删改查","url":"/2.Programming/4.Shell/Shell%E5%A4%84%E7%90%86MySQL%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5/","content":"<p>这几天做一个任务,比对两个数据表中的数据,昨天用PHP写了一个版本,但考虑到有的机器没有php或者php没有编译mysql扩展,就无法使用mysql系列的函数,脚本就无效了,今天写个shell版本的,这样,在所有linux系列机器上就都可以运行了。</p>\n<p> shell操作mysql其实就是通过mysql命令通过参数去执行语句,跟其他程序里面是一样的,看看下面这个参数:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">-e, --execute=name Execute command and quit. (Disables --force and history file.)</span><br></pre></td></tr></table></figure>\n\n<p>因此我们可以通过mysql -e来执行语句,就像下面这样:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">mysql -hlocalhost -P3306 -uroot -p123456 $test --default-character-set=utf8 -e "select * from users"</span><br></pre></td></tr></table></figure>\n\n<p>执行之后返回下面结果:<br><img src=\"/images/20200921-1.png\" alt=\"images\"></p>\n<h3 id=\"在shell脚本中操作mysql\"><a href=\"#在shell脚本中操作mysql\" class=\"headerlink\" title=\"在shell脚本中操作mysql\"></a>在shell脚本中操作mysql</h3><h4 id=\"导出数据\"><a href=\"#导出数据\" class=\"headerlink\" title=\"导出数据\"></a>导出数据</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">MYSQL="mysql -h192.168.1.102 -uroot -p123456 --default-character-set=utf8 -A -N"</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">这里面有两个参数,-A、-N,-A的含义是不去预读全部数据表信息,这样可以解决在数据表很多的时候卡死的问题</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">-N,很简单,Don<span class=\"string\">'t write column names in results,获取的数据信息省去列名称</span></span></span><br><span class=\"line\">sql="select * from test.user"</span><br><span class=\"line\">result="$($MYSQL -e "$sql")"</span><br><span class=\"line\"></span><br><span class=\"line\">dump_data=./data.user.txt</span><br><span class=\"line\"><span class=\"meta\">></span><span class=\"bash\"><span class=\"variable\">$dump_data</span></span></span><br><span class=\"line\">echo -e "$result" > $dump_data</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">这里要额外注意,<span class=\"built_in\">echo</span> -e <span class=\"string\">"<span class=\"variable\">$result</span>"</span> > <span class=\"variable\">$dump_data</span>的时候一定要加上双引号,不让导出的数据会挤在一行</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">下面是返回的测试数据</span></span><br><span class=\"line\">3 吴彦祖 32</span><br><span class=\"line\">5 王力宏 32</span><br><span class=\"line\">6 ab 32</span><br><span class=\"line\">7 黄晓明 33</span><br><span class=\"line\">8 anonymous 32</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"插入数据\"><a href=\"#插入数据\" class=\"headerlink\" title=\"插入数据\"></a>插入数据</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">先看看要导入的数据格式,三列,分别是id,名字,年龄(数据是随便捏造的),放入data.user.txt</span></span><br><span class=\"line\">12 tf 23</span><br><span class=\"line\">13 米勒 24</span><br><span class=\"line\">14 西安电子科技大学 90</span><br><span class=\"line\">15 西安交大 90</span><br><span class=\"line\">16 北京大学 90</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">OLF_IFS=<span class=\"variable\">$IFS</span></span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">IFS=<span class=\"string\">","</span></span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">临时设置默认分隔符为逗号</span></span><br><span class=\"line\">cat data.user.txt | while read id name age</span><br><span class=\"line\">do</span><br><span class=\"line\"> sql="insert into test.user(id, name, age) values(${id}, '${name}', ${age});"</span><br><span class=\"line\"> $MYSQL -e "$sql"</span><br><span class=\"line\">done</span><br></pre></td></tr></table></figure>\n\n<p>输出结果:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">+----+--------------------------+-----+</span><br><span class=\"line\">| id | name | age |</span><br><span class=\"line\">+----+--------------------------+-----+</span><br><span class=\"line\">| 12 | tf | 23 |</span><br><span class=\"line\">| 13 | 米勒 | 24 |</span><br><span class=\"line\">| 14 | 西安电子科技大学 | 90 |</span><br><span class=\"line\">| 15 | 西安交大 | 90 |</span><br><span class=\"line\">| 16 | 北京大学 | 90 |</span><br><span class=\"line\">+----+--------------------------+-----+</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"更新数据\"><a href=\"#更新数据\" class=\"headerlink\" title=\"更新数据\"></a>更新数据</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">先看看更新数据的格式,将左边一列替换为右边一列,只有左边一列的删除,下面数据放入update.user.txt</span></span><br><span class=\"line\">tf twoFile</span><br><span class=\"line\">西安电子科技大学 西军电</span><br><span class=\"line\">西安交大 西安交通大学</span><br><span class=\"line\">北京大学</span><br><span class=\"line\"></span><br><span class=\"line\">cat update.user.txt | while read src dst</span><br><span class=\"line\">do</span><br><span class=\"line\"> if [ ! -z "${src}" -a ! -z "${dst}" ]</span><br><span class=\"line\"> then</span><br><span class=\"line\"> sql="update test.user set name='${dst}' where name='${src}'"</span><br><span class=\"line\"> fi</span><br><span class=\"line\"> if [ ! -z "${src}" -a -z "${dst}" ]</span><br><span class=\"line\"> then</span><br><span class=\"line\"> sql="delete from test.user where name='${src}'"</span><br><span class=\"line\"> fi</span><br><span class=\"line\"> $MYSQL -e "$sql"</span><br><span class=\"line\">done</span><br></pre></td></tr></table></figure>\n\n<p>输出结果:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">+----+--------------------------+-----+</span><br><span class=\"line\">| id | name | age |</span><br><span class=\"line\">+----+--------------------------+-----+</span><br><span class=\"line\">| 12 | twoFile | 23 |</span><br><span class=\"line\">| 13 | 米勒 | 24 |</span><br><span class=\"line\">| 14 | 西军电 | 90 |</span><br><span class=\"line\">| 15 | 西安交通大学 | 90 |</span><br><span class=\"line\">+----+--------------------------+-----+</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"dump数据到sql文件\"><a href=\"#dump数据到sql文件\" class=\"headerlink\" title=\"dump数据到sql文件\"></a>dump数据到sql文件</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">利用mysqldump这个命令可以很轻松的导出所有数据的sql语句到指定文件</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">导出root@localhost下面的exp.Opes中的所有数据到tt.sql</span></span><br><span class=\"line\">mysqldump -h localhost -u root -p exp Opes > ./tt.sql</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">回车之后输入密码就可以将所有sql语句输出到tt.sql</span></span><br></pre></td></tr></table></figure>\n\n<h4 id=\"导入数据到mysql数据库\"><a href=\"#导入数据到mysql数据库\" class=\"headerlink\" title=\"导入数据到mysql数据库\"></a>导入数据到mysql数据库</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">设置编码,不然可能出现乱码</span></span><br><span class=\"line\">mysql -hlocalhost -uroot --default-character-set=gbk -p exp< ./tt.sql</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">回车之后输入密码,导入tt.sql中的所有数据到exp数据库中</span></span><br></pre></td></tr></table></figure>\n\n\n","categories":["2.Programming","Shell"],"tags":["MySQL","Shell"]},{"title":"使用Shell登录远程服务器执行多条命令,SSH登录之后执行脚本文件","url":"/2.Programming/4.Shell/%E4%BD%BF%E7%94%A8Shell%E7%99%BB%E5%BD%95%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%89%A7%E8%A1%8C%E5%A4%9A%E6%9D%A1%E5%91%BD%E4%BB%A4%EF%BC%8CSSH%E7%99%BB%E5%BD%95%E4%B9%8B%E5%90%8E%E6%89%A7%E8%A1%8C%E8%84%9A%E6%9C%AC%E6%96%87%E4%BB%B6/","content":"<h4 id=\"参考:\"><a href=\"#参考:\" class=\"headerlink\" title=\"参考:\"></a>参考:</h4><p><a href=\"https://blog.csdn.net/qq_36622490/article/details/100773589\">使用Shell登录远程服务器执行多条命令,SSH登录之后执行脚本文件</a></p>\n<p>这个需求主要是我在jenkins中pipeline的代码里,需要使用shell语言执行远程连接并且部署的工作,但是大多数的shell和服务器交互是使用expect解释器 就是之前我写过的那个关于expect有关的文章,问题是jenkins中默认的shell解释器只有bash,不能更改解释器的。所以就很难受,国内的百度基本都是搬运过来的内容,毫无意义,浪费时间,在国外博客浪荡几天之后终于找到了解决方案。</p>\n<p>下面我来分享一下,大致意思呢就是执行完ssh 连接远程主机之后需要执行的命令,可以进行如下操作,命令不要照抄,换成你自己的user名和ip地址。</p>\n<p><strong>【我在我自己电脑和服务器之间都配置了ssh免密码登录 直接使用ssh IP地址就可以登录了,强烈建议配置ssh,非常方便】</strong></p>\n<h4 id=\"登录远程主机执行单条命令\"><a href=\"#登录远程主机执行单条命令\" class=\"headerlink\" title=\"登录远程主机执行单条命令\"></a>登录远程主机执行单条命令</h4><p>登录完主机之后执行一条命令</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh USER@HOST <span class=\"string\">'COMMAND'</span></span></span><br></pre></td></tr></table></figure>\n\n<p>获取远程主机的最新更新时间</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@192.168.1.1 <span class=\"string\">'uptime'</span></span></span><br></pre></td></tr></table></figure>\n\n<p>登录完远程主机就进行重启远程主机</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> ssh root@192.168.1.1 <span class=\"string\">'reboot'</span></span></span><br></pre></td></tr></table></figure>\n\n<p>那么问题出来了,上面的都是执行一条命令,那如果我需要执行多条命令怎么办呢?之前困扰我最大的问题就是这个,执行多条命令,虽然直接堆叠多条ssh 登录的语句 那些前缀也可以,但是看着就恶心。这样我们就可以使用以下几个方案,原内容如下,我做了备注,这样比较一目了然。</p>\n<h4 id=\"登录远程主机执行多条命令\"><a href=\"#登录远程主机执行多条命令\" class=\"headerlink\" title=\"登录远程主机执行多条命令\"></a>登录远程主机执行多条命令</h4><p>\u000b<img src=\"/images/20191016-1.png\" alt=\"images\"></p>\n<p> 可能还有小伙伴会问,如果需要ssh登录远程之后执行指定的脚本文件怎么做?</p>\n<h4 id=\"登录远程主机执行指定脚本文件\"><a href=\"#登录远程主机执行指定脚本文件\" class=\"headerlink\" title=\"登录远程主机执行指定脚本文件\"></a>登录远程主机执行指定脚本文件</h4><p><img src=\"/images/20191016-2.png\" alt=\"images\"></p>\n<p>由此来看,英文还是非常重要的。不然遇到问题你都不知道怎么去搜了,不是我埋汰百度,确实国内搬运回答问题现象太严重,点进去一个除了站点不一样 内容都一样 连错别字都一样,如果你是经常和计算机打交道的一定下载个谷歌浏览器,必须可以使用谷歌,可以配置插件或者配置翻墙设备。</p>\n","categories":["2.Programming","Shell"],"tags":["Shell"]},{"title":"CDN简述","url":"/3.Testing/Others/CDN%E7%AE%80%E8%BF%B0/","content":"<h2 id=\"简介\"><a href=\"#简介\" class=\"headerlink\" title=\"简介\"></a>简介</h2><p>CDN全称Content Delivery Network,即内容分发网络;其工作原理是在全国各地增加节点机器,当用户访问源站时,就近选择最近的缓存节点机器,从而减少访问时间,也可避免源站承受巨大压力。</p>\n<p>加速对象:利用HTTP或FTP下载方式进行下载的各类文件。</p>\n<h2 id=\"工作原理\"><a href=\"#工作原理\" class=\"headerlink\" title=\"工作原理\"></a>工作原理</h2><p>借用阿里云官网的例子,介绍CDN的工作原理: \u0003<img src=\"/images/20190901-1.png\" alt=\"images\"></p>\n<p>从这个例子可以了解到:</p>\n<p>(1)CDN的加速资源是跟域名绑定的。</p>\n<p>(2)通过域名访问资源,首先是通过DNS分查找离用户最近的CDN节点(边缘服务器)的IP</p>\n<p>(3)通过IP访问实际资源时,如果CDN上并没有缓存资源,则会到源站请求资源,并缓存到CDN节点上,这样,用户下一次访问时,该CDN节点就会有对应资源的缓存了。</p>\n<h2 id=\"框架\"><a href=\"#框架\" class=\"headerlink\" title=\"框架\"></a>框架</h2><p>实际测试工作中会将DNS(调度系统)和CDN(缓存系统)分为两个系统,现就测试CDN的过程进行简述:<img src=\"/images/20190901-2.png\" alt=\"images\"></p>\n<p>①通过Boss后台下发的配置信息至服务器的Redis中,包括内容有”加速域名””缓存文件匹配策略””IP防盗链设置””缓存文件缓存时长”等常规配置;</p>\n<p>②CDN前端中主要负责业务处理,存储热点新闻事件等,存的是固态硬盘ssd盘(读取速度相对较快);③CDN后端主要负责的是回源合并,存储相对而言不是很频繁需要访问的资源,存的是sata盘 。</p>\n<h2 id=\"测试\"><a href=\"#测试\" class=\"headerlink\" title=\"测试\"></a>测试</h2><p>CDN测试内容较复杂,一方面是业务场景覆盖内容多,另一方面是完全底层测试,没有前端页面可以测试。</p>\n<p>功能测试时会使用curl命令进行请求域名和相关文件,通过日志了解缓存执行的流程,查看节点目录是否存在缓存文件等。</p>\n<p><img src=\"/images/20190901-3.png\" alt=\"images\"></p>\n<p>观察可发现,实际发送请求的是一个加速域名,日常新功能可使用curl等接口类工具进行测试;当工作量较大时,可使用接口自动化框架进行回归验证,这里使用的是HttpRunner:</p>\n<p>学习地址:<a href=\"https://docs.httprunner.org/\">https://docs.httprunner.org/</a></p>\n<p>主要实现原理:通过修改Redis的参数,验证返回值和存储信息达到快速检测的目的。</p>\n<p>Redis中参数校验部分内容如下:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">{</span><br><span class=\"line\"> "errno": 0, // 接口错误状态码</span><br><span class=\"line\"> "errmsg": "", // 接口错误描述信息</span><br><span class=\"line\"> "data": [</span><br><span class=\"line\"> {</span><br><span class=\"line\"> "version": 142258770700001, //必须有,无默认值</span><br><span class=\"line\"> "id": 12345, //必须配置,无默认值,域名ID</span><br><span class=\"line\"> </span><br><span class=\"line\"> "prefix_cache_first": false, // 前缀缓存优先,默认值false</span><br><span class=\"line\"> </span><br><span class=\"line\"> "prefix_cache": { // 前缀匹配缓存策略,不配置为null</span><br><span class=\"line\"> "\\/doc": 86400,</span><br><span class=\"line\"> "\\/dox\\/aaa": 86400</span><br><span class=\"line\"> },</span><br><span class=\"line\"> </span><br><span class=\"line\"> "suffix_cache": { // 后缀匹配缓存策略,不配置为null</span><br><span class=\"line\"> "png": 86400,</span><br><span class=\"line\"> "jpeg": 86400</span><br><span class=\"line\"> },</span><br><span class=\"line\"> </span><br><span class=\"line\"> "full_cache": { // 精确匹配缓存策略,在没有配置的时候为null</span><br><span class=\"line\"> "\\/index.html": 86400</span><br><span class=\"line\"> },</span><br><span class=\"line\"> </span><br><span class=\"line\"> "http_code_cache": { // 特殊状态码缓存策略,只允许填写 > 400 状态码,不需要配置时为null</span><br><span class=\"line\"> "404": 300, // 最多 10 条策略</span><br><span class=\"line\"> "502": 60</span><br><span class=\"line\"> },</span><br><span class=\"line\"> </span><br><span class=\"line\"> </span><br><span class=\"line\"> "ip_filter_type": "black", // IP 防盗链策略 [off|black|white]默认值off</span><br><span class=\"line\"> "ip_filter_list": [</span><br><span class=\"line\"> "127.0.1.1",</span><br><span class=\"line\"> "128.0.1.2/24"</span><br><span class=\"line\"> ],</span><br><span class=\"line\"> </span><br><span class=\"line\"> "referer_filter_type": "black", // Referer 防盗链控制 [off|black|white],默认值off</span><br><span class=\"line\"> "referer_filter_list": [ //当referer_filter_type不为off时,此list必须有值,referer_filter_type为off时,可以为null</span><br><span class=\"line\"> "http:\\/\\/www.baidu.com\\/",</span><br><span class=\"line\"> "ALLOW_EMPTY_REFERER" // 普通防盗链列表 "ALLOW_EMPTY_REFERER" 表示允许空 referer</span><br><span class=\"line\"> ],</span><br><span class=\"line\"> </span><br><span class=\"line\"> "ftag_list": { // ftag 防盗链,不配置为null</span><br><span class=\"line\"> "enable": false, // 策略开关</span><br><span class=\"line\"> "expire": 60000, // 使用过期验证时的过期时间,单位为秒</span><br><span class=\"line\"> "secret_key": "xxx", // 加密的 key,值为字符串 最大长度 64</span><br><span class=\"line\"> "regexp": [ // uri正则表达式,默认忽略大小写。如果配置成null表示域名下所有uri都生效</span><br><span class=\"line\"> "^/abc*123" // 默认 4 条策略</span><br><span class=\"line\"> ],</span><br><span class=\"line\"> "ip_filter_list": [ //IP白名单,默认值为null</span><br><span class=\"line\"> "127.0.1.1",</span><br><span class=\"line\"> "128.0.1.2/24"</span><br><span class=\"line\"> ]</span><br><span class=\"line\"> },</span><br><span class=\"line\"> </span><br><span class=\"line\"> // response_header_replace替换响应头,默认值null,为null不做处理,</span><br><span class=\"line\"> "response_header_replace": [</span><br><span class=\"line\"> {</span><br><span class=\"line\"> // request_url即请求url的正则表达式列表,最多包含有6个正则表达式,</span><br><span class=\"line\"> // 默认值为null(request_url:null),如果为null则对当前域名下的请求都生效</span><br><span class=\"line\"> "request_url" : ["http://abc.com/.*", "http://123.com/.*",...],</span><br><span class=\"line\"> },</span><br><span class=\"line\"> </span><br><span class=\"line\"> // replace_header即要替换的响应头及值,</span><br><span class=\"line\"> // 默认值null 替换请求头:name 最长 128 个字符;</span><br><span class=\"line\"> // value ,最长 256 个字符;</span><br><span class=\"line\"> // 最多支持6组</span><br><span class=\"line\"> "replace_header" : {</span><br><span class=\"line\"> "name1": "value1",</span><br><span class=\"line\"> "name2": "value2"</span><br><span class=\"line\"> ...</span><br><span class=\"line\"> },</span><br><span class=\"line\"> }</span><br><span class=\"line\"> ...</span><br><span class=\"line\"> ],</span><br><span class=\"line\"> </span><br><span class=\"line\"> </span><br><span class=\"line\"> "purge_dir": { // 默认值null, 目录刷新,最多 10 条策略</span><br><span class=\"line\"> "/1/2/3/": 1466680047,</span><br><span class=\"line\"> "/a/": 1466680047,</span><br><span class=\"line\"> "/b/b/b/": 1478056899,</span><br><span class=\"line\"> "/1/1/": 1478057169</span><br><span class=\"line\"> },</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["3.Testing","总结"],"tags":["总结"]},{"title":"HTTP基础知识","url":"/3.Testing/Others/HTTP%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/","content":"<h2 id=\"浏览器输入URL至相应的全过程\"><a href=\"#浏览器输入URL至相应的全过程\" class=\"headerlink\" title=\"浏览器输入URL至相应的全过程\"></a>浏览器输入URL至相应的全过程</h2><ol>\n<li><p>根据域名到DNS找到IP</p>\n</li>\n<li><p>根据IP建立TCP三次握手连接</p>\n</li>\n<li><p>连接成功发出http请求</p>\n</li>\n<li><p>服务器响应http请求</p>\n</li>\n<li><p>浏览器解析html代码并请求html中的静态资源(js/css)</p>\n</li>\n<li><p>关闭tcp连接(四次挥手)</p>\n</li>\n<li><p>浏览器渲染页面</p>\n</li>\n</ol>\n<h2 id=\"超文本传输协议(HTTP)\"><a href=\"#超文本传输协议(HTTP)\" class=\"headerlink\" title=\"超文本传输协议(HTTP)\"></a>超文本传输协议(HTTP)</h2><p>超文本传输协议(HTTP)设计目的是保证客户端与服务器之间的通信</p>\n<p>客户端与服务端进行交互有很多中方法,最基本的有GET、POST、PUT和DELETE;一个URL地址,主要用于描述一个网络上的资源,而HTTP中的GET、POST、PUT和DELETE则对应着对这个资源的查、改、增、删操作。(对资源的增删改查操作都可以使用GET/POST完成,不需要用到PUT和DELETE);现就对GET和POST进行详细说明:</p>\n<h3 id=\"GET方法\"><a href=\"#GET方法\" class=\"headerlink\" title=\"GET方法\"></a>GET方法</h3><p>查询字符串是在GET请求的URL中发送的;</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/test/demo_form.php?name1=value1&name2=value2</span><br></pre></td></tr></table></figure>\n\n<p>其他:</p>\n<ol>\n<li>URL长度限制:最多2048个字符(2KB)</li>\n<li>数据类型限制:只允许ASCII字符</li>\n<li>安全性:较差,发送信息是URL的一部分</li>\n<li>可见性:数据在URL中对所有人都是可见的</li>\n<li>缓存:可被浏览器缓存</li>\n</ol>\n<h3 id=\"POST方法\"><a href=\"#POST方法\" class=\"headerlink\" title=\"POST方法\"></a>POST方法</h3><p>查询字符串是在POST请求的HTTP消息体中发送的;</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">POST /test/demo_form.php HTTP/1.1</span><br><span class=\"line\">Host: runoob.com</span><br><span class=\"line\">name1=value1&name2=value2</span><br></pre></td></tr></table></figure>\n\n<p>其他:</p>\n<ol>\n<li>URL长度限制:无限制</li>\n<li>数据类型限制:无限制</li>\n<li>安全性:安全</li>\n<li>可见性:数据不会显示在URL中</li>\n<li>缓存:不可被浏览器缓存</li>\n</ol>\n<h2 id=\"会话\"><a href=\"#会话\" class=\"headerlink\" title=\"会话\"></a>会话</h2><p>会话(Session)跟踪主要用来跟踪用户的整个绘画,常用的跟踪技术是Cookie和Session;Cookie通过在客户端记录信息确定用户身份,Session通过在服务端记录信息确定用户身份。</p>\n<p>1、存放位置</p>\n<p>Cookie的数据存放在客户端的浏览器上,Session存放在服务器上</p>\n<p>2、安全程度</p>\n<p>Cookie不是很安全,别人通过分析本地的Cookie并进行Cookie欺骗;考虑到安全应该使用Session</p>\n<p>3、性能</p>\n<p>Session会在一定时间内保存在服务器上,当访问者增多,会占用你的内容;考虑到减轻服务器性能方面,应该使用Cookie</p>\n<p>4、存储数据</p>\n<p>单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie</p>\n<p>可以考虑将登陆等重要信息保存在session,其他信息如果需要可以保存在cookie中。</p>\n<h2 id=\"常用返回码\"><a href=\"#常用返回码\" class=\"headerlink\" title=\"常用返回码\"></a>常用返回码</h2><table>\n<thead>\n<tr>\n<th>2XX(成功)</th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody><tr>\n<td></td>\n<td>200(成功)</td>\n<td>服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。</td>\n</tr>\n<tr>\n<td>3XX(重定向)</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>301(永久移动)</td>\n<td>请求的网页已永久移动到新位置</td>\n</tr>\n<tr>\n<td></td>\n<td>302(临时移动)</td>\n<td>服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求</td>\n</tr>\n<tr>\n<td>4XX(请求错误)</td>\n<td>404(未找到)</td>\n<td>服务器找不到请求的网页</td>\n</tr>\n<tr>\n<td>5XX(服务器错误)</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>500(服务器内部错误)</td>\n<td>服务器遇到错误,无法完成请求</td>\n</tr>\n<tr>\n<td></td>\n<td>504(网关超时)</td>\n<td>服务器作为网关或代理,但是没有及时从上游服务器收到请求。</td>\n</tr>\n</tbody></table>\n<h2 id=\"TCP连接的‘三次握手’\"><a href=\"#TCP连接的‘三次握手’\" class=\"headerlink\" title=\"TCP连接的‘三次握手’\"></a>TCP连接的‘三次握手’</h2><p>比较重要的字段:</p>\n<ol>\n<li><p>序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。</p>\n</li>\n<li><p>确认号(acknowledgement number):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。</p>\n</li>\n<li><p>标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:</p>\n</li>\n</ol>\n<p>URG:紧急指针(urgent pointer)有效。ACK:确认序号有效。PSH:接收方应该尽快将这个报文交给应用层。RST:重置连接。SYN:发起一个新连接。FIN:释放一个连接。</p>\n<p>需要注意的是:不要将确认序号Ack与标志位中的ACK搞混了。确认方Ack=发起方Seq+1,两端配对。</p>\n<p><img src=\"/images/20210308-1.png\" alt=\"images\"></p>\n<p><strong>为什么建立连接时是三次握手,断开连接时是四次回收?</strong></p>\n<p>建立连接时,被动方服务器结束CLOSED阶段进入握手阶段不需要任何准备,可以直接返回SYN和ACK建立连接;</p>\n<p>断开连接时,被动方服务器收到客户端释放连接的请求时并不能立即释放连接,因为还有很多数据需要处理,所以服务器先返回ACK确认报文,经过CLOSED_WAIT阶段准备好后释放连接后,才能返回FIN释放连接报文。</p>\n<h2 id=\"TCP和UDP的区别\"><a href=\"#TCP和UDP的区别\" class=\"headerlink\" title=\"TCP和UDP的区别\"></a>TCP和UDP的区别</h2><p>TCP使用场景:IP电话、实时视频会议等</p>\n<p>UDP使用场景:文件传输、邮件发送与接收等</p>\n<ol>\n<li>TCP是面向连接(如打电话前要先拨号建立联系);UDP是无连接的,即发送数据前不需要建立连接</li>\n<li>TCP提供可靠的服务,通过TCP连接传送的数据无差错、不丢失、不重复,且按序到达;UDP尽最大努力交付,不保证可靠交付</li>\n<li>TCP面向字节流;UDP是面向报文的,没有阻塞控制</li>\n<li>每一条TCP连接只能是点到点的;UDP支持1:1,1:N,N:1和N:N的交互通信</li>\n<li>TCP首部开销是20字节;UDP只有8字节</li>\n<li>TCP的逻辑通信信道是全双工的可靠信道;UDP则是不可靠信道</li>\n</ol>\n","categories":["3.Testing","总结"],"tags":["总结"]},{"title":"Kafka串讲","url":"/3.Testing/Others/Kafka%E4%B8%B2%E8%AE%B2/","content":"<p><img src=\"/images/kafka/20211111-1.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-2.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-3.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-4.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-5.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-6.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-7.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-8.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-9.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-10.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-11.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-12.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-13.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-14.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-15.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-16.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-17.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-18.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-19.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-20.png\" alt=\"images\"></p>\n<p><img src=\"/images/kafka/20211111-21.png\" alt=\"images\"></p>\n","categories":["3.Testing","总结"],"tags":["总结"]},{"title":"Kafka性能测试","url":"/3.Testing/Others/Kafka%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/","content":"<h2 id=\"简介\"><a href=\"#简介\" class=\"headerlink\" title=\"简介\"></a>简介</h2><p>Kafka自带监控工具Kafka-Manager,但权限控制严格,而且只能够查询Mean、1Min、5Min、15Min的数据,无法查询一个时间段内的数据,因此需要一个可供用户查询集群和Topic监控数据的工具。</p>\n<h2 id=\"Kafka监控原理\"><a href=\"#Kafka监控原理\" class=\"headerlink\" title=\"Kafka监控原理\"></a>Kafka监控原理</h2><p><img src=\"/images/kafka/20211201-1.png\" alt=\"images\"></p>\n<h2 id=\"Kafka监控工具原理\"><a href=\"#Kafka监控工具原理\" class=\"headerlink\" title=\"Kafka监控工具原理\"></a>Kafka监控工具原理</h2><p>Jmxtrans:解析配置文件,通过jmx采集java应用的数据采集器,他的输出可以是Graphite、StatsD、Ganglia、InfluxDB等等<br>InfluxDB:开源的分布式时序、时间和指标数据库,使用go语言编写,无需外部依赖<br>Grafana:开源的时序性统计和监控平台,支持influxdb 等众多的数据源,界面编辑器功能强大,自带用户权限管理</p>\n<p><img src=\"/images/kafka/20211201-2.png\" alt=\"images\"></p>\n<p>Jmx+InfluxDB+Grafana架构的优点</p>\n<ul>\n<li>InfluxDB是时序、时间和指标数据库,非常适合存储jvm metric数据</li>\n<li>Grafana这意味U时序性统计和监控平台,对于展示jvm metric监控数据也很方便,界面编辑简单,无需适配;且Grafana有简单的用户权限管理功能,可以控制不同Dashboard的访问权限。</li>\n<li>Jmxtrans的推送数据是根据配置文件更新的,因此如果有增删的监控项,完全不需要跟新程序代码,修改配置即可。</li>\n</ul>\n<h2 id=\"Kafka安装工具\"><a href=\"#Kafka安装工具\" class=\"headerlink\" title=\"Kafka安装工具\"></a>Kafka安装工具</h2><h3 id=\"服务-InfluxDB\"><a href=\"#服务-InfluxDB\" class=\"headerlink\" title=\"服务 InfluxDB\"></a>服务 InfluxDB</h3><ul>\n<li>安装<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> wget https://dl.influxdata.com/influxdb/releases/influxdb-1.7.8.x86_64.rpm</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> rpm -ivh influxdb-1.7.8.x86_64.rpm</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> systemctl start influxdb.service</span></span><br></pre></td></tr></table></figure></li>\n<li>配置文件<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/etc/influxdb/influxdb.conf</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"服务-Granfana\"><a href=\"#服务-Granfana\" class=\"headerlink\" title=\"服务 Granfana\"></a>服务 Granfana</h3><ul>\n<li>安装<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.5.2-1.x86_64.rpm</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> rpm -ivh grafana-6.0.2-1.x86_64.rpm</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> service grafana-server start</span></span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"服务-Jmxtrans\"><a href=\"#服务-Jmxtrans\" class=\"headerlink\" title=\"服务 Jmxtrans\"></a>服务 Jmxtrans</h3><ul>\n<li>安装<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> yum install https://repo1.maven.org/maven2/org/jmxtrans/jmxtrans/270/jmxtrans-270.rpm</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> rpm -i jmxtrans-270.rpm --nodeps --force</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> /etc/init.d/jmxtrans start</span></span><br></pre></td></tr></table></figure></li>\n<li>配置文件<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> jmxtrans安装目录:/usr/share/jmxtrans</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> json文件默认目录:/var/lib/jmxtrans/</span></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 日志路径:/var/<span class=\"built_in\">log</span>/jmxtrans/jmxtrans.log</span></span><br></pre></td></tr></table></figure></li>\n</ul>\n<h2 id=\"配置文件说明\"><a href=\"#配置文件说明\" class=\"headerlink\" title=\"配置文件说明\"></a>配置文件说明</h2><h3 id=\"全局监控指标\"><a href=\"#全局监控指标\" class=\"headerlink\" title=\"全局监控指标\"></a>全局监控指标</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒输入的流量</span><br><span class=\"line\">"obj":"kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec""attr":["Count"]"resultAlias":"BytesInPerSec""tags":{"application":"BytesInPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒读出的流量</span><br><span class=\"line\">"obj":"kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec""attr":["Count"]"resultAlias":"BytesOutPerSec""tags":{"application":"BytesOutPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒输入的流量</span><br><span class=\"line\">"obj":"kafka.server:type=BrokerTopicMetrics,name=BytesRejectedPerSec""attr":["Count"]"resultAlias":"BytesRejectedPerSec""tags":{"application":"BytesRejectedPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒消息写入总量</span><br><span class=\"line\">"obj":"kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec""attr":["Count"]"resultAlias":"MessagesInPerSec""tags":{"application":"MessagesInPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒FetchFollower的请求次数</span><br><span class=\"line\">"obj":"kafka.network:type=RequestMetrics,name=RequestsPerSec,request=FetchFollower""attr":["Count"]"resultAlias":"RequestsPerSec""tags":{"request":"FetchFollower"}</span><br></pre></td></tr></table></figure>\n\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒FetchConsumer的请求次数</span><br><span class=\"line\">"obj":"kafka.network:type=RequestMetrics,name=RequestsPerSec,request=FetchConsumer""attr":["Count"]"resultAlias":"RequestsPerSec""tags":{"request":"FetchConsumer"}</span><br></pre></td></tr></table></figure>\n\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒Produce的请求次数</span><br><span class=\"line\">"obj":"kafka.network:type=RequestMetrics,name=RequestsPerSec,request=Produce""attr":["Count"]"resultAlias":"RequestsPerSec""tags":{"request":"Produce"}</span><br></pre></td></tr></table></figure>\n\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//内存使用的使用情况</span><br><span class=\"line\">"obj":"java.lang:type=Memory""attr":["HeapMemoryUsage", "NonHeapMemoryUsage"]"resultAlias":"MemoryUsage""tags":{"application":"MemoryUsage"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//GC的耗时和次数</span><br><span class=\"line\">"obj":"java.lang:type=GarbageCollector,name=*""attr":["CollectionCount","CollectionTime"]"resultAlias":"GC""tags":{"application":"GC"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//每秒读出的流量</span><br><span class=\"line\">"obj":"kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec""attr":["Count"]"resultAlias":"BytesOutPerSec""tags":{"application":"BytesOutPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//线程的使用情况</span><br><span class=\"line\">"obj":"java.lang:type=Threading""attr":["PeakThreadCount","ThreadCount"]"resultAlias":"Thread""tags":{"application":"Thread"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//副本落后主分片的最大消息数量</span><br><span class=\"line\">"obj":"kafka.server:type=ReplicaFetcherManager,name=MaxLag,clientId=Replica""attr":["Value"]"resultAlias":"ReplicaFetcherManager""tags":{"application":"MaxLag"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//该broker上的partition的数量</span><br><span class=\"line\">"obj":"kafka.server:type=ReplicaManager,name=PartitionCount""attr":["Value"]"resultAlias":"ReplicaManager""tags":{"application":"PartitionCount"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//正在做复制的partition的数量</span><br><span class=\"line\">"obj":"kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions""attr":["Value"]"resultAlias":"ReplicaManager""tags":{"application":"UnderReplicatedPartitions"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//Leader的replica的数量</span><br><span class=\"line\">"obj":"kafka.server:type=ReplicaManager,name=LeaderCount""attr":["Value"]"resultAlias":"ReplicaManager""tags":{"application":"LeaderCount"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//一个请求FetchConsumer耗费的所有时间</span><br><span class=\"line\">"obj":"kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchConsumer""attr":["Count","Max"]"resultAlias":"TotalTimeMs""tags":{"application":"FetchConsumer"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//一个请求FetchFollower耗费的所有时间</span><br><span class=\"line\">"obj":"kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchFollower""attr":["Count","Max"]"resultAlias":"TotalTimeMs""tags":{"application":"FetchFollower"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//一个请求Produce耗费的所有时间</span><br><span class=\"line\">"obj":"kafka.network:type=RequestMetrics,name=TotalTimeMs,request=Produce""attr":["Count","Max"]"resultAlias":"TotalTimeMs""tags":{"application":"Produce"}</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"Topic监控指标\"><a href=\"#Topic监控指标\" class=\"headerlink\" title=\"Topic监控指标\"></a>Topic监控指标</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//topic b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in每秒的写入流量</span><br><span class=\"line\">"kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec,topic= b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in""attr":["Count"]"resultAlias":" b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in""tags":{"application":"BytesInPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//topic b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in每秒的输出流量</span><br><span class=\"line\">"kafka.server:type=BrokerTopicMetrics,name=BytesOutPerSec,topic= b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in""attr":["Count"]"resultAlias":" b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in""tags":{"application":"BytesOutPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//topic b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in每秒写入消息的数量</span><br><span class=\"line\">"obj":"kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec,topic= b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in""attr":["Count"]"resultAlias":" b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in""tags":{"application":"MessagesInPerSec"}</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">//topic b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in在每个分区最后的Offset</span><br><span class=\"line\">"obj":"kafka.log:type=Log,name=LogEndOffset,topic= b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in,partition=*""attr":["Value"]"resultAlias":" b1f91fbe6fe54d2eaf70ef0025f1c3c2__ivc_alarm_in""tags":{"application":"LogEndOffset"}</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"说明\"><a href=\"#说明\" class=\"headerlink\" title=\"说明\"></a>说明</h2><p>使用Jmx+InfluxDB+Grafana架构,对于Kafka性能测试图形化展示很友好。</p>\n","categories":["3.Testing","总结"],"tags":["总结"]},{"title":"初探存储对象S3","url":"/3.Testing/Others/%E5%88%9D%E6%8E%A2%E5%AD%98%E5%82%A8%E5%AF%B9%E8%B1%A1S3/","content":"<p>云平台测试过程中,存储服务中的对象存储之S3(Simple Storage Service简单存储服务)有着举足轻重的作用。实际业务中权限限制较多,现就测试过程中对S3的理解做简单概述。</p>\n<h2 id=\"基本概念\"><a href=\"#基本概念\" class=\"headerlink\" title=\"基本概念\"></a>基本概念</h2><p>通过云平台提供的API,可以在任何应用、任何时间、任何地点进行文件的上传下载操作。</p>\n<h3 id=\"开发者和用户\"><a href=\"#开发者和用户\" class=\"headerlink\" title=\"开发者和用户\"></a>开发者和用户</h3><ol>\n<li><p>开发者:存储服务的使用者,比如某APP产品的开发者。</p>\n</li>\n<li><p>用户:开发者的用户,即某APP产品的使用者。</p>\n</li>\n</ol>\n<h3 id=\"空间(Bucket)\"><a href=\"#空间(Bucket)\" class=\"headerlink\" title=\"空间(Bucket)\"></a>空间(Bucket)</h3><ol>\n<li><p>空间是资源的一个集合,可以理解为目录,某一个资源必须在一个空间中。</p>\n</li>\n<li><p>所有存储服务的使用者共享一个Bucket的命令空间,即如果有人用了abcd作为空间名,其他人不能再使用这个名字。</p>\n</li>\n<li><p>空间具有 私有或者公共 两种属性,用来控制空间的访问权限。</p>\n</li>\n</ol>\n<h3 id=\"资源(Object)\"><a href=\"#资源(Object)\" class=\"headerlink\" title=\"资源(Object)\"></a>资源(Object)</h3><ol>\n<li><p>存储服务中最基本的单元,可以理解为文件。</p>\n</li>\n<li><p>资源名是一个字符串,可以理解为文件名。同一个bucket内,资源名必须唯一。</p>\n</li>\n<li><p>使用者可以通过良好的设计前缀,达到类似于文件目录的分类和层次效果。</p>\n</li>\n</ol>\n<h3 id=\"访问秘钥(Access-Key)\"><a href=\"#访问秘钥(Access-Key)\" class=\"headerlink\" title=\"访问秘钥(Access Key)\"></a>访问秘钥(Access Key)</h3><ol>\n<li><p>云存储通过使用Access Key ID和Access Key Secret对称加密的方式来验证某个请求的发送者身份。</p>\n</li>\n<li><p>每个业务会分配唯一的一个Access Key ID,用以标志业务身份。每个业务会被分配一个Access Key Secret用以验证身份。</p>\n</li>\n</ol>\n<h2 id=\"业务逻辑架构图\"><a href=\"#业务逻辑架构图\" class=\"headerlink\" title=\"业务逻辑架构图\"></a>业务逻辑架构图</h2><p><img src=\"/images/20210312-1.png\" alt=\"image-20210309123201765\"></p>\n<h2 id=\"测试工具\"><a href=\"#测试工具\" class=\"headerlink\" title=\"测试工具\"></a>测试工具</h2><p>“工欲善其事,必先利其器”,云平台提供了申请AK/SK及创建Bucket功能,实际测试过程中,除关注平台提供的功能外,需要额外测试服务端与存储服务系统的交互以及存储服务的有效性。测试S3存储的工具有很多,现就配置简单且为开源的工具 <a href=\"https://github.com/s3tools/s3cmd\">s3cmd </a>进行 例:</p>\n<h3 id=\"安装\"><a href=\"#安装\" class=\"headerlink\" title=\"安装\"></a><strong>安装</strong></h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">yum -y install s3cmd</span> </span><br></pre></td></tr></table></figure>\n\n<h3 id=\"配置s3cmd\"><a href=\"#配置s3cmd\" class=\"headerlink\" title=\"配置s3cmd\"></a><strong>配置s3cmd</strong></h3><p>执行 <code>$ s3cmd --configure</code>生成配置文件,一路<code>Enter</code>,注意跳过认证并保存配置:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">......</span><br><span class=\"line\">...</span><br><span class=\"line\">Test access with supplied credentials? [Y/n] n</span><br><span class=\"line\"></span><br><span class=\"line\">Save settings? [y/N] y</span><br><span class=\"line\">Configuration saved to '/root/.s3cfg'</span><br></pre></td></tr></table></figure>\n\n<p>修改以下信息:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> vim /root/.s3cfg</span></span><br><span class=\"line\">access_key = xxx #创建S3时获取</span><br><span class=\"line\">secret_key = xxx #创建S3时获取</span><br><span class=\"line\">host_base = ip:port #S3提供的集群地址</span><br><span class=\"line\">host_bucket = ip/kucketname #S3用户下的一个bucket</span><br><span class=\"line\">use_https = False #是否使用https</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"使用s3cmd\"><a href=\"#使用s3cmd\" class=\"headerlink\" title=\"使用s3cmd\"></a><strong>使用s3cmd</strong></h3><p>通过s3cmd –help查看具体使用方法;</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">s3cmd ls <span class=\"comment\">#列举所有 Buckets</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">s3cmd ls s3://my-bucket-name <span class=\"comment\">#列举Bucket中的内容</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">s3cmd put file.txt s3://my-bucket-name/file.txt <span class=\"comment\">#上传 file.txt 到某个 bucket</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">s3cmd get s3://my-bucket-name/file.txt file.txt <span class=\"comment\">#下载文件</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">s3cmd del s3://my-bucket-name/file.txt <span class=\"comment\">#删除文件</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">s3cmd du -H s3://my-bucket-name <span class=\"comment\">#来获得对应的bucket所占用的空间大小</span></span></span><br></pre></td></tr></table></figure>\n\n<p>通过s3cmd操作bucket,可以独立判断出业务层逻辑正确性。</p>\n<p>其他如服务端与存储系统的交互可以使用radosgw-admin进行查看,暂不进行详细介绍。</p>\n<h2 id=\"业务理解\"><a href=\"#业务理解\" class=\"headerlink\" title=\"业务理解\"></a>业务理解</h2><h3 id=\"Multipart原理\"><a href=\"#Multipart原理\" class=\"headerlink\" title=\"Multipart原理\"></a>Multipart原理</h3><p>ceph默认对于单一上传文件的大小限制是5GB</p>\n<p>s3在上传大文件时,采用了multipart机制,将大文件进行分片。</p>\n<p>以下是s3cmd的两个配置</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">default_mime_type = binary/octet-stream #默认上传文件类型</span><br><span class=\"line\"></span><br><span class=\"line\">multipart_chunk_size_mb = 15 #配置分片的大小,默认是15MB</span><br><span class=\"line\">multipart_max_chunks = 10000 #配置分片的最大数量,默认是1000</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"Bucket信息\"><a href=\"#Bucket信息\" class=\"headerlink\" title=\"Bucket信息\"></a>Bucket信息</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">查看Bucket授权信息</span></span><br><span class=\"line\"></span><br></pre></td></tr></table></figure>\n\n\n\n","categories":["3.Testing","总结"],"tags":["总结"]},{"title":"软件测试流程","url":"/3.Testing/Others/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B/","content":"<p>说明:<br>项目立项后,由产品人员、前端开发人员、服务端开发人员和测试人员组成的云管团队成立。<br>提高效率的其中一个环节就是树立健全的项目流程,现就实际工作中的流程进行总结:</p>\n<table>\n<thead>\n<tr>\n<th><strong>产研发测流程</strong></th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody><tr>\n<td>1.产品为主</td>\n<td>测试前准备工作</td>\n<td>说明</td>\n</tr>\n<tr>\n<td></td>\n<td>1、产品提出需求评审(与开发/测试人员确认测试范围/内容及上线时间)</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>2、产品提供原型/需求文档等</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>3、开发确定技术方案/技术评审</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>4、测试设计case,用例评审</td>\n<td>Xmind记录检查点,Excel记录测试过程</td>\n</tr>\n<tr>\n<td>2.产品/开发为主</td>\n<td>冒烟测试</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>1、需求要提测,提测前RD必须严格自测</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>2、需求RD进行提测(禅道),务必写清楚本次修改点及影响范围</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>3、提测的需求RD必须严格进行自测,保证提供的测试内容主流程正常、业务逻辑正确,测试人员更多是验证测试、异常场景测试等</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>4、冒烟测试通过后,进行详细测试;冒烟测试不通过,测试需求驳回</td>\n<td></td>\n</tr>\n<tr>\n<td>3.测试/开发为主</td>\n<td>迭代测试</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>1、测试收到提测消息后与开发人员进行沟通,如果当前提测需求量较多,排优先级</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>2、Jenkins自动部署测试环境(开发修改Bug同步代码到相应分支)</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>3、每天沟通测试进展必要时增加测试报告;至测试结束</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>4、准上线环境验收测试</td>\n<td></td>\n</tr>\n<tr>\n<td>4.开发为主</td>\n<td>交付</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>1、上线后通过标记代码分支打Tag确定上线版本</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>2、上线后全体人员进行线上回归测试</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>3、线上问题记录</td>\n<td></td>\n</tr>\n<tr>\n<td>5.其他</td>\n<td>总结</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>1、bugreview</td>\n<td></td>\n</tr>\n<tr>\n<td></td>\n<td>2、测试总结</td>\n<td></td>\n</tr>\n</tbody></table>\n","categories":["3.Testing","总结"],"tags":["总结"]},{"title":"Postman常用设置全局变量的js片段","url":"/3.Testing/%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/Postman%E5%B8%B8%E7%94%A8%E8%AE%BE%E7%BD%AE%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%9A%84js%E7%89%87%E6%AE%B5/","content":"<h4 id=\"Postman知识总结\"><a href=\"#Postman知识总结\" class=\"headerlink\" title=\"Postman知识总结\"></a>Postman知识总结</h4><p><a href=\"http://www.bayescafe.com/tools/use-postman-to-test-api-automatically.html\">API自动化利器</a></p>\n<h4 id=\"获取环境变量内容\"><a href=\"#获取环境变量内容\" class=\"headerlink\" title=\"获取环境变量内容\"></a>获取环境变量内容</h4><figure class=\"highlight js\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">var</span> ostype = pm.environment.get(<span class=\"string\">"ostype"</span>);</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"设置全局变量内容\"><a href=\"#设置全局变量内容\" class=\"headerlink\" title=\"设置全局变量内容\"></a>设置全局变量内容</h4><figure class=\"highlight js\"><table><tr><td class=\"code\"><pre><span class=\"line\">postman.setEnvironmentVariable(<span class=\"string\">"ts"</span>,<span class=\"built_in\">Math</span>.floor(<span class=\"keyword\">new</span> <span class=\"built_in\">Date</span>().getTime()/<span class=\"number\">1000</span>));</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"auth签名\"><a href=\"#auth签名\" class=\"headerlink\" title=\"auth签名\"></a>auth签名</h4><figure class=\"highlight js\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">var</span> auth = CryptoJS.SHA1(pm.environment.get(<span class=\"string\">"device_secret"</span>),{<span class=\"attr\">asString</span>: <span class=\"literal\">true</span>});</span><br><span class=\"line\">postman.setEnvironmentVariable(<span class=\"string\">"auth"</span>, auth);</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"随机标识\"><a href=\"#随机标识\" class=\"headerlink\" title=\"随机标识\"></a>随机标识</h4><figure class=\"highlight js\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">const</span> randomInt = <span class=\"function\">(<span class=\"params\">min, max</span>) =></span> <span class=\"built_in\">Math</span>.floor(<span class=\"built_in\">Math</span>.random() * (max - min + <span class=\"number\">1</span>)) + min; <span class=\"comment\">// 随机整数</span></span><br><span class=\"line\"><span class=\"keyword\">const</span> getRandomValue = <span class=\"function\"><span class=\"params\">list</span> =></span> list[randomInt(<span class=\"number\">0</span>, list.length - <span class=\"number\">1</span>)]; <span class=\"comment\">// 随机选项</span></span><br><span class=\"line\"><span class=\"keyword\">const</span> chars = [<span class=\"string\">'a'</span>, <span class=\"string\">'b'</span>, <span class=\"string\">'c'</span>, <span class=\"string\">'d'</span>, <span class=\"string\">'e'</span>, <span class=\"string\">'f'</span>, <span class=\"string\">'g'</span>, <span class=\"string\">'h'</span>, <span class=\"string\">'i'</span>, <span class=\"string\">'g'</span>, <span class=\"string\">'k'</span>, <span class=\"string\">'l'</span>, <span class=\"string\">'m'</span>, <span class=\"string\">'n'</span>, <span class=\"string\">'o'</span>, <span class=\"string\">'1'</span>];</span><br><span class=\"line\"><span class=\"keyword\">let</span> identifier = <span class=\"string\">''</span>;</span><br><span class=\"line\"><span class=\"keyword\">for</span> (<span class=\"keyword\">let</span> i = <span class=\"number\">0</span>; i < <span class=\"number\">5</span>; i++) {</span><br><span class=\"line\"> identifier += getRandomValue(chars);</span><br><span class=\"line\">}</span><br><span class=\"line\">pm.environment.set(<span class=\"string\">"identifier"</span>, identifier);</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"schema校验\"><a href=\"#schema校验\" class=\"headerlink\" title=\"schema校验\"></a>schema校验</h4><figure class=\"highlight js\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">let</span> json;</span><br><span class=\"line\"><span class=\"keyword\">try</span> {</span><br><span class=\"line\"> json = <span class=\"built_in\">JSON</span>.parse(responseBody);</span><br><span class=\"line\">} <span class=\"keyword\">catch</span>(err) {</span><br><span class=\"line\"> tests[<span class=\"string\">'服务端没返回合法的JSON格式,请检查相关服务、网络或反向代理设置(以下跳过其他断言)'</span>] = <span class=\"literal\">false</span>;</span><br><span class=\"line\"> tests[<span class=\"string\">`[INFO] 返回:<span class=\"subst\">${responseBody}</span>`</span>] = <span class=\"literal\">true</span>;</span><br><span class=\"line\"> <span class=\"built_in\">console</span>.error(err);</span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"keyword\">if</span> (json) {</span><br><span class=\"line\"> <span class=\"keyword\">const</span> result = tv4.validateResult(json, schema);</span><br><span class=\"line\"> <span class=\"built_in\">console</span>.log(result);</span><br><span class=\"line\"> tests[<span class=\"string\">'JSON Schema格式正确 '</span> + result.error ] = result.valid;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"built_in\">console</span>.error(result.error);</span><br><span class=\"line\"> <span class=\"built_in\">console</span>.error(responseBody);</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["3.Testing","接口"],"tags":["接口"]},{"title":"Postman设置环境变量和全局变量","url":"/3.Testing/%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/Postman%E8%AE%BE%E7%BD%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E5%92%8C%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F/","content":"<h2 id=\"设置环境变量\"><a href=\"#设置环境变量\" class=\"headerlink\" title=\"设置环境变量\"></a>设置环境变量</h2><h3 id=\"postman通过变换环境变量来快速变换环境地址\"><a href=\"#postman通过变换环境变量来快速变换环境地址\" class=\"headerlink\" title=\"postman通过变换环境变量来快速变换环境地址\"></a>postman通过变换环境变量来快速变换环境地址</h3><p><img src=\"/images/20190730-1.png\" alt=\"postman\"></p>\n<h3 id=\"现可以将localhost-80信息添加至环境\"><a href=\"#现可以将localhost-80信息添加至环境\" class=\"headerlink\" title=\"现可以将localhost:80信息添加至环境\"></a>现可以将localhost:80信息添加至环境</h3><p><img src=\"/images/20190730-2.png\" alt=\"postman\"></p>\n<h3 id=\"点击确定后,在首页可看到已添加的环境变量信息及设置的变量信息\"><a href=\"#点击确定后,在首页可看到已添加的环境变量信息及设置的变量信息\" class=\"headerlink\" title=\"点击确定后,在首页可看到已添加的环境变量信息及设置的变量信息\"></a>点击确定后,在首页可看到已添加的环境变量信息及设置的变量信息</h3><p><img src=\"/images/20190730-3.png\" alt=\"postman\"></p>\n<h2 id=\"设置全局变量\"><a href=\"#设置全局变量\" class=\"headerlink\" title=\"设置全局变量\"></a>设置全局变量</h2><h3 id=\"设置全局变量-1\"><a href=\"#设置全局变量-1\" class=\"headerlink\" title=\"设置全局变量\"></a>设置全局变量</h3><p>进入全局变量设置页面;</p>\n<p><img src=\"/images/20190730-4.png\" alt=\"postman\"></p>\n<h3 id=\"设置变量值\"><a href=\"#设置变量值\" class=\"headerlink\" title=\"设置变量值\"></a>设置变量值</h3><p>key填<code>token</code>,value填<code>123456</code>(填具体token的值),点右下角<code>Save</code>保存全局变量。如有多个可以全部填好再保存。(全局变量值可用js获取实现)</p>\n<p><img src=\"/images/20190730-5.png\" alt=\"postman\"></p>\n<h3 id=\"获取变量值\"><a href=\"#获取变量值\" class=\"headerlink\" title=\"获取变量值\"></a>获取变量值</h3><p>在<code>Headers</code>中添加一个header,key填<code>token</code>(接口自行规定),value为<code>{{token}}</code>(刚刚在global设置的key)。鼠标移动到上面,会显示具体的value值。也可以点右上角的小眼睛,看所有的全局变量。</p>\n<p><img src=\"/images/20190730-6.png\" alt=\"postman\"></p>\n<h3 id=\"查看日志\"><a href=\"#查看日志\" class=\"headerlink\" title=\"查看日志\"></a>查看日志</h3><p>View–Show Postman Console</p>\n","categories":["3.Testing","接口"],"tags":["接口"]},{"title":"Dcoker使用普通用户执行","url":"/4.ToolsNotes/Docker/Dcoker%E4%BD%BF%E7%94%A8%E6%99%AE%E9%80%9A%E7%94%A8%E6%88%B7%E6%89%A7%E8%A1%8C/","content":"<p>原文:<a href=\"https://www.cnblogs.com/klvchen/p/9098745.html\">https://www.cnblogs.com/klvchen/p/9098745.html</a></p>\n<h4 id=\"CentOS-版本-7-4,Docker-版本-docker-1-13-及以下\"><a href=\"#CentOS-版本-7-4,Docker-版本-docker-1-13-及以下\" class=\"headerlink\" title=\"CentOS 版本 7.4,Docker 版本 docker-1.13 及以下\"></a>CentOS 版本 7.4,Docker 版本 docker-1.13 及以下</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">ll /var/run/docker.sock</span><br><span class=\"line\">srw-rw----. 1 root root 0 May 25 14:43 /var/run/docker.sock</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 添加 docker 用户组</span></span><br><span class=\"line\">groupadd docker</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 把需要执行的 docker 用户添加进该组,这里是 ibaboss</span></span><br><span class=\"line\">gpasswd -a ibaboss docker</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 重启 docker</span></span><br><span class=\"line\">systemctl restart docker</span><br><span class=\"line\"></span><br><span class=\"line\">su - ibaboss</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 运行成功</span></span><br><span class=\"line\">docker ps -a </span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"CentOS-版本-7-4,Docker-版本-docker-ce-17-及以上\"><a href=\"#CentOS-版本-7-4,Docker-版本-docker-ce-17-及以上\" class=\"headerlink\" title=\"CentOS 版本 7.4,Docker 版本 docker-ce 17 及以上\"></a>CentOS 版本 7.4,Docker 版本 docker-ce 17 及以上</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">ll /var/run/docker.sock</span><br><span class=\"line\"></span><br><span class=\"line\">srw-rw----. 1 root docker 0 May 25 14:12 /var/run/docker.sock</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 添加执行 docker 命令的用户,这里为 ibaboss</span></span><br><span class=\"line\">useradd ibaboss</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"> 把 ibaboss 用户加入 docker 组</span></span><br><span class=\"line\">usermod -G docker ibaboss </span><br><span class=\"line\"></span><br><span class=\"line\">su - ibaboss</span><br><span class=\"line\"></span><br><span class=\"line\">docker ps -a </span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"注意事项\"><a href=\"#注意事项\" class=\"headerlink\" title=\"注意事项\"></a>注意事项</h4><p>如果之前是使用 root 用户拉取的镜像,ibaboss 用户启动镜像可能会出现问题,eg:<br>docker.elastic.co/elasticsearch/elasticsearch 6.2.4<br>会出现<br>mktemp: failed to create directory via template ‘/tmp/elasticsearch.XXXXXXXX’: Permission denied<br>解决方案:<br>使用 ibaboss 用户重新拉取镜像</p>\n","categories":["4. ToolsNotes","Docker"],"tags":["Docker"]},{"title":"Docker配置参数详解---/etc/docker/daemon.json完整参数","url":"/4.ToolsNotes/Docker/Dcoker%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E8%AF%A6%E8%A7%A3/","content":"<h2 id=\"Docker配置参数详解\"><a href=\"#Docker配置参数详解\" class=\"headerlink\" title=\"Docker配置参数详解\"></a>Docker配置参数详解</h2><p><strong>实际配置的参数</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">{"insecure-registries":["XXX.XXX.XXX.XXX:XXX"] }</span><br><span class=\"line\">{ </span><br><span class=\"line\"> "credsStore": "pass"</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n\n\n<p><strong>全部参数</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">{</span><br><span class=\"line\">“api-cors-header”:"", ——————在引擎API中设置CORS标头</span><br><span class=\"line\">“authorization-plugins”:[], ——————要加载的授权插件</span><br><span class=\"line\">“bridge”:"", ————将容器附加到网桥</span><br><span class=\"line\">“cgroup-parent”:"", ——————为所有容器设置父cgroup</span><br><span class=\"line\">“cluster-store”:"", ——————分布式存储后端的URL</span><br><span class=\"line\">“cluster-store-opts”:{}, ————————设置集群存储选项(默认map [])</span><br><span class=\"line\">“cluster-advertise”:"", ————————要通告的地址或接口名称</span><br><span class=\"line\">“debug”: true, ————————启用调试模式,启用后,可以看到很多的启动信息。默认false</span><br><span class=\"line\">“default-gateway”:"", ——————容器默认网关IPv4地址</span><br><span class=\"line\">“default-gateway-v6”:"", ——————容器默认网关IPv6地址</span><br><span class=\"line\">“default-runtime”:“runc”, ————————容器的默认OCI运行时(默认为“ runc”)</span><br><span class=\"line\">“default-ulimits”:{}, ——————容器的默认ulimit(默认[])</span><br><span class=\"line\">“dns”: [“192.168.1.1”], ——————设定容器DNS的地址,在容器的 /etc/resolv.conf文件中可查看。</span><br><span class=\"line\">“dns-opts”: [], ————————容器 /etc/resolv.conf 文件,其他设置</span><br><span class=\"line\">“dns-search”: [], ————————设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的 主机时,DNS不仅搜索host,还会搜</span><br><span class=\"line\">索host.example.com 。 注意:如果不设置, Docker 会默认用主机上的 /etc/resolv.conf 来配置容器。</span><br><span class=\"line\">“exec-opts”: [], ————————运行时执行选项</span><br><span class=\"line\">“exec-root”:"", ————————执行状态文件的根目录(默认为’/var/run/docker‘)</span><br><span class=\"line\">“fixed-cidr”:"", ————————固定IP的IPv4子网</span><br><span class=\"line\">“fixed-cidr-v6”:"", ————————固定IP的IPv6子网</span><br><span class=\"line\">“data-root”:"/var/lib/docker", ————-Docker运行时使用的根路径,默认/var/lib/docker</span><br><span class=\"line\">“group”: “”, ——————UNIX套接字的组(默认为“docker”)</span><br><span class=\"line\">“hosts”: [], ——————设置容器hosts</span><br><span class=\"line\">“icc”: false, ——————启用容器间通信(默认为true)</span><br><span class=\"line\">“ip”:“0.0.0.0”, ————————绑定容器端口时的默认IP(默认0.0.0.0)</span><br><span class=\"line\">“iptables”: false, ———————启用iptables规则添加(默认为true)</span><br><span class=\"line\">“ipv6”: false, ——————启用IPv6网络</span><br><span class=\"line\">“ip-forward”: false, ————————默认true, 启用 net.ipv4.ip_forward ,进入容器后使用 sysctl -a | grepnet.ipv4.ip_forward 查看</span><br><span class=\"line\">“ip-masq”:false, ——————启用IP伪装(默认为true)</span><br><span class=\"line\">“labels”:[“nodeName=node-121”], ————————docker主机的标签,很实用的功能,例如定义:–label nodeName=host-121</span><br><span class=\"line\">“live-restore”: true, ——————在容器仍在运行时启用docker的实时还原</span><br><span class=\"line\">“log-driver”:"", ——————容器日志的默认驱动程序(默认为“ json-file”)</span><br><span class=\"line\">“log-level”:"", ——————设置日志记录级别(“调试”,“信息”,“警告”,“错误”,“致命”)(默认为“信息”)</span><br><span class=\"line\">“max-concurrent-downloads”:3, ——————设置每个请求的最大并发下载量(默认为3)</span><br><span class=\"line\">“max-concurrent-uploads”:5, ——————设置每次推送的最大同时上传数(默认为5)</span><br><span class=\"line\">“mtu”: 0, ——————设置容器网络MTU</span><br><span class=\"line\">“oom-score-adjust”:-500, ——————设置守护程序的oom_score_adj(默认值为-500)</span><br><span class=\"line\">“pidfile”: “”, ——————Docker守护进程的PID文件</span><br><span class=\"line\">“raw-logs”: false, ——————全时间戳机制</span><br><span class=\"line\">“selinux-enabled”: false, ——————默认 false,启用selinux支持</span><br><span class=\"line\">“storage-driver”:"", ——————要使用的存储驱动程序</span><br><span class=\"line\">“swarm-default-advertise-addr”:"", ——————设置默认地址或群集广告地址的接口</span><br><span class=\"line\">“tls”: true, ————————默认 false, 启动TLS认证开关</span><br><span class=\"line\">“tlscacert”: “”, ——————默认 ~/.docker/ca.pem,通过CA认证过的的certificate文件路径</span><br><span class=\"line\">“tlscert”: “”, ————————默认 ~/.docker/cert.pem ,TLS的certificate文件路径</span><br><span class=\"line\">“tlskey”: “”, ————————默认~/.docker/key.pem,TLS的key文件路径</span><br><span class=\"line\">“tlsverify”: true, ————————默认false,使用TLS并做后台进程与客户端通讯的验证</span><br><span class=\"line\">“userland-proxy”:false, ——————使用userland代理进行环回流量(默认为true)</span><br><span class=\"line\">“userns-remap”:"", ————————用户名称空间的用户/组设置</span><br><span class=\"line\">“bip”:“192.168.88.0/22”, ——————————指定网桥IP</span><br><span class=\"line\">“registry-mirrors”: [“https://192.498.89.232:89”], ————————设置镜像加速</span><br><span class=\"line\">“insecure-registries”: [“120.123.122.123:12312”], ———————设置私有仓库地址可以设为http</span><br><span class=\"line\">“storage-opts”: [</span><br><span class=\"line\">“overlay2.override_kernel_check=true”,</span><br><span class=\"line\">“overlay2.size=15G”</span><br><span class=\"line\">], ————————存储驱动程序选项</span><br><span class=\"line\">“log-opts”: {</span><br><span class=\"line\">“max-file”: “3”,</span><br><span class=\"line\">“max-size”: “10m”,</span><br><span class=\"line\">}, ————————容器默认日志驱动程序选项</span><br><span class=\"line\">“iptables”: false ————————启用iptables规则添加(默认为true)</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Docker"],"tags":["Docker"]},{"title":"Docker上传镜像至Harbor","url":"/4.ToolsNotes/Docker/Docker%E4%B8%8A%E4%BC%A0%E9%95%9C%E5%83%8F%E8%87%B3Harbor/","content":"<p>构造镜像的两种方式:1.commit 2.Dockerfile</p>\n<p>Docker提供了一个docker commit命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。</p>\n<p>以后我们运行这个新镜像的时候,就会拥有原有容器的最后的文件变化。</p>\n<p>docker commit的语法格式为:</p>\n<figure class=\"highlight sh\"><table><tr><td class=\"code\"><pre><span class=\"line\">docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]</span><br></pre></td></tr></table></figure>\n\n<p> 实例:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">docker commit -m 'Test' -a 'Tester' 14277e296feb 192.168.0.0:8888/shtest/rtmp:v2</span><br></pre></td></tr></table></figure>\n\n<p>-m ‘Test’ :记录本地修改的内容</p>\n<p>-a ‘Tester’:指定修改的作者</p>\n<p>14277e296feb:复制的基础镜像</p>\n<p>192.168.0.0:8888/shetest/rtmp:复制后的镜像</p>\n<p>v2:复制后的镜像tag</p>\n","categories":["4. ToolsNotes","Docker"],"tags":["Docker"]},{"title":"Docker本地/容器文件互传","url":"/4.ToolsNotes/Docker/Docker%E6%9C%AC%E5%9C%B0:%E5%AE%B9%E5%99%A8%E6%96%87%E4%BB%B6%E4%BA%92%E4%BC%A0/","content":"<h4 id=\"将容器内文件拷贝到宿主机\"><a href=\"#将容器内文件拷贝到宿主机\" class=\"headerlink\" title=\"将容器内文件拷贝到宿主机\"></a>将容器内文件拷贝到宿主机</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">docker cp <containerId>:/导出文件的位置/xxx.sql /宿主机的位置</span></span><br><span class=\"line\"></span><br><span class=\"line\">示例:</span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">docker cp bf4c4fff338c:/root/rest.sql /root/</span></span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"将宿主机文件拷贝到容器内\"><a href=\"#将宿主机文件拷贝到容器内\" class=\"headerlink\" title=\"将宿主机文件拷贝到容器内\"></a>将宿主机文件拷贝到容器内</h4><h5 id=\"查找所有容器\"><a href=\"#查找所有容器\" class=\"headerlink\" title=\"查找所有容器\"></a>查找所有容器</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">docker ps a</span></span><br></pre></td></tr></table></figure>\n\n<p><img src=\"/images/20190717-1.png\" alt=\"images\"></p>\n<h5 id=\"查找容器名字和容器长ID\"><a href=\"#查找容器名字和容器长ID\" class=\"headerlink\" title=\"查找容器名字和容器长ID\"></a>查找容器名字和容器长ID</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">docker inspect -f <span class=\"string\">'{{.ID}}'</span> python</span></span><br></pre></td></tr></table></figure>\n\n<h5 id=\"拷贝本地文件到容器\"><a href=\"#拷贝本地文件到容器\" class=\"headerlink\" title=\"拷贝本地文件到容器\"></a>拷贝本地文件到容器</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">docker cp 本地路径 容器长ID:容器路径</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\">docker cp /XXX/auto-post-advance.py 容器长ID:/root/auto-post-advance.py</span></span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Docker"],"tags":["Docker"]},{"title":"Harbor安装及使用","url":"/4.ToolsNotes/Docker/Harbor%E5%AE%89%E8%A3%85%E5%8F%8A%E4%BD%BF%E7%94%A8/","content":"<h4 id=\"Harbor简介\"><a href=\"#Harbor简介\" class=\"headerlink\" title=\"Harbor简介\"></a>Harbor简介</h4><p>Harbor是一个用于存储和分发Docker镜像的企业级私有Registry服务器。</p>\n<h4 id=\"Harbor安装\"><a href=\"#Harbor安装\" class=\"headerlink\" title=\"Harbor安装\"></a>Harbor安装</h4><h5 id=\"选择Harbor版本\"><a href=\"#选择Harbor版本\" class=\"headerlink\" title=\"选择Harbor版本\"></a>选择Harbor版本</h5><p>官网地址:<a href=\"https://github.com/goharbor/harbor/releases\">https://github.com/goharbor/harbor/releases</a></p>\n<p>下载harbor-online-installer-v1.7.5.tgz</p>\n<p><img src=\"/images/20200214-1.png\" alt=\"harbot\"></p>\n<h5 id=\"下载软件\"><a href=\"#下载软件\" class=\"headerlink\" title=\"下载软件\"></a>下载软件</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">cd /data/harbor/</span><br><span class=\"line\"></span><br><span class=\"line\">wget https://storage.googleapis.com/harbor-releases/release-1.7.0/harbor-online-installer-v1.7.5.tgz</span><br><span class=\"line\"></span><br><span class=\"line\">sudo tar xf harbor-online-installer-v1.7.5.tgz</span><br></pre></td></tr></table></figure>\n\n<h5 id=\"开始安装\"><a href=\"#开始安装\" class=\"headerlink\" title=\"开始安装\"></a>开始安装</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@qa02v harbor]# [root@qa02v harbor]# </span><br><span class=\"line\"><code class="hljs coffeescript">docker-compose pull</code></span><br><span class=\"line\"></span><br><span class=\"line\">[root@qa02v harbor]# [root@qa02v harbor]# ./install.sh</span><br><span class=\"line\">总用量 1588</span><br><span class=\"line\">drwxr-xr-x 4 root root 35 1月 20 12:16 common</span><br><span class=\"line\">-rw-r--r-- 1 root root 727 11月 9 2018 docker-compose.chartmuseum.yml</span><br><span class=\"line\">-rw-r--r-- 1 root root 777 11月 9 2018 docker-compose.clair.yml</span><br><span class=\"line\">-rw-r--r-- 1 root root 1258 11月 9 2018 docker-compose.notary.yml</span><br><span class=\"line\">-rw-r--r-- 1 root root 3591 1月 20 12:35 docker-compose.yml</span><br><span class=\"line\">drwxr-xr-x 3 root root 131 11月 9 2018 ha</span><br><span class=\"line\">-rw-r--r-- 1 root root 7908 1月 20 12:14 harbor.cfg</span><br><span class=\"line\">-rwxr-xr-x 1 root root 6162 11月 9 2018 install.sh</span><br><span class=\"line\">-rw-r--r-- 1 root root 10768 11月 9 2018 LICENSE</span><br><span class=\"line\">-rw-r--r-- 1 root root 482 11月 9 2018 NOTICE</span><br><span class=\"line\">-rw-r--r-- 1 root root 1535603 11月 9 2018 open_source_license</span><br><span class=\"line\">-rwxr-xr-x 1 root root 39496 11月 9 2018 prepare</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">#</span><span class=\"bash\"><span class=\"comment\">######################################################</span></span></span><br><span class=\"line\">harbor.cfg #这就是harbor的配置文件了</span><br><span class=\"line\">install.sh #安装脚本</span><br><span class=\"line\">docker-compose.yml #docker-compose启动文件</span><br></pre></td></tr></table></figure>\n\n<p>#修改配置文件</p>\n<p><strong># sudo vi /data/harbor/harbor.cfg</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">hostname = XXX.XXX.XXX.XXX #如果端口冲突则增加端口信息 hostname = XXX.XXX.XXX.XXX:XXX</span><br><span class=\"line\"></span><br><span class=\"line\">harbor_admin_password = xxxxxxx (备注:密码自己设置8位,默认Harbor12345)</span><br></pre></td></tr></table></figure>\n\n<p> <strong># sudo vi docker-compose.yml</strong></p>\n<p>如果端口冲突,就更改端口: 80改成:8080</p>\n<p>\u000b<img src=\"/images/20200214-2.png\" alt=\"harbor\"></p>\n<h5 id=\"启动harbor\"><a href=\"#启动harbor\" class=\"headerlink\" title=\"启动harbor\"></a>启动harbor</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">nulige@harbor:/nulige/tools/harbor$ sudo docker-compose up -d</span><br><span class=\"line\">harbor-log is up-to-date</span><br><span class=\"line\">harbor-adminserver is up-to-date</span><br><span class=\"line\">harbor-db is up-to-date</span><br><span class=\"line\">registry is up-to-date</span><br><span class=\"line\">redis is up-to-date</span><br><span class=\"line\">registryctl is up-to-date</span><br><span class=\"line\">harbor-core is up-to-date</span><br><span class=\"line\">harbor-portal is up-to-date</span><br><span class=\"line\">harbor-jobservice is up-to-date</span><br><span class=\"line\">Recreating nginx ...</span><br><span class=\"line\">Recreating nginx ... done </span><br></pre></td></tr></table></figure>\n\n<h5 id=\"登录首页\"><a href=\"#登录首页\" class=\"headerlink\" title=\"登录首页\"></a>登录首页</h5><p><a href=\"http://XXX.XXX.XXX.XXX:XXX\">http://XXX.XXX.XXX.XXX:XXX</a></p>\n<p>账号: admin</p>\n<p>密码:xxxxxxxx (自已设置的密码)</p>\n<h5 id=\"修改daemon-json\"><a href=\"#修改daemon-json\" class=\"headerlink\" title=\"修改daemon.json\"></a>修改daemon.json</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@qa02v harbor]# cat /etc/docker/daemon.json</span><br><span class=\"line\">{"insecure-registries":["XXX.XXX.XXX.XXX:XXX"] }</span><br><span class=\"line\">{</span><br><span class=\"line\"> "credsStore": "pass"</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h5 id=\"重启docker\"><a href=\"#重启docker\" class=\"headerlink\" title=\"重启docker\"></a>重启docker</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">[root@qa02v harbor]# systemctl restart docker</span><br></pre></td></tr></table></figure>\n\n<h5 id=\"登录docker\"><a href=\"#登录docker\" class=\"headerlink\" title=\"登录docker\"></a>登录docker</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">docker login -u admin -p Harbor12345 http://XXX.XXX.XXX.XXX:XXX</span><br></pre></td></tr></table></figure>\n\n<h5 id=\"修改tag\"><a href=\"#修改tag\" class=\"headerlink\" title=\"修改tag\"></a>修改tag</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">docker tag docker.io/jrottenberg/ffmpeg XXX.XXX.XXX.XXX:XXX/shtest/ffmpeg:v1.0</span><br></pre></td></tr></table></figure>\n\n<h5 id=\"上传镜像至Harbor\"><a href=\"#上传镜像至Harbor\" class=\"headerlink\" title=\"上传镜像至Harbor\"></a>上传镜像至Harbor</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">docker push XXX.XXX.XXX.XXX:XXX/shtest/ffmpeg:v1.0</span><br></pre></td></tr></table></figure>\n\n<h5 id=\"下载镜像至本地\"><a href=\"#下载镜像至本地\" class=\"headerlink\" title=\"下载镜像至本地\"></a>下载镜像至本地</h5><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">docker pull XXX.XXX.XXX.XXX:XXX/shtest/ffmpeg:v1.0</span><br></pre></td></tr></table></figure>\n\n\n\n<h4 id=\"docker-login-遇到的问题\"><a href=\"#docker-login-遇到的问题\" class=\"headerlink\" title=\"docker login 遇到的问题\"></a>docker login 遇到的问题</h4><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">Username: yanshinian</span><br><span class=\"line\">Password:</span><br><span class=\"line\">Error saving credentials: error storing credentials - err: exit status 1, out: `The user name or passphrase you entered is not correct.`</span><br></pre></td></tr></table></figure>\n\n<p>参考链接:<a href=\"https://github.com/docker/docker-credential-helpers/issues/65\">https://github.com/docker/docker-credential-helpers/issues/65</a></p>\n<p>解决办法:rm /usr/local/bin/docker-credential-osxkeychain</p>\n<h5 id=\"参考资料\"><a href=\"#参考资料\" class=\"headerlink\" title=\"参考资料\"></a>参考资料</h5><p><a href=\"https://blog.51cto.com/bigboss/2316525\">Docker私有仓库Harbor v1.6.1安装</a><a href=\"https://blog.51cto.com/bigboss/2317324?source=drh\">\n</a></p>\n<p><a href=\"https://www.cnblogs.com/nulige/p/10778554.html\"><a href=\"https://www.cnblogs.com/nulige/p/10778554.html\">安装Harbor之http版本</a></a></p>\n","categories":["4. ToolsNotes","Docker"],"tags":["Docker"]},{"title":"docker-compose 管理docker的多容器配置","url":"/4.ToolsNotes/Docker/docker-compose%20%E7%AE%A1%E7%90%86docker%E7%9A%84%E5%A4%9A%E5%AE%B9%E5%99%A8%E9%85%8D%E7%BD%AE/","content":"<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">version: '3.4'</span><br><span class=\"line\">x-defaults: &defaults</span><br><span class=\"line\"> restart: unless-stopped#启动模式,当值为always时,容器总是重新启动;当值为no-failure时,即出现报错容器退出时,容器重新启动;unless-stopped为容器自启模式</span><br><span class=\"line\"> network_mode: "host"</span><br><span class=\"line\">services:</span><br><span class=\"line\"> mysql: #服务名</span><br><span class=\"line\"> hostname: mysql #主机名</span><br><span class=\"line\"> image: mysql/mysql:latest #镜像</span><br><span class=\"line\"> container_name: mysql #容器名称</span><br><span class=\"line\"> environment:</span><br><span class=\"line\"> - TZ=Asia/Shanghai #时区</span><br><span class=\"line\"> ports: #端口</span><br><span class=\"line\"> - 80:80</span><br><span class=\"line\"> - 3000:3000</span><br><span class=\"line\"> volumes:</span><br><span class=\"line\"> - "/etc/localtime:/etc/localtime:ro" # 设置容器时区与宿主机保持一致</span><br><span class=\"line\"> - /home/用户名/mysql/data:/data</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Docker"],"tags":["Docker"]},{"title":"Jenkins-pipeline使用邮件扩展发送邮件","url":"/4.ToolsNotes/Jenkins/Jenkins-pipeline%E4%BD%BF%E7%94%A8%E9%82%AE%E4%BB%B6%E6%89%A9%E5%B1%95%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6/","content":"<h3 id=\"Jenkins-pipeline-使用邮件扩展发送邮件\"><a href=\"#Jenkins-pipeline-使用邮件扩展发送邮件\" class=\"headerlink\" title=\"Jenkins pipeline 使用邮件扩展发送邮件\"></a>Jenkins pipeline 使用邮件扩展发送邮件</h3><p><a href=\"https://www.cnblogs.com/imyalost/p/8781759.html\">参考</a></p>\n<h3 id=\"Jenkins配置邮件通知\"><a href=\"#Jenkins配置邮件通知\" class=\"headerlink\" title=\"Jenkins配置邮件通知\"></a>Jenkins配置邮件通知</h3><p><a href=\"https://blog.51cto.com/5766902/2317533\">参考</a></p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins-pipeline参数化显示及插件","url":"/4.ToolsNotes/Jenkins/Jenkins-pipeline%E5%8F%82%E6%95%B0%E5%8C%96%E6%98%BE%E7%A4%BA%E5%8F%8A%E6%8F%92%E4%BB%B6/","content":"<h2 id=\"Git-Parameter\"><a href=\"#Git-Parameter\" class=\"headerlink\" title=\"Git Parameter\"></a>Git Parameter</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">gitParameter branch: '',</span><br><span class=\"line\"></span><br><span class=\"line\">branchFilter: '.*', #分支过滤</span><br><span class=\"line\"></span><br><span class=\"line\">defaultValue: 'master',</span><br><span class=\"line\"></span><br><span class=\"line\">description: '选择代码分支',</span><br><span class=\"line\"></span><br><span class=\"line\">name: 'branch',</span><br><span class=\"line\"></span><br><span class=\"line\">quickFilterEnabled: false, #快速搜索</span><br><span class=\"line\"></span><br><span class=\"line\">selectedValue: 'NONE',</span><br><span class=\"line\"></span><br><span class=\"line\">sortMode: 'NONE', #排序</span><br><span class=\"line\"></span><br><span class=\"line\">tagFilter: '*', #tag过滤</span><br><span class=\"line\"></span><br><span class=\"line\">type: 'PT_BRANCH' </span><br></pre></td></tr></table></figure>\n\n\n\n<h2 id=\"when判断\"><a href=\"#when判断\" class=\"headerlink\" title=\"when判断\"></a>when判断</h2><p><a href=\"https://www.cnblogs.com/zoujiaojiao/p/13219057.html\">参考</a></p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins-pipeline资料汇总","url":"/4.ToolsNotes/Jenkins/Jenkins-pipeline%E8%B5%84%E6%96%99%E6%B1%87%E6%80%BB/","content":"<p><a href=\"https://www.cnblogs.com/python-diy/p/10381385.html\">docker-compose 快速部署持续集成环境</a></p>\n<p><a href=\"https://www.jenkins.io/zh/doc/book/pipeline/syntax/\">Jenkins流水线语法</a></p>\n<p><a href=\"https://jenkins.io/zh/doc/\">Jenkins 用户手册</a></p>\n<p><a href=\"https://blog.51cto.com/11243465/2157080?source=dra\">Jenkins Pipeline+Docker实现流水线自动化构建(上百个项目共用一个脚本方案)-linux运维-51CTO博客</a></p>\n<p><a href=\"https://wiki.jenkins.io/display/JENKINS/Git+Parameter+Plugin\">Git Parameter Plugin - Jenkins - Jenkins Wiki</a></p>\n<p><a href=\"https://www.w3cschool.cn/jenkins/jenkins-qc8a28op.html\">Jenkinsfile使用_w3cschool</a></p>\n<p><a href=\"https://blog.51cto.com/bigboss/2317324?source=drh\">Gitlab+Harbor+Jenkins pipeline实现利用tag部署docker容器-三和大神-51CTO博客</a></p>\n<p><a href=\"https://blog.csdn.net/xj90314/article/details/100074208\">Jenkins配置pipeline选择git分支发布 - xj90314的专栏 - CSDN博客</a></p>\n<p><a href=\"https://www.cnblogs.com/xiaodai12138/p/9996995.html\">Jenkins Pipeline+Maven+Gitlab持续集成构建 - xiaodai12138 - 博客园</a></p>\n<p><a href=\"https://www.cnblogs.com/cay83/p/7537843.html\">持续交付实践pipeline使用:项目样例 - 蒋刚毅 - 博客园</a></p>\n<p><a href=\"https://www.cnblogs.com/111testing/p/9721424.html\">Jenkins pipeline 语法详解 - 清风软件测试 - 博客园</a></p>\n<p><a href=\"https://www.jianshu.com/p/c3a858050c31\">Jenkins Pipeline与Docker的集成实践 - 简书</a></p>\n<p><a href=\"http://www.pianshen.com/article/4561306963/\">Jenkins与Docker的自动化CI/CD - 程序员大本营</a></p>\n<p><a href=\"http://linuxsogood.org/1551.html\">基于jenkins参数化构建git项目(可选择要构建的git分支) – Honway’s Blog</a></p>\n<p><a href=\"https://www.jianshu.com/p/c94eb8a739f9\">jenkins应用【参数化构建过程】 - 简书</a></p>\n<p><a href=\"https://www.jianshu.com/p/18327865a38a\">Jenkins Pipeline语法(上) - 简书</a></p>\n<p><a href=\"https://blog.csdn.net/workdsz/article/category/7125153/1\">【 分类 】- jenkins - workdsz的专栏 - CSDN博客</a></p>\n<p>问题总结:</p>\n<p><a href=\"https://blog.csdn.net/a_story_donkey/article/details/85163306\">docker registry push/pull 错误“server gave HTTP response to HTTPS client” - 李阳阳的博客 - CSDN博客</a></p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins在不同的stage之间共享文件","url":"/4.ToolsNotes/Jenkins/Jenkins%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84stage%E4%B9%8B%E9%97%B4%E5%85%B1%E4%BA%AB%E6%96%87%E4%BB%B6/","content":"<p>在使用 k8s 或者 docker 作为 jenkins 的 slave 的时候,会出现一个问题:两个 stage 可能不再同一个机器,或者不再同一个目录上,stage A 中编译的 dist 文件, stage B 中部署需要用到的时候当前目录无法找到 dist 文件。解决方式是使用 stash 和 unstash。</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">stage("npm build") {</span><br><span class=\"line\"> when {</span><br><span class=\"line\"> branch "dev"</span><br><span class=\"line\"> }</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> sh """</span><br><span class=\"line\"> npm run deploy</span><br><span class=\"line\"> """</span><br><span class=\"line\"> stash includes: 'dist/**/*', name:'npm_dist'</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br><span class=\"line\">stage("ansible deploy") {</span><br><span class=\"line\"> when {</span><br><span class=\"line\"> branch "dev"</span><br><span class=\"line\"> }</span><br><span class=\"line\"> agent {</span><br><span class=\"line\"> docker {</span><br><span class=\"line\"> image "ansible:1.2.11"</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> unstash 'npm_dist'</span><br><span class=\"line\"> script {</span><br><span class=\"line\"> if (fileExists('dist.zip')) {</span><br><span class=\"line\"> sh('rm -f dist.zip')</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> zip zipFile: 'dist.zip',archive: false,dir: 'dist'</span><br><span class=\"line\"> sh """</span><br><span class=\"line\"> ansible-playbook ansible-deploy.yml --inventory-file=hosts -e target=dev --timeout=120</span><br><span class=\"line\"> """</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins在容器中编译代码","url":"/4.ToolsNotes/Jenkins/Jenkins%E5%9C%A8%E5%AE%B9%E5%99%A8%E4%B8%AD%E7%BC%96%E8%AF%91%E4%BB%A3%E7%A0%81/","content":"<p><strong>1、声明式</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">stages{</span><br><span class=\"line\"> stage("go build") {</span><br><span class=\"line\"> agent {</span><br><span class=\"line\"> image "golang:1.12.1"</span><br><span class=\"line\"> }</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> sh """</span><br><span class=\"line\"> go build</span><br><span class=\"line\"> """</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p><strong>2、脚本式</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">stages {</span><br><span class=\"line\"> stage("go build") {</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> script {</span><br><span class=\"line\"> docker.image("golang:1.12.1").inside() {</span><br><span class=\"line\"> sh """</span><br><span class=\"line\"> go build</span><br><span class=\"line\"> """</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、前端</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">stage("npm build") {</span><br><span class=\"line\"> agent {</span><br><span class=\"line\"> docker {</span><br><span class=\"line\"> image "XXX/node:1.1.3"</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> sh """</span><br><span class=\"line\"> npm run build</span><br><span class=\"line\"> """</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins将Slave运行在Docker容器中","url":"/4.ToolsNotes/Jenkins/Jenkins%E5%B0%86Slave%E8%BF%90%E8%A1%8C%E5%9C%A8Docker%E5%AE%B9%E5%99%A8%E4%B8%AD/","content":"<h2 id=\"说明\"><a href=\"#说明\" class=\"headerlink\" title=\"说明\"></a>说明</h2><p>Jenkins的Master-Slave架构特点可解决多并发任务的负载问题;Master节点提供WebGUI和API功能来管理运行任务,Slave节点运行Master分配的任务;这也意味着Slave节点可以分布在不同平台并且无需安装Jenkins的完整包。</p>\n<h2 id=\"配置\"><a href=\"#配置\" class=\"headerlink\" title=\"配置\"></a>配置</h2><p>jenkins版本:V2.249.1</p>\n<h3 id=\"添加node节点配置\"><a href=\"#添加node节点配置\" class=\"headerlink\" title=\"添加node节点配置\"></a>添加node节点配置</h3><p><strong>1、首页-ManageJenkins-ManageNodesAndClouds页面,新建节点操作</strong><br><img src=\"/images/20201214-16.png\" alt=\"addnode\"></p>\n<p><strong>2、首页-新建自由风格任务选择该Slave节点</strong></p>\n<p><img src=\"/images/20201214-4.png\" alt=\"addnode\"></p>\n<p><strong>3、运行</strong></p>\n<p><img src=\"/images/20201214-5.png\" alt=\"run\"></p>\n<h3 id=\"添加Docker节点信息\"><a href=\"#添加Docker节点信息\" class=\"headerlink\" title=\"添加Docker节点信息\"></a>添加Docker节点信息</h3><p><strong>1、Jenkins首页-ManageJenkins-ManagePlugins页面,下载「Docker plugin」和「Docker Slaves Plugin」两个插件</strong></p>\n<p><strong>2、Slave机器,下载docker</strong></p>\n<p><img src=\"/images/20201214-6.png\" alt=\"docker\"></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">1 成功下载</span><br><span class=\"line\">2 </span><br><span class=\"line\">3 docker pull jenkins/ssh-slave</span><br></pre></td></tr></table></figure>\n\n<p>因为docker默认不允许外面链接的,所以要修改配置放开:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">修改这个文件 /usr/lib/systemd/system/docker.service中的</span><br><span class=\"line\"></span><br><span class=\"line\">ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock</span><br><span class=\"line\"></span><br><span class=\"line\">改成下面这个</span><br><span class=\"line\">ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock</span><br><span class=\"line\"></span><br><span class=\"line\">然后 systemctl restart docker</span><br></pre></td></tr></table></figure>\n\n<p>设置docker的可执行权限:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">chmod 666 /var/run/docker.sock</span><br></pre></td></tr></table></figure>\n\n<p><strong>3、Jenkins首页-ManageJenkins-ManageNodesAndClouds页面,ConfigureClouds菜单下-AddANewCloud</strong></p>\n<p><img src=\"/images/20201214-7.png\" alt=\"docker\"></p>\n<p><strong>4、配置DOCKER CLOUD DETAILS信息;测试Slave机器docker可访问</strong></p>\n<p><img src=\"/images/20201214-8.png\" alt=\"docker\"></p>\n<p> <strong>5、配置DOCKER AGENT TEMPLATES信息</strong></p>\n<p>基本信息:</p>\n<p><img src=\"/images/20201214-9.png\" alt=\"docker\"></p>\n<p>容器信息:</p>\n<p><img src=\"/images/20201214-10.png\" alt=\"docker\"></p>\n<p><img src=\"/images/20201214-11.png\" alt=\"docker\"></p>\n<p><strong>6、首页-新建自由风格任务选择该Slave节点:</strong></p>\n<p><img src=\"/images/20201214-12.png\" alt=\"docker\"></p>\n<p><strong>7、运行:</strong></p>\n<p>生成镜像过程:</p>\n<p><img src=\"/images/20201214-13.png\" alt=\"docker\"></p>\n<p>执行结果:</p>\n<p><img src=\"/images/20201214-14.png\" alt=\"docker\"></p>\n<h2 id=\"Docker-in-Docker\"><a href=\"#Docker-in-Docker\" class=\"headerlink\" title=\"Docker in Docker\"></a>Docker in Docker</h2><p><img src=\"/images/20201214-15.png\" alt=\"docker\"></p>\n<p>参考 <a href=\"https://blog.csdn.net/qq_31977125/article/details/104000507\">Jenkins Slave in Docker</a></p>\n<h2 id=\"参考\"><a href=\"#参考\" class=\"headerlink\" title=\"参考\"></a>参考</h2><p>参考 <a href=\"https://blog.csdn.net/qq_31977125/article/details/82999872\">Jenkins通过Docker-plugin部署Slave</a></p>\n<p>参考 <a href=\"https://blog.csdn.net/yanggd1987/article/details/105112939\">从socket权限重新认识docker架构</a></p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins常用插件","url":"/4.ToolsNotes/Jenkins/Jenkins%E5%B8%B8%E7%94%A8%E6%8F%92%E4%BB%B6/","content":"<h2 id=\"Timestamper\"><a href=\"#Timestamper\" class=\"headerlink\" title=\"Timestamper\"></a>Timestamper</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">The Timestamper plugin adds timestamps to the console output of Jenkins jobs. For example:</span><br><span class=\"line\"></span><br><span class=\"line\">21:51:15 Started by user anonymous</span><br><span class=\"line\">21:51:15 Building on master</span><br><span class=\"line\">21:51:17 Finished: SUCCESS</span><br></pre></td></tr></table></figure>\n\n<p><strong>使用</strong></p>\n<p><img src=\"/images/20200821-1.png\" alt=\"timestamper\"></p>\n<h2 id=\"AnsiColor\"><a href=\"#AnsiColor\" class=\"headerlink\" title=\"AnsiColor\"></a>AnsiColor</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">This plugin adds support for standard ANSI escape sequences, including color, to Console Output. </span><br></pre></td></tr></table></figure>\n\n<p><strong>使用</strong></p>\n<p><img src=\"/images/20200821-2.png\" alt=\"timestamper\"></p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins更新主题","url":"/4.ToolsNotes/Jenkins/Jenkins%E6%9B%B4%E6%96%B0%E4%B8%BB%E9%A2%98/","content":"<h2 id=\"选择主题\"><a href=\"#选择主题\" class=\"headerlink\" title=\"选择主题\"></a>选择主题</h2><p>主题制作网站 jenkins-material-theme</p>\n<p><strong>1、选择主题颜色</strong><br>可以选择自己喜欢的任何颜色,这里紫色只做演示</p>\n<p><img src=\"/images/20200910-1.png\" alt=\"color\"></p>\n<p><strong>2、上传logo</strong></p>\n<p>要求png格式图片,最小高度40px</p>\n<p><img src=\"/images/20200910-2.png\" alt=\"color\"></p>\n<p><strong>3、下载主题</strong></p>\n<p>上传好logo后就可以下载插件主题</p>\n<ol>\n<li>下载的主题文件名为: <code>jenkins-material-theme.css</code></li>\n</ol>\n<p><img src=\"/images/20200910-3.png\" alt=\"color\"></p>\n<p><strong>4、配置css文件</strong></p>\n<p>在Jenkins安装路径的userContent目录下新建layout文件夹</p>\n<ol>\n<li>将<code>jenkins-material-theme.css</code>文件复制到该目录下</li>\n<li>在该目录下新建title.css文件,其中修改代码里面的content就可以改变Jenkins的Title</li>\n</ol>\n<p><img src=\"/images/20200910-4.png\" alt=\"color\"></p>\n<figure class=\"highlight css\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"selector-id\">#title</span><span class=\"selector-class\">.css</span>内容如下:</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"selector-id\">#jenkins-name-icon</span> {</span><br><span class=\"line\"> <span class=\"attribute\">display</span>: none;</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"selector-class\">.logo</span>:after {</span><br><span class=\"line\"> content: <span class=\"string\">"Jenkins of Chaos-Notebook"</span>;</span><br><span class=\"line\"> <span class=\"attribute\">text-transform</span>:none;</span><br><span class=\"line\"> <span class=\"attribute\">font-weight</span>: bold;</span><br><span class=\"line\"> <span class=\"attribute\">font-size</span>: <span class=\"number\">30px</span>;</span><br><span class=\"line\"> <span class=\"attribute\">color</span>: White;</span><br><span class=\"line\"> <span class=\"attribute\">line-height</span>: <span class=\"number\">40px</span>;</span><br><span class=\"line\"> <span class=\"attribute\">margin-left</span>: <span class=\"number\">40px</span>;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"主题插件配置\"><a href=\"#主题插件配置\" class=\"headerlink\" title=\"主题插件配置\"></a>主题插件配置</h2><p><strong>1、 安装插件</strong></p>\n<blockquote>\n<p><a href=\"https://plugins.jenkins.io/simple-theme-plugin/\">Simple Theme</a></p>\n</blockquote>\n<p><strong>2、配置插件</strong></p>\n<p>Configure System -> Theme, 新增两个Css Url</p>\n<p><img src=\"/images/20200910-5.png\" alt=\"color\"></p>\n<p>添加<code>jenkins-material-theme.css</code>和<code>Title.css</code>的url</p>\n<ol>\n<li><a href=\"http://localhost:8080/userContent/layout/jenkins-material-theme.css\">http://localhost:8080/userContent/layout/jenkins-material-theme.css</a></li>\n<li><a href=\"http://localhost:8080/userContent/layout/title.css\">http://localhost:8080/userContent/layout/title.css</a></li>\n</ol>\n<p><img src=\"/images/20200910-6.png\" alt=\"color\"></p>\n<h2 id=\"新的主题\"><a href=\"#新的主题\" class=\"headerlink\" title=\"新的主题\"></a>新的主题</h2><p>查看新的主题效果</p>\n<p><strong>1、界面整体UI</strong></p>\n<p><img src=\"/images/20200910-7.png\" alt=\"color\"></p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins的权限控制","url":"/4.ToolsNotes/Jenkins/Jenkins%E6%9D%83%E9%99%90%E6%8E%A7%E5%88%B6/","content":"<h2 id=\"介绍\"><a href=\"#介绍\" class=\"headerlink\" title=\"介绍\"></a>介绍</h2><p>多人使用同一套Jenkins进行操作时,会存在任务多部署慢和误操作等不方便之处,二次开发的Jenkins可以通过业务逻辑层进行权限划分,原生的Jenkins则提供了Role-based Authorization Strategy权限插件,分为管理员和普通用户,根据目录来控制用户对job的操作。</p>\n<p><strong>1.创建目录</strong></p>\n<p>在Jenkins首页点击新建任务–》输入名称test–选择文件夹–点击确定—》点击保存,目录就创建好了。</p>\n<p><img src=\"/images/20201214-1.png\" alt=\"新建任务\"></p>\n<p><strong>2.添加角色</strong></p>\n<p>在Jenkins首页,点击系统管理–》选择Manage and Assign Roles–》点击Manage Roles—》在Project roles下,创建角色test,对test目录下的job有权限—》设置角色test的权限—》点击save,保存。</p>\n<p><img src=\"/images/20201214-2.png\" alt=\"添加角色\"></p>\n<p><strong>3.分配角色</strong></p>\n<p>在Jenkins首页点击系统管理–》选择Manage and Assign Roles–-》选择Assign Roles—》在Item roles下,输入用户名wangqian02,点击add,选择角色—》点击save保存</p>\n<p><img src=\"/images/20201214-3.png\" alt=\"分配角色\"></p>\n<p>至此用户wangqian02仅可以查看操作test文件里的任务了。</p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins知识点","url":"/4.ToolsNotes/Jenkins/Jenkins%E7%9F%A5%E8%AF%86%E7%82%B9/","content":"<h2 id=\"凭据\"><a href=\"#凭据\" class=\"headerlink\" title=\"凭据\"></a>凭据</h2><p><strong>1、目的</strong></p>\n<p>与第三方网站或应用程序进行交互,如代码仓库、云存储系统和服务等</p>\n<p><strong>2、操作</strong></p>\n<p>Jenkins-凭据-系统-全局凭据</p>\n<p><strong>3、权限</strong></p>\n<p>Jenkins 中保存的凭证可以用于:</p>\n<ul>\n<li>任何适用于 Jenkins 的任何地方(即全局证书)</li>\n<li>特定的 Pipeline 项目</li>\n<li>特定的 Jenkins 用户</li>\n</ul>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins自动杀掉衍生程序","url":"/4.ToolsNotes/Jenkins/Jenkins%E8%87%AA%E5%8A%A8%E6%9D%80%E6%8E%89%E8%A1%8D%E7%94%9F%E7%A8%8B%E5%BA%8F/","content":"<p>在执行 shell输入框中加入<code>BUILD_ID=dontKillMe</code> ,即可防止jenkins杀死启动的进程</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">export BUILD_ID=dontKillMe</span><br><span class=\"line\">PROJECT_LOCATION="/usr/local/project/"</span><br><span class=\"line\">HOST=$HOST</span><br><span class=\"line\"></span><br><span class=\"line\">rsync -avz --delete --progress --exclude "config*" --exclude "db" ${WORKSPACE}/ root@${HOST}:$PROJECT_LOCATION</span><br><span class=\"line\"> </span><br><span class=\"line\">ssh -tt root@${HOST} " </span><br><span class=\"line\"> cd $PROJECT_LOCATION</span><br><span class=\"line\"> nohup ./server >server.log 2>&1 &</span><br><span class=\"line\"> sleep 10</span><br><span class=\"line\"> exit </span><br><span class=\"line\">"</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Jenkins触发其他项目构建","url":"/4.ToolsNotes/Jenkins/Jenkins%E8%A7%A6%E5%8F%91%E5%85%B6%E4%BB%96%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA/","content":"<p><strong>说明</strong></p>\n<p>两个项目他们在 jenkins 上的任务分别是 job1 和 job2 , 在构建 job2 的时候触发 job1 的自动构建。</p>\n<p><strong>job1构建代码</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">pipeline {</span><br><span class=\"line\"> agent {label "XXXX1"}</span><br><span class=\"line\"> parameters {</span><br><span class=\"line\"> booleanParam(name: 'enable',defaultValue: true,description: 'Checkbox parameter')</span><br><span class=\"line\"> string(name: 'name',defaultValue: 'licong!',description: 'what is your name!')</span><br><span class=\"line\"> }</span><br><span class=\"line\"> stages {</span><br><span class=\"line\"> stage("one") {</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> echo "${params['enable']}"</span><br><span class=\"line\"> echo "${params['name']}"</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> } </span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n\n\n<p><strong>job2构建代码</strong></p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">pipeline {</span><br><span class=\"line\"> agent {label "XXX2"}</span><br><span class=\"line\"> stages {</span><br><span class=\"line\"> stage("stage one") {</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> echo "done something"</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> stage("stage two") {</span><br><span class=\"line\"> when {</span><br><span class=\"line\"> expression {true} </span><br><span class=\"line\"> }</span><br><span class=\"line\"> steps {</span><br><span class=\"line\"> build job: './job1', parameters: [string(name: 'name', value: "demo"),booleanParam(name: 'enable' , value: false)]</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> } </span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"CentOS7.X更新yum源","url":"/4.ToolsNotes/Others/CentOS7.X%E6%9B%B4%E6%96%B0yum%E6%BA%90/","content":"<h4 id=\"备份原来的yum源\"><a href=\"#备份原来的yum源\" class=\"headerlink\" title=\"备份原来的yum源\"></a>备份原来的yum源</h4><figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">$sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo-backup</span><br></pre></td></tr></table></figure>\n\n<h4 id=\"设置aliyun的yum源\"><a href=\"#设置aliyun的yum源\" class=\"headerlink\" title=\"设置aliyun的yum源\"></a>设置aliyun的yum源</h4><figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">$sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo</span><br></pre></td></tr></table></figure>\n\n<h4 id=\"添加EPEL源\"><a href=\"#添加EPEL源\" class=\"headerlink\" title=\"添加EPEL源\"></a>添加EPEL源</h4><figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">$sudo wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/epel-7.repo</span><br></pre></td></tr></table></figure>\n\n<h4 id=\"清理缓存,生成新缓存,执行yum系统更新\"><a href=\"#清理缓存,生成新缓存,执行yum系统更新\" class=\"headerlink\" title=\"清理缓存,生成新缓存,执行yum系统更新\"></a>清理缓存,生成新缓存,执行yum系统更新</h4><figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">$sudo yum clean all</span><br><span class=\"line\"></span><br><span class=\"line\">$sudo yum makecache</span><br><span class=\"line\"></span><br><span class=\"line\">$sudo yum update(可选)</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Tool"],"tags":["Tool"]},{"title":"获取Jenkins构建时GitChangeLog","url":"/4.ToolsNotes/Jenkins/%E8%8E%B7%E5%8F%96Jenkins%E6%9E%84%E5%BB%BA%E6%97%B6GitChangeLog/","content":"<h4 id=\"参考:\"><a href=\"#参考:\" class=\"headerlink\" title=\"参考:\"></a>参考:</h4><p><a href=\"https://www.cnblogs.com/HYanqing/p/11697097.html\">获取Jenkins构建时Git Change Log</a></p>\n<p>在基于Jenkins进行CI持续集成的工作,在构建后上传蒲公英时想将本次版本的git commit信息同步到蒲公英的下载页面。Jenkins每次构建都会根据Git 的提交记录生成一个Web页面来显示自上次构建之后的提交记录列表(如图1),但是Jenkins却并没有提供可以获取这个Strings的功能。 </p>\n<p><img src=\"/images/20191018-1.png\" alt=\"images\"></p>\n<h4 id=\"Maven安装\"><a href=\"#Maven安装\" class=\"headerlink\" title=\"Maven安装\"></a>Maven安装</h4><p> 下载地址:<a href=\"https://maven.apache.org/download.cgi%EF%BC%88%E5%A6%82%E5%9B%BE%EF%BC%89%E3%80%82\">https://maven.apache.org/download.cgi(如图)。</a></p>\n<p> 将下载的压缩包解压到某个目录下,例如:/Users/用户名/apache-maven-3.5.3。</p>\n<p> 在终端执行:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> vi ~/.bash_profile</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> <span class=\"built_in\">export</span> M2_HOME=/Users/用户名/apache-maven-3.5.3</span> </span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> <span class=\"built_in\">export</span> PATH=<span class=\"variable\">$PATH</span>:<span class=\"variable\">$M2_HOME</span>/bin</span></span><br></pre></td></tr></table></figure>\n\n<p> 最后在终端执行如下命令来使.bash_profile生效:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> <span class=\"built_in\">source</span> ~/.bash_profile</span></span><br></pre></td></tr></table></figure>\n\n<p> 可以输入mvn -v来检查Maven是否生效</p>\n<p><img src=\"/images/20191018-2.png\" alt=\"images\"></p>\n<h4 id=\"插件安装\"><a href=\"#插件安装\" class=\"headerlink\" title=\"插件安装\"></a>插件安装</h4><p> Jenkins里面同样有人反馈了同样的需求,有人给出了一个插件解决获取git change log的需求,插件开源地址(<a href=\"https://links.jianshu.com/go?to=https://github.com/daniel-beck/changelog-environment-plugin\">https://github.com/daniel-beck/changelog-environment-plugin</a>)</p>\n<ol>\n<li><p>因作者并没有将插件编译上传,所以我们需要将项目Clone到本地</p>\n</li>\n<li><p>然后在项目根目录下执行 <em>mvn verify</em> ,因为依赖较多,第一次build时间会比较漫长,需耐心等待</p>\n</li>\n<li><p>build完成之后项目根目录中“target”文件夹中会出现“changelog-environment.hpi”这个文件</p>\n</li>\n</ol>\n<p>(注:<em>mvn verify</em> 是Maven命令,文章最后简单说明如何安装),插件现已上传到GitHub上(<a href=\"https://links.jianshu.com/go?to=https://github.com/KrisMarko/kr-changelog\">https://github.com/KrisMarko/kr-changelog</a>)。</p>\n<h4 id=\"使用\"><a href=\"#使用\" class=\"headerlink\" title=\"使用\"></a>使用</h4><p> 在Jenkins的系统管理-> 管理插件-> 高级->上传插件,将刚刚编译生成的“changelog-environment.hpi”文件上传并安装到Jenkins中,安装完成后,会在“构建环境”中有“Add Changelog Information to Environment”选项,选中后会有Entry Format、File Item Format、Date Format三个可配置项,第一个就是填写提交日志输出格式的地方,采用的是Java String.format占位符的形式。其中可以使用四个参数,分别是:</p>\n<ol>\n<li><p>提交的作者</p>\n</li>\n<li><p>提交的 ID</p>\n</li>\n<li><p>提交信息</p>\n</li>\n<li><p>提交时间(通过 Date Format 控制格式)</p>\n</li>\n</ol>\n<p> 例,我在Entry Format输入 %3$s (via %1$s)\\n,然后有一条提交记录,提交信息为「fix bug」,提交者为 Kris.Marko,那么输出到环境变量的字符串就是 “fix bug (via Kris.Marko)\\n” (后面的 \\n 是为了多层转义,视使用情况请自行调整)。</p>\n<p> 通过如上设置之后,在构建时就可以在shell中来获得SCM_CHANGELOG变量来取到更新日志了。比如自动上传更新信息到内测平台(如蒲公英)。</p>\n","categories":["4. ToolsNotes","Jenkins"],"tags":["Jenkins"]},{"title":"Git中Submodule管理子项目的使用","url":"/4.ToolsNotes/Others/Git%E4%B8%ADSubmodule%E7%AE%A1%E7%90%86%E5%AD%90%E9%A1%B9%E7%9B%AE%E7%9A%84%E4%BD%BF%E7%94%A8/","content":"<h2 id=\"说明\"><a href=\"#说明\" class=\"headerlink\" title=\"说明\"></a><strong>说明</strong></h2><p>云平台业务中,管理端代码使用微服务结构管理。模块较多,部署时间较长,针对此问题,解决方式是使用Git的Submodule子模块功能。</p>\n<p><strong>主要作用</strong></p>\n<p>子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。</p>\n<p><strong>详情参考</strong></p>\n<p><a href=\"https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97\">Git工具-子模块</a></p>\n<p><a href=\"https://zhuanlan.zhihu.com/p/87053283\">Git中submodule的使用</a></p>\n<h2 id=\"操作步骤\"><a href=\"#操作步骤\" class=\"headerlink\" title=\"操作步骤\"></a><strong>操作步骤</strong></h2><p>假定现有两个项目:project-main 和 project-sub-1;</p>\n<p>其中 project-main 表示主项目,而 project-sub-1 表示子模块项目;</p>\n<p>其中 project-main 的远程仓库地址为 <a href=\"https://github.com/username/project-main.git%EF%BC%8C%E8%80%8C\">https://github.com/username/project-main.git,而</a> project-sub-1 的远程仓库地址为 <a href=\"https://github.com/username/project-sub-1.git%E3%80%82\">https://github.com/username/project-sub-1.git。</a></p>\n<h2 id=\"使用\"><a href=\"#使用\" class=\"headerlink\" title=\"使用\"></a>使用</h2><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> git submodule add git@github.com:username/project-sub-1.git</span></span><br></pre></td></tr></table></figure>\n\n<h3 id=\"详情\"><a href=\"#详情\" class=\"headerlink\" title=\"详情\"></a><strong>详情</strong></h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule/project-main (master)$ git submodule add git@github.com:username/project-sub-1.git</span><br><span class=\"line\">Cloning into 'D:/work/github/submodule/project-main/project-sub-1'...</span><br><span class=\"line\">remote: Enumerating objects: 3, done.</span><br><span class=\"line\">remote: Counting objects: 100% (3/3), done.</span><br><span class=\"line\">remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0</span><br><span class=\"line\">Receiving objects: 100% (3/3), done.</span><br><span class=\"line\">warning: LF will be replaced by CRLF in .gitmodules.</span><br><span class=\"line\">The file will have its original line endings in your working directory</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"查看\"><a href=\"#查看\" class=\"headerlink\" title=\"查看\"></a>查看</h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule/project-main (master)$ git status</span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Your branch is up to date with 'origin/master'.</span><br><span class=\"line\"></span><br><span class=\"line\">Changes to be committed:</span><br><span class=\"line\"> (use "git restore --staged <file>..." to unstage)</span><br><span class=\"line\"> new file: .gitmodules #显示子模块的相关信息</span><br><span class=\"line\"> new file: project-sub-1 #显示子模块当前的版本号信息</span><br><span class=\"line\"></span><br></pre></td></tr></table></figure>\n\n<p><strong>说明</strong>:此时在 .git/config 文件中也会多出一些信息,在 .git/modules 文件夹下也会多出一份内容。</p>\n<p>通常此时可以使用 git commit -m “add submodule xxx” 提交一次,表示引入了某个子模块。</p>\n<p>提交后,在主项目仓库中,会显示出子模块文件夹,并带上其所在仓库的版本号。</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule/project-main (master)$ git commit -m "add submodule"</span><br><span class=\"line\">[master d858d0a] add submodule</span><br><span class=\"line\"> 2 files changed, 4 insertions(+)</span><br><span class=\"line\"> create mode 100644 .gitmodules</span><br><span class=\"line\"> create mode 160000 project-sub-1</span><br></pre></td></tr></table></figure>\n\n<h2 id=\"获取\"><a href=\"#获取\" class=\"headerlink\" title=\"获取\"></a><strong>获取</strong></h2><p>上述步骤在创建子模块的过程中,会自动将相关代码克隆到对应路径,但对于后续使用者而言,对于主项目使用普通的 clone 操作并不会拉取到子模块中的实际代码。</p>\n<ul>\n<li>使用以下命令进行克隆,完成后 project-main/project-sub-1 文件夹是空的</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule1 (master)$ git clone git@github.com:username/project-main.git</span><br><span class=\"line\">Cloning into 'project-main'...</span><br><span class=\"line\">remote: Enumerating objects: 8, done.</span><br><span class=\"line\">remote: Counting objects: 100% (8/8), done.</span><br><span class=\"line\">remote: Compressing objects: 100% (5/5), done.</span><br><span class=\"line\">remote: Total 8 (delta 1), reused 8 (delta 1), pack-reused 0</span><br><span class=\"line\">Receiving objects: 100% (8/8), done.</span><br><span class=\"line\">Resolving deltas: 100% (1/1), done.</span><br></pre></td></tr></table></figure>\n\n<ul>\n<li>如果希望子模块代码也获取到,一种方式是在克隆主项目的时候带上参数 –recurse-submodules,这样会递归地将项目中所有子模块的代码拉取。</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule1 (master)$ git clone git@github.com:Huangyq116/project-main.git --recurse-submodules</span><br><span class=\"line\">Cloning into 'project-main'...</span><br><span class=\"line\">remote: Enumerating objects: 8, done.</span><br><span class=\"line\">remote: Counting objects: 100% (8/8), done.</span><br><span class=\"line\">remote: Compressing objects: 100% (5/5), done.</span><br><span class=\"line\">remote: Total 8 (delta 1), reused 8 (delta 1), pack-reused 0</span><br><span class=\"line\">Receiving objects: 100% (8/8), done.</span><br><span class=\"line\">Resolving deltas: 100% (1/1), done.</span><br><span class=\"line\">Submodule 'project-sub-1' (git@github.com:Huangyq116/project-sub-1.git) registered for path 'project-sub-1'</span><br><span class=\"line\">Cloning into 'D:/work/github/submodule1/project-main/project-sub-1'...</span><br><span class=\"line\">remote: Enumerating objects: 10, done.</span><br><span class=\"line\">remote: Counting objects: 100% (10/10), done.</span><br><span class=\"line\">remote: Compressing objects: 100% (3/3), done.</span><br><span class=\"line\">remote: Total 10 (delta 1), reused 10 (delta 1), pack-reused 0</span><br><span class=\"line\">Receiving objects: 100% (10/10), done.</span><br><span class=\"line\">Resolving deltas: 100% (1/1), done.</span><br><span class=\"line\">Submodule path 'project-sub-1': checked out '196215e644fccda0a53b703a7accd2dd405bc636'</span><br></pre></td></tr></table></figure>\n\n<p>此时 project-main/project-sub-1 文件夹是有内容的,并且固定在某个 Git 提交的版本上。</p>\n<ul>\n<li>另外一种可行的方式是,在当前主项目中执行:</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule1/project-main (master)$git submodule init</span><br><span class=\"line\">Submodule 'project-sub-1' (git@github.com:username/project-sub-1.git) registered for path 'project-sub-1'</span><br></pre></td></tr></table></figure>\n\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule1/project-main (master)$ git submodule update</span><br><span class=\"line\">Cloning into 'D:/work/github/submodule1/project-main/project-sub-1'...</span><br><span class=\"line\">Submodule path 'project-sub-1': checked out '196215e644fccda0a53b703a7accd2dd405bc636'</span><br></pre></td></tr></table></figure>\n\n<p>则会根据主项目的配置信息,拉取更新子模块中的代码。</p>\n<h2 id=\"更新\"><a href=\"#更新\" class=\"headerlink\" title=\"更新\"></a><strong>更新</strong></h2><p>对于子模块而言,并不需要知道引用自己的主项目的存在。对于自身而言,子模块是一个完整的Git仓库,按照正常的Git代码管理规范即可。</p>\n<p>对于主项目而言,子模块的内容发生变动时,通常有三种情况:</p>\n<p>1)当前项目下子模块文件夹内的内容发生了未跟踪的内容变动</p>\n<p>2)当前项目下子模块文件夹内的内容发生了版本变化</p>\n<p>3)当前项目下子模块文件夹内的内容没变,远程有更新</p>\n<h3 id=\"子模块有未跟踪的内容变动\"><a href=\"#子模块有未跟踪的内容变动\" class=\"headerlink\" title=\"子模块有未跟踪的内容变动\"></a><strong>子模块有未跟踪的内容变动</strong></h3><p>对于第1种情况,通常是在开发环境中,直接修改子模块文件夹中的代码导致的。</p>\n<p>此时在主项目中使用 git status 能够看到关于子模块尚未暂存以备提交的变更,但是于主项目而言是无能为力的,使用 git add/commit 对其也不会产生影响。</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule/project-main (master)$ git status</span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Your branch is up to date with 'origin/master'.</span><br><span class=\"line\"></span><br><span class=\"line\">Changes not staged for commit:</span><br><span class=\"line\"> (use "git add <file>..." to update what will be committed)</span><br><span class=\"line\"> (use "git restore <file>..." to discard changes in working directory)</span><br><span class=\"line\"> (commit or discard the untracked or modified content in submodules)</span><br><span class=\"line\"> modified: project-sub-1 (modified content)</span><br><span class=\"line\"></span><br><span class=\"line\">no changes added to commit (use "git add" and/or "git commit -a")</span><br></pre></td></tr></table></figure>\n\n<p>在此情景下,通常需要进入子模块文件夹,按照子模块内部的版本控制体系提交代码。</p>\n<p>当提交完成后,主项目的状态则进入了情况2,即当前项目下子模块文件夹内的内容发生了版本变化</p>\n<h3 id=\"子模块有版本变化\"><a href=\"#子模块有版本变化\" class=\"headerlink\" title=\"子模块有版本变化\"></a><strong>子模块有版本变化</strong></h3><figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> git status</span></span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Your branch is up to date with 'origin/master'.</span><br><span class=\"line\"></span><br><span class=\"line\">Changes not staged for commit:</span><br><span class=\"line\"> (use "git add <file>..." to update what will be committed)</span><br><span class=\"line\"> (use "git restore <file>..." to discard changes in working directory)</span><br><span class=\"line\"> modified: project-sub-1 (new commits)</span><br><span class=\"line\"></span><br><span class=\"line\">no changes added to commit (use "git add" and/or "git commit -a")</span><br><span class=\"line\"></span><br></pre></td></tr></table></figure>\n\n<p>在这种情况下,可以使用 git add/commit 将其添加到主项目的代码提交中,实际的改动就是那个子模块 文件 所表示的版本信息。</p>\n<h3 id=\"子模块远程有更新\"><a href=\"#子模块远程有更新\" class=\"headerlink\" title=\"子模块远程有更新\"></a><strong>子模块远程有更新</strong></h3><p>通常来讲,主项目与子模块的开发不会恰好是同时进行的。通常是子模块负责维护自己的版本升级后,推送到远程仓库,并告知主项目可以更新对子模块的版本依赖。</p>\n<p>在这种情况下,主项目是比较茫然的。</p>\n<p>之前曾经提到,主项目可以使用 git submodule update 更新子模块的代码,但那是指 当前主项目文件夹下的子模块目录内容 与 当前主项目记录的子模块版本 不一致时,会参考后者进行更新。</p>\n<p>但如今这种情况下,后者 当前主项目记录的子模块版本 还没有变化,在主项目看来当前情况一切正常。</p>\n<p>此时,需要让主项目主动进入子模块拉取新版代码,进行升级操作。</p>\n<ul>\n<li>通常流程是</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> <span class=\"built_in\">cd</span> project-sub-1 $ git pull origin master</span></span><br></pre></td></tr></table></figure>\n\n<p>子模块目录下的代码版本会发生变化,转到情况2的流程进行主项目的提交。</p>\n<ul>\n<li>当主项目的子项目特别多时,可能会不太方便,此时可以使用 git submodule 的一个命令 foreach 执行:</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\"> git submodule foreach <span class=\"string\">'git pull origin master'</span></span></span><br></pre></td></tr></table></figure>\n\n<h3 id=\"情况汇总\"><a href=\"#情况汇总\" class=\"headerlink\" title=\"情况汇总\"></a><strong>情况汇总</strong></h3><ul>\n<li>终上所述,可知在不同场景下子模块的更新方式如下:</li>\n<li>对于子模块,只需要管理好自己的版本,并推送到远程分支即可;</li>\n<li>对于父模块,若子模块版本信息未提交,需要更新子模块目录下的代码,并执行 commit 操作提交子模块版本信息;</li>\n<li>对于父模块,若子模块版本信息已提交,需要使用 git submodule update ,Git 会自动根据子模块版本信息更新所有子模块目录的相关代码。</li>\n</ul>\n<h2 id=\"删除\"><a href=\"#删除\" class=\"headerlink\" title=\"删除\"></a><strong>删除</strong></h2><p>根据官方文档的说明,应该使用 git submodule deinit 命令卸载一个子模块。这个命令如果添加上参数 –force,则子模块工作区内即使有本地的修改,也会被移除。</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">git submodule deinit project-sub-1</span> </span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"meta\">$</span><span class=\"bash\">git rm project-sub-1</span></span><br></pre></td></tr></table></figure>\n\n<ul>\n<li>执行 git submodule deinit project-sub-1 命令的实际效果,是自动在 .git/config 中删除了以下内容:</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">[submodule "project-sub-1"]</span><br><span class=\"line\">url = https://github.com/username/proproject-sub-1</span><br></pre></td></tr></table></figure>\n\n<ul>\n<li>执行 git rm project-sub-1 的效果,是移除了 project-sub-1 文件夹,并自动在 .gitmodules 中删除了以下内容:</li>\n</ul>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">[submodule "project-sub-1"]</span><br><span class=\"line\"> path = project-sub-1</span><br><span class=\"line\"> url = git@github.com:Huangyq116/project-sub-1.git</span><br></pre></td></tr></table></figure>\n\n<p>此时,主项目中关于子模块的信息基本已经删除:</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"code\"><pre><span class=\"line\">/d/work/github/submodule/project-main (master)$ git status</span><br><span class=\"line\">On branch master</span><br><span class=\"line\">Your branch is up to date with 'origin/master'.</span><br><span class=\"line\"></span><br><span class=\"line\">Changes to be committed:</span><br><span class=\"line\"> (use "git restore --staged <file>..." to unstage)</span><br><span class=\"line\"> modified: .gitmodules</span><br><span class=\"line\"> deleted: project-sub-1</span><br></pre></td></tr></table></figure>\n\n<p>可以提交代码:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"code\"><pre><span class=\"line\">git commit -m "delete submodule project-sub-1"</span><br></pre></td></tr></table></figure>\n\n<p>至此完成对子模块的删除。</p>\n<p><strong>总结</strong></p>\n<p>当项目比较复杂,部分代码希望独立为子模块进行版本控制时,可以使用 git submodule 功能。</p>\n<p>使用 git submodule 功能时,主项目仓库并不会包含子模块的文件,只会保留一份子模块的配置信息及版本信息,作为主项目版本管理的一部分。</p>\n","categories":["4. ToolsNotes","Tool"],"tags":["Git","Tool"]},{"title":"Nginx配置文件","url":"/4.ToolsNotes/Others/Nginx%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/","content":"<h3 id=\"学习网址\"><a href=\"#学习网址\" class=\"headerlink\" title=\"学习网址\"></a>学习网址</h3><p><a href=\"https://devdocs.io/nginx/\">nginx documentation — DevDocs</a> </p>\n<h3 id=\"配置文件信息\"><a href=\"#配置文件信息\" class=\"headerlink\" title=\"配置文件信息\"></a>配置文件信息</h3><figure class=\"highlight nginx\"><table><tr><td class=\"code\"><pre><span class=\"line\"><span class=\"section\">server</span> {</span><br><span class=\"line\"> <span class=\"attribute\">listen</span> <span class=\"number\">80</span> ;</span><br><span class=\"line\"> <span class=\"attribute\">listen</span> [::]:<span class=\"number\">80</span> ipv6only=<span class=\"literal\">on</span>;</span><br><span class=\"line\"> <span class=\"attribute\">listen</span> <span class=\"number\">443</span> default ssl;</span><br><span class=\"line\"> <span class=\"attribute\">listen</span> [::]:<span class=\"number\">443</span> default ssl;</span><br><span class=\"line\"> <span class=\"comment\">#listen [::]:443 ssl ;</span></span><br><span class=\"line\"> <span class=\"comment\">#listen 443 ssl;</span></span><br><span class=\"line\"> <span class=\"attribute\">ssl</span> <span class=\"literal\">off</span>; </span><br><span class=\"line\"> <span class=\"attribute\">ssl_certificate</span> /etc/nginx/sslkey/kcs.default.crt;</span><br><span class=\"line\"> <span class=\"attribute\">ssl_certificate_key</span> /etc/nginx/sslkey/kcs.default.key;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"attribute\">server_name</span> test1116.com;</span><br><span class=\"line\"> <span class=\"comment\">#max_ranges 0;</span></span><br><span class=\"line\"> <span class=\"attribute\">autoindex</span> <span class=\"literal\">on</span>;</span><br><span class=\"line\"> <span class=\"attribute\">autoindex_exact_size</span> <span class=\"literal\">off</span>;</span><br><span class=\"line\"> <span class=\"attribute\">autoindex_localtime</span> <span class=\"literal\">on</span>;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"attribute\">error_log</span> /var/log/nginx/error.log;</span><br><span class=\"line\"> <span class=\"attribute\">access_log</span> /var/log/nginx/access.log;</span><br><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"comment\">#302跳转使用</span></span><br><span class=\"line\"> <span class=\"attribute\">location</span> = /test302.html {</span><br><span class=\"line\"> <span class=\"attribute\">root</span> html;</span><br><span class=\"line\"> <span class=\"attribute\">rewrite</span><span class=\"regexp\"> ^/(.*)$</span> http://127.0.0.1/a/123.mp4 <span class=\"literal\">redirect</span>;</span><br><span class=\"line\"> </span><br><span class=\"line\"> }</span><br><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"attribute\">location</span> = /index12.html {</span><br><span class=\"line\"> <span class=\"attribute\">root</span> /home/root/auto_test/Report/html/;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"attribute\">location</span> /a/ {</span><br><span class=\"line\"> <span class=\"attribute\">root</span> html; </span><br><span class=\"line\"> <span class=\"attribute\">rewrite</span><span class=\"regexp\"> ^/(.*)$</span> http://127.0.0.1/b/123.mp4 <span class=\"literal\">redirect</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"># 配合html/php上传文件使用</span></span><br><span class=\"line\"> <span class=\"attribute\">location</span> <span class=\"regexp\">~ .*\\.(php|php5)?$</span> {</span><br><span class=\"line\"> <span class=\"attribute\">fastcgi_pass</span> <span class=\"number\">127.0.0.1:9000</span>;</span><br><span class=\"line\"> <span class=\"attribute\">client_max_body_size</span> <span class=\"number\">30m</span>;</span><br><span class=\"line\"> <span class=\"comment\"># fastcgi_param HTTPS on;</span></span><br><span class=\"line\"> <span class=\"attribute\">fastcgi_param</span> HTTPS $https if_not_empty;</span><br><span class=\"line\"> <span class=\"attribute\">fastcgi_param</span> SCRIPT_FILENAME /etc/nginx/html$fastcgi_script_name;</span><br><span class=\"line\"> <span class=\"attribute\">include</span> fastcgi_params; </span><br><span class=\"line\"> <span class=\"comment\">#include fastcgi.conf;</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"attribute\">error_page</span> <span class=\"number\">405</span> =<span class=\"number\">200</span> $uri;</span><br><span class=\"line\"> <span class=\"comment\">#error_page 405 =200 @405;</span></span><br><span class=\"line\"> <span class=\"comment\">#location @405 {</span></span><br><span class=\"line\"> <span class=\"comment\"># root /etc/nginx/html;</span></span><br><span class=\"line\"> <span class=\"comment\">#root /tmp/upload_tmp2;</span></span><br><span class=\"line\"> <span class=\"comment\"># proxy_method GET;</span></span><br><span class=\"line\"> <span class=\"comment\">#} </span></span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">#location /b {</span></span><br><span class=\"line\"> <span class=\"comment\"># root html;</span></span><br><span class=\"line\"> <span class=\"comment\"># rewrite /(.*) http://127.0.0.1/c/yunkong.mp4 redirect;</span></span><br><span class=\"line\"> <span class=\"comment\"># }</span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">#location /c {</span></span><br><span class=\"line\"> <span class=\"comment\"># root html;</span></span><br><span class=\"line\"> <span class=\"comment\"># rewrite /(.*) http://127.0.0.1/d/yunkong.mp4 redirect;</span></span><br><span class=\"line\"> <span class=\"comment\"># }</span></span><br><span class=\"line\"> </span><br><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"comment\">#location /d {</span></span><br><span class=\"line\"> <span class=\"comment\"># root html;</span></span><br><span class=\"line\"> <span class=\"comment\">#}</span></span><br><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"attribute\">location</span> /refresh30.html {</span><br><span class=\"line\"> <span class=\"attribute\">expires</span> <span class=\"number\">30s</span>;</span><br><span class=\"line\"> <span class=\"attribute\">root</span> html; </span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"attribute\">location</span> ~^/.* {</span><br><span class=\"line\"> <span class=\"attribute\">root</span> /etc/nginx/html;</span><br><span class=\"line\"> <span class=\"attribute\">add_header</span> <span class=\"number\">123</span> <span class=\"number\">123</span>; <span class=\"comment\">#添加请求接口响应头信息 </span></span><br><span class=\"line\"> <span class=\"attribute\">gzip</span> <span class=\"literal\">on</span>; <span class=\"comment\">#响应信息是否进行压缩</span></span><br><span class=\"line\"><span class=\"comment\"># gzip_types text/html text/plain application/javascript application/x-javascript text/javascript text/xml text/css;</span></span><br><span class=\"line\"> <span class=\"comment\">#gzip_vary on;</span></span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n","categories":["4. ToolsNotes","Tool"],"tags":["Tool"]},{"title":"OpenResty学习","url":"/4.ToolsNotes/Others/OpenResty%E5%AD%A6%E4%B9%A0/","content":"<h3 id=\"学习网址\"><a href=\"#学习网址\" class=\"headerlink\" title=\"学习网址\"></a>学习网址</h3><p><a href=\"https://moonbingbing.gitbooks.io/openresty-best-practices/content/\">1、OpenResty最佳实践</a></p>\n<p><a href=\"http://openresty.org/cn/\">2、OpenResty中文官网</a></p>\n<p><a href=\"https://www.runoob.com/lua/lua-tutorial.html\">3、Lua入门教程</a></p>\n<p><a href=\"http://www.nginx.cn/doc/\">4、Nginx中文文档</a></p>\n","categories":["4. ToolsNotes","Tool"],"tags":["Tool"]}]