-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
405 lines (248 loc) · 118 KB
/
atom.xml
File metadata and controls
405 lines (248 loc) · 118 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Weineel Sprinting</title>
<subtitle>weineel 的个人博客</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://sprint.weineel.top/"/>
<updated>2019-02-01T03:13:57.863Z</updated>
<id>http://sprint.weineel.top/</id>
<author>
<name>weineel lee</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>hexo 使用next主题配置第三方插件</title>
<link href="http://sprint.weineel.top/2017/12/11/hexo-next-theme-third-part-plugin/"/>
<id>http://sprint.weineel.top/2017/12/11/hexo-next-theme-third-part-plugin/</id>
<published>2017-12-11T10:46:37.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<h1 id="实现功能"><a href="#实现功能" class="headerlink" title="实现功能"></a>实现功能</h1><ol><li>搜索, <a href="https://github.com/flashlab/hexo-generator-search" target="_blank" rel="noopener">Local search</a></li><li>tags</li><li>评论,<a href="https://imsun.net/posts/gitment-introduction/" target="_blank" rel="noopener">gitment</a></li><li>RSS,<code>npm install hexo-generator-feed --save</code> 就可以了。</li><li>阅读次数统计, LeanCloud</li></ol><a id="more"></a><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="http://www.jianshu.com/p/5973c05d7100" target="_blank" rel="noopener">2个小时教你hexo博客添加评论、打赏、RSS等功能</a></li><li><a href="https://imsun.net/posts/gitment-introduction/" target="_blank" rel="noopener">Gitment:使用 GitHub Issues 搭建评论系统</a></li></ul>]]></content>
<summary type="html">
<h1 id="实现功能"><a href="#实现功能" class="headerlink" title="实现功能"></a>实现功能</h1><ol>
<li>搜索, <a href="https://github.com/flashlab/hexo-generator-search" target="_blank" rel="noopener">Local search</a></li>
<li>tags</li>
<li>评论,<a href="https://imsun.net/posts/gitment-introduction/" target="_blank" rel="noopener">gitment</a></li>
<li>RSS,<code>npm install hexo-generator-feed --save</code> 就可以了。</li>
<li>阅读次数统计, LeanCloud</li>
</ol>
</summary>
<category term="tutorial" scheme="http://sprint.weineel.top/categories/tutorial/"/>
<category term="github" scheme="http://sprint.weineel.top/tags/github/"/>
<category term="hexo" scheme="http://sprint.weineel.top/tags/hexo/"/>
</entry>
<entry>
<title>Github Pages 四种形式,以及每种方式使用travis进行持续集成的方案。</title>
<link href="http://sprint.weineel.top/2017/12/11/github-pages-zero2hero/"/>
<id>http://sprint.weineel.top/2017/12/11/github-pages-zero2hero/</id>
<published>2017-12-11T08:21:07.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<ol><li>个人主页,使用<code>username.github.io</code>作为项目名的仓库。</li><li>在某个项目中开启使用ng-graph分支做项目文档的设置。</li><li>master分支<code>/docs</code>作为文档目录。</li><li>项目master分支README.md编译成单页的github pages,<code>https://username.github.io/project-name</code>。</li></ol><a id="more"></a><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://help.github.com/articles/user-organization-and-project-pages/" target="_blank" rel="noopener">User, Organization, and Project Pages</a></li><li><a href="https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/" target="_blank" rel="noopener">Configuring a publishing source for GitHub Pages</a></li><li><a href="http://notes.iissnan.com/2016/publishing-github-pages-with-travis-ci/" target="_blank" rel="noopener">使用 Travis CI 自动更新 GitHub Pages</a></li></ul>]]></content>
<summary type="html">
<ol>
<li>个人主页,使用<code>username.github.io</code>作为项目名的仓库。</li>
<li>在某个项目中开启使用ng-graph分支做项目文档的设置。</li>
<li>master分支<code>/docs</code>作为文档目录。</li>
<li>项目master分支README.md编译成单页的github pages,<code>https://username.github.io/project-name</code>。</li>
</ol>
</summary>
<category term="tutorial" scheme="http://sprint.weineel.top/categories/tutorial/"/>
<category term="github" scheme="http://sprint.weineel.top/tags/github/"/>
<category term="hexo" scheme="http://sprint.weineel.top/tags/hexo/"/>
</entry>
<entry>
<title>log4j配置示例, 资料汇总</title>
<link href="http://sprint.weineel.top/2017/11/09/java-log4j-config/"/>
<id>http://sprint.weineel.top/2017/11/09/java-log4j-config/</id>
<published>2017-11-09T07:28:05.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><p>日志是一个很庞大的话题,有机会要仔细研究下。</p><a id="more"></a><h2 id="配置示例log4j1-2-17"><a href="#配置示例log4j1-2-17" class="headerlink" title="配置示例log4j1.2.17"></a>配置示例log4j1.2.17</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"># log4j.properties</span><br><span class="line"># debug, D, C, E:第一个是日志输出级别,后面都是输出目的地</span><br><span class="line">log4j.rootLogger = debug, D, C, E</span><br><span class="line"></span><br><span class="line">### console ###</span><br><span class="line">log4j.appender.C = org.apache.log4j.ConsoleAppender</span><br><span class="line">log4j.appender.C.Target = System.out</span><br><span class="line">log4j.appender.C.layout = org.apache.log4j.PatternLayout</span><br><span class="line">log4j.appender.C.layout.ConversionPattern = [financeTown-web][%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C.%M(%L) | %m%n</span><br><span class="line">log4j.appender.C.file.encoding=UTF-8</span><br><span class="line"></span><br><span class="line">### log file ###</span><br><span class="line">log4j.appender.D = org.apache.log4j.DailyRollingFileAppender</span><br><span class="line">log4j.appender.D.Append = true</span><br><span class="line"># 对使用这个appender的日志二次过滤。</span><br><span class="line">log4j.appender.D.Threshold = DEBUG</span><br><span class="line">log4j.appender.D.layout = org.apache.log4j.PatternLayout</span><br><span class="line">log4j.appender.D.layout.ConversionPattern = [financeTown-web][%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C.%M(%L) | %m%n</span><br><span class="line">log4j.appender.D.file.encoding=UTF-8</span><br><span class="line">log4j.appender.D.File = ../logs/financeTown-web</span><br><span class="line"># 按日期每天一个日志,当天是日志文件名为没有日期的文件名,会在后一天另存为追加为有以下日期格式的文件。</span><br><span class="line">log4j.appender.D.DatePattern='-'yyyy-MM-dd.'log'</span><br><span class="line"># 每分钟生成一个log文件</span><br><span class="line"># log4j.appender.D.DatePattern='-'yyyy-MM-dd-HH-mm.'log'</span><br><span class="line"></span><br><span class="line">### exception ###</span><br><span class="line">log4j.appender.E = org.apache.log4j.DailyRollingFileAppender</span><br><span class="line">log4j.appender.E.Append = true</span><br><span class="line">log4j.appender.E.Threshold = ERROR</span><br><span class="line">log4j.appender.E.layout = org.apache.log4j.PatternLayout</span><br><span class="line">log4j.appender.E.layout.ConversionPattern = [financeTown-web][%p] [%-d{yyyy-MM-dd HH:mm:ss}] %C.%M(%L) | %m%n</span><br><span class="line">log4j.appender.E.file.encoding=UTF-8</span><br><span class="line">log4j.appender.E.File = ../logs/financeTown-web_error</span><br><span class="line">log4j.appender.E.DatePattern='-'yyyy-MM-dd.'log'</span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>项目原因,研究了下log4j,之前只是用已有的配置,没有自己配置过。以下是我参考的一些文章。</p><ul><li><a href="https://www.cnblogs.com/chenhongliang/p/5312517.html" target="_blank" rel="noopener">java常用日志库</a>,概括了java日志发展的历史,值得一看,但是主要讲了Slf4j,算是篇软文。</li><li><a href="http://logging.apache.org/log4j/1.2/" target="_blank" rel="noopener">apache 官方</a></li><li><a href="http://www.cnblogs.com/zerotomax/p/7400085.html" target="_blank" rel="noopener">Log4j1.2配置详解</a></li><li><a href="http://lzhw1985.iteye.com/blog/1940880" target="_blank" rel="noopener">配置日志文件相对路径</a></li><li><a href="http://blog.csdn.net/aitangyong/article/details/50392227" target="_blank" rel="noopener">log4j框架logger的继承关系以及使用场景</a></li></ul>]]></content>
<summary type="html">
<hr>
<p>日志是一个很庞大的话题,有机会要仔细研究下。</p>
</summary>
<category term="java" scheme="http://sprint.weineel.top/categories/java/"/>
<category term="java" scheme="http://sprint.weineel.top/tags/java/"/>
<category term="log4j" scheme="http://sprint.weineel.top/tags/log4j/"/>
</entry>
<entry>
<title>关于git reset 的总结</title>
<link href="http://sprint.weineel.top/2017/10/27/git-reset/"/>
<id>http://sprint.weineel.top/2017/10/27/git-reset/</id>
<published>2017-10-27T09:00:19.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><p>git reset/revert 就是程序员的后悔药。主要总结了reset,懂了reset自然就懂了revert(更安全的reset,后悔药的后悔药),但是git reset 会有更干净的commit路径。<br><a id="more"></a></p><h4 id="常用格式"><a href="#常用格式" class="headerlink" title="常用格式"></a>常用格式</h4><ol><li><p><code>git reset [option] [commit]</code> //重制指定提交,可以具体指定到文件,否则就是所有文件。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 重置前一次提交的filename.java,会丢弃所有修改没有任何保留。</span><br><span class="line">git reset --hard head^ filename.java</span><br></pre></td></tr></table></figure></li><li><p><code>git reset head [file list]</code> // 重制为当前提交,一般用于重制暂存区到工作区。</p></li><li><code>git reset head^</code> // 重制到当前提交的前次提交</li><li><code>git reset head~n</code> // 重制到当前提交的前n此提交,即在这次提交之后提交都删除, head^ 相当于head~1</li><li><code>git reset [commit-hash/tag name]</code> // 可以指定提交的hash值或者tag名</li></ol><h4 id="选项详解"><a href="#选项详解" class="headerlink" title="选项详解"></a>选项详解</h4><p>options: 如果会把重置的内容放到哪个位置,哪个位置就不能有和重置内容相同的文件。</p><ol><li><code>--mixed</code> // 重置提交和暂存区,即所有被重置的提交(和暂存区)的修改都放到工作区, 默认选项。在可能情况下不会影响工作区原有内容。</li><li><p><code>--soft</code> // 重置提交, 即被重置的提交的修改放到暂存区。在可能情况下不会影响暂存区和工作区原有内容。</p></li><li><p><code>--hard</code> // 重置提交, 暂存区,工作区。将丢失所有被重置的修改。</p></li><li><code>--merge</code> // 保留工作区,直接丢弃暂存区的修改,丢弃所有重置的提交 。。</li><li><code>--keep</code> // 保留工作区,把暂存区的内容放到工作区(两个区中不能有相同的文件),丢弃所有重置的提交。</li></ol>]]></content>
<summary type="html">
<hr>
<p>git reset/revert 就是程序员的后悔药。主要总结了reset,懂了reset自然就懂了revert(更安全的reset,后悔药的后悔药),但是git reset 会有更干净的commit路径。<br>
</summary>
<category term="git" scheme="http://sprint.weineel.top/categories/git/"/>
<category term="git" scheme="http://sprint.weineel.top/tags/git/"/>
</entry>
<entry>
<title>chrome 和 微信开发者工具 跨域</title>
<link href="http://sprint.weineel.top/2017/10/17/cross-domain/"/>
<id>http://sprint.weineel.top/2017/10/17/cross-domain/</id>
<published>2017-10-17T05:12:21.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<p>mac 和 windos平台下,chrome和微信开发者工具的跨域,跨域主要是为了在开发阶段调用接口。</p><a id="more"></a><p><img src="http://upload-images.jianshu.io/upload_images/1855546-b2ba87fc80bbd9d5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p><h2 id="Mac-平台"><a href="#Mac-平台" class="headerlink" title="Mac 平台"></a>Mac 平台</h2><p>要先完全退出chrome或微信开发者工具后执行。有可能需要尝试多次才能起作用。一般会提示 <code>你使用的是不受支持的命令标记 --disable-web-security</code></p><h4 id="chrome"><a href="#chrome" class="headerlink" title="chrome"></a>chrome</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open -a /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir</span><br></pre></td></tr></table></figure><h4 id="微信开发者工具"><a href="#微信开发者工具" class="headerlink" title="微信开发者工具"></a>微信开发者工具</h4><p>不同版本的微信开发者工具在/Applications下的名字可能不同,根据实际情况修改命令行。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open -a /Applications/wechatwebdevtools.app --args --disable-web-security --user-data-dir</span><br></pre></td></tr></table></figure><p><img src="http://upload-images.jianshu.io/upload_images/1855546-3fd0efc77a2fb503.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="微信开发者工具跨域"></p><h2 id="Windows"><a href="#Windows" class="headerlink" title="Windows"></a>Windows</h2><h4 id="chrome-1"><a href="#chrome-1" class="headerlink" title="chrome"></a>chrome</h4><ol><li>新建一个目录,例如: <code>C:\path\to\ChromeUserData</code>,可以根据自己的习惯创建。</li><li>新建一个能打开chrome的快捷方式,右击快捷方式,选择<code>属性</code>,弹出属性窗口。</li><li>在<code>快捷方式</code>选项卡下的<code>目标</code>输入框中追加上<code>--disable-web-security --user-data-dir=C:\path\to\ChromeUserData</code></li></ol><p><img src="http://upload-images.jianshu.io/upload_images/1855546-33e75ae59dcd07a0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></p><ol><li>点击应用和确定按钮关闭属性窗口,双击这个快捷方式,并打开chrome,查看是否有<code>你使用的是不受支持的命令标记 --disable-web-security</code>的提示。</li></ol><h4 id="微信开发者工具-1"><a href="#微信开发者工具-1" class="headerlink" title="微信开发者工具"></a>微信开发者工具</h4><p>对比chrom的操作执行。</p><h2 id="警告"><a href="#警告" class="headerlink" title="警告"></a>警告</h2><p>所有操作要在完全退出chrome或微信开发者工具后操作。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="http://www.cnblogs.com/lhyforfront/p/6867683.html" target="_blank" rel="noopener">微信开发者工具 跨域问题</a></li><li><a href="http://www.cnblogs.com/laden666666/p/5544572.html" target="_blank" rel="noopener">chrome浏览器的跨域设置——包括版本49前后两种设置</a></li></ul>]]></content>
<summary type="html">
<p>mac 和 windos平台下,chrome和微信开发者工具的跨域,跨域主要是为了在开发阶段调用接口。</p>
</summary>
<category term="tutorial" scheme="http://sprint.weineel.top/categories/tutorial/"/>
<category term="跨域" scheme="http://sprint.weineel.top/tags/%E8%B7%A8%E5%9F%9F/"/>
</entry>
<entry>
<title>在idea上使用docker作为java的开发环境</title>
<link href="http://sprint.weineel.top/2017/09/28/docker-java-dev/"/>
<id>http://sprint.weineel.top/2017/09/28/docker-java-dev/</id>
<published>2017-09-28T07:19:25.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><h2 id="准备,开发环境使用的MacOS-windows-和-Linux理论上差异不大。"><a href="#准备,开发环境使用的MacOS-windows-和-Linux理论上差异不大。" class="headerlink" title="准备,开发环境使用的MacOS, windows 和 Linux理论上差异不大。"></a>准备,开发环境使用的MacOS, windows 和 Linux理论上差异不大。</h2><a id="more"></a><ol><li><code>idea 2017.2</code>, <code>docker integration 3.0.1</code></li><li>安装idea插件 <code>Docker integration 3.0.1</code></li><li>安装docker for Mac 和 docker-compose (一般使用pip或brew安装)</li><li><p>在idea中指定docker-compose的目录。</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># 安装完成docker-compose查看可执行文件目录</span><br><span class="line">which docker-compose</span><br><span class="line"># /usr/local/bin/docker-compose</span><br></pre></td></tr></table></figure><p> 在idea中打开 IntelliJ IDEA > Preferences > Build, Execution, Deployment > Docker > Tools. 在<code>Docker Compose executable</code> 中配置<code>/usr/local/bin/docker-compose</code></p><p> <img src="http://upload-images.jianshu.io/upload_images/1855546-4246351b217b4316.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="配置docker-compose"></p></li><li><p>安装方法自行百度或Google,文章结尾有部分参考。</p></li></ol><h2 id="配置连接本地docker-daemon"><a href="#配置连接本地docker-daemon" class="headerlink" title="配置连接本地docker daemon"></a>配置连接本地docker daemon</h2><ol><li>配置<br><img src="http://upload-images.jianshu.io/upload_images/1855546-05a07ffe7fcb855c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="连接本地docker daemon"></li><li>连接<br><img src="http://upload-images.jianshu.io/upload_images/1855546-dd91c39faefdd812.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="链接到 docker daemo"></li></ol><h2 id="配置连接远程docker-daemon"><a href="#配置连接远程docker-daemon" class="headerlink" title="配置连接远程docker daemon"></a>配置连接远程docker daemon</h2><ol><li><p>在服务器上配置可以远程连接的docker daemon</p><ul><li><p>远程登录到<a href="http://www.jianshu.com/p/f2194618fd3c" target="_blank" rel="noopener">安装docker的服务器</a>,编辑文件 <code>/etc/docker/daemon.json</code>, 在json最外层加上 <code>"hosts":["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"],</code>, 类似下面的结构。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># 0.0.0.0表示任意IP的主机都可以访问,安全起见 0.0.0.0 改成允许访问的IP。</span><br><span class="line">{</span><br><span class="line"> "hosts":["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"],</span><br><span class="line"> "registry-mirrors": ["https://ftichs.mirror.aliyuncs.com"]</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>防火墙开启 2375 端口</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">firewall-cmd --zone=public --add-port=2375/tcp --permanen</span><br><span class="line">firewall-cmd --reload</span><br></pre></td></tr></table></figure></li><li><p>重启docker,<code>systemctl restart docker</code></p></li><li>在本地机器(外网ip必须是daemon.json配置的IP)测试,<code>docker -H server_ip:2375 images</code></li></ul></li><li>配置 idea,和配置本地基本一样。<br> <img src="http://upload-images.jianshu.io/upload_images/1855546-ac1eddbc54a379e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="配置远程docker daemon"></li><li>连接和连接本地docker一样。</li></ol><h2 id="编写一个配置文件,部署应用"><a href="#编写一个配置文件,部署应用" class="headerlink" title="编写一个配置文件,部署应用"></a>编写一个配置文件,部署应用</h2><ol><li><p>要先有一个docker-compose.yml/Dockerfile/docker镜像。任意一个都行,看你想用什么方式部署了。下面用<a href="https://docs.docker.com/compose/compose-file/" target="_blank" rel="noopener">docker-compose</a>做实例。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">version: '3.1'</span><br><span class="line"></span><br><span class="line">services:</span><br><span class="line"> tomcat:</span><br><span class="line"> image: tomcat:7.0.81-jre8</span><br><span class="line"> ports:</span><br><span class="line"> - "8088:8080"</span><br></pre></td></tr></table></figure></li><li><p>配置,使用docker-compose就可以忽略Container选项卡了。<br><img src="http://upload-images.jianshu.io/upload_images/1855546-15b47785006e923a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="配置运行配置项"></p></li><li><p>运行(部署)<br><img src="http://upload-images.jianshu.io/upload_images/1855546-737ed26bfd5af175.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="运行(部署)"></p></li></ol><p>部署成功后访问 <code>http://localhost:8088</code>查看效果。可以通过编写Dockerfile(在docker-compose.yml中引用Dockerfile编译镜像)把java应用部署到docker 容器。</p><h2 id="idea配置远程调试-调试部署到docker中的应用"><a href="#idea配置远程调试-调试部署到docker中的应用" class="headerlink" title="idea配置远程调试, 调试部署到docker中的应用"></a>idea配置远程调试, 调试部署到docker中的应用</h2><p>下面是不使用docker时的远程调试</p><ul><li><a href="http://blog.csdn.net/mingjie1212/article/details/52281847" target="_blank" rel="noopener">Intellij IDEA 配置Tomcat远程调试</a></li><li><a href="https://www.jetbrains.com/help/idea/debugging-a-java-app-in-a-container.html" target="_blank" rel="noopener">Debugging a Java app in a container</a></li></ul><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.jetbrains.com/help/idea/docker.html?search=docker" target="_blank" rel="noopener">idea 官方文档</a></li><li><a href="https://yq.aliyun.com/articles/138741" target="_blank" rel="noopener">ubuntu+docker+docker-compose+intellij idea 部署java web项目</a></li><li><a href="http://www.cnblogs.com/xiaohunshi/p/5892067.html" target="_blank" rel="noopener">IDEA使用docker进行调试</a></li><li><a href="http://blog.csdn.net/u010397369/article/details/41349587" target="_blank" rel="noopener">从零开始使用Docker构建Java Web开发运行环境</a></li><li><a href="http://www.jianshu.com/p/f2194618fd3c" target="_blank" rel="noopener">centos docker环境搭建</a></li><li><a href="https://yq.aliyun.com/articles/86626?spm=5176.8091938.0.0.btZh0s" target="_blank" rel="noopener">docker 配置外网访问</a></li><li><a href="https://www.jetbrains.com/help/idea/debugging-a-java-app-in-a-container.html" target="_blank" rel="noopener">Debugging a Java app in a container</a></li></ul>]]></content>
<summary type="html">
<hr>
<h2 id="准备,开发环境使用的MacOS-windows-和-Linux理论上差异不大。"><a href="#准备,开发环境使用的MacOS-windows-和-Linux理论上差异不大。" class="headerlink" title="准备,开发环境使用的MacOS, windows 和 Linux理论上差异不大。"></a>准备,开发环境使用的MacOS, windows 和 Linux理论上差异不大。</h2>
</summary>
<category term="docker" scheme="http://sprint.weineel.top/categories/docker/"/>
<category term="java" scheme="http://sprint.weineel.top/tags/java/"/>
<category term="docker" scheme="http://sprint.weineel.top/tags/docker/"/>
<category term="idea" scheme="http://sprint.weineel.top/tags/idea/"/>
</entry>
<entry>
<title>python 爬虫在 docker 中的应用实战</title>
<link href="http://sprint.weineel.top/2017/09/07/docker-python-spider/"/>
<id>http://sprint.weineel.top/2017/09/07/docker-python-spider/</id>
<published>2017-09-07T10:41:56.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><p>使用 docker 统一开发、测试、发布环境。<a href="https://github.com/weineel/docker-scrapy-example" target="_blank" rel="noopener">示例项目地址</a>。</p><a id="more"></a><h3 id="docker-的在线和离线安装"><a href="#docker-的在线和离线安装" class="headerlink" title="docker 的在线和离线安装"></a>docker 的在线和离线安装</h3><ol><li><p>在线安装</p><ul><li><a href="http://www.jianshu.com/p/f2194618fd3c" target="_blank" rel="noopener">centos docker环境搭建</a></li></ul></li><li><p>离线安装</p><p> 官网下载对应平台的安装包。</p></li><li><p>核心概念</p><ul><li>镜像,类似于虚拟机/操作系统镜像,可以理解为面向Docker引擎的只读模版。是创建docker容器的基础,可以看作面向对象中的类。</li><li>容器,通过镜像创建的一个实例,类似于一个轻量级的沙箱,或者说是一个已经启动的操作系统。Docker使用容器来运行和隔离应用。可以看作面向对象中的对象。</li><li>仓库,可以看作代码库(如果是java,可以看作是maven或者gradle的仓库)。是Docker集中存放镜像文件的地方。</li></ul></li><li><p>基本使用(对比git),mac和windows都有相应的图形界面。</p><ul><li>镜像拉取: <code>docker pull imagename:tag</code></li><li>从镜像运行容器(镜像不存在时会自动pull,任务结束后容器就会自动停止): <code>docker run --rm -v /var/code:/root/code -p 8080:80 --name=example imagename:tag</code></li><li><code>--rm</code> 和 <code>-d</code> 不能同时使用</li><li>交互式运行容器中的指定程序(容器要处于运行状态): <code>docker exec -it example bash</code></li><li>启动和停止容器: <code>docker start/stop example</code> </li><li>从容器中复制文件或目录: <code>docker copy</code></li></ul></li><li><p>数据卷(Data Volumes)管理</p><p> 数据卷的使用,类似Linux下对目录或文件进行mount操作。</p><ul><li><p>创建默认数据卷</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 只能是rw模式,会分配一个默认的VolumesName(hash值),容器被删除时会自动删除数据卷</span><br><span class="line">docker run -v /test_py --name=test_python --rm -it python:2.7.12 bash</span><br></pre></td></tr></table></figure><ol><li>容器中的 /test_py 目录会被持久化在 /var/lib/docker/volumes/VolumesName (可以使用docker volume inspect 命令查看)中。</li><li>Mac下无法直接查看 /var/lib/docker 到,需要在这个模式下 <code>screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty 查看</code>,具体可以查看<a href="https://stackoverflow.com/questions/38532483/where-is-var-lib-docker-on-mac-os-x" target="_blank" rel="noopener">这里</a>。</li></ol></li><li><p>给数据卷挂载宿主主机的目录或文件</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># 容器被删除时不会删除数据卷</span><br><span class="line">docker run -v ~/project/pythonProject/test_py:/code:rw --name=test_python --rm -it python:2.7.12 bash</span><br><span class="line">docker run -v ~/project/pythonProject/test_py/helloworld.py:/code/helloworld.py:ro --name=test_python --rm -it python:2.7.12 bash</span><br></pre></td></tr></table></figure></li></ul></li></ol><ul><li><p>命名数据卷的使用,使用这个数据卷的容器被删除时不会删除数据卷</p><p> <img src="http://upload-images.jianshu.io/upload_images/1855546-4e7cb5b3e4171017.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="数据卷命令"></p></li></ul><ol><li><p>网络管理</p><p> 默认情况下,在容器外部是无法通过网络来访问容器内的网络应用和服务的。通过 <code>-p</code> 参数来指定端口映射。</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -p ip:hostport:containerport imagename</span><br></pre></td></tr></table></figure><p> 实例</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># ip一般省略为127.0.0.1, 访问宿主主机的8080端口相当于访问容器的80端口</span><br><span class="line">docker run -p 8080:80 imagename</span><br></pre></td></tr></table></figure></li></ol><h3 id="实战–搭建基于docker的scrapy开发和发布环境。"><a href="#实战–搭建基于docker的scrapy开发和发布环境。" class="headerlink" title="实战–搭建基于docker的scrapy开发和发布环境。"></a>实战–搭建基于docker的scrapy开发和发布环境。</h3><ul><li><p><a href="https://github.com/weineel/docker-scrapy-example" target="_blank" rel="noopener">示例项目地址</a></p></li><li><p>使用<a href="https://jiajially.gitbooks.io/dockerguide/content/chapter_fastlearn/dockerfile_details.html" target="_blank" rel="noopener">Dockerfile</a>构建一个python scrapy爬虫的镜像,可以直接通过<code>docker build -t scrapyd-dev:1.0.0 .</code>命令构建镜像,最终会使用docker-compose来实现。</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"># Dockerfile</span><br><span class="line"># Author: weineel</span><br><span class="line">FROM python:2.7.13</span><br><span class="line"></span><br><span class="line">MAINTAINER weineel LiJF_wn@163.com</span><br><span class="line"></span><br><span class="line">WORKDIR /var/code</span><br><span class="line"></span><br><span class="line"># COPY/ADD(可以是一个压缩包,会自动解压)</span><br><span class="line">COPY ./etc/pip.conf /root/.pip/pip.conf</span><br><span class="line">COPY ./etc/scrapyd.conf /etc/scrapyd/scrapyd.conf</span><br><span class="line"></span><br><span class="line">RUN pip install --no-cache-dir scrapy scrapyd</span><br><span class="line"></span><br><span class="line"># 定义编译指令</span><br><span class="line"># 在编译时通过 docker build --build-arg _TZ=Asia/Shanghai,_TC=weiguo -t test_python:1.0.0 . 方式指定,</span><br><span class="line"># 可以用在run等指令中,做分支判断</span><br><span class="line">ARG _TZ=Asia/Shanghai</span><br><span class="line">ARG _TC</span><br><span class="line"># 在启动容器是 -e 指定环境变量,会覆盖编译时赋的值。</span><br><span class="line">ENV TZ $_TZ</span><br><span class="line">ENV TC $_TC</span><br><span class="line"></span><br><span class="line">VOLUME /var/code</span><br><span class="line"></span><br><span class="line">EXPOSE 6800</span><br><span class="line"></span><br><span class="line"># ENTRYPOINT ["/bin/bash"]</span><br><span class="line"># ENTRYPOINT 和 CMD的区别</span><br><span class="line"># 相当于开机启动项,container在启动时执行</span><br><span class="line">CMD ["scrapyd", "--pidfile="]</span><br></pre></td></tr></table></figure></li></ul><ul><li><p>使用docker-compose管理docker</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"># docker-compose.yml</span><br><span class="line">version: '3.1'</span><br><span class="line"></span><br><span class="line">services:</span><br><span class="line"></span><br><span class="line"> scrapyd:</span><br><span class="line"> build:</span><br><span class="line"> context: ./scrapyd</span><br><span class="line"> dockerfile: ${ScrapydDockerfileName}</span><br><span class="line"> ports:</span><br><span class="line"> - "6800:6800"</span><br><span class="line"> volumes:</span><br><span class="line"> - ./scrapyd_data:/var/lib/scrapyd</span><br><span class="line"> - ../:/var/code</span><br><span class="line"> # depends_on:</span><br><span class="line"> # - splash</span><br><span class="line"> # links:</span><br><span class="line"> # - splash</span><br><span class="line"> restart: always</span><br><span class="line"></span><br><span class="line"> splash:</span><br><span class="line"> image: scrapinghub/splash</span><br><span class="line"> ports:</span><br><span class="line"> - "8050:8050"</span><br></pre></td></tr></table></figure></li></ul><ul><li><p>构建步骤, 以下命令在项目根目录中的docker目录下执行</p><ol><li><p>初始项目目录结构</p><p> <img src="http://upload-images.jianshu.io/upload_images/1855546-17c9d1b6e358d6bc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="屏幕快照 2017-09-07 下午5.45.52.png"></p></li><li><p><code>docker-compose up scrapyd</code> 启动容器。</p></li><li><code>docker-compose exec scrapyd bash</code> 进入容器(相当于远程登录的服务器),容器中安装了scrapy包,可以执行scrapy的命令行工具等,因为把项目根目录挂在到了容器的<code>/var/code</code> 所以在容器中的<code>/var/code</code>目录下的内容和项目根目录一致的。</li><li><code>scrapy startproject myproject</code> <a href="https://docs.scrapy.org/en/latest/topics/commands.html#creating-projects" target="_blank" rel="noopener">创建爬虫项目</a>,此命令是在容器中执行的,注意观察命令行提示符。</li><li><code>scrapy genspider gjfgw http://www.ndrc.gov.cn</code> <a href="https://docs.scrapy.org/en/latest/topics/commands.html#genspider" target="_blank" rel="noopener">创建爬虫</a></li><li>接下来就是快乐的写爬虫了<a href="https://docs.scrapy.org/en/latest/index.html" target="_blank" rel="noopener">scrapy</a>。</li></ol></li></ul><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ul><li><a href="https://www.amazon.cn/Docker%E6%8A%80%E6%9C%AF%E5%85%A5%E9%97%A8%E4%B8%8E%E5%AE%9E%E6%88%98-%E6%9D%A8%E4%BF%9D%E5%8D%8E-%E6%88%B4%E7%8E%8B%E5%89%91-%E6%9B%B9%E4%BA%9A%E4%BB%91/dp/B00SMJ0VFA/ref=sr_1_2?ie=UTF8&qid=1504778990&sr=8-2&keywords=docker%E6%8A%80%E6%9C%AF%E5%85%A5%E9%97%A8%E4%B8%8E%E5%AE%9E%E6%88%98" target="_blank" rel="noopener">docker技术入门与实战</a></li></ul>]]></content>
<summary type="html">
<hr>
<p>使用 docker 统一开发、测试、发布环境。<a href="https://github.com/weineel/docker-scrapy-example" target="_blank" rel="noopener">示例项目地址</a>。</p>
</summary>
<category term="python" scheme="http://sprint.weineel.top/categories/python/"/>
<category term="docker" scheme="http://sprint.weineel.top/tags/docker/"/>
<category term="python" scheme="http://sprint.weineel.top/tags/python/"/>
<category term="spider" scheme="http://sprint.weineel.top/tags/spider/"/>
</entry>
<entry>
<title>python 中文编码问题总结 -- str 和 unicode</title>
<link href="http://sprint.weineel.top/2017/08/16/python-coding/"/>
<id>http://sprint.weineel.top/2017/08/16/python-coding/</id>
<published>2017-08-16T11:06:56.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<h3 id="术语"><a href="#术语" class="headerlink" title="术语"></a>术语</h3><ul><li><strong>unicode</strong> 是通用码(原始码)一个字符对应一个整数, 但不是程序数据。具体的怎么编码和存储由不同版本的UTF定义。</li><li><strong>UTF(Unicode Transformation Format)</strong>:是针对unicode变长编码设计的一种前缀吗,根据前缀可判断是几个字节表示一个字符。定义了unicode 定义的数字怎么转换成程序数据(实际使用和存储的数据)。常用的用utf-8,utf-16</li><li><strong>codec</strong>: 编码解码器,根据不同的字符集执行编码解码。</li></ul><a id="more"></a><h3 id="python2"><a href="#python2" class="headerlink" title="python2"></a>python2</h3><ol><li>关于文件开头的 <code># -*- coding: utf-8 -*-</code>。 这个是指定当前python代码文件的编码方式,python2默认是ascii。这个决定了python解释器用什么编码解释代码文件。</li><li>字符串的两种形式,str(字节序列)和unicode(<em>用某种编码格式解码字节序列形成的字符串</em>),str更底层所以unicode到str的转换是encode(编码)。</li><li>str 是通过wchar_t(宽字符,根据不容系统或编译方式长度不同)类型存储的,可以看作是字节流。console打印一个字符串,需要看console当前使用的编码格式。</li><li><code>encode</code>: unicode对象调用,根据指定编码类型生成str类型(字节序列/宽字节序列),str类型调用的话会先使用系统默认编码decode成unicode对象,然后再根据指定的编码encode,注意默认的一次decode. <code>u.encode("utf-8")</code></li><li><code>decode</code>: str对象调用,根据制定的编码格式解码成unicode对象。</li><li>关于<code>'ascii' codec can't decode byte 0xe5 in position 23: ordinal not in range(128)</code> 经典错误。报这个错一般是因为uncode和str对象混用了,在使用默认的<code>ascii codec</code>转换时导致的错误。</li><li>使用unicode的建议,主要是为了<strong>避免混用</strong>:<ol><li>程序中出现字符串时一定要加一个前缀u。</li><li>不要用str()函数,用Unicode()代替</li><li>不要用过时的string模块。如果传给它非ASCII码,它会把一切搞砸。</li><li>不到必须时不要在你的程序里编解码Unicode字符,只在你要写入文件或者数据库或者网络时,才调用encode()函数和decode()函数。</li><li>使用什么字符编码,就要采用对应的字符集进行解码。</li></ol></li></ol><h3 id="python3"><a href="#python3" class="headerlink" title="python3"></a>python3</h3><ol><li>使用byte表示字节序列</li><li>使用str表示unicode。所以一般不会遇到编码问题。</li></ol><h4 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h4><ul><li><a href="http://baike.baidu.com/link?url=LJNiGd7XUTRs2Qm5OYc8agh9IBBh4WWPoBAjdkSFl6f2vMLVdG7SkQOTkfcgqCt2pbIc36BA06T4L5fiNw_r0a#reference-[1]-40801-wrap" target="_blank" rel="noopener">百度百科</a></li><li><a href="http://www.cnblogs.com/shine-lee/p/4504559.html" target="_blank" rel="noopener">python中的应用</a></li><li><a href="http://blog.csdn.net/trochiluses/article/details/16825269" target="_blank" rel="noopener">python decode encode</a></li><li><a href="http://www.cnblogs.com/pengei/p/6407077.html" target="_blank" rel="noopener">中文报错/乱码</a></li><li><a href="http://www.jianshu.com/p/ae31c83ce9f5?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=qq" target="_blank" rel="noopener">python2 和 python3的主要区别</a></li></ul>]]></content>
<summary type="html">
<h3 id="术语"><a href="#术语" class="headerlink" title="术语"></a>术语</h3><ul>
<li><strong>unicode</strong> 是通用码(原始码)一个字符对应一个整数, 但不是程序数据。具体的怎么编码和存储由不同版本的UTF定义。</li>
<li><strong>UTF(Unicode Transformation Format)</strong>:是针对unicode变长编码设计的一种前缀吗,根据前缀可判断是几个字节表示一个字符。定义了unicode 定义的数字怎么转换成程序数据(实际使用和存储的数据)。常用的用utf-8,utf-16</li>
<li><strong>codec</strong>: 编码解码器,根据不同的字符集执行编码解码。</li>
</ul>
</summary>
<category term="python" scheme="http://sprint.weineel.top/categories/python/"/>
<category term="python" scheme="http://sprint.weineel.top/tags/python/"/>
<category term="unicode" scheme="http://sprint.weineel.top/tags/unicode/"/>
</entry>
<entry>
<title>centos docker环境搭建</title>
<link href="http://sprint.weineel.top/2017/08/15/centos-install-docker/"/>
<id>http://sprint.weineel.top/2017/08/15/centos-install-docker/</id>
<published>2017-08-15T02:06:58.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>基于centos搭建docker部署或开发环境。使用docker-compose实现单机的容器集群。</p><a id="more"></a><h2 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h2><hr><h4 id="更换yum源"><a href="#更换yum源" class="headerlink" title="更换yum源"></a>更换yum源</h4><p><strong>参考</strong>: </p><ol><li><a href="http://mirrors.aliyun.com/help/centos" target="_blank" rel="noopener">Ali-OSM-CentOS</a></li><li><a href="http://mirrors.aliyun.com/help/centos" target="_blank" rel="noopener">centos7 修改yum源为阿里源</a><h4 id="安装pip,python的包管理工具"><a href="#安装pip,python的包管理工具" class="headerlink" title="安装pip,python的包管理工具"></a>安装pip,python的包管理工具</h4></li><li><p>更新yum缓存,安装python-pip包</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">yum update -y</span><br><span class="line"># 如果没找到包,执行yum -y install epel-release 然后再次执行一次。</span><br><span class="line">yum install python-pip</span><br></pre></td></tr></table></figure></li><li><p>更换pip镜像源到阿里,新建<code>~/.pip/pip.conf</code>:</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">mkdir ~/.pip</span><br><span class="line">tee ~/.pip/pip.conf <<-'EOF'</span><br><span class="line">[global]</span><br><span class="line">index-url = http://mirrors.aliyun.com/pypi/simple/</span><br><span class="line">[install]</span><br><span class="line">trusted-host=mirrors.aliyun.com</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure></li><li><p>升级pip: <code>pip install --upgrade pip</code></p><h3 id="安装docker-compose"><a href="#安装docker-compose" class="headerlink" title="安装docker-compose"></a>安装docker-compose</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install docker-compose</span><br></pre></td></tr></table></figure></li></ol><h3 id="安装并启动docker"><a href="#安装并启动docker" class="headerlink" title="安装并启动docker"></a>安装并启动docker</h3><ol><li>使用阿里云提供的docker安装方式<br> i. 登录阿里<a href="https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fcr.console.aliyun.com%2F%3Fspm%3D5176.1971733.0.2.h888jf&lang=zh" target="_blank" rel="noopener">docker平台-管理中心</a><br> ii. 点击Docker Hub 镜像站点根据系统版本和提示进行安装和修改registry镜像源。<br> <img src="http://upload-images.jianshu.io/upload_images/1855546-ea238070a3207731.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="阿里docker平台管理中心"></li><li>直接去官网下载安装包,或者yum安装,为了下载docker镜像快一点,registry的镜像源还是要换一下的。</li><li><p>使用阿里云的安装步骤<br> i. 安装:<code>curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -</code><br> ii. 使用Docker加速器(修改registry 镜像源)</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">sudo mkdir -p /etc/docker</span><br><span class="line">sudo tee /etc/docker/daemon.json <<-'EOF'</span><br><span class="line">{</span><br><span class="line"> "registry-mirrors": ["获取的专属加速地址"]</span><br><span class="line">}</span><br><span class="line">EOF</span><br><span class="line">sudo systemctl daemon-reload</span><br></pre></td></tr></table></figure><p> iii. 启动docker:<br> <code>sudo systemctl restart docker</code><br> iv. 测试:<br> 命令:<code>docker -v</code> 输出:<code>Docker version 17.05.0-ce, build 89658be</code></p></li><li><p>设置docker开机启动: <code>systemctl enable docker</code></p></li><li><p>容器自动重启: </p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --restart=always imagename</span><br></pre></td></tr></table></figure></li></ol><h4 id="以上所有操作都是用的root用户。。。"><a href="#以上所有操作都是用的root用户。。。" class="headerlink" title="以上所有操作都是用的root用户。。。"></a>以上所有操作都是用的root用户。。。</h4><h5 id="待续-mac下-docker化开发"><a href="#待续-mac下-docker化开发" class="headerlink" title="待续: mac下 docker化开发"></a>待续: <em>mac下 docker化开发</em></h5><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><hr><ul><li><a href="http://blog.csdn.net/yulei_qq/article/details/52984334" target="_blank" rel="noopener">CentOS7下安装python-pip</a></li><li><a href="http://blog.csdn.net/jameshadoop/article/details/54881295" target="_blank" rel="noopener">centos7 修改yum源为阿里源</a></li><li><a href="http://mirrors.aliyun.com/help/centos" target="_blank" rel="noopener">Ali-OSM-CentOS</a></li><li><a href="http://www.mamicode.com/info-detail-1304628.html" target="_blank" rel="noopener">centos7安装docker并设置开机启动</a></li></ul>]]></content>
<summary type="html">
<hr>
<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>基于centos搭建docker部署或开发环境。使用docker-compose实现单机的容器集群。</p>
</summary>
<category term="docker" scheme="http://sprint.weineel.top/categories/docker/"/>
<category term="centos" scheme="http://sprint.weineel.top/tags/centos/"/>
<category term="docker" scheme="http://sprint.weineel.top/tags/docker/"/>
</entry>
<entry>
<title>docker 容器中使用 crontab</title>
<link href="http://sprint.weineel.top/2017/08/01/docker-crontab/"/>
<id>http://sprint.weineel.top/2017/08/01/docker-crontab/</id>
<published>2017-08-01T02:37:05.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<h1 id="docker-中使用crontab"><a href="#docker-中使用crontab" class="headerlink" title="docker 中使用crontab"></a>docker 中使用crontab</h1><a id="more"></a><h3 id="相关命令"><a href="#相关命令" class="headerlink" title="相关命令"></a>相关命令</h3><ul><li>使用 python:2.7.13 镜像,是基于buildpack-deps:jessie镜像的,是一个Debian系统。</li><li><p>docker中使用cron执行python脚本时:</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sys.path = ['/var/code/XHTSpider/XHTSpider/es', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']</span><br></pre></td></tr></table></figure><p>在直接使用python命令执行脚本时</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sys.path = ['/var/code/XHTSpider/XHTSpider/es', '/usr/local/lib/python27.zip', '/usr/local/lib/python2.7', '/usr/local/lib/python2.7/plat-linux2', '/usr/local/lib/python2.7/lib-tk', '/usr/local/lib/python2.7/lib-old', '/usr/local/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/site-packages']</span><br></pre></td></tr></table></figure><p>注意 dite-packages 和 site-packages。然而在使用pip安装包时,是安装在site-packages下的,所以在要在要执行的脚本开始部分加上</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">import sys</span><br><span class="line">sys.path.append("/usr/local/lib/python2.7/site-packages")</span><br></pre></td></tr></table></figure><p> 这可能和docker容器的用户管理有关,执行cron的用户环境变量的不同。</p></li><li><p>debian 中 crontab 程序叫 cron,服务名也是cron,不同系统的使用方式会有所不同。</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">service cron start/stop/restart/reload/status</span><br><span class="line"># 直接启动</span><br><span class="line">cron</span><br></pre></td></tr></table></figure></li></ul><h3 id="Dockerfile"><a href="#Dockerfile" class="headerlink" title="Dockerfile"></a>Dockerfile</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">FROM python:2.7.13</span><br><span class="line"></span><br><span class="line">WORKDIR /root</span><br><span class="line"></span><br><span class="line">COPY ./etc/apt.sources.list /etc/apt/sources.list</span><br><span class="line"></span><br><span class="line">RUN apt-get update -y && \</span><br><span class="line"> apt-get install -y cron && \</span><br><span class="line"> touch /var/log/cron.log</span><br><span class="line"></span><br><span class="line">ADD ./etc/crontab /etc/cron.d/crontab</span><br><span class="line"></span><br><span class="line"># tail 可以防止容器自动退出运行</span><br><span class="line">CMD cron && tail -f /var/log/cron.log</span><br></pre></td></tr></table></figure><h3 id="相关文件"><a href="#相关文件" class="headerlink" title="相关文件"></a>相关文件</h3><ol><li><p><code>./etc/apt.sources.list</code></p><p> apt-get 使用阿里云源</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">deb http://mirrors.aliyun.com/debian wheezy main contrib non-free</span><br><span class="line">deb-src http://mirrors.aliyun.com/debian wheezy main contrib non-free</span><br><span class="line">deb http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free</span><br><span class="line">deb-src http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free</span><br><span class="line">deb http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free</span><br><span class="line">deb-src http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free</span><br></pre></td></tr></table></figure></li></ol><ol><li><p><code>./etc/crontab</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">*/1 * * * * root echo $(date) >> /var/log/cron.log 2>&1</span><br></pre></td></tr></table></figure></li></ol><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ol><li><a href="http://blog.csdn.net/lizhihua0925/article/details/52370479" target="_blank" rel="noopener">docker下计划任务crontab的使用方法</a></li><li><a href="http://www.cnblogs.com/peida/archive/2013/01/08/2850483.html" target="_blank" rel="noopener">crontab 使用</a></li><li><a href="https://stackoverflow.com/questions/34095397/running-cron-within-a-docker-debianjessie-container" target="_blank" rel="noopener">Running cron within a docker debian:jessie container</a></li><li><a href="http://www.jb51.net/LINUXjishu/19905.html" target="_blank" rel="noopener">Linux crontab定时执行任务 命令格式与详细例子</a></li><li><a href="http://www.cnblogs.com/gabin/p/6519352.html" target="_blank" rel="noopener">apt-get安装源替换 阿里云源</a></li><li><a href="http://www.cnblogs.com/kevin922/p/3161411.html" target="_blank" rel="noopener"><a href="http://www.cnblogs.com/kevin922/p/3161411.html" target="_blank" rel="noopener">Python 安装路径, dist-packages 和 site-packages 区别</a></a></li></ol>]]></content>
<summary type="html">
<h1 id="docker-中使用crontab"><a href="#docker-中使用crontab" class="headerlink" title="docker 中使用crontab"></a>docker 中使用crontab</h1>
</summary>
<category term="docker" scheme="http://sprint.weineel.top/categories/docker/"/>
<category term="docker" scheme="http://sprint.weineel.top/tags/docker/"/>
<category term="crontab" scheme="http://sprint.weineel.top/tags/crontab/"/>
</entry>
<entry>
<title>javascript 变量提升</title>
<link href="http://sprint.weineel.top/2017/07/04/js-scope-v/"/>
<id>http://sprint.weineel.top/2017/07/04/js-scope-v/</id>
<published>2017-07-04T07:36:33.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><a id="more"></a><h4 id="源代码"><a href="#源代码" class="headerlink" title="源代码"></a>源代码</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(x); <span class="comment">// undefined</span></span><br><span class="line"><span class="comment">// console.log(y); // 这个会报为定义的错误</span></span><br><span class="line">f(); <span class="comment">// f 是个函数,函数定义也提升,函数定义就是定义实现,所以f是可以调用的(f不是通过赋值获得的引用)。</span></span><br><span class="line"><span class="comment">// f1(); // 会报 undefined 不是一个函数的错误,因为f1是一个函数类型的变量(不管什么类型他也是个变量),定义提升了,所以f1的值是undefined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> x = <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"ffff"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f1 = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"f111"</span>);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="效果等同"><a href="#效果等同" class="headerlink" title="效果等同"></a>效果等同</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">var x;</span><br><span class="line">function f(){</span><br><span class="line"> console.log("ffff");</span><br><span class="line">}</span><br><span class="line">var f1;</span><br><span class="line"></span><br><span class="line">console.log(x); // undefined</span><br><span class="line">// console.log(y);</span><br><span class="line">f(); </span><br><span class="line">// f1();</span><br><span class="line"></span><br><span class="line">x = 3;</span><br><span class="line"></span><br><span class="line">f1 = function() {</span><br><span class="line"> console.log("f111"); </span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ol><li>变量定义提升,只提升定义,不会初始化值</li><li>函数定义时,直接进行函数定义函数可以调用,变量赋值的方式定义函数会报错。</li></ol>]]></content>
<summary type="html">
<hr>
</summary>
<category term="javascript" scheme="http://sprint.weineel.top/categories/javascript/"/>
<category term="javascript" scheme="http://sprint.weineel.top/tags/javascript/"/>
<category term="scope" scheme="http://sprint.weineel.top/tags/scope/"/>
</entry>
<entry>
<title>jQuery 中 ajax 使用 FormData 上传多个Base64或文件(File)</title>
<link href="http://sprint.weineel.top/2017/06/16/ajax-formdata/"/>
<id>http://sprint.weineel.top/2017/06/16/ajax-formdata/</id>
<published>2017-06-16T06:49:22.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><h2 id="1-base64-字符串-作为数据源(在前端生成的文件而非选择的文件)。"><a href="#1-base64-字符串-作为数据源(在前端生成的文件而非选择的文件)。" class="headerlink" title="1. base64(字符串)作为数据源(在前端生成的文件而非选择的文件)。"></a>1. base64(字符串)作为数据源(在前端生成的文件而非选择的文件)。</h2><h3 id="前端调用上传接口示例"><a href="#前端调用上传接口示例" class="headerlink" title="前端调用上传接口示例"></a>前端调用上传接口示例</h3><a id="more"></a><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 图片分组上传,images,subjectTypeImages 为图片转的base64数组,titles是字符串数组。</span></span><br><span class="line"><span class="keyword">var</span> formData = <span class="keyword">new</span> FormData();</span><br><span class="line">images.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">image</span>) </span>{</span><br><span class="line"> formData.append(<span class="string">"picture[]"</span>, image);</span><br><span class="line">});</span><br><span class="line">subjectTypeImages.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">image</span>) </span>{</span><br><span class="line"> formData.append(<span class="string">"subjectTypeImages[]"</span>, image);</span><br><span class="line">});</span><br><span class="line">subjectStatusImages.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">image</span>) </span>{</span><br><span class="line"> formData.append(<span class="string">"subjectStatusImages[]"</span>, image);</span><br><span class="line">});</span><br><span class="line">titles.forEach(<span class="function"><span class="keyword">function</span> (<span class="params">image</span>) </span>{</span><br><span class="line"> formData.append(<span class="string">"titles[]"</span>, image);</span><br><span class="line">});</span><br><span class="line"><span class="comment">// 而外的参数数据</span></span><br><span class="line">formData.append(<span class="string">"titleKey"</span>, titleKey);</span><br><span class="line">formData.append(<span class="string">"searchType"</span>, searchType);</span><br><span class="line"></span><br><span class="line">$.ajax({</span><br><span class="line"> url:<span class="string">'upload.do'</span>,</span><br><span class="line"> method:<span class="string">'POST'</span>,</span><br><span class="line"> data:formData,</span><br><span class="line"> <span class="comment">// 默认为true,设为false后直到ajax请求结束(调完回掉函数)后才会执行$.ajax(...)后面的代码</span></span><br><span class="line"> <span class="keyword">async</span>: <span class="literal">false</span>, </span><br><span class="line"> <span class="comment">// 下面三个,因为直接使用FormData作为数据,contentType会自动设置,也不需要jquery做进一步的数据处理(序列化)。</span></span><br><span class="line"> cache: <span class="literal">false</span>,</span><br><span class="line"> contentType: <span class="literal">false</span>,</span><br><span class="line"> processData: <span class="literal">false</span>,</span><br><span class="line"> success:<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(data);</span><br><span class="line"> },</span><br><span class="line"> error:<span class="function"><span class="keyword">function</span>(<span class="params">error</span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(error.message);</span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="java-springMVC-后端接收示例"><a href="#java-springMVC-后端接收示例" class="headerlink" title="java(springMVC) 后端接收示例"></a>java(springMVC) 后端接收示例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(value = <span class="string">"upload.do"</span>, method = RequestMethod.POST)</span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">upload</span><span class="params">(HttpServletRequest request)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> CommonsMultipartResolver multipartResolver = <span class="keyword">new</span> CommonsMultipartResolver(request.getSession().getServletContext());</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 先判断request中是否包涵multipart类型的数据,</span></span><br><span class="line"> <span class="keyword">if</span> (multipartResolver.isMultipart(request)) {</span><br><span class="line"> MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;</span><br><span class="line"> String[] picture = multiRequest.getParameterValues(<span class="string">"picture[]"</span>);</span><br><span class="line"> String[] subjectTypeImages = multiRequest.getParameterValues(<span class="string">"subjectTypeImages[]"</span>);</span><br><span class="line"> String[] subjectStatusImages = multiRequest.getParameterValues(<span class="string">"subjectStatusImages[]"</span>);</span><br><span class="line"> String[] titles = multiRequest.getParameterValues(<span class="string">"titles[]"</span>);</span><br><span class="line"> String searchType = multiRequest.getParameter(<span class="string">"searchType"</span>);</span><br><span class="line"> String titleKey = multiRequest.getParameter(<span class="string">"titleKey"</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// todo: any-thing</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"success"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="2-form-表单中使用input-选择文件上传,-File类型"><a href="#2-form-表单中使用input-选择文件上传,-File类型" class="headerlink" title="2. form 表单中使用input 选择文件上传, File类型"></a>2. form 表单中使用input 选择文件上传, File类型</h2><h3 id="form-表单"><a href="#form-表单" class="headerlink" title="form 表单"></a>form 表单</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">form</span> <span class="attr">id</span>=<span class="string">"form111"</span> <span class="attr">enctype</span>=<span class="string">"multipart/form-data"</span> <span class="attr">method</span>=<span class="string">"post"</span> <span class="attr">action</span>=<span class="string">"#"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"file"</span> <span class="attr">name</span>=<span class="string">"files"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"file"</span> <span class="attr">name</span>=<span class="string">"files"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"file"</span> <span class="attr">name</span>=<span class="string">"files"</span>></span></span><br><span class="line"> <span class="comment"><!-- 这个可以选择多个文件,而且只可以选图片 --></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"file"</span> <span class="attr">name</span>=<span class="string">"files"</span> <span class="attr">accept</span>=<span class="string">"image/*"</span> <span class="attr">multiple</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">name</span>=<span class="string">"username"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">id</span>=<span class="string">"btn"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">form</span>></span></span><br></pre></td></tr></table></figure><h3 id="javascript-上传接口调用示例"><a href="#javascript-上传接口调用示例" class="headerlink" title="javascript 上传接口调用示例"></a>javascript 上传接口调用示例</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">$(<span class="string">"#btn"</span>).click(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">// 获取所有文件</span></span><br><span class="line"> <span class="comment">// 1. 使用直接使用form表单获取,会获取所有input值</span></span><br><span class="line"> <span class="keyword">var</span> fomdata = <span class="keyword">new</span> FormData(<span class="built_in">document</span>.getElementById(<span class="string">"form111"</span>));</span><br><span class="line"> <span class="comment">// 2. 只获取文件</span></span><br><span class="line"> <span class="keyword">var</span> fomdata = <span class="keyword">new</span> FormData();</span><br><span class="line"> $(<span class="string">"#form111"</span>).children(<span class="string">"input[name='files']"</span>).each(<span class="function"><span class="keyword">function</span> (<span class="params">index, input</span>) </span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>; i<input.files.length; i++) {</span><br><span class="line"> fomdata.append(<span class="string">"files"</span>, input.files[i]);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> $.ajax({</span><br><span class="line"> method:<span class="string">'POST'</span>,</span><br><span class="line"> data:formData,</span><br><span class="line"> url:<span class="string">'upload.do'</span>,</span><br><span class="line"> <span class="comment">// async: false, // 同步上传,默认(true)异步</span></span><br><span class="line"> cache: <span class="literal">false</span>,</span><br><span class="line"> contentType: <span class="literal">false</span>,</span><br><span class="line"> processData: <span class="literal">false</span>,</span><br><span class="line"> success:<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(data);</span><br><span class="line"> },</span><br><span class="line"> error:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'上传失败'</span>);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="java-springMVC-后端代码示例"><a href="#java-springMVC-后端代码示例" class="headerlink" title="java(springMVC) 后端代码示例"></a>java(springMVC) 后端代码示例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(value = <span class="string">"upload.do"</span>, method = RequestMethod.POST)</span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">upload</span><span class="params">(MultipartFile[] files<span class="comment">/* files 为input的name,这样就可以获取所有文件的数组了。*/</span>, String filename, HttpServletRequest request)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="comment">// 遍历数组保存文件,并把文件相对路径存到数据库。。。等。</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"success"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="推荐一个前端上传组件"><a href="#推荐一个前端上传组件" class="headerlink" title="推荐一个前端上传组件"></a>推荐一个前端上传组件</h2><ul><li><p><a href="http://fex.baidu.com/webuploader/getting-started.html" target="_blank" rel="noopener">webuploader</a></p></li><li><p>java 后端代码示例</p></li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(value = <span class="string">"upload.do"</span>, method = RequestMethod.POST)</span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">uploadFile</span><span class="params">(MultipartFile file, String name1, HttpServletRequest request)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> UploadDto uploadDto = <span class="keyword">new</span> UploadDto(); <span class="comment">// 就是一个格式化返回信息的类。</span></span><br><span class="line"> CommonsMultipartResolver multipartResolver = <span class="keyword">new</span> CommonsMultipartResolver(request.getSession().getServletContext());</span><br><span class="line"> <span class="comment">// 先判断request中是否包涵multipart类型的数据,</span></span><br><span class="line"> <span class="keyword">if</span> (multipartResolver.isMultipart(request)) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// </span></span><br><span class="line"> String fileId = service.saveFile(file);</span><br><span class="line"> uploadDto.setMessage(<span class="string">"上传成功!"</span>);</span><br><span class="line"> uploadDto.setCode(<span class="number">0</span>);</span><br><span class="line"> uploadDto.setFileId(fileId);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> uploadDto.setMessage(<span class="string">"上传失败!"</span>);</span><br><span class="line"> uploadDto.setCode(-<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> uploadDto;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><h4 id="不同的上传方式需要配合不同的接收方式。同一个项目尽量使用同一套规范进行封装。这里使用ajax作为客户端上传,其它平台遵循http协议的情况下可以使用同一个上传接口。"><a href="#不同的上传方式需要配合不同的接收方式。同一个项目尽量使用同一套规范进行封装。这里使用ajax作为客户端上传,其它平台遵循http协议的情况下可以使用同一个上传接口。" class="headerlink" title="不同的上传方式需要配合不同的接收方式。同一个项目尽量使用同一套规范进行封装。这里使用ajax作为客户端上传,其它平台遵循http协议的情况下可以使用同一个上传接口。"></a>不同的上传方式需要配合不同的接收方式。同一个项目尽量使用同一套规范进行封装。这里使用ajax作为客户端上传,其它平台遵循http协议的情况下可以使用同一个上传接口。</h4><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ol><li><a href="http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143449993875172bbfac4b9764e2d9e2b5a17c706b3db000" target="_blank" rel="noopener">廖雪峰javascript教程</a></li><li><a href="https://stackoverflow.com/questions/5392344/sending-multipart-formdata-with-jquery-ajax" target="_blank" rel="noopener">Sending multipart/formdata with jQuery.ajax</a></li></ol>]]></content>
<summary type="html">
<hr>
<h2 id="1-base64-字符串-作为数据源(在前端生成的文件而非选择的文件)。"><a href="#1-base64-字符串-作为数据源(在前端生成的文件而非选择的文件)。" class="headerlink" title="1. base64(字符串)作为数据源(在前端生成的文件而非选择的文件)。"></a>1. base64(字符串)作为数据源(在前端生成的文件而非选择的文件)。</h2><h3 id="前端调用上传接口示例"><a href="#前端调用上传接口示例" class="headerlink" title="前端调用上传接口示例"></a>前端调用上传接口示例</h3>
</summary>
<category term="java" scheme="http://sprint.weineel.top/categories/java/"/>
<category term="java" scheme="http://sprint.weineel.top/tags/java/"/>
<category term="ajax" scheme="http://sprint.weineel.top/tags/ajax/"/>
<category term="formdata" scheme="http://sprint.weineel.top/tags/formdata/"/>
</entry>
<entry>
<title>使用 vimrc 配置 vim</title>
<link href="http://sprint.weineel.top/2017/02/26/vim-vimrc/"/>
<id>http://sprint.weineel.top/2017/02/26/vim-vimrc/</id>
<published>2017-02-26T12:32:07.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><h2 id="配置vim"><a href="#配置vim" class="headerlink" title="配置vim"></a>配置vim</h2><a id="more"></a><ol><li><p><a href="https://github.com/amix/vimrc" target="_blank" rel="noopener">github 地址</a> 包含了详尽的安装的配置方法</p> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">// Awesome 版本</span><br><span class="line">git clone https://github.com/amix/vimrc.git ~/.vim_runtime</span><br><span class="line">sh ~/.vim_runtime/install_awesome_vimrc.sh</span><br></pre></td></tr></table></figure> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">// 基础版本</span><br><span class="line">git clone git://github.com/amix/vimrc.git ~/.vim_runtime</span><br><span class="line">sh ~/.vim_runtime/install_basic_vimrc.sh</span><br></pre></td></tr></table></figure></li><li><p>升级</p> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd ~/.vim_runtime</span><br><span class="line">git pull --rebase</span><br></pre></td></tr></table></figure></li></ol>]]></content>
<summary type="html">
<hr>
<h2 id="配置vim"><a href="#配置vim" class="headerlink" title="配置vim"></a>配置vim</h2>
</summary>
<category term="vim" scheme="http://sprint.weineel.top/categories/vim/"/>
<category term="vim" scheme="http://sprint.weineel.top/tags/vim/"/>
</entry>
<entry>
<title>更方便实用的shell:zsh</title>
<link href="http://sprint.weineel.top/2017/02/14/shell-zsh/"/>
<id>http://sprint.weineel.top/2017/02/14/shell-zsh/</id>
<published>2017-02-14T03:23:22.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><h4 id="mac-和-centos测试。"><a href="#mac-和-centos测试。" class="headerlink" title="mac 和 centos测试。"></a>mac 和 centos测试。</h4><a id="more"></a><p><img src="http://upload-images.jianshu.io/upload_images/1855546-bc8ec8bf0be53316.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="mac 下使用item2效果图,根据主题 smt 做了部分调整"></p><h2 id="1-安装zsh"><a href="#1-安装zsh" class="headerlink" title="1. 安装zsh"></a>1. <a href="http://blog.csdn.net/lina_acm/article/details/51815095" target="_blank" rel="noopener">安装zsh</a></h2><ol><li>查看是否安装zsh:<code>cat /etc/shells</code>, 如果已经安装了的话,就可以跳过2或3了。</li><li><strong>RedHat / centos</strong>: <code>sudo yum install zsh</code></li><li><strong>Debian / Ubuntu</strong>: <code>sudo apt-get install zsh</code></li><li><p><strong>修改默认使用的shell</strong>:</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">chsh # 命令会提示输入要使用的shell程序名, 只能修改当前用户。</span><br><span class="line">chsh -s /bin/zsh # 直接指定shell</span><br></pre></td></tr></table></figure><p> 或者</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/passwd #有管理员权限,修改任意用户的shell</span><br></pre></td></tr></table></figure><p> 或者</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">useradd -s /bin/bash {用户名} # 创建用户时指定使用的shell</span><br></pre></td></tr></table></figure></li></ol><p><strong>参考:</strong> <a href="http://blog.csdn.net/lina_acm/article/details/51815095" target="_blank" rel="noopener">Linux下安装终极Shell Zsh</a> , mac下也一样</p><h2 id="2-配置"><a href="#2-配置" class="headerlink" title="2. 配置"></a>2. <a href="http://blog.csdn.net/yangcs2009/article/details/45720193" target="_blank" rel="noopener">配置</a></h2><h4 id="oh-my-zsh"><a href="#oh-my-zsh" class="headerlink" title="oh-my-zsh"></a><strong>oh-my-zsh</strong></h4><ol><li><a href="https://github.com/robbyrussell/oh-my-zsh" target="_blank" rel="noopener">github</a></li><li><p><strong>安装oh-my-zsh</strong>:<br> 在zsh下执行以下命令。</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 手动安装(不推荐)。。。</span><br><span class="line">git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh</span><br></pre></td></tr></table></figure><p> 或者, 以下两个会自动初始化一些东西</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -L https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | sh</span><br></pre></td></tr></table></figure><p> 或者</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O - | sh</span><br></pre></td></tr></table></figure><p> 安装完成后重新打开shell。</p></li><li><p><strong>更新</strong>:</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd ~/.oh-my-zsh</span><br><span class="line">git pull --rebase</span><br></pre></td></tr></table></figure></li><li><p><strong>配置</strong>:在~/.zshrc 文件中配置主题和插件.</p></li></ol><p><strong>参考:</strong> <a href="http://blog.csdn.net/yangcs2009/article/details/45720193" target="_blank" rel="noopener">Shell(一):功能、配置和插件(附iTerm 2(for mac) && Oh My Zsh教程)</a></p>]]></content>
<summary type="html">
<hr>
<h4 id="mac-和-centos测试。"><a href="#mac-和-centos测试。" class="headerlink" title="mac 和 centos测试。"></a>mac 和 centos测试。</h4>
</summary>
<category term="tutorial" scheme="http://sprint.weineel.top/categories/tutorial/"/>
<category term="zsh" scheme="http://sprint.weineel.top/tags/zsh/"/>
<category term="shell" scheme="http://sprint.weineel.top/tags/shell/"/>
</entry>
<entry>
<title>使用ssl自签证书搭建 Nodejs https 服务器, 并采用 AFNetworking 调用示例接口</title>
<link href="http://sprint.weineel.top/2016/09/28/ssl-nodejs-https/"/>
<id>http://sprint.weineel.top/2016/09/28/ssl-nodejs-https/</id>
<published>2016-09-28T13:07:35.000Z</published>
<updated>2019-02-01T03:13:57.863Z</updated>
<content type="html"><![CDATA[<hr><h2 id="使用-openssl-生成证书"><a href="#使用-openssl-生成证书" class="headerlink" title="使用 openssl 生成证书"></a>使用 openssl 生成证书</h2><p>openssl 说明: 使用 openssl 命令会把生成的证书输出到当前目录.</p><a id="more"></a><ol><li>创建 CA 证书: 此证书是自签证书的根本, 创建了此证书相当于你自己就是第三方证书签发机构 (CA)了.<br>生成步骤: <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1. 生成 CA 秘钥 </span><br><span class="line"> openssl genrsa -out ca-key.pem -des3 2048</span><br><span class="line">2. 通过CA私钥生成CSR(证书请求文件)</span><br><span class="line"> openssl req -new -key ca-key.pem -out ca-csr.pem</span><br><span class="line">3. 通过CSR文件和私钥生成CA证书(我理解为公钥, 包含了CA的信息)</span><br><span class="line"> openssl x509 -req -in ca-csr.pem -signkey ca-key.pem -out ca-cert.pem</span><br></pre></td></tr></table></figure></li></ol><h4 id="如果遇到权限问题"><a href="#如果遇到权限问题" class="headerlink" title="如果遇到权限问题"></a>如果遇到权限问题</h4><p> 你需要root或者admin的权限 Unable to load config info from /user/local/ssl/openssl.cnf 对于这个问题,你可以从网上下载一份正确的openssl.cnf文件, 然后set OPENSSL_CONF=openssl.cnf文件的本地路径</p><ol><li>创建服务器端证书: 此证书主要是在创建服务器时使用的, 在不同的认证方式中使用的证书不同, 下面会给出一些区别例子.<br>在当前目录新建 openssl.cnf 文件<br>模板:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">[req] </span><br><span class="line"> distinguished_name = req_distinguished_name </span><br><span class="line"> req_extensions = v3_req </span><br><span class="line"> </span><br><span class="line"> [req_distinguished_name] </span><br><span class="line"> countryName = Country Name (2 letter code) </span><br><span class="line"> countryName_default = CN </span><br><span class="line"> stateOrProvinceName = State or Province Name (full name) </span><br><span class="line"> stateOrProvinceName_default = BeiJing </span><br><span class="line"> localityName = Locality Name (eg, city) </span><br><span class="line"> localityName_default = YaYunCun </span><br><span class="line"> organizationalUnitName = Organizational Unit Name (eg, section) </span><br><span class="line"> organizationalUnitName_default = Domain Control Validated </span><br><span class="line"> commonName = Internet Widgits Ltd </span><br><span class="line"> commonName_max = 64 </span><br><span class="line"> </span><br><span class="line"> [ v3_req ] </span><br><span class="line"> # Extensions to add to a certificate request </span><br><span class="line"> basicConstraints = CA:FALSE </span><br><span class="line"> keyUsage = nonRepudiation, digitalSignature, keyEncipherment </span><br><span class="line"> subjectAltName = @alt_names </span><br><span class="line"> </span><br><span class="line"> [alt_names] </span><br><span class="line">#注意这个IP.1的设置,IP地址需要和你的服务器的监听地址一样</span><br><span class="line"> IP.1 = 127.0.0.1</span><br></pre></td></tr></table></figure></li></ol><p>生成步骤:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1. 生成服务器秘钥 </span><br><span class="line"> openssl genrsa -out server-key.pem 2048</span><br><span class="line">2. 通过服务器私钥生成CSR(证书请求文件)</span><br><span class="line"> openssl req -new -key server-key.pem -config openssl.cnf -out server-csr.pem</span><br><span class="line">3. 通过CSR文件和私钥以及CA证书生成服务器证书(我理解为公钥, 包含了 CA 证书,服务器信息(域名等..), 和服务器公钥)</span><br><span class="line"> openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in server-csr.pem -out server-cert.pem -extensions v3_req -extfile openssl.cnf</span><br></pre></td></tr></table></figure></p><ol><li>创建客户端证书: 此证书,在某些情况下可以不使用. 比如我们下面的 iOS 端使用 AFNetworking 调用接口的例子.<br>生成步骤:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">生成客户端私钥</span><br><span class="line"> openssl genrsa -out client-key.pem</span><br><span class="line">生成CSR</span><br><span class="line"> openssl req -new -key client-key.pem -out client-csr.pem</span><br><span class="line">生成客户端证书(我理解为公钥)</span><br><span class="line">openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in client-csr.pem -out client-cert.pem</span><br></pre></td></tr></table></figure></li></ol><h3 id="参考"><a href="#参考" class="headerlink" title="参考:"></a>参考:</h3><p><a href="http://my.oschina.net/nearzk/blog/485652" target="_blank" rel="noopener">HTTPS单向认证和双向认证</a></p><hr><h2 id="使用express框架创建-nodejs-服务器"><a href="#使用express框架创建-nodejs-服务器" class="headerlink" title="使用express框架创建 nodejs 服务器"></a>使用express框架创建 nodejs 服务器</h2><ol><li>安装express generator , 我使用的是4.13.4版本, nodejs 的版本为v5.11.1, npm 的版本为3.8.6<br><code>npm install -g express-generator #必要时可能需要 sudo</code></li><li>安装完成后使用 express 命令,生成 express app<br><code>express httpsapp #执行结束后会在当前目录下生成 nodejs 项目 httpsapp</code></li><li><p>安装依赖,测试项目创建是否成功</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">cd httpsapp</span><br><span class="line">npm install</span><br><span class="line">//執行</span><br><span class="line">npm start</span><br></pre></td></tr></table></figure><p>在浏览器中打开<a href="http://localhost:3000/" target="_blank" rel="noopener">http://localhost:3000</a>查看是否启动成功.<br><img src="http://upload-images.jianshu.io/upload_images/1855546-74f8590a2a6970e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="启动成功返回的页面"></p></li><li><p>在项目根目录下创建 ssl 文件夹, 并把刚刚生成的证书放到其中.</p></li><li><p>修改bin/www的代码, 把 http服务器改成 https 服务器<br>以下是修改后的代码: 保证核心代码一样就行.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env node</span><br><span class="line">var app = require('../app');</span><br><span class="line">var debug = require('debug')('httpsApp:server');</span><br><span class="line">// var http = require('http');</span><br><span class="line">var https = require('https');</span><br><span class="line">var fs = require('fs');</span><br><span class="line">var port = normalizePort(process.env.PORT || '3000');</span><br><span class="line">app.set('port', port);</span><br><span class="line">/**</span><br><span class="line"> * 创建 https 服务器</span><br><span class="line">*/</span><br><span class="line">// 获取证书</span><br><span class="line">var options = {</span><br><span class="line"> key: fs.readFileSync('./ssl/server-key.pem'),</span><br><span class="line"> ca: [fs.readFileSync('./ssl/ca-cert.pem')],</span><br><span class="line"> cert: fs.readFileSync('./ssl/server-cert.pem')</span><br><span class="line">};</span><br><span class="line">var server = https.createServer(options, app).listen(app.get('port'),'127.0.0.1');</span><br><span class="line">server.listen(port);</span><br><span class="line">server.on('error', onError);</span><br><span class="line">server.on('listening', onListening);</span><br><span class="line">function normalizePort(val) {</span><br><span class="line"> var port = parseInt(val, 10);</span><br><span class="line"> if (isNaN(port)) {</span><br><span class="line"> // named pipe</span><br><span class="line"> return val;</span><br><span class="line"> }</span><br><span class="line"> if (port >= 0) {</span><br><span class="line"> // port number</span><br><span class="line"> return port;</span><br><span class="line"> }</span><br><span class="line"> return false;</span><br><span class="line">}</span><br><span class="line">function onError(error) {</span><br><span class="line"> if (error.syscall !== 'listen') {</span><br><span class="line"> throw error;</span><br><span class="line"> }</span><br><span class="line"> var bind = typeof port === 'string'</span><br><span class="line"> ? 'Pipe ' + port</span><br><span class="line"> : 'Port ' + port;</span><br><span class="line"> switch (error.code) {</span><br><span class="line"> case 'EACCES':</span><br><span class="line"> console.error(bind + ' requires elevated privileges');</span><br><span class="line"> process.exit(1);</span><br><span class="line"> break;</span><br><span class="line"> case 'EADDRINUSE':</span><br><span class="line"> console.error(bind + ' is already in use');</span><br><span class="line"> process.exit(1);</span><br><span class="line"> break;</span><br><span class="line"> default:</span><br><span class="line"> throw error;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">function onListening() {</span><br><span class="line"> var addr = server.address();</span><br><span class="line"> var bind = typeof addr === 'string'</span><br><span class="line"> ? 'pipe ' + addr</span><br><span class="line"> : 'port ' + addr.port;</span><br><span class="line"> debug('Listening on ' + bind);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>再次打开浏览器查看<a href="http://localhost:3000/" target="_blank" rel="noopener">https://localhost:3000</a>.如下图则服务器创建成功.</p></li></ol><p><img src="http://upload-images.jianshu.io/upload_images/1855546-e6b12047f1e49cf6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="修改为 https 服务器后的页面"></p><ol><li>打开routs/users.js 文件(或者自己根据路由创建自己的测试接口)<br>修改为:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">var express = require('express');</span><br><span class="line">var router = express.Router();</span><br><span class="line">/* GET users listing. */</span><br><span class="line">router.get('/', function(req, res, next) {</span><br><span class="line"> res.send({</span><br><span class="line"> "code" : "1100",</span><br><span class="line"> "message" : "test success"</span><br><span class="line"> });</span><br><span class="line">});</span><br><span class="line">module.exports = router;</span><br></pre></td></tr></table></figure></li></ol><p>这样就完成了一个简单的测试接口.</p><ol><li>编写客户端代码测试接口是否可用.<br>在任意目录创建文件 client.js<br>内容为:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">var https = require('https');</span><br><span class="line">var fs = require('fs');</span><br><span class="line">var options = {</span><br><span class="line">hostname:'127.0.0.1',</span><br><span class="line">port:3000,</span><br><span class="line">path:'/users',</span><br><span class="line">method:'GET',</span><br><span class="line">key:fs.readFileSync('../ssl/client-key.pem'),</span><br><span class="line">cert:fs.readFileSync('../ssl/client-cert.pem'),</span><br><span class="line">ca: [fs.readFileSync('../ssl/ca-cert.pem')],</span><br><span class="line">agent:false</span><br><span class="line">};</span><br><span class="line">options.agent = new https.Agent(options);</span><br><span class="line">var req = https.request(options,function(res){</span><br><span class="line">console.log("statusCode: ", res.statusCode);</span><br><span class="line"> console.log("headers: ", res.headers);</span><br><span class="line">res.setEncoding('utf-8');</span><br><span class="line">res.on('data',function(d){</span><br><span class="line">console.log(d);</span><br><span class="line">})</span><br><span class="line">});</span><br><span class="line">req.end();</span><br><span class="line">req.on('error',function(e){</span><br><span class="line">console.log(e);</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li></ol><p>最后执行命令<br><figure class="highlight plain"><figcaption><span>client.js``` </span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">返回结果为:</span><br><span class="line"></span><br><span class="line">说明接口没有问题.</span><br><span class="line"></span><br><span class="line">## 以上过程, 可以参考 :</span><br><span class="line">[用Node.js创建自签名的HTTPS服务器](https://cnodejs.org/topic/54745ac22804a0997d38b32d)</span><br><span class="line">[Node.js - Express 4.x 使用 HTTPS/SSL](http://jade.logdown.com/posts/233332-nodejs-express-4x-using-https-ssl)</span><br><span class="line"></span><br><span class="line">************************************************</span><br><span class="line">在 iOS 端使用 AFNWorking 调用接口</span><br><span class="line">---------------------------------------------</span><br><span class="line"></span><br><span class="line">1. ** 在 iOS 中使用 https 需要注意 **</span><br><span class="line">首先必须要基于TLS 1.2版本协议。再来就是连接的加密方式要提供Forward Secrecy (这个不太懂)。最后就是证书至少要使用一个SHA256的指纹与任一个2048位或者更高位的RSA密钥,或者是256位或者更高位的ECC密钥。如果不符合其中一项,请求将被中断并返回nil。从我们生成证书的过程中也看到秘钥的长度是2048.</span><br><span class="line"></span><br><span class="line">2. ** 转换证书格式**</span><br><span class="line">此部分参考[使用openssl进行证书格式转换](http://blog.csdn.net/linda1000/article/details/8676330)</span><br><span class="line">其中 cer 和 der 是基本通用的,由于 AFNWorking 推荐使用 cer 类型的证书,所以我们可以使用一下命令把我们生成的 pem 证书转换成 cer.</span><br><span class="line">``` </span><br><span class="line">openssl x509 -outform der -in server-cert.pem -out server-cert.cer</span><br></pre></td></tr></table></figure></p><p>基于AFNWorking 的验证方式我们只需要 server 的证书(公钥)就可以了.</p><ol><li>把生成的 cer 证书拖到项目中.</li><li><p>使用一下代码条用接口查看返回数据</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">//把服务端证书(需要转换成cer格式)放到APP项目资源里,AFSecurityPolicy会自动寻找根目录下所有cer文件</span><br><span class="line">NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server-cert" ofType:@"cer"];</span><br><span class="line">NSData *cerData = [NSData dataWithContentsOfFile:cerPath];</span><br><span class="line">NSSet *cerSet = [[NSSet alloc] initWithObjects:cerData, nil];</span><br><span class="line">AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:cerSet];</span><br><span class="line">securityPolicy.allowInvalidCertificates = YES;</span><br><span class="line"> securityPolicy.validatesDomainName = NO;</span><br><span class="line"> AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];</span><br><span class="line"> manager.requestSerializer = [AFHTTPRequestSerializer serializer];</span><br><span class="line"> manager.responseSerializer = [AFJSONResponseSerializer serializer]; // 这一步需要注意否者返回的数据可能是 NSData 需要自行转换成 json.</span><br><span class="line"> manager.securityPolicy = securityPolicy;</span><br><span class="line"> manager.responseSerializer.acceptableContentTypes=[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/plain", nil];</span><br><span class="line">//关闭缓存避免干扰测试</span><br><span class="line"> manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;[manager GET:@"https://127.0.0.1:3000/users" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {</span><br><span class="line">DDLogDebug(@"%@", responseObject);</span><br><span class="line">} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {</span><br><span class="line">DDLogError(@"%@", error);</span><br><span class="line">}];</span><br></pre></td></tr></table></figure><p>返回结果为</p></li></ol><p><img src="http://upload-images.jianshu.io/upload_images/1855546-21d4033994d565a4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="iOS 控制台返回结果"></p><p>以上内容很多地方引用自<a href="http://www.jianshu.com/p/20d5fb4cd76d" target="_blank" rel="noopener">iOS中AFNetworking HTTPS的使用</a></p>]]></content>
<summary type="html">
<hr>
<h2 id="使用-openssl-生成证书"><a href="#使用-openssl-生成证书" class="headerlink" title="使用 openssl 生成证书"></a>使用 openssl 生成证书</h2><p>openssl 说明: 使用 openssl 命令会把生成的证书输出到当前目录.</p>
</summary>
<category term="https" scheme="http://sprint.weineel.top/categories/https/"/>
<category term="nodejs" scheme="http://sprint.weineel.top/tags/nodejs/"/>
<category term="ios" scheme="http://sprint.weineel.top/tags/ios/"/>
<category term="https" scheme="http://sprint.weineel.top/tags/https/"/>
</entry>
</feed>