<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="https://blog.xiaoi.me/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.xiaoi.me/" rel="alternate" type="text/html" /><updated>2019-11-15T10:51:43+08:00</updated><id>https://blog.xiaoi.me/feed.xml</id><title type="html">Xiaoi’s Blog</title><subtitle>Material theme based on &lt;a href=&quot;http://materializecss.com&quot;&gt;Materialize.css&lt;/a&gt; for jekyll sites
</subtitle><entry><title type="html">搭建 Elasticsearch 单节点以及简单的使用教程</title><link href="https://blog.xiaoi.me/2019/11/12/elastic-search-get-start" rel="alternate" type="text/html" title="搭建 Elasticsearch 单节点以及简单的使用教程" /><published>2019-11-12T00:00:00+08:00</published><updated>2019-11-12T00:00:00+08:00</updated><id>https://blog.xiaoi.me/2019/11/12/elastic-search-get-start</id><content type="html" xml:base="https://blog.xiaoi.me/2019/11/12/elastic-search-get-start">&lt;p&gt;Elasticsearch是一个基于Lucene库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎，具有HTTP Web接口和无模式JSON文档。Elasticsearch是用Java开发的，并在Apache许可证下作为开源软件发布。&lt;/p&gt;

&lt;p&gt;官方客户端在Java、.NET（C#）、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示，Elasticsearch是最受欢迎的企业搜索引擎，其次是Apache Solr，也是基于Lucene。&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;搭建-elasticsearch-单节点以及简单的使用教程&quot;&gt;搭建 Elasticsearch 单节点以及简单的使用教程&lt;/h1&gt;
&lt;p&gt;接下来介绍如何本地搭建一个单节点的 Elasticsearch 服务器以及进行一些增删改查的简单操作。&lt;/p&gt;

&lt;h2 id=&quot;安装-elasticsearch&quot;&gt;安装 Elasticsearch&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;第一步：所需要的软件环境：最新稳定版 Java，若使用 docker 方式则不必安装 Java；&lt;/li&gt;
  &lt;li&gt;第二步：下载&lt;a href=&quot;https://github.com/elastic/Elasticsearch/releases&quot;&gt;最新版 Elasticsearch&lt;/a&gt;；&lt;/li&gt;
  &lt;li&gt;第三步：解压下载的 Elasticsearch，建议位置选择一个用于存放数据的目录，磁盘剩余空间尽量留大一点；&lt;/li&gt;
  &lt;li&gt;第四步：运行 Elasticsearch，Linux 或者 macOS 运行 bin/Elasticsearch，Windows 运行 bin\Elasticsearch.bat；&lt;/li&gt;
  &lt;li&gt;第五步：使用命令 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -X GET http://localhost:9200/&lt;/code&gt; 检查运行状态，或者直接复制链接到浏览器中打开也可以，
 正常情况下会显示以下类似的内容：
    &lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;DESKTOP-FHFP51P&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cluster_name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Elasticsearch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cluster_uuid&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lAdgnvl8TrmSrzRn321AKw&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;7.4.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;build_flavor&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;build_type&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;zip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;build_hash&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2f90bbf7b93631e52bafb59b3b049cb44ec25e96&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;build_date&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2019-10-28T20:40:44.881551Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;build_snapshot&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lucene_version&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8.2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;minimum_wire_compatibility_version&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;6.8.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;minimum_index_compatibility_version&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;6.0.0-beta1&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tagline&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;You Know, for Search&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;使用-elasticsearch-进行简单的操作&quot;&gt;使用 Elasticsearch 进行简单的操作&lt;/h2&gt;

&lt;h3 id=&quot;添加数据&quot;&gt;添加数据&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-curl&quot;&gt;curl -XPOST 'http://localhost:9200/twitter/_doc/?pretty' -H 'Content-Type: application/json' -d '
{
    &quot;user&quot;: &quot;kimchy&quot;,
    &quot;post_date&quot;: &quot;2009-11-15T13:12:00&quot;,
    &quot;message&quot;: &quot;Trying out Elasticsearch, so far so good?&quot;
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;查找数据&quot;&gt;查找数据&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-curl&quot;&gt;curl -XGET 'http://localhost:9200/twitter/_search?pretty=true' -H 'Content-Type: application/json' -d '
{
    &quot;query&quot; : {
        &quot;match_all&quot; : {}
    }
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;修改数据&quot;&gt;修改数据&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-curl&quot;&gt;curl -XPUT 'http://localhost:9200/twitter/_doc/{ID}?pretty' -H 'Content-Type: application/json' -d '
{
    &quot;user&quot;: &quot;kimchy&quot;,
    &quot;post_date&quot;: &quot;2009-11-15T13:12:00&quot;,
    &quot;message&quot;: &quot;Trying out Elasticsearch, so far so good?&quot;
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;删除数据不建议直接删除&quot;&gt;删除数据（不建议直接删除）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-curl&quot;&gt;curl -XDELETE 'http://localhost:9200/twitter/_doc/{ID}?pretty''
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：上文中的{ID}为变量，具体要操作哪条数据应当传入数据的实际 ID&lt;/p&gt;

&lt;h2 id=&quot;elasticsearch-性能测试&quot;&gt;Elasticsearch 性能测试&lt;/h2&gt;
&lt;p&gt;经过上文的教程，我们对 Elasticsearch 有了初步的了解以及学会了如何使用基本的操作，接下来我们测一下单节点的性能。&lt;/p&gt;

&lt;p&gt;首先我们主要使用的是 ab 命令（Apache-Bench）进行压力测试，命令如下&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ab &lt;span class=&quot;nt&quot;&gt;-n100000&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c10&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; ./postfile.ab &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'application/json'&lt;/span&gt; http://localhost:9200/twitter/_doc/?pretty&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其中，postfile.ab 为我们需要发送给 Elasticsearch 的模拟数据，数据内容参考如下&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;kimchy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;post_date&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2009-11-15T13:12:00&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Trying out Elasticsearch, so far so good?&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;并发-10tps-请求-10-万次&quot;&gt;并发 10TPS 请求 10 万次&lt;/h3&gt;
&lt;p&gt;测试报告如下&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 1807734 $&amp;gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:
Server Hostname:        localhost
Server Port:            9200

Document Path:          /twitter/_doc/?pretty=true
Document Length:        243 bytes

Concurrency Level:      10
Time taken for tests:   28.107 seconds
Complete requests:      10000
Failed requests:        5557
   (Connect: 0, Receive: 0, Length: 5557, Exceptions: 0)
Total transferred:      3815557 bytes
Total body sent:        2860000
HTML transferred:       2435557 bytes
Requests per second:    355.79 [#/sec] (mean)
Time per request:       28.107 [ms] (mean)
Time per request:       2.811 [ms] (mean, across all concurrent requests)
Transfer rate:          132.57 [Kbytes/sec] received
                        99.37 kb/s sent
                        231.94 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    6   6.5      5     170
Processing:     6   21  19.5     17     529
Waiting:        4   17  17.4     13     527
Total:         11   28  21.7     23     534

Percentage of the requests served within a certain time (ms)
  50%     23
  66%     26
  75%     29
  80%     31
  90%     41
  95%     53
  98%     79
  99%    112
 100%    534 (longest request)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过 ab 的测试报告可以看出，单节点的 Elasticsearch 性能非常强悍，达到了 355.79 / 秒处理量，另外通过观测 JVM 的系统资源使用，也是比较低的水平。
&lt;img src=&quot;/assets/res/img/20191112105205.png&quot; alt=&quot;搭建 Elasticsearch 单节点以及简单的使用教程&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;并发-400tps-请求-10-万次&quot;&gt;并发 400TPS 请求 10 万次&lt;/h3&gt;
&lt;p&gt;接下来我们进行更高的并发测试&lt;/p&gt;
&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 1807734 $&amp;gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests


Server Software:
Server Hostname:        localhost
Server Port:            9200

Document Path:          /twitter/_doc/?pretty=true
Document Length:        245 bytes

Concurrency Level:      400
Time taken for tests:   209.947 seconds
Complete requests:      100000
Failed requests:        0
Total transferred:      38300000 bytes
Total body sent:        28600000
HTML transferred:       24500000 bytes
Requests per second:    476.31 [#/sec] (mean)
Time per request:       839.787 [ms] (mean)
Time per request:       2.099 [ms] (mean, across all concurrent requests)
Transfer rate:          178.15 [Kbytes/sec] received
                        133.03 kb/s sent
                        311.18 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       87  392 214.7    345    3133
Processing:    26  445 216.2    397    3697
Waiting:       25  300 188.6    265    2722
Total:        443  838 380.2    746    6498

Percentage of the requests served within a certain time (ms)
  50%    746
  66%    822
  75%    884
  80%    951
  90%   1074
  95%   1314
  98%   1637
  99%   2002
 100%   6498 (longest request)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看出，并发量达到了 476.31 / 秒，JVM 的资源使用情况也没有发生大幅提升的情况，可以说是非常的稳定。
&lt;img src=&quot;/assets/res/img/20191112105940.png&quot; alt=&quot;搭建 Elasticsearch 单节点以及简单的使用教程&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;
&lt;p&gt;Elasticsearch 单节点的性能已经非常强悍了，并且支持分布式提升更大的性能扩容，可以说是完全满足日常的需求已经高并发的需求。
另外我们可以将系统日志、网络日志、应用日志、业务日志等易产生大量数据的接入 Elasticsearch 进行统一的管理，这样既保证效率，也避免了日志分散、数量大无法维护等带来问题。&lt;/p&gt;

&lt;h1 id=&quot;参考文献&quot;&gt;参考文献&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/elastic/Elasticsearch&quot;&gt;Elasticsearch - Getting Started&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://zh.wikipedia.org/zh-hans/Elasticsearch&quot;&gt;Elasticsearch - 维基百科，自由的百科全书&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;版权&quot;&gt;版权&lt;/h1&gt;
&lt;blockquote&gt;
  &lt;p&gt;版权声明：自由转载-非商用-非衍生-保持署名（创意共享3.0许可证）&lt;br /&gt;
原创作者：10086@xiaoi.me 发表于 Xiaoi’s Blog：&lt;a href=&quot;https://blog.xiaoi.me&quot;&gt;https://blog.xiaoi.me&lt;/a&gt;&lt;br /&gt;
原文链接：&lt;a href=&quot;https://blog.xiaoi.me/2019/11/12/elastic-search-get-start&quot;&gt;https://blog.xiaoi.me/2019/11/12/elastic-search-get-start&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;扫码关注我，在线与我沟通、咨询
&lt;img src=&quot;/assets/res/qrcode.png&quot; alt=&quot;Xiaoi's Blog&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;转载请保留原文链接以及版权信息&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><category term="Java" /><category term="elastic" /><summary type="html">Elasticsearch是一个基于Lucene库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎，具有HTTP Web接口和无模式JSON文档。Elasticsearch是用Java开发的，并在Apache许可证下作为开源软件发布。</summary></entry><entry><title type="html">Nextcloud 解决 MySQL 没有支持 4 字节字符时报错： SQLSTATE[42000]，解决办法</title><link href="https://blog.xiaoi.me/2019/11/04/nextcloud-mysql-utf8mb4-error" rel="alternate" type="text/html" title="Nextcloud 解决 MySQL 没有支持 4 字节字符时报错： SQLSTATE[42000]，解决办法" /><published>2019-11-04T00:00:00+08:00</published><updated>2019-11-04T00:00:00+08:00</updated><id>https://blog.xiaoi.me/2019/11/04/nextcloud-mysql-utf8mb4-error</id><content type="html" xml:base="https://blog.xiaoi.me/2019/11/04/nextcloud-mysql-utf8mb4-error">&lt;p&gt;根据 Nextcloud 控制面板安全及设置警告，解决最后一个报警，不支持 4 字节的问题时，遇到该问题，
所使用的数据库为MySQL但没有对4字节字符的支持。为正确处理文件名或评论中使用的4字节字符（比如emoji表情），建议开启MySQL的4字节字符支持。详细信息请阅读相关文档页面。&lt;/p&gt;

&lt;p&gt;本文撰写时所使用的版本：Nextcloud 16.0.4&lt;/p&gt;

&lt;h1 id=&quot;问题过程&quot;&gt;问题过程&lt;/h1&gt;
&lt;p&gt;按照 Nextcloud 给出的文档需要需要进行一系列的修复，本文到最后一步执行以下命令时遇到问题：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; www-data php occ maintenance:repair
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;异常截图：
&lt;img src=&quot;/assets/res/img/219ac8fa9c61bb023bb783389d7ff12ee29c60ff.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;In AbstractMySQLDriver.php line 125:

  An exception occurred while executing 'ALTER TABLE `oc_systemtag_group` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;':

  SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经过研究，发现是因为使用 3 字节的 utf8 编码时，索引长度最大 767 可以存储 767/3 = 255 个字符。
但使用 utf8mb4 时，因为是 4 字节，索引最大长度 767 不变的情况下，最多可以存储 767/4 = 191 个字符。&lt;/p&gt;

&lt;p&gt;于是排查了数据库相关的字段，发现比较多的字段使用了 varchar(255)，经过手动处理后，上面的 repair 执行成功。
&lt;img src=&quot;/assets/res/img/9352add5b0cc26772b2334116adadfa25e8fb135.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;以下将修复过程中使用的 SQL 进行了汇总整理，遇到此问题时，可以直接执行以下 SQL，不必手动去修复。&lt;/p&gt;
&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_addressbooks`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`principaluri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`id`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`uri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`displayname`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_authtoken`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`token`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`name`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_calendarobjects`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`uri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`calendardata`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_calendars`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`principaluri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`id`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`uri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`displayname`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_calendarsubscriptions`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`uri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`id`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`principaluri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`uri`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_dav_shares`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`principaluri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`id`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`type`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`principaluri`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`publicuri`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`resourceid`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_login_flow_v2`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`poll_token`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`started`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`login_token`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`poll_token`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_migrations`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`app`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FIRST&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`version`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`app`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_mimetypes`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`mimetype`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`id`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_systemtag_group`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`gid`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`systemtagid`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`oc_trusted_servers`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;MODIFY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLUMN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`url_hash`&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CHARACTER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COLLATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utf8_bin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;COMMENT&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'sha1 hash of the url without the protocol'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;`url`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;
&lt;p&gt;我们在设计数据库时，也应该注意此问题，utf8 的情况下索引字段最大 varchar(255)，utf8mb4 的情况下索引最大 varchar(191)。我们可以修改 mysql.conf 最大索引长度，但不推荐这样做，这样会导致性能下降。我们应该尽量让索引字段低于限制，索引字段太长时，我们是不是应该考虑设计上有问题了？&lt;/p&gt;

&lt;h1 id=&quot;版权&quot;&gt;版权&lt;/h1&gt;
&lt;blockquote&gt;
  &lt;p&gt;版权声明：自由转载-非商用-非衍生-保持署名（创意共享3.0许可证）&lt;br /&gt;
原创作者：10086@xiaoi.me 发表于 Xiaoi’s Blog：&lt;a href=&quot;https://blog.xiaoi.me&quot;&gt;https://blog.xiaoi.me&lt;/a&gt;&lt;br /&gt;
原文链接：&lt;a href=&quot;https://blog.xiaoi.me/2019/11/04/nextcloud-mysql-utf8mb4-error&quot;&gt;https://blog.xiaoi.me/2019/11/04/nextcloud-mysql-utf8mb4-error&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;扫码关注我，在线与我沟通、咨询
&lt;img src=&quot;/assets/res/qrcode.png&quot; alt=&quot;Xiaoi's Blog&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;转载请保留原文链接以及版权信息&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><category term="php" /><summary type="html">根据 Nextcloud 控制面板安全及设置警告，解决最后一个报警，不支持 4 字节的问题时，遇到该问题， 所使用的数据库为MySQL但没有对4字节字符的支持。为正确处理文件名或评论中使用的4字节字符（比如emoji表情），建议开启MySQL的4字节字符支持。详细信息请阅读相关文档页面。</summary></entry><entry><title type="html">PHP 使用 curl 访问获取 https 网站的内容</title><link href="https://blog.xiaoi.me/2019/10/31/php-curl-ssl" rel="alternate" type="text/html" title="PHP 使用 curl 访问获取 https 网站的内容" /><published>2019-10-31T00:00:00+08:00</published><updated>2019-10-31T00:00:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/31/php-curl-ssl</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/31/php-curl-ssl">&lt;p&gt;遇到一个 PHP 获取 https 网站内容的问题，这里整理成博文供搭建参考。
需求是目前自己搭建了一个国外的博文网站，打算使用国内的服务器进行加速访问。&lt;/p&gt;

&lt;p&gt;查阅了 PHP 相关资料之后，发现 PHP 的 get_file_contents 和 curl 均可以实现。
get_file_contents 能实现简单的，考虑到要实现 Header 等内容的获取和传输，
于是使用了 curl 实现。编码完成之后发现报以下错误信息：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Exception 35: SSL connect error
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;面向搜索引擎解决 BUG，发现是因为 SSL 协议的问题，默认的情况下服务器端禁用了低版本的 SSL 协议，
于是我们需要指定 PHP 使用高版本的 SSL 协议请求服务器端（国外的博文网站）。&lt;/p&gt;
&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 这是我的博客网站&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$siteUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://blog.xiaoi.me'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;httpGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;curl_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;FALSE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'failed to initialize'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
 
        &lt;span class=&quot;nb&quot;&gt;curl_setopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CURLOPT_URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 这里为关键代码，经过几次测试只有，发现需要调整到 6 以上，具体可参考博文底部链接&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;curl_setopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CURLOPT_SSLVERSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
        &lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;curl_exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;FALSE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;curl_error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;curl_errno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    
        &lt;span class=&quot;nb&quot;&gt;var_dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Exception '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;': '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;httpGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$siteUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'uri'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;通过使用以上的 PHP 代码即可完成基本的加速访问，原来使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://blog.xiaoi.me/a/b/c.html`` 访问的内容，
可以通过 PHP 加速访问，例如：&lt;/code&gt;proxy.php?uri=/a/b/c.html```&lt;/p&gt;

&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;
&lt;p&gt;低版本 SSL 协议安全性很低，建议将自己的网站等应用禁用低版本 SSL 协议，并且有类似本文这样的需求时，
同时也将客户端的 SSL 协议版本提高，这样保证数据安全以及代码可用性。&lt;/p&gt;

&lt;h1 id=&quot;参考文献&quot;&gt;参考文献&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/function.curl-setopt.php&quot;&gt;PHP: curl_setopt - Manual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;版权&quot;&gt;版权&lt;/h1&gt;
&lt;blockquote&gt;
  &lt;p&gt;版权声明：自由转载-非商用-非衍生-保持署名（创意共享3.0许可证）&lt;br /&gt;
原创作者：10086@xiaoi.me 发表于 Xiaoi’s Blog：&lt;a href=&quot;https://blog.xiaoi.me&quot;&gt;https://blog.xiaoi.me&lt;/a&gt;&lt;br /&gt;
原文链接：&lt;a href=&quot;https://blog.xiaoi.me/2019/10/31/php-curl-ssl&quot;&gt;https://blog.xiaoi.me/2019/10/31/php-curl-ssl&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;扫码关注我，在线与我沟通、咨询
&lt;img src=&quot;/assets/res/qrcode.png&quot; alt=&quot;Xiaoi's Blog&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;转载请保留原文链接以及版权信息&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><category term="php" /><summary type="html">遇到一个 PHP 获取 https 网站内容的问题，这里整理成博文供搭建参考。 需求是目前自己搭建了一个国外的博文网站，打算使用国内的服务器进行加速访问。</summary></entry><entry><title type="html">使用 ngrok 内网穿透工具</title><link href="https://blog.xiaoi.me/2019/10/23/ngrok-service" rel="alternate" type="text/html" title="使用 ngrok 内网穿透工具" /><published>2019-10-23T14:08:00+08:00</published><updated>2019-10-23T14:08:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/23/ngrok-service</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/23/ngrok-service">&lt;p&gt;ngrok 微信开发必备神器，ngrok 是一个反向代理，通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。QQ群：619152722&lt;/p&gt;

&lt;h2 id=&quot;使用&quot;&gt;使用&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;下载客户端，解压之后运行 start.bat，默认 8080 可直接通过生成的随机域名访问。&lt;/li&gt;
  &lt;li&gt;若本地非 8080 端口，右键编辑 start.bat 文件，将最后的 8080 换成指定端口，例如 80 即可。&lt;/li&gt;
  &lt;li&gt;若需要固定域名例如: test ，修改内容：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ngrok -config ngrok.cfg --subdomain test 8080&lt;/code&gt;，访问时通过：http://test.4kb.cn（或者：https://test.4kb.cn 加密访问） 即可。&lt;/li&gt;
  &lt;li&gt;如果无法连接服务器，请使用命令 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping ngrok.4kb.cn&lt;/code&gt; 检查 IP 是否为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;112.124.46.214&lt;/code&gt;，若不是，请手动绑定 HOSTS，若不知道如何绑定 HOSTS，请善用搜索引擎&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;下载&quot;&gt;下载&lt;/h2&gt;
&lt;h3 id=&quot;64-位系统&quot;&gt;64 位系统&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://img.xiaoi.me/static/ngrok_windows_x64-0.0.2.zip&quot;&gt;Windows 客户端&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://img.xiaoi.me/static/ngrok_linux_x64-0.0.2.zip&quot;&gt;Linux 客户端&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://img.xiaoi.me/static/ngrok_mac_x64-0.0.2.zip&quot;&gt;Mac 客户端&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;32-位系统&quot;&gt;32 位系统&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://img.xiaoi.me/static/ngrok_windows-0.0.2.zip&quot;&gt;Windows 客户端（32位）&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://img.xiaoi.me/static/ngrok_linux-0.0.2.zip&quot;&gt;Linux 客户端（32位）&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://img.xiaoi.me/static/ngrok_mac-0.0.2.zip&quot;&gt;Mac 客户端（32位）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><category term="tool" /><summary type="html">ngrok 微信开发必备神器，ngrok 是一个反向代理，通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。QQ群：619152722</summary></entry><entry><title type="html">使用 docker 运行 frp 服务端，并且上传到 docker hub 在线仓库</title><link href="https://blog.xiaoi.me/2019/10/23/build-frps-docker" rel="alternate" type="text/html" title="使用 docker 运行 frp 服务端，并且上传到 docker hub 在线仓库" /><published>2019-10-23T10:23:00+08:00</published><updated>2019-10-23T10:23:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/23/build-frps-docker</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/23/build-frps-docker">&lt;p&gt;最近在使用 frp 内网穿透服务，运行了一段时间，发现 frp 挺稳定的，突发奇想，之前学习了一下 docker 的使用，何不把 frp 打包成 docker 镜像，这样在任意服务器上就能快速开启 frp 服务了，于是折腾了一下午总算是搞定了。&lt;/p&gt;

&lt;p&gt;如果不想自己配置，可以使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run -p 7000:7000 xiaoi/frp_for_docker:0.27.0&lt;/code&gt; 命令直接运行已经打包好的镜像。若要修改配置，覆盖镜像中的 /app/frps.ini 配置文件即可。&lt;/p&gt;

&lt;h1 id=&quot;操作步骤&quot;&gt;操作步骤&lt;/h1&gt;
&lt;h2 id=&quot;下载和配置-frp&quot;&gt;下载和配置 frp&lt;/h2&gt;
&lt;p&gt;首先我们需要下载一个 frp 服务端程序，可以在 &lt;a href=&quot;https://github.com/fatedier/frp/releases&quot;&gt;github.com&lt;/a&gt; 上下载到最新发布的版本，这里下载 &lt;a href=&quot;https://github.com/fatedier/frp/releases/download/v0.27.0/frp_0.27.0_linux_386.tar.gz&quot;&gt;frp_0.27.0_linux_386.tar.gz&lt;/a&gt; 版本作为演示。&lt;/p&gt;

&lt;p&gt;下载好了之后解压得到相关的应用程序和配置文件，我们只需要保留 frps 和 frps.ini 即可。若有需要可以在 frps.ini 进行自定义配置。
&lt;img src=&quot;/assets/res/img/601c77bc816e902053b08ef01f614cfc53c82303.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;dockerfile-编写&quot;&gt;Dockerfile 编写&lt;/h2&gt;
&lt;p&gt;接下来我们编写 Dockerfile 文件，由于 frp 使用 golang 开发，发布的版本可以直接在 alpine 环境下运行，于是我们的工作变得非常简单，按照如下的代码编写即可&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FROM alpine:latest

WORKDIR /app

COPY . /app

EXPOSE 7000

CMD [&quot;./start.sh&quot;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;由于我在 frps.ini 中配置的 7000 端口，这里 EXPOSE 也设置 7000 端口保持一致。&lt;/p&gt;

&lt;p&gt;CMD 这里填写 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;./start.sh&quot;&lt;/code&gt;方便启动，start.sh 内容如下&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/bin/sh
./frps -c ./frps.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;docker-命令打包镜像&quot;&gt;docker 命令打包镜像&lt;/h2&gt;
&lt;p&gt;编写好 Dockerfile 和启动脚本之后，我们就可以使用 docker 命令打包了&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker build --tag=frp_for_docker .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;打包好了之后使用 docker image ls 查看打包好的镜像
&lt;img src=&quot;/assets/res/img/2185aeb84f9982879e8f44a9b0439f40e524d180.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;运行和检查镜像&quot;&gt;运行和检查镜像&lt;/h2&gt;
&lt;p&gt;使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run -p 7000:7000 frp_for_docker&lt;/code&gt; 运行我们打包好的镜像，出现 success 等字样信息表明运行成功
&lt;img src=&quot;/assets/res/img/21ddb25956d3f290b3f3f5ffc7938245def518a6.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;上传镜像至在线仓库&quot;&gt;上传镜像至在线仓库&lt;/h2&gt;
&lt;p&gt;如果想要在任意地方都能运行我们打包好的镜像，则需要上传镜像至 &lt;a href=&quot;https://hub.docker.com&quot;&gt;hub.docker.com&lt;/a&gt; 在线仓库，上传之前需要 &lt;a href=&quot;https://hub.docker.com/signup&quot;&gt;注册 docker 账号&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;注册好了之后回到控制台运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker login&lt;/code&gt; 然后输入账号密码登录&lt;/p&gt;

&lt;p&gt;然后将我们的镜像改名，格式为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;用户名/镜像名:版本号&lt;/code&gt; ，例如我的用户名为 xiaoi，镜像名我定义为 frp_for_docker ，版本号我这里按照 frp 版本号来定义，其中除了用户名不能自定义，镜像名和版本号都是可以任意命名，使用如下命令将本地镜像改名。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker tag frp_by_docker xiaoi/frp_by_docker:0.27.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;改好之后使用 docker push 命令上传至在线仓库&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker push xiaoi/frp_for_docker:0.27.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上传完成之后我们就可以在 &lt;a href=&quot;https://hub.docker.com&quot;&gt;hub.docker.com&lt;/a&gt; 在线仓库中查看我们的镜像了
&lt;img src=&quot;/assets/res/img/aeb5c75aeeb375eb398a26237ae5c2a697c0f820.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;在别处直接运行在线仓库中的镜像&quot;&gt;在别处直接运行在线仓库中的镜像&lt;/h2&gt;
&lt;p&gt;在有 docker 环境的服务器或者个人电脑上使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run&lt;/code&gt; 命令就可以运行在线仓库中的镜像，例如运行我们上传的镜像&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run -p 7000:7000 xiaoi/frp_for_docker:0.27.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;运行命令之后，接下来的这一切都是自动化完成的，无需我们再做任何操作
&lt;img src=&quot;/assets/res/img/9929ddd33af26d74c34d748aa2ec81c389ca467e.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;使用 docker 我们可以很容易的将一个应用程序分发到各个地方运行，便于后期的维护和管理，同时也不用担心跨平台的问题产生；&lt;/li&gt;
  &lt;li&gt;程序所依赖的环境我们也可以通过编写 Dockerfile 来解决，不必再为各个环境依赖重复安装运行环境，这样极大的减轻来工作量；&lt;/li&gt;
  &lt;li&gt;docker 能运行的程序远不于此，我们可以将所熟悉的一切软件都使用 docker 来运行和管理；&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;版权&quot;&gt;版权&lt;/h1&gt;
&lt;blockquote&gt;
  &lt;p&gt;版权声明：自由转载-非商用-非衍生-保持署名（创意共享3.0许可证）&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;原创作者 10086@xiaoi.me 发表于阿里云·云栖社区：&lt;a href=&quot;https://yq.aliyun.com/users/y4epujtm5wye6&quot;&gt;https://yq.aliyun.com/users/y4epujtm5wye6&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;扫码关注我，在线与我沟通、咨询
&lt;img src=&quot;/assets/res/qrcode.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;转载请保留原文链接以及版权信息&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><category term="Linux" /><summary type="html">最近在使用 frp 内网穿透服务，运行了一段时间，发现 frp 挺稳定的，突发奇想，之前学习了一下 docker 的使用，何不把 frp 打包成 docker 镜像，这样在任意服务器上就能快速开启 frp 服务了，于是折腾了一下午总算是搞定了。</summary></entry><entry><title type="html">CentOS 7 下搭建自己的 ngrok 内网穿透服务</title><link href="https://blog.xiaoi.me/2019/10/23/build-ngrok-on-centos7" rel="alternate" type="text/html" title="CentOS 7 下搭建自己的 ngrok 内网穿透服务" /><published>2019-10-23T09:56:00+08:00</published><updated>2019-10-23T09:56:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/23/build-ngrok-on-centos7</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/23/build-ngrok-on-centos7">&lt;p&gt;现在的家庭宽带或者部分公司的宽带都没有直接分配公网 IP ，这个给我们做开发调试时带来的很大的不便，比如我们需要对接微信公众号、支付宝等第三方系统时，第三方系统需要通过异步回调通知我们的服务，但是我们自己电脑上的应用程序都无法对外访问，这样也就通知不了，无法很好的进行联调测试。&lt;/p&gt;

&lt;p&gt;在这样的背景下，ngrok 对于我们来说就提供了很大的帮助，他可以让我们内网的应用可以对外访问，无论是 HTTP(s) 服务还是 TCP/SSH 等场景，均可以通过 ngrok 服务内网穿透来达到对外提供访问的目的。&lt;/p&gt;

&lt;h1 id=&quot;搭建步骤&quot;&gt;搭建步骤&lt;/h1&gt;
&lt;h2 id=&quot;第一步安装-golang-环境&quot;&gt;第一步：安装 golang 环境&lt;/h2&gt;
&lt;p&gt;博主的服务器统一使用的 CentOS 7 发行版本，所以通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yum install golang&lt;/code&gt; 就可以安装好 golang 环境，如果是其他操作系统可以参考官方文档 &lt;a href=&quot;https://golang.org/doc/install&quot;&gt;How to install golang&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;第二步下载-ngrok-源码&quot;&gt;第二步：下载 ngrok 源码&lt;/h2&gt;
&lt;p&gt;目前 ngrok 2.x 版本已经闭源，我们能下载到的最新版本为 &lt;a href=&quot;https://github.com/inconshreveable/ngrok/archive/1.7.1.zip&quot;&gt;ngrok-1.7.1.zip&lt;/a&gt;，
下载完成之后解压 zip 包，这里我们需要修改 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/ngrok/log/logger.go&lt;/code&gt; 中的源代码，
将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log &quot;code.google.com/p/log4go&quot;&lt;/code&gt; 修改为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log &quot;github.com/alecthomas/log4go&quot;&lt;/code&gt;，
否则编译时会报错 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build fails: 'package code.google.com/p/log4go: unable to detect version control system for code.google.com/ path'&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;第三步生成-tls-证书&quot;&gt;第三步：生成 TLS 证书&lt;/h2&gt;
&lt;p&gt;例如我们以 4kb.cn 域名为例，我们在生成证书的时候可以指定 ngrok.4kb.cn 这个域名指定 ngrok 服务器地址（需要 DNS 解析到 ngrok 所在服务器的 IP 上），同时我们对外提供 ngrok 域名为 *.4kb.cn （需要泛域名解析 *.4kb.cn 到 ngrok 所在服务器的 IP 上），这里的 ngrok.4kb.cn 和 *.4kb.cn 解析并不冲突。&lt;/p&gt;

&lt;p&gt;生成 TLS 证书的命令如下：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj &quot;/CN=ngrok.4kb.cn&quot; -days 3650 -out rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj &quot;/CN=ngrok.4kb.cn&quot; -out device.csr
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 3650
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;第四步覆盖-ngrok-默认-tls-证书&quot;&gt;第四步：覆盖 ngrok 默认 TLS 证书&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cp rootCA.pem assets/client/tls/ngrokroot.crt
cp device.crt assets/server/tls/snakeoil.crt 
cp device.key assets/server/tls/snakeoil.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;第五步设置-golang-编译目录和参数&quot;&gt;第五步：设置 Golang 编译目录和参数&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export GOPATH=/go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;为了可以在 docker 环境下运行，我们还需要运行下面的命令，否则会报错 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unable to run a go program inside docker /bin/sh: ./ngrokd: not found&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export CGO_ENABLED=0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;第六步编译-ngrok-服务端和客户端&quot;&gt;第六步：编译 ngrok 服务端和客户端&lt;/h2&gt;
&lt;p&gt;Linux 32 位系统 ngrok 编译命令&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export GOOS=linux GOARCH=386
make release-server release-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Linux 64 位系统 ngrok 编译命令&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export GOOS=linux GOARCH=amd64
make release-server release-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Windows 32 位系统 ngrok 编译命令&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export GOOS=windows GOARCH=386
make release-server release-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Windows 64 位系统 ngrok 编译命令&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export GOOS=windows GOARCH=amd64
make release-server release-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;macOS 32 位系统 ngrok 编译命令&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export GOOS=darwin GOARCH=386
make release-server release-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;macOS 64 位系统 ngrok 编译命令&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export GOOS=darwin GOARCH=amd64
make release-server release-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其他操作系统修改 GOOS 和 GOARCH 为对应的即可：&lt;a href=&quot;https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63&quot;&gt;Go (Golang) GOOS and GOARCH&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;第七步运行-ngrokd-服务端&quot;&gt;第七步：运行 ngrokd 服务端&lt;/h2&gt;
&lt;p&gt;编译完成之后可以在 bin 目录下看到 ngrokd（服务端）和 ngrok（客户端），运行服务端时需要将 assets/server/tls/snakeoil.crt 和 assets/server/tls/snakeoil.key
复制到同级目录，启动的命令参考如下：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./ngrokd -tlsKey=snakeoil.key -tlsCrt=snakeoil.crt -domain=&quot;4kb.cn&quot; -httpAddr=&quot;:80&quot; -httpsAddr=&quot;:443&quot; -tunnelAddr=&quot;:4443&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果使用默认 80、443、4443 端口，则可以使用以下命令运行：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./ngrokd -tlsKey=snakeoil.key -tlsCrt=snakeoil.crt -domain=&quot;4kb.cn&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;第八步运行-ngrok-客户端&quot;&gt;第八步：运行 ngrok 客户端&lt;/h2&gt;
&lt;p&gt;运行之前我们需要编写一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ngrok.cfg&lt;/code&gt; 文件，内容如下&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;server_addr: &quot;ngrok.4kb.cn:4443&quot;
trust_host_root_certs: false
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里的 server_addr 需要和第三步生成 TLS 时保持一致，否则服务端会报 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls: bad certificate&lt;/code&gt; 证书错误，
编辑完成之后使用 ngrok 客户端运行即可&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./ngrok -config=ngrok.cfg 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;指定域名运行命令&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./ngrok -config=ngrok.cfg -subdomain=xxx 8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;映射 SSH 22 端口，使用 tcp 协议&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./ngrok -config=ngrok.cfg -proto=tcp 22
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;
&lt;p&gt;我们搭建完成 ngrok 服务端后，任意能连接到服务器的应用程序均可以通过 ngrok 内网穿透，不仅 Java、PHP 等开发的网站可以通过 ngrok 映射对外提供域名访问，也可以让 SSH 的 22 端口映射之后，我们连接无公网 IP 的服务器（比如在家里面搭建一个私有服务器），甚至还可以将 MySQL 的 3306 端口映射之后，在任意地点远程连接内网的数据库。这给我们带来来极大的方便，也不需要购买第三方服务（例如花生壳）。&lt;/p&gt;

&lt;h1 id=&quot;参考文献&quot;&gt;参考文献&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.ifengse.com/post/ngrok-install/&quot;&gt;编译自己的ngrok服务&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63&quot;&gt;Go (Golang) GOOS and GOARCH&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/48124388/unable-to-run-a-go-program-inside-docker-bin-sh-program-not-found&quot;&gt;Unable to run a go program inside docker /bin/sh: &amp;lt; program&amp;gt;: not found&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;版权&quot;&gt;版权&lt;/h1&gt;
&lt;blockquote&gt;
  &lt;p&gt;版权声明：自由转载-非商用-非衍生-保持署名（创意共享3.0许可证）&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;原创作者 10086@xiaoi.me 发表于阿里云·云栖社区：&lt;a href=&quot;https://yq.aliyun.com/users/y4epujtm5wye6&quot;&gt;https://yq.aliyun.com/users/y4epujtm5wye6&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;扫码关注我，在线与我沟通、咨询
&lt;img src=&quot;/assets/res/qrcode.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;转载请保留原文链接以及版权信息&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><category term="ngrok" /><category term="Linux" /><category term="CentOS" /><summary type="html">现在的家庭宽带或者部分公司的宽带都没有直接分配公网 IP ，这个给我们做开发调试时带来的很大的不便，比如我们需要对接微信公众号、支付宝等第三方系统时，第三方系统需要通过异步回调通知我们的服务，但是我们自己电脑上的应用程序都无法对外访问，这样也就通知不了，无法很好的进行联调测试。</summary></entry><entry><title type="html">手机型号数据库</title><link href="https://blog.xiaoi.me/2019/10/23/model-lib" rel="alternate" type="text/html" title="手机型号数据库" /><published>2019-10-23T00:00:00+08:00</published><updated>2019-10-23T00:00:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/23/model-lib</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/23/model-lib">&lt;p&gt;有时候我们遇到获取用户的手机型号时，只能获取 XX-XXX 这样的型号，我们无法直接得知用户的手机名称，在网上各大数据接口上搜寻了一番也未找到一种可以直接将手机型号（例如：SM901）转换为人类可直接阅读的名称（例如：锤子 M1），于是我和另外一个小伙伴（51587124@github）发起了该项目。&lt;/p&gt;

&lt;p&gt;该项目的主旨为提供一个统一、公开、人人可参与的手机型号数据库，采用 github 进行托管和维护，同时我个人提供了基于该数据库实现的在线 API ，大家也可以基于该数据库文件实现私有的 API，定期同步数据库文件即可。&lt;/p&gt;

&lt;p&gt;若在使用的过程中有缺失的机型信息，欢迎提交 issues&lt;/p&gt;

&lt;h1 id=&quot;存储格式&quot;&gt;存储格式&lt;/h1&gt;
&lt;p&gt;model:name:brand&lt;/p&gt;

&lt;h1 id=&quot;在线-api&quot;&gt;在线 API&lt;/h1&gt;
&lt;p&gt;正常状态返回 0，name 为手机名称，brand 为手机品牌&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://model-lib.4kb.cn/api/model/{model}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;example:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://model-lib.4kb.cn/api/model/SM901
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h1 id=&quot;版权信息&quot;&gt;版权信息&lt;/h1&gt;
&lt;p&gt;原作者 &lt;a href=&quot;https://weibo.com/huangyf9883&quot;&gt;weibo@@KHwang9883&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;修改者 &lt;a href=&quot;https://xiaoi.me&quot;&gt;10086@xiaoi.me&lt;/a&gt;，整合了原作者的数据为标准格式，并提供在线 API&lt;/p&gt;

&lt;h2 id=&quot;许可&quot;&gt;许可&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/4.0/&quot;&gt;&lt;img src=&quot;https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png&quot; alt=&quot;知识共享许可协议&quot; /&gt;&lt;/a&gt;
本作品采用&lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/4.0/&quot;&gt;知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议&lt;/a&gt; 进行许可。&lt;/p&gt;

&lt;p&gt;文档版的分发和传播亦适用于该协议。&lt;/p&gt;

&lt;h1 id=&quot;参考文献&quot;&gt;参考文献&lt;/h1&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://github.com/KHwang9883/MobileModels&quot;&gt;手机品牌型号汇总&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content><author><name></name></author><category term="项目" /><summary type="html">有时候我们遇到获取用户的手机型号时，只能获取 XX-XXX 这样的型号，我们无法直接得知用户的手机名称，在网上各大数据接口上搜寻了一番也未找到一种可以直接将手机型号（例如：SM901）转换为人类可直接阅读的名称（例如：锤子 M1），于是我和另外一个小伙伴（51587124@github）发起了该项目。</summary></entry><entry><title type="html">IntelliJ Idea 常用快捷键列表</title><link href="https://blog.xiaoi.me/2019/10/23/idea-keymap" rel="alternate" type="text/html" title="IntelliJ Idea 常用快捷键列表" /><published>2019-10-23T00:00:00+08:00</published><updated>2019-10-23T00:00:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/23/idea-keymap</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/23/idea-keymap">&lt;p&gt;File - Settings - Keymap 可以修改快捷键绑定，建议将默认的关闭当前 Tab 标签修改为 Ctrl+W 键（路径：Main menu - Window - Editor Tabs - Close）这样可以编辑完当前文件之后直接 Ctrl+W 关闭，一是可以减少 Tab 标签数量，二是可以确认自己的代码已经保存过了（未保存时会提示保存），同时也可以避免手误把已经改好的代码改错或者撤回之类的误操作。&lt;/p&gt;

&lt;h5 id=&quot;快捷键列表&quot;&gt;快捷键列表&lt;/h5&gt;

&lt;p&gt;Alt+回车 导入包,自动修正
Ctrl+N 查找类
Ctrl+Shift+N 查找文件
Ctrl+Alt+L 格式化代码&lt;/p&gt;

&lt;p&gt;Ctrl+Alt+O 优化导入的类和包
Alt+Insert 生成代码(如get,set方法,构造函数等)
Ctrl+E或者Alt+Shift+C 最近更改的代码
Ctrl+R 替换文本&lt;/p&gt;

&lt;p&gt;Ctrl+F 查找文本
Ctrl+Shift+Space 自动补全代码
Ctrl+空格 代码提示&lt;/p&gt;

&lt;p&gt;Ctrl+Alt+方向左、Ctrl+Alt+方向右，可以在最近几次编辑的位置之间切换&lt;/p&gt;

&lt;p&gt;Ctrl+Alt+Space 类名或接口名提示&lt;/p&gt;

&lt;p&gt;Ctrl+P 方法参数提示&lt;/p&gt;

&lt;p&gt;Ctrl+Shift+Alt+N 查找类中的方法或变量&lt;/p&gt;

&lt;p&gt;Alt+Shift+C 对比最近修改的代码&lt;/p&gt;

&lt;p&gt;Shift+F6 重构-重命名
Ctrl+Shift+先上键
Ctrl+X 删除行
Ctrl+D 复制行
Ctrl+/ 或 Ctrl+Shift+/ 注释（// 或者/&lt;em&gt;…&lt;/em&gt;/ ）
Ctrl+J 自动代码
Ctrl+E 最近打开的文件&lt;/p&gt;

&lt;p&gt;Ctrl+H 显示类结构图&lt;/p&gt;

&lt;p&gt;Ctrl+Q 显示注释文档
Alt+F1 查找代码所在位置
Alt+1 快速打开或隐藏工程面板&lt;/p&gt;

&lt;p&gt;Ctrl+Alt+ left/right 返回至上次浏览的位置
Alt+ left/right 切换代码视图&lt;/p&gt;

&lt;p&gt;Alt+ Up/Down 在方法间快速移动定位&lt;/p&gt;

&lt;p&gt;Ctrl+Shift+Up/Down 代码向上/下移动。&lt;/p&gt;

&lt;p&gt;F2 或Shift+F2 高亮错误或警告快速定位&lt;/p&gt;

&lt;p&gt;代码标签输入完成后，按Tab，生成代码。&lt;/p&gt;

&lt;p&gt;选中文本，按Ctrl+Shift+F7 ，高亮显示所有该文本，按Esc高亮消失。&lt;/p&gt;

&lt;p&gt;Ctrl+W 选中代码，连续按会有其他效果&lt;/p&gt;

&lt;p&gt;选中文本，按Alt+F3 ，逐个往下查找相同文本，并高亮显示。&lt;/p&gt;

&lt;p&gt;Ctrl+Up/Down 光标跳转到第一行或最后一行下&lt;/p&gt;

&lt;p&gt;Ctrl+B 快速打开光标处的类或方法&lt;/p&gt;

&lt;h5 id=&quot;最常用快捷键&quot;&gt;最常用快捷键&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt;Ctrl＋E，可以显示最近编辑的文件列表&lt;/li&gt;
  &lt;li&gt;Shift＋Click可以关闭文件&lt;/li&gt;
  &lt;li&gt;Ctrl＋[或]可以跳到大括号的开头结尾&lt;/li&gt;
  &lt;li&gt;Ctrl＋Shift＋Backspace可以跳转到上次编辑的地方&lt;/li&gt;
  &lt;li&gt;Ctrl＋F12，可以显示当前文件的结构&lt;/li&gt;
  &lt;li&gt;Ctrl＋F7可以查询当前元素在当前文件中的引用，然后按F3可以选择&lt;/li&gt;
  &lt;li&gt;Ctrl＋N，可以快速打开类&lt;/li&gt;
  &lt;li&gt;Ctrl＋Shift＋N，可以快速打开文件&lt;/li&gt;
  &lt;li&gt;Alt＋Q可以看到当前方法的声明&lt;/li&gt;
  &lt;li&gt;Ctrl＋W可以选择单词继而语句继而行继而函数&lt;/li&gt;
  &lt;li&gt;Alt＋F1可以将正在编辑的元素在各个面板中定位&lt;/li&gt;
  &lt;li&gt;Ctrl＋P，可以显示参数信息&lt;/li&gt;
  &lt;li&gt;Ctrl＋Shift＋Insert可以选择剪贴板内容并插入&lt;/li&gt;
  &lt;li&gt;Alt＋Insert可以生成构造器/Getter/Setter等&lt;/li&gt;
  &lt;li&gt;Ctrl＋Alt＋V 可以引入变量。例如把括号内的SQL赋成一个变量&lt;/li&gt;
  &lt;li&gt;Ctrl＋Alt＋T可以把代码包在一块内，例如try/catch&lt;/li&gt;
  &lt;li&gt;Alt＋Up and Alt＋Down可在方法间快速移动&lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;下面的不是很有用&quot;&gt;下面的不是很有用&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt;在一些地方按Alt＋Enter可以得到一些Intention Action，例如将”==”改为”equals()”&lt;/li&gt;
  &lt;li&gt;Ctrl＋Shift＋Alt＋N可以快速打开符号&lt;/li&gt;
  &lt;li&gt;Ctrl＋Shift＋Space在很多时候都能够给出Smart提示&lt;/li&gt;
  &lt;li&gt;Alt＋F3可以快速寻找&lt;/li&gt;
  &lt;li&gt;Ctrl＋/和Ctrl＋Shift＋/可以注释代码&lt;/li&gt;
  &lt;li&gt;Ctrl＋Alt＋B可以跳转到抽象方法的实现&lt;/li&gt;
  &lt;li&gt;Ctrl＋O可以选择父类的方法进行重写&lt;/li&gt;
  &lt;li&gt;Ctrl＋Q可以看JavaDoc&lt;/li&gt;
  &lt;li&gt;Ctrl＋Alt＋Space是类名自动完成&lt;/li&gt;
  &lt;li&gt;快速打开类/文件/符号时，可以使用通配符，也可以使用缩写&lt;/li&gt;
  &lt;li&gt;Live Templates! Ctrl＋J&lt;/li&gt;
  &lt;li&gt;Ctrl＋Shift＋F7可以高亮当前元素在当前文件中的使用&lt;/li&gt;
  &lt;li&gt;Ctrl＋Alt＋Up /Ctrl＋Alt＋Down可以快速跳转搜索结果&lt;/li&gt;
  &lt;li&gt;Ctrl＋Shift＋J可以整合两行&lt;/li&gt;
  &lt;li&gt;Alt＋F8是计算变量值&lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;intellij-idea使用技巧一览表&quot;&gt;IntelliJ IDEA使用技巧一览表&lt;/h5&gt;

&lt;p&gt;在使用 InelliJ IDEA 的过程中，通过查找资料以及一些自己的摸索，发现这个众多 Java 程序员喜欢的 IDE 里有许多值得一提的小窍门，如果能熟练的将它们应用于实际开发过程中，相信它会大大节省你的开发时间，而且随之而来的还会有那么一点点成就感：） Try it ！&lt;/p&gt;

&lt;p&gt;1 、写代码时用 Alt-Insert （ Code|Generate… ）可以创建类里面任何字段的 getter 与 setter 方法。 
&amp;lt;?xml:namespace prefix = v ns = “urn:schemas-microsoft-com:vml” /&amp;gt; 
2 、右键点击断点标记（在文本的左边栏里）激活速查菜单，你可以快速设置 enable/disable 断点或者条件它的属性。
3 、 CodeCompletion （代码完成）属性里的一个特殊的变量是，激活 Ctrl-Alt-Space 可以完成在或不在当前文件里的类名。如果类没有引入则 import 标志会自动创建。
4 、使用 Ctrl-Shift-V 快捷键可以将最近使用的剪贴板内容选择插入到文本。使用时系统会弹出一个含有剪贴内容的对话框，从中你可以选择你要粘贴的部分。 
5 、利用 CodeCompletion （代码完成）属性可以快速地在代码中完成各种不同地语句，方法是先键入一个类名地前几个字母然后再用 Ctrl-Space 完成全称。如果有多个选项，它们会列在速查列表里。 
6 、用 Ctrl-/ 与 Ctrl-Shift-/ 来注释 / 反注释代码行与代码块。 
-/ 用单行注释标记（“ //… ”）来注释 / 反注释当前行或者选择地代码块。而 Ctrl-Shift-/ 则可以用块注释标记（“ /&lt;em&gt;…&lt;/em&gt;/ ”）把所选块包围起来。要反注释一个代码块就在块中任何一个地方按 Ctrl-Shift-/ 即可。
7 、按 Alt-Q （ View|Context Info ）可以不需要移动代码就能查看当前方法地声明。连续按两次会显示当前所编辑的类名。 
8 、使用 Refactor|Copy Class… 可以创建一个所选择的类的“副本”。这一点很有用，比如，在你想要创建一个大部分内容都和已存在类相同的类时。 
9 、在编辑器里 Ctrl-D 可以复制选择的块或者没有所选块是的当前行。 
10 、 Ctrl-W （选择字）在编辑器里的功能是先选择脱字符处的单词，然后选择源代码的扩展区域。举例来说，先选择一个方法名，然后是调用这个方法的表达式，然后是整个语句，然后包容块，等等。
11 、如果你不想让指示事件细节的“亮球”图标在编辑器上显示，通过按 Alt-Enter 组合键打开所有事件列表然后用鼠标点击它就可以把这个事件文本附件的亮球置成非活动状态。 
这样以后就不会有指示特殊事件的亮球出现了，但是你仍然可以用 Alt-Enter 快捷键使用它。
12 、在使用 CodeCompletion 时，可以用逗点（ . ）字符，逗号（，）分号（；），空格和其它字符输入弹出列表里的当前高亮部分。选择的名字会随着输入的字符自动输入到编辑器里。 
13 、在任何工具窗口里使用 Escape 键都可以把焦点移到编辑器上。 
Shift-Escape 不仅可以把焦点移到编辑器上而且还可以隐藏当前（或最后活动的）工具窗口。 
F12 键把焦点从编辑器移到最近使用的工具窗口。 
14 、在调试程序时查看任何表达式值的一个容易的方法就是在编辑器中选择文本（可以按几次 Ctrl-W 组合键更有效地执行这个操作）然后按 Alt-F8 。 
15 、要打开编辑器脱字符处使用的类或者方法 Java 文档的浏览器，就按 Shift-F1 （右键菜单的 External JavaDoc ）。 
要使用这个功能须要把加入浏览器的路径，在“ General ”选项中设置（ Options | IDE Settings ），另外还要把创建的 Java 文档加入到工程中（ File | Project Properties ）。 
16 、用 Ctrl-F12 （ View | File Structure Popup ）键你可以在当前编辑的文件中快速导航。 
这时它会显示当前类的成员列表。选中一个要导航的元素然后按 Enter 键或 F4 键。要轻松地定位到列表中的一个条目，只需键入它的名字即可。 
17 、在代码中把光标置于标记符或者它的检查点上再按 Alt-F7 （右键菜单中的 Find Usages… ）会很快地查找到在整个工程中使用地某一个类、方法或者变量的位置。
18 、按 Ctrl-N （ Go to | Class… ）再键入类的名字可以快速地在编辑器里打开任何一个类。从显示出来的下拉列表里选择类。 
同样的方法你可以通过使用 Ctrl-Shift-N （ Go to | File… ）打开工程中的非 Java 文件。
19 、要导航代码中一些地方使用到的类、方法或者变量的声明，把光标放在查看项上再按 Ctrl-B 即可。也可以通过按 Ctrl 键的同时在查看点上单击鼠标键调转到声明处。 
20 、把光标放到查看点上再按 Ctrl-Alt-B 可以导航到一个抽象方法的实现代码。
21 、要看一个所选择的类的继承层次，按 Ctrl-H （ Browse Type Hierarchy ）即可。也可以激活编辑器中的继承关系视图查看当前编辑类的继承关系。22 、使用 Ctrl-Shift-F7 （ Search | Highlight Usages in File ）可以快速高亮显示当前文件中某一变量的使用地方。按 Escape 清除高亮显示。 
23 、用 Alt-F3 （ Search | Incremental Search ）在编辑器中实现快速查查找功能。 
在“ Search for: ”提示工具里输入字符，使用箭头键朝前和朝后搜索。按 Escape 退出。
24 、按 Ctrl-J 组合键来执行一些你记不起来的 Live Template 缩写。比如，键“ it ”然后按 Ctrl-J 看看有什么发生。
25 、 Introduce Variable 整合帮助你简化代码中复杂的声明。举个例子，在下面的代码片断里，在代码中选择一个表达式：然后按 Ctrl-Alt-V 。
26 、 Ctrl-Shift-J 快捷键把两行合成一行并把不必要的空格去掉以匹配你的代码格式。
27 、 Ctrl-Shift-Backspace （ Go to | Last Edit Location ）让你调转到代码中所做改变的最后一个地方。 
多按几次 Ctrl-Shift-Backspace 查看更深的修改历史。 
28 、用 Tools | Reformat Code… 根据你的代码样式参考（查看 Options | IDE Setting | Code Style ）格式化代码。 
使用 Tools | Optimize Imports… 可以根据设置（查看 Options | IDE Setting | Code Style | Imports ）自动“优化” imports （清除无用的 imports 等）。
29 、使用 IDEA 的 Live Templates | Live Templates 让你在眨眼间创建许多典型代码。比如，在一个方法里键入 
再按 Tab 键看有什么事情发生了。 
用 Tab 键在不同的模板域内移动。查看 Options | Live Templates 获取更多的细节。
30 、要查看一个文件中修改的本地历史，激活右键菜单里的 Local VCS | Show History… 。也许你可以导航不同的文件版本，看看它们的不同之处再回滚到以前的任何一个版本吧。 
使用同样的右键菜单条目还可以看到一个目录里修改的历史。有了这个特性你就不会丢失任何代码了。
31 、如果要了解主菜单里每一个条目的用途，把鼠标指针移到菜单条目上再应用程序框架的底部的状态栏里就会显示它们的一些简短描述，也许会对你有帮助。 
32 、要在编辑器里显示方法间的分隔线，打开 Options | IDE Settings | Editor ，选中“ Show method separators ”检查盒（ checkbox ）。 
33 、用 Alt-Up 和 Alt-Down 键可以在编辑器里不同的方法之间快速移动。 
34 、用 F2/Shift-F2 键在高亮显示的语法错误间跳转。 
用 Ctrl-Alt-Down/Ctrl-Alt-Up 快捷键则可以在编译器错误信息或者查找操作结果间跳转。
35 、通过按 Ctrl-O （ Code | Override Methods… ）可以很容易地重载基本类地方法。 
要完成当前类 implements 的（或者抽象基本类的）接口的方法，就使用 Ctrl-I （ Code | Implement Methods… ）。 
36 、如果光标置于一个方法调用的括号间，按 Ctrl-P 会显示一个可用参数的列表。
37 、要快速查看编辑器脱字符处使用的类或方法的 Java 文档，按 Ctrl-Q （在弹出菜单的 Show Quick JavaDoc 里）即可。 
38 、像 Ctrl-Q （ Show Quick JavaDoc 显示简洁 Java 文档）， Ctrl-P （ Show Parameter Info 显示参数信息）， Ctrl-B （ Go to Declaration 跳转到声明）， Shift-F1 （ External JavaDoc 外部 Java 文档）以及其它一些快捷键不仅可以在编辑器里使用，也可以应用在代码完成右键列表里。 
39 、 Ctrl-E （ View | Recent Files ）弹出最近访问的文件右键列表。选中文件按 Enter 键打开。 
40 、在 IDEA 中可以很容易地对你的类，方法以及变量进行重命名并在所有使用到它们的地方自动更正。 
试一下，把编辑器脱字符置于任何一个变量名字上然后按 Shift-F6 （ Refactor | Rename… ）。在对话框里键入要显示地新名字再按 Enter 。你会浏览到使用这个变量地所有地方然后按“ Do Refactor ”按钮结束重命名操作。 
41 、要在任何视图（ Project View 工程视图， Structure View 结构视图或者其它视图）里快速 
选择当前编辑地部分（类，文件，方法或者字段），按 Alt-F1 （ View | Select in… ）。 
42 、在“ new ”字符后实例化一个已知类型对象时也许你会用到 SmartType 代码完成这个特性。比如，键入 
再按 Ctrl-Shift-Space ：
43 、通过使用 SmartType 代码完成，在 IDEA 中创建接口的整个匿名 implementation 也是非常容易的，比如，对于一些 listener （监听器），可以键入 
Component component; 
component.addMouseListener( 
new &lt;caret is=&quot;&quot; here=&quot;&quot;&gt; 
); 
然后再按 Ctrl-Shift-Space 看看有什么发生了。 
44 、在你需要设置一个已知类型的表达式的值时用 SmartType 代码完成也很有帮助。比如，键入 
String s = ( &lt;caret is=&quot;&quot; here=&quot;&quot;&gt; 
再按 Ctrl-Shift-Space 看看会有什么出现。 
45 、在所有视图里都提供了速查功能：在树里只需键入字符就可以快速定位到一个条目。 
46 、当你想用代码片断捕捉异常时，在编辑器里选中这个片断，按 Ctrl-Alt-T （ Code | Surround with… ）然后选择“ try/catch ”。它会自动产生代码片断中抛出的所有异常的捕捉块。在 Options | File Templates | Code tab 中你还可以自己定制产生捕捉块的模板。 
用列表中的其它项可以包围别的一些结构。 
47 、在使用代码完成时，用 Tab 键可以输入弹出列表里的高亮显示部分。 
不像用 Enter 键接受输入，这个选中的名字会覆盖掉脱字符右边名字的其它部分。这一点在用一个方法或者变量名替换另一个时特别有用。 
48 、在声明一个变量时代码完成特性会给你显示一个建议名。比如，开始键入“ private FileOutputStream ”然后按 Ctrl-Space&lt;/caret&gt;&lt;/caret&gt;&lt;/p&gt;

&lt;h5 id=&quot;参考文章&quot;&gt;参考文章&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;h1 id=&quot;intellij-idea-常用快捷键列表&quot;&gt;&lt;a href=&quot;https://www.cnblogs.com/EhPartment/archive/2012/08/24/2653789.html&quot;&gt;IntelliJ Idea 常用快捷键列表&lt;/a&gt;&lt;/h1&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><category term="idea" /><summary type="html">File - Settings - Keymap 可以修改快捷键绑定，建议将默认的关闭当前 Tab 标签修改为 Ctrl+W 键（路径：Main menu - Window - Editor Tabs - Close）这样可以编辑完当前文件之后直接 Ctrl+W 关闭，一是可以减少 Tab 标签数量，二是可以确认自己的代码已经保存过了（未保存时会提示保存），同时也可以避免手误把已经改好的代码改错或者撤回之类的误操作。</summary></entry><entry><title type="html">欢迎使用 Frp 内网穿透服务</title><link href="https://blog.xiaoi.me/2019/10/22/use-frps" rel="alternate" type="text/html" title="欢迎使用 Frp 内网穿透服务" /><published>2019-10-22T16:03:00+08:00</published><updated>2019-10-22T16:03:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/22/use-frps</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/22/use-frps">&lt;p&gt;近期收到部分群友反馈，ngrok 服务偶尔会出现无法连接、访问缓慢、客户端闪退等情况，群主决定研究一下如何搭建 frp 服务，经过一下午的时间，总算搭建好了 frp 服务，现在将 frp 服务公开给群友供大家使用。&lt;/p&gt;

&lt;p&gt;目前客户端只打包了 windows，其他操作系统的群友可以在 frp 官方下载对应的客户端，目前服务端使用的 0.27.0 版本，客户端尽量使用相同版本：https://github.com/fatedier/frp/releases/tag/v0.27.0&lt;/p&gt;

&lt;p&gt;windows 客户端下载地址：https://img.xiaoi.me/pms-upload/20190605/15a82187-d4b8-e1f9-371b-5113463b57f0.zip&lt;/p&gt;

&lt;p&gt;另外，服务器提供了更多“黑科技”服务，欢迎大家的使用和咨询。&lt;/p&gt;

&lt;p&gt;若对群主提供的服务满意，还请捐赠支持一下：https://tb.4kb.cn&lt;/p&gt;</content><author><name></name></author><category term="Linux" /><summary type="html">近期收到部分群友反馈，ngrok 服务偶尔会出现无法连接、访问缓慢、客户端闪退等情况，群主决定研究一下如何搭建 frp 服务，经过一下午的时间，总算搭建好了 frp 服务，现在将 frp 服务公开给群友供大家使用。</summary></entry><entry><title type="html">Docker 容器化服务笔记</title><link href="https://blog.xiaoi.me/2019/10/22/docker-guide" rel="alternate" type="text/html" title="Docker 容器化服务笔记" /><published>2019-10-22T09:14:00+08:00</published><updated>2019-10-22T09:14:00+08:00</updated><id>https://blog.xiaoi.me/2019/10/22/docker-guide</id><content type="html" xml:base="https://blog.xiaoi.me/2019/10/22/docker-guide">&lt;p&gt;容器化服务笔记&lt;/p&gt;

&lt;h1 id=&quot;安装和启用-docker&quot;&gt;安装和启用 docker&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; yum install docker

&amp;gt; systemctl enable docker.service

&amp;gt; systemctl start docker.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;1、运行时时区设置问题：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FROM openjdk:8-jdk-alpine

RUN apk add --no-cache tzdata

ENV TZ Asia/Shanghai



RUN date -R
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;运行时字体加载失败：NPE at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RUN apk add --no-cache fontconfig

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2、进入容器执行 bash 命令&lt;/p&gt;

&lt;h1 id=&quot;container-id-不用输全&quot;&gt;container id 不用输全&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker exec -t -i {container id} /bin/bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;查询日志&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker logs 9573ada
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;服务的方式 docker 运行 nginx&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo docker run --name my-nginx -p 80:80 -v /Users/stevenkang-mac/docker-nginx/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;打包镜像命令&quot;&gt;打包镜像命令&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mvn clean package docker:build -D maven.test.skip=true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;打包并上传镜像&quot;&gt;打包并上传镜像&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mvn clean package docker:build -DpushImage -D maven.test.skip=true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;docker-maven-plugin-无法推送时清除-dockerconfigjson-中的-autos-配置信息后重拾&quot;&gt;docker-maven-plugin 无法推送时，清除 ~/.docker/config.json 中的 autos 配置信息后重拾&lt;/h1&gt;

&lt;p&gt;Failed to push registry&lt;/p&gt;

&lt;h1 id=&quot;mysql-容器化运行&quot;&gt;MySQL 容器化运行&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &amp;gt; docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

 &amp;gt; docker run --rm --name mysql -v /var/lib/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pwd -p 3306:3306 -d mysql:5.7

 &amp;gt; docker run --rm --name mysql -v /var/lib/mysql:/var/lib/mysql -p 3306:3306 -d mysql:5.6

 &amp;gt; sudo docker run --rm --name mysql -v /Users/stevenkang-mac/mysql:/var/lib/mysql -p 3306:3306 -m 256m --memory-swap=512m -d mysql:5.6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;spring-config-server-容器化运行&quot;&gt;Spring Config Server 容器化运行&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &amp;gt; docker run —rm --name config-server -p 192.168.1.145:8888:8888 -v /etc/spring/config_server-application.yml:/application.yml -d springcloud/configserver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;redis-容器化运行&quot;&gt;Redis 容器化运行&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &amp;gt; docker run --name redis -d redis:4-alpine

 &amp;gt; docker run --name redis -p 6379:6379 -d --rm redis --requirepass &quot;password&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;nginx-容器化运行&quot;&gt;Nginx 容器化运行&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &amp;gt; docker run --name my-nginx -v /etc/nginx.conf:/etc/nginx/nginx.conf:ro -v /etc/nginx:/v-nginx -p 80:80 -p 443:443 --rm -d nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;编译-kms-服务dockerfile&quot;&gt;编译 kms 服务：Dockerfile&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
FROM alpine:latest



RUN echo 'https://mirrors.aliyun.com/alpine/latest-stable/main/' &amp;gt; /etc/apk/repositories \

    &amp;amp;&amp;amp; echo 'https://mirrors.aliyun.com/alpine/latest-stable/community/' &amp;gt;&amp;gt; /etc/apk/repositories \

    &amp;amp;&amp;amp; apk update \

    &amp;amp;&amp;amp; apk upgrade \

    &amp;amp;&amp;amp; apk add --no-cache build-base gcc abuild binutils cmake git \

    &amp;amp;&amp;amp; cd / \

    &amp;amp;&amp;amp; git clone https://github.com/Wind4/vlmcsd.git vlmgit \

    &amp;amp;&amp;amp; cd vlmgit \

    &amp;amp;&amp;amp; make \

    &amp;amp;&amp;amp; chmod +x bin/vlmcsd \

    &amp;amp;&amp;amp; mv bin/vlmcsd / \

    &amp;amp;&amp;amp; cd / \

    &amp;amp;&amp;amp; apk del build-base gcc abuild binutils cmake git \

    &amp;amp;&amp;amp; rm -rf /vlmgit  \

    &amp;amp;&amp;amp; rm -rf /var/cache/apk/*



EXPOSE 1688



CMD [&quot;/vlmcsd&quot;, &quot;-D&quot;, &quot;-d&quot;, &quot;-t&quot;, &quot;3&quot;, &quot;-e&quot;, &quot;-v&quot;]

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;阿里云日志服务&quot;&gt;阿里云日志服务&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&amp;gt; docker pull registry.cn-hangzhou.aliyuncs.com/log-service/logtail

&amp;gt; docker run -d -v /:/logtail_host:ro -v /var/run/docker.sock:/var/run/docker.sock --env ALIYUN_LOGTAIL_CONFIG=/etc/ilogtail/conf/cn-hangzhou/ilogtail_config.json --env ALIYUN_LOGTAIL_USER_ID=1553473*******38 --env ALIYUN_LOGTAIL_USER_DEFINED_ID=userdefined registry.cn-hangzhou.aliyuncs.com/log-service/logtail 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;参考文献&quot;&gt;参考文献&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://docs.docker.com/get-started/&quot;&gt;Docker 官方使用指南&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://github.com/nginxinc/docker-nginx/issues/92#issuecomment-224974379&quot;&gt;Github: docker-nginx issues #92&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://hub.docker.com/_/nginx&quot;&gt;Docker 官方镜像之 Nginx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://hub.docker.com/_/mysql&quot;&gt;Docker 官方镜像之 MySQL&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://github.com/spotify/docker-maven-plugin&quot;&gt;A Maven plugin for building and pushing Docker images.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content><author><name></name></author><category term="Linux" /><summary type="html">容器化服务笔记</summary></entry></feed>