-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
720 lines (410 loc) · 136 KB
/
index.html
File metadata and controls
720 lines (410 loc) · 136 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
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>zeroBlog</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta property="og:type" content="website">
<meta property="og:title" content="zeroBlog">
<meta property="og:url" content="http://example.com/index.html">
<meta property="og:site_name" content="zeroBlog">
<meta property="og:locale">
<meta property="article:author" content="zero">
<meta name="twitter:card" content="summary">
<link rel="alternate" href="/atom.xml" title="zeroBlog" type="application/atom+xml">
<link rel="shortcut icon" href="/favicon.png">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-source-code-pro@0.0.71/index.min.css">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/fancybox/jquery.fancybox.min.css">
<meta name="generator" content="Hexo 6.3.0"></head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">zeroBlog</a>
</h1>
<h2 id="subtitle-wrap">
<a href="/" id="subtitle">zero's life and study record</a>
</h2>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
<a id="nav-search-btn" class="nav-icon" title="Search"></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://example.com"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-thirdAPISecret" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/03/03/thirdAPISecret/" class="article-date">
<time class="dt-published" datetime="2024-03-03T02:33:29.000Z" itemprop="datePublished">2024-03-03</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/03/03/thirdAPISecret/">thirdAPISecret</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="与第三方通信API"><a href="#与第三方通信API" class="headerlink" title="与第三方通信API"></a>与第三方通信API</h3><h4 id="方案一,提供两个接口(api-x2F-token-x2F-api-x2F-code-)第三方可以分为前端后后端来调用"><a href="#方案一,提供两个接口(api-x2F-token-x2F-api-x2F-code-)第三方可以分为前端后后端来调用" class="headerlink" title="方案一,提供两个接口(api/token, /api/{code})第三方可以分为前端后后端来调用."></a>方案一,提供两个接口(api/token, /api/{code})第三方可以分为前端后后端来调用.</h4><p>初始化机构数据关键字段:appId、appSecret、RSA公钥、私钥。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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></pre></td><td class="code"><pre><span class="line">// =========/api/token========</span><br><span class="line">定义:获取accessToken</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"> body: {</span><br><span class="line"> appId: { appId },</span><br><span class="line"> appSecretRSAEncryptData: { rsa 公钥加密appSecret后的值 }</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"> token: { 一串数字 }</span><br><span class="line"> }</span><br><span class="line">返回过程判断:拿到参数后,取appId,对比数据库是否存在,存在则用对应的rsa解密appSecretRSAEncryptData字段的值,然后对比数据库appid对应存储的appSecret值是否一致。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">// =========/api/{code}========</span><br><span class="line">定义:业务接口</span><br><span class="line"></span><br><span class="line">接口设计如下:</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line"> headers: {</span><br><span class="line"> timestamp: {时间戳},</span><br><span class="line"> salt: {随机16位字符A用RSA公钥加密后},</span><br><span class="line"> sign: {token + timestamp + 明文body(B)} - MD5 加密</span><br><span class="line"> token: {从/api/token返回的token内容}</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> body: {</span><br><span class="line"> 将原业务内容(B)用随机16位字符A 用AES加密</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">返回:</span><br><span class="line"> {</span><br><span class="line"> 接口业务字段对应内容</span><br><span class="line"> }</span><br><span class="line">返回过程判断:</span><br><span class="line">(1): 校验timestamp时间是否超范围</span><br><span class="line">(2): 校验token是否有效</span><br><span class="line">(3): 根据salt用RSA私钥解出随机16位字符A</span><br><span class="line">(4): 根据A 用AES 解密body得到原业务内容(B)</span><br><span class="line">(5): 根据token + timestamp + B 使用MD5 加密后与 sign对比是否一致。确保内容没有被篡改</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h4 id="方案二,提供一个接口(-x2F-api-x2F-code-)第三方后端调用接口获取数据"><a href="#方案二,提供一个接口(-x2F-api-x2F-code-)第三方后端调用接口获取数据" class="headerlink" title="方案二,提供一个接口(/api/{code})第三方后端调用接口获取数据"></a>方案二,提供一个接口(/api/{code})第三方后端调用接口获取数据</h4><p>初始化机构数据关键字段:appId、appSecret</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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></pre></td><td class="code"><pre><span class="line">// =========/api/{code}========</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">header: {</span><br><span class="line"> salt: 用随机16位字符A 用appSecret 采用AES 加密后</span><br><span class="line"> sign: [appId + timestamp + body] --> MD5 加密</span><br><span class="line"> timestamp: 时间戳</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">body: {</span><br><span class="line"> appId: { appId },</span><br><span class="line"> data: { 将原业务内容(B)用随机16位字符A 用AES加密 }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">返回:</span><br><span class="line"> {</span><br><span class="line"> 接口业务字段对应内容</span><br><span class="line"> }</span><br><span class="line">返回过程判断:</span><br><span class="line">(1): 校验timestamp 是否符合时间范围</span><br><span class="line">(2): 校验appId是否有效,查出appId对应的appSecret(C)</span><br><span class="line">(3): 根据C解出salt的原随机数A</span><br><span class="line">(4): 用随机数A解开原body的data字段,也就是业务内容B</span><br><span class="line">(5): 根据sign的字段 appId + timestamp + body 通过MD5加密对比sign 可以查看是否有效</span><br></pre></td></tr></table></figure>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/03/03/thirdAPISecret/" data-id="cltdpes1a005254dk3kffh6me" data-title="thirdAPISecret" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/api/" rel="tag">api</a></li></ul>
</footer>
</div>
</article>
<article id="post-mvvm-resource-read" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/02/21/mvvm-resource-read/" class="article-date">
<time class="dt-published" datetime="2024-02-21T10:06:08.000Z" itemprop="datePublished">2024-02-21</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/02/21/mvvm-resource-read/">mvvm-resource-read</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="读react原理记录"><a href="#读react原理记录" class="headerlink" title="读react原理记录"></a>读react原理记录</h3><p>为了深入复习一下react的原理,我特重新反向梳理react的源码,目的是为了剥丝抽茧,一点点弄清楚每一个方法到底是怎么执行的。</p>
<h4 id="先看看我们是怎么使用react的"><a href="#先看看我们是怎么使用react的" class="headerlink" title="先看看我们是怎么使用react的"></a>先看看我们是怎么使用react的</h4><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></pre></td><td class="code"><pre><span class="line">...... 省略其他,这里主要是建一个app盒子,用于后面js生成的dom插入进来。展示成完成的页面</span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line">import React from 'mini-react'</span><br><span class="line">....</span><br><span class="line">React.render(<App />, document.getElementById('root'))</span><br><span class="line"></span><br><span class="line">就从这一句开始分析,我们看是React的render方法接收了两个参数,一个 <App />, 一个是dom</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">1. 根据这个我们可以写出render函数类似下面</span><br><span class="line"></span><br><span class="line">const render = render(element, container) => {</span><br><span class="line"> ...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">2. 我们需要去了解 <App /> 是什么</span><br><span class="line"></span><br><span class="line">那么跟着看我们找到了 App的相关代码类似如下</span><br><span class="line"></span><br><span class="line">class App extends React.Component {</span><br><span class="line"> constructor() {</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"> render() {</span><br><span class="line"> return (</span><br><span class="line"> <div className="app-container"></span><br><span class="line"> ......</span><br><span class="line"> </div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">可以看到App实际返回的是 div 这里面是使用了jsx (语法糖,因为写的时候便捷,不用写为对象的形式, jsx会自动执行类里面的render函数) 的语法,便捷的讲 App 实例化为 <App /> </span><br><span class="line">jsx在实际运行的时候会转化为React.createElement语法也就是上面的实际执行的执行是的以下代码</span><br><span class="line"></span><br><span class="line"><App/> = React.createElement('div', {className: 'app-container'}, ....)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">简单点来说,<App /> 是一个虚拟dom的对象,而document.getElementById('root') 是获取的html的dom元素,虽然也是对象,但是是真实的。</span><br><span class="line"></span><br><span class="line">3. 分析结构</span><br><span class="line">那我们不妨大胆预估,其实render做的就是把<App /> 这个虚拟dom(本质上就是javascript的一个object,不过结构参考了DOM对象的形式,比如会按照类似下面的样子)挂载到了真实DOM(document.getElementById('root')) 里面。</span><br><span class="line"></span><br><span class="line">虚拟dom结构猜测:</span><br><span class="line">{</span><br><span class="line"> type: 'div',</span><br><span class="line"> className: 'app-container',</span><br><span class="line"> ....</span><br><span class="line"> child: [{</span><br><span class="line"> type: 'div',</span><br><span class="line"> ....</span><br><span class="line"> }]</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">类似这样的一个对象结构,里面可以无限嵌套子节点。</span><br><span class="line"></span><br><span class="line">4. React.render(<App />, document.getElementById('root')) 既然是文件的入口,且刚上面分析是将这个虚拟dom挂在到真实dom下,那如果虚拟dom内容改变了呢?</span><br><span class="line"></span><br><span class="line">虚拟更换了,肯定是需要页面重新渲染的。也就是说react里面有一套机制会去刷新,完整版的react里面肯定是使用了算法,在应用的状态变化的情况下才去更新dom,而且更新dom也采取了合并多个相邻更新为一次和最小化dom更新(不会从根节点全部重新渲染)</span><br><span class="line">那么我们的mini-react在这方面就写了个弱化版本的dom刷新机制,同时在dom节点循环阶段绑定了setState函数,为useState作为hooks可以导出页面刷新节点使用。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">5. 那么当页面调用setState的时候本质上也就是对比dom节点变化,刷新页面</span><br></pre></td></tr></table></figure>
<h4 id="总结,整个mini-react的内容本质上就是将页面内容转为虚拟dom,在虚拟dom中间对比变更节点,然后更新到页面上展示。当然完整版的react有更多更优化的方法和边界处理。"><a href="#总结,整个mini-react的内容本质上就是将页面内容转为虚拟dom,在虚拟dom中间对比变更节点,然后更新到页面上展示。当然完整版的react有更多更优化的方法和边界处理。" class="headerlink" title="总结,整个mini-react的内容本质上就是将页面内容转为虚拟dom,在虚拟dom中间对比变更节点,然后更新到页面上展示。当然完整版的react有更多更优化的方法和边界处理。"></a>总结,整个mini-react的内容本质上就是将页面内容转为虚拟dom,在虚拟dom中间对比变更节点,然后更新到页面上展示。当然完整版的react有更多更优化的方法和边界处理。</h4><h4 id="附上源码(Zack大佬的)"><a href="#附上源码(Zack大佬的)" class="headerlink" title="附上源码(Zack大佬的)"></a>附上源码(Zack大佬的)</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br></pre></td><td class="code"><pre><span class="line">let wipRoot = null;</span><br><span class="line">let nextUnitOfWork = null;</span><br><span class="line">let currentRoot = null;</span><br><span class="line">let deletions = [];</span><br><span class="line">let wipFiber;</span><br><span class="line">let hookIndex = 0;</span><br><span class="line">// Support React.Fragment syntax.</span><br><span class="line">const Fragment = Symbol.for("react.fragment");</span><br><span class="line"></span><br><span class="line">// Enhanced requestIdleCallback.</span><br><span class="line">((global) => {</span><br><span class="line"> const id = 1;</span><br><span class="line"> const fps = 1e3 / 60;</span><br><span class="line"> let frameDeadline;</span><br><span class="line"> let pendingCallback;</span><br><span class="line"> const channel = new MessageChannel();</span><br><span class="line"> const timeRemaining = () => frameDeadline - window.performance.now();</span><br><span class="line"></span><br><span class="line"> const deadline = {</span><br><span class="line"> didTimeout: false,</span><br><span class="line"> timeRemaining</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> channel.port2.onmessage = () => {</span><br><span class="line"> if (typeof pendingCallback === "function") {</span><br><span class="line"> pendingCallback(deadline);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> global.requestIdleCallback = (callback) => {</span><br><span class="line"> global.requestAnimationFrame((frameTime) => {</span><br><span class="line"> frameDeadline = frameTime + fps;</span><br><span class="line"> pendingCallback = callback;</span><br><span class="line"> channel.port1.postMessage(null);</span><br><span class="line"> });</span><br><span class="line"> return id;</span><br><span class="line"> };</span><br><span class="line">})(window);</span><br><span class="line"></span><br><span class="line">const isDef = (param) => param !== void 0 && param !== null;</span><br><span class="line"></span><br><span class="line">const isPlainObject = (val) =></span><br><span class="line"> Object.prototype.toString.call(val) === "[object Object]" &&</span><br><span class="line"> [Object.prototype, null].includes(Object.getPrototypeOf(val));</span><br><span class="line"></span><br><span class="line">// Simple judgment of virtual elements.</span><br><span class="line">const isVirtualElement = (e) => typeof e === "object";</span><br><span class="line"></span><br><span class="line">// Text elements require special handling.</span><br><span class="line">const createTextElement = (text) => ({</span><br><span class="line"> type: "TEXT",</span><br><span class="line"> props: {</span><br><span class="line"> nodeValue: text</span><br><span class="line"> }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">// Create custom JavaScript data structures.</span><br><span class="line">const createElement = (type, props = {}, ...child) => {</span><br><span class="line"> const children = child.map((c) =></span><br><span class="line"> isVirtualElement(c) ? c : createTextElement(String(c))</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> return {</span><br><span class="line"> type,</span><br><span class="line"> props: {</span><br><span class="line"> ...props,</span><br><span class="line"> children</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">// Update DOM properties.</span><br><span class="line">// For simplicity, we remove all the previous properties and add next properties.</span><br><span class="line">const updateDOM = (DOM, prevProps, nextProps) => {</span><br><span class="line"> const defaultPropKeys = "children";</span><br><span class="line"></span><br><span class="line"> for (const [removePropKey, removePropValue] of Object.entries(prevProps)) {</span><br><span class="line"> if (removePropKey.startsWith("on")) {</span><br><span class="line"> DOM.removeEventListener(</span><br><span class="line"> removePropKey.slice(2).toLowerCase(),</span><br><span class="line"> removePropValue</span><br><span class="line"> );</span><br><span class="line"> } else if (removePropKey !== defaultPropKeys) {</span><br><span class="line"> DOM[removePropKey] = "";</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> for (const [addPropKey, addPropValue] of Object.entries(nextProps)) {</span><br><span class="line"> if (addPropKey.startsWith("on")) {</span><br><span class="line"> DOM.addEventListener(addPropKey.slice(2).toLowerCase(), addPropValue);</span><br><span class="line"> } else if (addPropKey !== defaultPropKeys) {</span><br><span class="line"> DOM[addPropKey] = addPropValue;</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">// Create DOM based on node type.</span><br><span class="line">const createDOM = (fiberNode) => {</span><br><span class="line"> const { type, props } = fiberNode;</span><br><span class="line"> let DOM = null;</span><br><span class="line"></span><br><span class="line"> if (type === "TEXT") {</span><br><span class="line"> DOM = document.createTextNode("");</span><br><span class="line"> } else if (typeof type === "string") {</span><br><span class="line"> DOM = document.createElement(type);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // Update properties based on props after creation.</span><br><span class="line"> if (DOM !== null) {</span><br><span class="line"> updateDOM(DOM, {}, props);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return DOM;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">// Change the DOM based on fiber node changes.</span><br><span class="line">// Note that we must complete the comparison of all fiber nodes before commitRoot.</span><br><span class="line">// The comparison of fiber nodes can be interrupted, but the commitRoot cannot be interrupted.</span><br><span class="line">const commitRoot = () => {</span><br><span class="line"> const findParentFiber = (fiberNode) => {</span><br><span class="line"> if (fiberNode) {</span><br><span class="line"> let parentFiber = fiberNode.return;</span><br><span class="line"> while (parentFiber && !parentFiber.dom) {</span><br><span class="line"> parentFiber = parentFiber.return;</span><br><span class="line"> }</span><br><span class="line"> return parentFiber;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return null;</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> const commitDeletion = (parentDOM, DOM) => {</span><br><span class="line"> if (isDef(parentDOM)) {</span><br><span class="line"> parentDOM.removeChild(DOM);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> const commitReplacement = (parentDOM, DOM) => {</span><br><span class="line"> if (isDef(parentDOM)) {</span><br><span class="line"> parentDOM.appendChild(DOM);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> const commitWork = (fiberNode) => {</span><br><span class="line"> if (fiberNode) {</span><br><span class="line"> if (fiberNode.dom) {</span><br><span class="line"> const parentFiber = findParentFiber(fiberNode);</span><br><span class="line"> const parentDOM = parentFiber?.dom;</span><br><span class="line"> switch (fiberNode.effectTag) {</span><br><span class="line"> case "REPLACEMENT":</span><br><span class="line"> commitReplacement(parentDOM, fiberNode.dom);</span><br><span class="line"> break;</span><br><span class="line"> case "UPDATE":</span><br><span class="line"> updateDOM(</span><br><span class="line"> fiberNode.dom,</span><br><span class="line"> fiberNode.alternate ? fiberNode.alternate.props : {},</span><br><span class="line"> fiberNode.props</span><br><span class="line"> );</span><br><span class="line"> break;</span><br><span class="line"> default:</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> commitWork(fiberNode.child);</span><br><span class="line"> commitWork(fiberNode.sibling);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> for (const deletion of deletions) {</span><br><span class="line"> if (deletion.dom) {</span><br><span class="line"> const parentFiber = findParentFiber(deletion);</span><br><span class="line"> commitDeletion(parentFiber?.dom, deletion.dom);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (wipRoot !== null) {</span><br><span class="line"> commitWork(wipRoot.child);</span><br><span class="line"> currentRoot = wipRoot;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wipRoot = null;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">// Reconcile the fiber nodes before and after, compare and record the differences.</span><br><span class="line">const reconcileChildren = (fiberNode, elements = []) => {</span><br><span class="line"> let index = 0;</span><br><span class="line"> let oldFiberNode = void 0;</span><br><span class="line"> let prevSibling = void 0;</span><br><span class="line"> const virtualElements = elements.flat(Infinity);</span><br><span class="line"></span><br><span class="line"> if (fiberNode.alternate && fiberNode.alternate.child) {</span><br><span class="line"> oldFiberNode = fiberNode.alternate.child;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> while (</span><br><span class="line"> index < virtualElements.length ||</span><br><span class="line"> typeof oldFiberNode !== "undefined"</span><br><span class="line"> ) {</span><br><span class="line"> const virtualElement = virtualElements[index];</span><br><span class="line"> let newFiber = void 0;</span><br><span class="line"> const isSameType = Boolean(</span><br><span class="line"> oldFiberNode &&</span><br><span class="line"> virtualElement &&</span><br><span class="line"> oldFiberNode.type === virtualElement.type</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> if (isSameType && oldFiberNode) {</span><br><span class="line"> newFiber = {</span><br><span class="line"> type: oldFiberNode.type,</span><br><span class="line"> dom: oldFiberNode.dom,</span><br><span class="line"> alternate: oldFiberNode,</span><br><span class="line"> props: virtualElement.props,</span><br><span class="line"> return: fiberNode,</span><br><span class="line"> effectTag: "UPDATE"</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (!isSameType && Boolean(virtualElement)) {</span><br><span class="line"> newFiber = {</span><br><span class="line"> type: virtualElement.type,</span><br><span class="line"> dom: null,</span><br><span class="line"> alternate: null,</span><br><span class="line"> props: virtualElement.props,</span><br><span class="line"> return: fiberNode,</span><br><span class="line"> effectTag: "REPLACEMENT"</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (!isSameType && oldFiberNode) {</span><br><span class="line"> deletions.push(oldFiberNode);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (oldFiberNode) {</span><br><span class="line"> oldFiberNode = oldFiberNode.sibling;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (index === 0) {</span><br><span class="line"> fiberNode.child = newFiber;</span><br><span class="line"> } else if (typeof prevSibling !== "undefined") {</span><br><span class="line"> prevSibling.sibling = newFiber;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> prevSibling = newFiber;</span><br><span class="line"> index += 1;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">// Execute each unit task and return to the next unit task.</span><br><span class="line">// Different processing according to the type of fiber node.</span><br><span class="line">const performUnitOfWork = (fiberNode) => {</span><br><span class="line"> const { type } = fiberNode;</span><br><span class="line"></span><br><span class="line"> switch (typeof type) {</span><br><span class="line"> case "function": {</span><br><span class="line"> wipFiber = fiberNode;</span><br><span class="line"> wipFiber.hooks = [];</span><br><span class="line"> hookIndex = 0;</span><br><span class="line"> let children;</span><br><span class="line"></span><br><span class="line"> if (typeof Object.getPrototypeOf(type).REACT_COMPONENT !== "undefined") {</span><br><span class="line"> const C = type;</span><br><span class="line"> const component = new C(fiberNode.props);</span><br><span class="line"> // eslint-disable-next-line react-hooks/rules-of-hooks</span><br><span class="line"> const [state, setState] = useState(component.state);</span><br><span class="line"> component.props = fiberNode.props;</span><br><span class="line"> component.state = state;</span><br><span class="line"> component.setState = setState;</span><br><span class="line"> children = component.render?.bind(component)();</span><br><span class="line"> } else {</span><br><span class="line"> children = type(fiberNode.props);</span><br><span class="line"> }</span><br><span class="line"> reconcileChildren(fiberNode, [</span><br><span class="line"> isVirtualElement(children)</span><br><span class="line"> ? children</span><br><span class="line"> : createTextElement(String(children))</span><br><span class="line"> ]);</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> case "number":</span><br><span class="line"> case "string":</span><br><span class="line"> if (!fiberNode.dom) {</span><br><span class="line"> fiberNode.dom = createDOM(fiberNode);</span><br><span class="line"> }</span><br><span class="line"> reconcileChildren(fiberNode, fiberNode.props.children);</span><br><span class="line"> break;</span><br><span class="line"></span><br><span class="line"> case "symbol":</span><br><span class="line"> if (type === Fragment) {</span><br><span class="line"> reconcileChildren(fiberNode, fiberNode.props.children);</span><br><span class="line"> }</span><br><span class="line"> break;</span><br><span class="line"></span><br><span class="line"> default:</span><br><span class="line"> if (typeof fiberNode.props !== "undefined") {</span><br><span class="line"> reconcileChildren(fiberNode, fiberNode.props.children);</span><br><span class="line"> }</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (fiberNode.child) {</span><br><span class="line"> return fiberNode.child;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> let nextFiberNode = fiberNode;</span><br><span class="line"></span><br><span class="line"> while (typeof nextFiberNode !== "undefined") {</span><br><span class="line"> if (nextFiberNode.sibling) {</span><br><span class="line"> return nextFiberNode.sibling;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> nextFiberNode = nextFiberNode.return;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return null;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">// Use requestIdleCallback to query whether there is currently a unit task</span><br><span class="line">// and determine whether the DOM needs to be updated.</span><br><span class="line">const workLoop = (deadline) => {</span><br><span class="line"> while (nextUnitOfWork && deadline.timeRemaining() > 1) {</span><br><span class="line"> nextUnitOfWork = performUnitOfWork(nextUnitOfWork);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (!nextUnitOfWork && wipRoot) {</span><br><span class="line"> commitRoot();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> window.requestIdleCallback(workLoop);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">// Initial or reset.</span><br><span class="line">const render = (element, container) => {</span><br><span class="line"> currentRoot = null;</span><br><span class="line"> wipRoot = {</span><br><span class="line"> type: "div",</span><br><span class="line"> dom: container,</span><br><span class="line"> props: {</span><br><span class="line"> children: [</span><br><span class="line"> {</span><br><span class="line"> ...element</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line"> },</span><br><span class="line"> alternate: currentRoot</span><br><span class="line"> };</span><br><span class="line"> nextUnitOfWork = wipRoot;</span><br><span class="line"> deletions = [];</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">// Associate the hook with the fiber node.</span><br><span class="line">function useState(initState) {</span><br><span class="line"> const hook = wipFiber?.alternate?.hooks</span><br><span class="line"> ? wipFiber.alternate.hooks[hookIndex]</span><br><span class="line"> : {</span><br><span class="line"> state: initState,</span><br><span class="line"> queue: []</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> while (hook.queue.length) {</span><br><span class="line"> let newState = hook.queue.shift();</span><br><span class="line"> if (isPlainObject(hook.state) && isPlainObject(newState)) {</span><br><span class="line"> newState = { ...hook.state, ...newState };</span><br><span class="line"> }</span><br><span class="line"> hook.state = newState;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (typeof wipFiber.hooks === "undefined") {</span><br><span class="line"> wipFiber.hooks = [];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wipFiber.hooks.push(hook);</span><br><span class="line"> hookIndex += 1;</span><br><span class="line"></span><br><span class="line"> const setState = (value) => {</span><br><span class="line"> hook.queue.push(value);</span><br><span class="line"></span><br><span class="line"> if (currentRoot) {</span><br><span class="line"> wipRoot = {</span><br><span class="line"> type: currentRoot.type,</span><br><span class="line"> dom: currentRoot.dom,</span><br><span class="line"> props: currentRoot.props,</span><br><span class="line"> alternate: currentRoot</span><br><span class="line"> };</span><br><span class="line"> nextUnitOfWork = wipRoot;</span><br><span class="line"> deletions = [];</span><br><span class="line"> currentRoot = null;</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> return [hook.state, setState];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">class Component {</span><br><span class="line"> props;</span><br><span class="line"></span><br><span class="line"> constructor(props) {</span><br><span class="line"> this.props = props;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // Identify Component.</span><br><span class="line"> static REACT_COMPONENT = true;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// Start the engine!</span><br><span class="line">void (function main() {</span><br><span class="line"> window.requestIdleCallback(workLoop);</span><br><span class="line">})();</span><br><span class="line"></span><br><span class="line">export default {</span><br><span class="line"> createElement,</span><br><span class="line"> render,</span><br><span class="line"> useState,</span><br><span class="line"> Component,</span><br><span class="line"> Fragment</span><br><span class="line">};</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="读vue原理记录"><a href="#读vue原理记录" class="headerlink" title="读vue原理记录"></a>读vue原理记录</h3><p>…wait…</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/02/21/mvvm-resource-read/" data-id="cltdpes12004754dkbj9sbpn7" data-title="mvvm-resource-read" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/mvvm/" rel="tag">mvvm</a></li></ul>
</footer>
</div>
</article>
<article id="post-jwt" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/02/04/jwt/" class="article-date">
<time class="dt-published" datetime="2024-02-04T03:14:45.000Z" itemprop="datePublished">2024-02-04</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/02/04/jwt/">jwt</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="JWT家族"><a href="#JWT家族" class="headerlink" title="JWT家族"></a>JWT家族</h3><h4 id="JWT-json-web-token"><a href="#JWT-json-web-token" class="headerlink" title="JWT(json web token)"></a>JWT(json web token)</h4><ul>
<li>用途是:在网络上安全传输的开放标准,通常用于身份验证和信息交换</li>
<li>结构是:Header(头部:包含关于生成jwt的原信息,例如使用的加密算法和令牌的类型).Payload(负载:关于实体/用户的数据信息).Signature(签名:使用头部和负载以及秘密密钥生成的签名)</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># jwt 示例</span><br><span class="line">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. </span><br><span class="line">eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9. </span><br><span class="line">TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ </span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h4 id="JWS-json-web-Signature"><a href="#JWS-json-web-Signature" class="headerlink" title="JWS(json web Signature)"></a>JWS(json web Signature)</h4><ul>
<li>其实我们大部分正常用于身份校验的JWT 就是 JWS,也就是头部一定要声明算法,然后经过了秘钥加密头部、负载后生成了Signature的内容。</li>
</ul>
<h4 id="JWE-json-web-encryption"><a href="#JWE-json-web-encryption" class="headerlink" title="JWE(json web encryption)"></a>JWE(json web encryption)</h4><p>JWS 仅仅是对声明(claims)作了签名,保证了其不被篡改,但是其 payload(中段负载) 信息是暴露的。也就是 JWS 仅仅能保证数据的完整性而不能保证数据不被泄露。它不适合传递敏感数据。JWE 的出现就是为了解决这个问题的。具体的可以看下图:</p>
<p>JWE 生成步骤</p>
<ul>
<li>与JWS Header相同标志加密算法和类型</li>
<li>生成一个随机的256位的 content encryption key(CEK)</li>
<li>使用 rsa(pkcs1)算法对token接收者的公钥对CEK进行加密,以生成JWE加密秘钥</li>
<li>生成随机128位JWE初始化向量</li>
<li>将附加身份平局参数加入Header</li>
<li>使用CEK作为加密秘钥,JWT初始化向量 和 上面的附加身份凭据参数,使用AES(cbc_hmac_sha_256)算法对纯文本执行身份证加密,生成密文,同时<br>会随之生成一个128位的Authentication Tag</li>
<li>将生成的五段加密串使用Base64进行编码,然后使用”.”按照顺序连接起来就是组成Token</li>
</ul>
<p><img src="/2024/02/04/jwt/Snipaste_2024-02-04_15-41-12.png" alt="服务器图"></p>
<p>可见,JWE的计算过程相对繁琐,不够轻量级,因此适合与数据传输而非token认证,但该协议也足够安全可靠,用简短字符串描述了传输内容,兼顾数据的安全性与完整性。</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/02/04/jwt/" data-id="cltdpes10004254dk5i291v1c" data-title="jwt" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/jwt/" rel="tag">jwt</a></li></ul>
</footer>
</div>
</article>
<article id="post-auth-code" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/02/02/auth-code/" class="article-date">
<time class="dt-published" datetime="2024-02-02T08:04:20.000Z" itemprop="datePublished">2024-02-02</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/02/02/auth-code/">auth-code</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="一点小思考"><a href="#一点小思考" class="headerlink" title="一点小思考"></a>一点小思考</h3><p><code>在和做微信平台的开发的时候,有一个场景是这样的,微信方给出了一个code,5分钟过期,且用一次过期,调用方需要拿着code,与accessToken一起才能拿回用户相关信息。</code></p>
<p>那我们可以从这个例子里面去分析哈,首先 accessToken 的获取需要我方的 appKey 与 appSecret 一起获取,那么可以保证这个是不被篡改的。<br>那么我们今天就是研究一下这里的 code 是如何生成的,是什么机制然后如何能保证 5 分钟过期,且调用一次过期。做到与 accessToken 一起使用,发送给微信,保障了信息获取流程的安全性。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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"># 从逻辑上思考,code应该是使用某种加密算法生成的一串随机字符串,而且加密之前的内容应该有以下内容</span><br><span class="line"></span><br><span class="line">1. 时间戳(或者时间),反正解析出来后能够获取到生成时间的,因为有了生成时间才能判断有效时间</span><br><span class="line">2. 用户信息的唯一标志,也就是通过这个唯一标志可以关联查询到用户相关信息</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">也就是说 code 是通过可以解码的算法来加密的</span><br></pre></td></tr></table></figure>
<h3 id="微信小程序交互方式分析"><a href="#微信小程序交互方式分析" class="headerlink" title="微信小程序交互方式分析"></a>微信小程序交互方式分析</h3><h1 id="那么-accessToken"><a href="#那么-accessToken" class="headerlink" title="那么 accessToken"></a>那么 accessToken</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1. 这里的 accessToken 是通过appId + appSecret 获取到的</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">这里猜测:accessToken也是采用的可逆的加密算法获取的,但是为了防止时间过长被破译的可能性,所以设置了2h过期的,且有新的生成后旧的就自动过期的原理</span><br><span class="line"></span><br><span class="line">那么这里的accessToken是服务器端的行为,理论上是完全不会被泄露的。</span><br><span class="line"></span><br><span class="line">2. 当服务器端 拿着code + accessToken 就认为是能够安全的行为。</span><br></pre></td></tr></table></figure>
<h3 id="普通的-auth-认证流程"><a href="#普通的-auth-认证流程" class="headerlink" title="普通的 auth 认证流程"></a>普通的 auth 认证流程</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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><br><span class="line">接口1 - 生成: 可以采用可逆向解密的算法来生成一串code,返给用户方</span><br><span class="line">接口2 - 生成:用户传入code 以及 Sign 以及 AppId 三个参数,通过协商好的Sign以及code来判断内容是否被篡改,若正常,则查出Code中根据用户唯一Id查出用户信息返回。</span><br><span class="line"></span><br><span class="line"># 服务方:</span><br><span class="line">接口3:通过AppId 和 AppSecret 以及 用户方给的 code 生成签名 Sign, 调用定制规则方的接口2来获取数据后返回给用户方</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 客户端用户方:</span><br><span class="line">调用 - 接口1,拿到code,调用服务方接口3 获取到用户存于定制规则方的用户相关数据。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 好文地址:</span><br><span class="line">https://www.cnblogs.com/blowing00/p/4524412.html</span><br></pre></td></tr></table></figure>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/02/02/auth-code/" data-id="cltdperzy001254dkdr3egkyg" data-title="auth-code" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/authCode-auth/" rel="tag">authCode, auth</a></li></ul>
</footer>
</div>
</article>
<article id="post-shell-cron-check-process" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/01/22/shell-cron-check-process/" class="article-date">
<time class="dt-published" datetime="2024-01-22T07:19:05.000Z" itemprop="datePublished">2024-01-22</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/01/22/shell-cron-check-process/">shell-cron-check-process</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="Shell-cron-来解决服务挂掉自启动"><a href="#Shell-cron-来解决服务挂掉自启动" class="headerlink" title="Shell + cron 来解决服务挂掉自启动"></a>Shell + cron 来解决服务挂掉自启动</h3><p><code>前言</code>: 有时候你必须要去检测某个进程是否还存在,当不存在的时候启动服务,来保障服务的正常运行。当然这个必须慎用,最主要的还是要保障服务的稳定性,但是这个也有应用场景。</p>
<h4 id="Shell"><a href="#Shell" class="headerlink" title="Shell"></a>Shell</h4><p>简单介绍一下,就是用户与计算机进行交互的,常见的命令行 比如:cd、mkdir 等</p>
<p>下面是一个简单的检测java进程是否存在,存在则不作为,不存在则去启动的脚本。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">#!/bin/bash</span><br><span class="line"></span><br><span class="line"># 设置 Java 安装路径,如果未设置,则使用默认路径</span><br><span class="line">if [ ! -n "$JAVA_HOME" ]; then</span><br><span class="line"> JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-1.el7.x86_64/jre</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line"># 设置 Java 进程名称</span><br><span class="line">java_a_process_name="$JAVA_HOME/bin/java -jar /home/tomcat/apps_test/a-SNAPSHOT.jar" #这里是进程名称 可以通过 ps -ef | grep 来查看</span><br><span class="line">java_b_process_name="$JAVA_HOME/bin/java -jar /home/tomcat/apps_test/b-SNAPSHOT.jar" </span><br><span class="line">java_c_process_name="$JAVA_HOME/bin/java -jar /home/tomcat/apps_test/c-SNAPSHOT.jar" </span><br><span class="line">java_d_process_name="$JAVA_HOME/bin/java -jar /home/tomcat/apps_test/d-SNAPSHOT.jar" </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 检查Java进程是否存在</span><br><span class="line">if ! pgrep -f "$java_a_process_name" > /dev/null; then</span><br><span class="line"> # 如果Java进程不存在,启动它</span><br><span class="line"> echo ">>>>> Not found service SMS Java process, start it ...."</span><br><span class="line"> </span><br><span class="line"> # 在这里添加启动Java进程的命令,例如:</span><br><span class="line"> /home/tomcat/apps_test/start.sh a-SNAPSHOT.jar</span><br><span class="line"> </span><br><span class="line"> # 请根据你的实际情况修改上面的启动命令</span><br><span class="line"> echo ">>>>> Java process service SMS start end"</span><br><span class="line">else</span><br><span class="line"> # 如果Java进程已经在运行,输出提示信息</span><br><span class="line"> echo ">>>>> Java process service SMS is running"</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">......</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h4 id="Cron"><a href="#Cron" class="headerlink" title="Cron"></a>Cron</h4><p>简单介绍一下,cron是用于定期执行任务的时间管理工具,大部分linux服务器都默认已经安装了</p>
<p>用法简介:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"># 查看当前用户的crontab</span><br><span class="line"></span><br><span class="line">crontab -l</span><br><span class="line"></span><br><span class="line">#编辑当前用户的 Crontab (也就是新增啊、修改定时任务使用的)</span><br><span class="line"></span><br><span class="line">crontab -e</span><br><span class="line"></span><br><span class="line">#Cron 表达式格式</span><br><span class="line"></span><br><span class="line">* * * * * command-to-be-executed </span><br><span class="line"></span><br><span class="line">这里不得不提到 5个 *是如何使用的</span><br><span class="line">5个* 分别代表:分(0-59)、小时(0-23)、日期 (1 - 31)、月份 (1 - 12)、星期几 (0 - 6,其中 0 是星期天)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">举几个例子:</span><br><span class="line">0 3 * * * /path/to/your/script.sh (每天早上3点执行script.sh 脚本)</span><br><span class="line">0 4 * * 1 /path/to/your/script.sh (每周一早上4点执行)</span><br><span class="line">*/30 * * * * /path/to/your/script.sh (每隔30分钟执行)</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/01/22/shell-cron-check-process/" data-id="cltdpes19004y54dk2ukwgpiq" data-title="shell-cron-check-process" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/shell/" rel="tag">shell</a></li></ul>
</footer>
</div>
</article>
<article id="post-network-set-fixed-ip" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/01/19/network-set-fixed-ip/" class="article-date">
<time class="dt-published" datetime="2024-01-19T02:35:55.000Z" itemprop="datePublished">2024-01-19</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/01/19/network-set-fixed-ip/">network-set-fixed-ip</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="一文说得透透的,如何将开发环境的局域网ip固定,再也不用每天来了ipconfig了"><a href="#一文说得透透的,如何将开发环境的局域网ip固定,再也不用每天来了ipconfig了" class="headerlink" title="一文说得透透的,如何将开发环境的局域网ip固定,再也不用每天来了ipconfig了"></a>一文说得透透的,如何将开发环境的局域网ip固定,再也不用每天来了ipconfig了</h3><h3 id="步骤一:静态IP地址设置"><a href="#步骤一:静态IP地址设置" class="headerlink" title="步骤一:静态IP地址设置"></a>步骤一:静态IP地址设置</h3><h4 id="Windows-实操"><a href="#Windows-实操" class="headerlink" title="Windows (实操)"></a>Windows (实操)</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">Windows 操作系统:</span><br><span class="line"></span><br><span class="line">进入“控制面板” > “网络和共享中心” > “更改适配器设置”。</span><br><span class="line">找到你的网络连接,右键点击选择“属性”。</span><br><span class="line">选择“Internet 协议版本 4 (TCP/IPv4)”并点击“属性”。</span><br><span class="line">选择“使用下面的 IP 地址”,然后填写IP地址、子网掩码、网关和DNS服务器等信息。</span><br></pre></td></tr></table></figure>
<h5 id="敲黑板了,这里的使用下面的IP地址以及手动DNS应该如何配置呢?"><a href="#敲黑板了,这里的使用下面的IP地址以及手动DNS应该如何配置呢?" class="headerlink" title="敲黑板了,这里的使用下面的IP地址以及手动DNS应该如何配置呢?"></a>敲黑板了,这里的使用下面的IP地址以及手动DNS应该如何配置呢?</h5><ol>
<li>ipv4 地址填写啥? 你可以先使用arp -a 查看哪些地址已经被使用,挑一个没被占用的ip</li>
<li>子网掩码填啥 和 网关 ? 可以使用ipconfig 里面找到对应的网卡,里面有子网掩码<br>示例图如下<br><img src="/2024/01/19/network-set-fixed-ip/network-01.png"></li>
</ol>
<h4 id="macOS-操作系统"><a href="#macOS-操作系统" class="headerlink" title="macOS 操作系统"></a>macOS 操作系统</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">进入“系统偏好设置” > “网络”。</span><br><span class="line">选择你的连接,点击“高级”。</span><br><span class="line">在“TCP/IP”标签中选择“手动”,然后填写IP地址、子网掩码、路由器等信息。</span><br></pre></td></tr></table></figure>
<h4 id="Linux-操作系统:"><a href="#Linux-操作系统:" class="headerlink" title="Linux 操作系统:"></a>Linux 操作系统:</h4><figure class="highlight plaintext"><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">在终端中使用文本编辑器编辑网络配置文件,例如 /etc/network/interfaces 或 /etc/sysconfig/network-scripts/ifcfg-<interface>。</span><br><span class="line">添加或编辑相关行,指定IP地址、子网掩码、网关等信息。</span><br></pre></td></tr></table></figure>
<h3 id="步骤二:配置静态ARP条目"><a href="#步骤二:配置静态ARP条目" class="headerlink" title="步骤二:配置静态ARP条目"></a>步骤二:配置静态ARP条目</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">arp -s <IP地址> <MAC地址> </span><br></pre></td></tr></table></figure>
<p>注意,这里的arp -s 操作需要在管理员权限进行操作。eg: windows 需要将cmd用管理员权限打开。</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/01/19/network-set-fixed-ip/" data-id="cltdpes12004954dkao290i1h" data-title="network-set-fixed-ip" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/network/" rel="tag">network</a></li></ul>
</footer>
</div>
</article>
<article id="post-stream" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2023/03/03/stream/" class="article-date">
<time class="dt-published" datetime="2023-03-03T03:42:10.000Z" itemprop="datePublished">2023-03-03</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2023/03/03/stream/">stream</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="文件流"><a href="#文件流" class="headerlink" title="文件流"></a>文件流</h3><ol>
<li>可以对大文件进行操作</li>
</ol>
<p>Stream 有四种流类型:<br>. Readable - 可读性<br>. Writable - 可写性<br>. Duplex - 可读可写性<br>. Transform - 操作被写入数据,然后读出结果</p>
<p>所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:<br>. data - 当有数据可读时触发<br>. end - 没有更多的数据可读时触发<br>. error - 在接收和写入过程中发生错误时触发<br>. finish - 所有数据已被写入到底层系统时触发</p>
<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</span><br><span class="line"><span class="keyword">const</span> { createReadStream, createWriteStream } = <span class="built_in">require</span>(<span class="string">'fs'</span>)</span><br></pre></td></tr></table></figure>
<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><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> readStream = <span class="title function_">createReadStream</span>(<span class="string">'input.txt'</span>)</span><br><span class="line">readStream.<span class="title function_">setEncoding</span>(<span class="string">'utf8'</span>)</span><br><span class="line"><span class="keyword">let</span> data = <span class="string">''</span></span><br><span class="line"><span class="comment">// 处理流事件</span></span><br><span class="line">readerStream.<span class="title function_">on</span>(<span class="string">'data'</span>, <span class="keyword">function</span> (<span class="params">chunk</span>) {</span><br><span class="line"> data += chunk</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">readerStream.<span class="title function_">on</span>(<span class="string">'end'</span>, <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(data) <span class="comment">// 这里就是输出了文件内容</span></span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">readerStream.<span class="title function_">on</span>(<span class="string">'error'</span>, <span class="keyword">function</span> (<span class="params">err</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">stack</span>)</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'程序执行完毕'</span>)</span><br></pre></td></tr></table></figure>
<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><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> data = <span class="string">'我是写入文件的内容'</span></span><br><span class="line"><span class="comment">// 创建一个可以写入的流,写入到文件 output.txt 中</span></span><br><span class="line"><span class="keyword">var</span> writerStream = fs.<span class="title function_">createWriteStream</span>(<span class="string">'output.txt'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用 utf8 编码写入数据</span></span><br><span class="line">writerStream.<span class="title function_">write</span>(data, <span class="string">'UTF8'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 标记文件末尾</span></span><br><span class="line">writerStream.<span class="title function_">end</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理流事件 --> finish、error</span></span><br><span class="line">writerStream.<span class="title function_">on</span>(<span class="string">'finish'</span>, <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'写入完成。'</span>)</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">writerStream.<span class="title function_">on</span>(<span class="string">'error'</span>, <span class="keyword">function</span> (<span class="params">err</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(err.<span class="property">stack</span>)</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'程序执行完毕'</span>)</span><br></pre></td></tr></table></figure>
<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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个可读流</span></span><br><span class="line"><span class="keyword">var</span> readerStream = fs.<span class="title function_">createReadStream</span>(<span class="string">'input.txt'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个可写流</span></span><br><span class="line"><span class="keyword">var</span> writerStream = fs.<span class="title function_">createWriteStream</span>(<span class="string">'output.txt'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 管道读写操作</span></span><br><span class="line"><span class="comment">// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中</span></span><br><span class="line">readerStream.<span class="title function_">pipe</span>(writerStream)</span><br></pre></td></tr></table></figure>
<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</span><br><span class="line"><span class="keyword">var</span> zlib = <span class="built_in">require</span>(<span class="string">'zlib'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 压缩 input.txt 文件为 input.txt.gz</span></span><br><span class="line">fs.<span class="title function_">createReadStream</span>(<span class="string">'input.txt'</span>)</span><br><span class="line"> .<span class="title function_">pipe</span>(zlib.<span class="title function_">createGzip</span>())</span><br><span class="line"> .<span class="title function_">pipe</span>(fs.<span class="title function_">createWriteStream</span>(<span class="string">'input.txt.gz'</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">// 解压 input.txt.gz 文件为 input.txt</span></span><br><span class="line">fs.<span class="title function_">createReadStream</span>(<span class="string">'input.txt.gz'</span>)</span><br><span class="line"> .<span class="title function_">pipe</span>(zlib.<span class="title function_">createGunzip</span>())</span><br><span class="line"> .<span class="title function_">pipe</span>(fs.<span class="title function_">createWriteStream</span>(<span class="string">'input.txt'</span>))</span><br></pre></td></tr></table></figure>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2023/03/03/stream/" data-id="cltdpes19004z54dk0yg346yk" data-title="stream" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/node/" rel="tag">node</a></li></ul>
</footer>
</div>
</article>
<article id="post-fs" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2023/03/03/fs/" class="article-date">
<time class="dt-published" datetime="2023-03-03T02:35:25.000Z" itemprop="datePublished">2023-03-03</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2023/03/03/fs/">fs</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="fs-模块"><a href="#fs-模块" class="headerlink" title="fs 模块"></a>fs 模块</h3><p>nodejs 的内置模块,主要用于文件操作。下面介绍几种常见用法。</p>
<ol>
<li>权限介绍<br><img src="/2023/03/03/fs/fs-01.jpeg"></li>
</ol>
<h4 id="普通用法"><a href="#普通用法" class="headerlink" title="普通用法"></a>普通用法</h4><h5 id="引用方法"><a href="#引用方法" class="headerlink" title="引用方法"></a>引用方法</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> fs <span class="keyword">from</span> <span class="string">'node:fs'</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</span><br></pre></td></tr></table></figure>
<h5 id="读文件"><a href="#读文件" class="headerlink" title="读文件"></a>读文件</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 异步</span></span><br><span class="line">fs.<span class="title function_">readFile</span>(filePath, <span class="string">'utf8'</span>, <span class="function">(<span class="params">err, data</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (err) <span class="keyword">throw</span> err</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'data'</span>, data)</span><br><span class="line">})</span><br><span class="line"><span class="comment">// 同步</span></span><br><span class="line"><span class="keyword">const</span> fileResult = fs.<span class="title function_">readFileSync</span>(filePath, <span class="string">'utf8'</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'data'</span>, fileResult)</span><br></pre></td></tr></table></figure>
<h5 id="写文件"><a href="#写文件" class="headerlink" title="写文件"></a>写文件</h5><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * options是可选参数, 配置项为</span></span><br><span class="line"><span class="comment"> * {</span></span><br><span class="line"><span class="comment"> * encoding: {String || null} default = 'utf8',</span></span><br><span class="line"><span class="comment"> * mode: {Number} default = 438,</span></span><br><span class="line"><span class="comment"> * flag: {String} default = 'w', flag值,默认为w,会清空文件,然后再写。flag值,r代表读取文件,w代表写文件,a代表追加。</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 异步</span></span><br><span class="line">fs.<span class="title function_">writeFile</span>(fileName, data, [, options], callback)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 同步</span></span><br><span class="line">fs.<span class="title function_">writeFileSync</span>(fileName, data [, options])</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h5 id="写文件-追加内容"><a href="#写文件-追加内容" class="headerlink" title="写文件(追加内容)"></a>写文件(追加内容)</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 异步</span></span><br><span class="line">fs.<span class="title function_">appendFile</span>(fileName, data, [, options], callback)</span><br><span class="line"><span class="comment">// 同步</span></span><br><span class="line">fs.<span class="title function_">appendFileSync</span>(fileName, data, [, options])</span><br></pre></td></tr></table></figure>
<h5 id="拷贝文件"><a href="#拷贝文件" class="headerlink" title="拷贝文件"></a>拷贝文件</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 异步</span></span><br><span class="line">fs.<span class="title function_">copyFile</span>(fileNameA, fileNameB, callback)</span><br><span class="line"><span class="comment">// 同步</span></span><br><span class="line">fs.<span class="title function_">copyFileSync</span>(fileNameA, fileNameB)</span><br></pre></td></tr></table></figure>
<h5 id="删除文件"><a href="#删除文件" class="headerlink" title="删除文件"></a>删除文件</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 异步</span></span><br><span class="line">fs.<span class="title function_">unlink</span>(filePath, callback)</span><br><span class="line"><span class="comment">// 同步</span></span><br><span class="line">fs.<span class="title function_">unlinkSync</span>(filePath, callback)</span><br></pre></td></tr></table></figure>
<h5 id="文件打开"><a href="#文件打开" class="headerlink" title="文件打开"></a>文件打开</h5><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><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 大文件操作与上面的有所不同,可以用 fs.open打开,fs.read / fs.write 读写, 最后fs.close 关闭</span></span><br><span class="line">fs.<span class="title function_">open</span>(path, flags, [,mode], callback)</span><br><span class="line">fs.<span class="title function_">close</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 示例用法</span></span><br><span class="line"><span class="comment">// copy 方法 一般不用这个,可以借助stream</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">copy</span>(<span class="params">src, dest, size = <span class="number">16</span> * <span class="number">1024</span>, callback</span>) {</span><br><span class="line"> <span class="comment">// 打开源文件</span></span><br><span class="line"> fs.<span class="title function_">open</span>(src, <span class="string">'r'</span>, <span class="function">(<span class="params">err, readFd</span>) =></span> {</span><br><span class="line"> <span class="comment">// 打开目标文件</span></span><br><span class="line"> fs.<span class="title function_">open</span>(dest, <span class="string">'w'</span>, <span class="function">(<span class="params">err, writeFd</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> buf = <span class="title class_">Buffer</span>.<span class="title function_">alloc</span>(size);</span><br><span class="line"> <span class="keyword">let</span> readed = <span class="number">0</span>; <span class="comment">// 下次读取文件的位置</span></span><br><span class="line"> <span class="keyword">let</span> writed = <span class="number">0</span>; <span class="comment">// 下次写入文件的位置</span></span><br><span class="line"></span><br><span class="line"> (<span class="keyword">function</span> <span class="title function_">next</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 读取</span></span><br><span class="line"> fs.<span class="title function_">read</span>(readFd, buf, <span class="number">0</span>, size, readed, <span class="function">(<span class="params">err, bytesRead</span>) =></span> {</span><br><span class="line"> readed += bytesRead;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果都不到内容关闭文件</span></span><br><span class="line"> <span class="keyword">if</span> (!bytesRead) fs.<span class="title function_">close</span>(readFd, <span class="function"><span class="params">err</span> =></span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'关闭源文件'</span>));</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 写入</span></span><br><span class="line"> fs.<span class="title function_">write</span>(writeFd, buf, <span class="number">0</span>, bytesRead, writed, <span class="function">(<span class="params">err, bytesWritten</span>) =></span> {</span><br><span class="line"> <span class="comment">// 如果没有内容了同步缓存,并关闭文件后执行回调</span></span><br><span class="line"> <span class="keyword">if</span> (!bytesWritten) {</span><br><span class="line"> <span class="comment">// fs.fsync 是请求将打开文件描述符的所有数据刷新到存储设备。 具体实现是操作系统和设备特定的。</span></span><br><span class="line"> fs.<span class="title function_">fsync</span>(writeFd, <span class="function"><span class="params">err</span> =></span> {</span><br><span class="line"> fs.<span class="title function_">close</span>(writeFd, <span class="function"><span class="params">err</span> =></span> <span class="keyword">return</span> !err && <span class="title function_">callback</span>());</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> writed += bytesWritten;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 继续读取、写入</span></span><br><span class="line"> <span class="title function_">next</span>();</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> })();</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="Promise-用法"><a href="#Promise-用法" class="headerlink" title="Promise 用法"></a>Promise 用法</h4><h5 id="引入方法"><a href="#引入方法" class="headerlink" title="引入方法"></a>引入方法</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> fs <span class="keyword">from</span> <span class="string">'node:fs/promises'</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs/promises'</span>)</span><br></pre></td></tr></table></figure>
<h5 id="使用示例-readFile"><a href="#使用示例-readFile" class="headerlink" title="使用示例 readFile"></a>使用示例 readFile</h5><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { readFile } <span class="keyword">from</span> <span class="string">'node:fs/promises'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">const</span> data = <span class="keyword">await</span> <span class="title function_">readFile</span>(<span class="string">'/tmp/hello'</span>)</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'data'</span>, data)</span><br><span class="line">} <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">'error'</span>, err.<span class="property">message</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>所有其他语法promise语法类似……</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2023/03/03/fs/" data-id="cltdpes0q003254dk6n9kgbuz" data-title="fs" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/node/" rel="tag">node</a></li></ul>
</footer>
</div>
</article>
<article id="post-merge-multiple-csv-or-xlsx" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2023/02/27/merge-multiple-csv-or-xlsx/" class="article-date">
<time class="dt-published" datetime="2023-02-27T07:00:31.000Z" itemprop="datePublished">2023-02-27</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2023/02/27/merge-multiple-csv-or-xlsx/">merge-multiple-csv-or-xlsx</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="合并多个列相同的文件到同一个,eg:csv,xlsx文件"><a href="#合并多个列相同的文件到同一个,eg:csv,xlsx文件" class="headerlink" title="合并多个列相同的文件到同一个,eg:csv,xlsx文件"></a>合并多个列相同的文件到同一个,eg:csv,xlsx文件</h3><p>生活中总有那么一种问题,丢你几十上百个csv,或者xlsx文件,让你筛选里面的条件达到某一个取出。今日的我就遇到了,手工达人是不可能手工达人的,我们要实现全自动化!</p>
<h4 id="合并多个csv"><a href="#合并多个csv" class="headerlink" title="合并多个csv"></a>合并多个csv</h4><p>未实际操作的方案(因为我是windows党…), linux系统的copy csv方案。</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 /{your all csv dir}</span><br><span class="line">cat *.csv all.csv</span><br></pre></td></tr></table></figure>
<p>实操了2种方案 (本人实际操作过,都可以。速度也还能接受)</p>
<ol>
<li>windows 复制多个csv到同一个</li>
</ol>
<p>操作路径:<br>打开cmd(注意一定要是cmd,powershell是不会成功滴)<br>然后进入到你的所有csv存在的目录下</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">copy *.csv all.csv ---- 对的,就这一行命令。搞定!无需任何安装,无需编码环境。高手中的高手~、</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>若你是开发者,还可以看看python 的pandas操作。<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> glob</span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"><span class="comment"># set working directory</span></span><br><span class="line">os.chdir(<span class="string">"csv_1"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># find all csv files in the folder</span></span><br><span class="line"><span class="comment"># use glob pattern matching -> extension = 'csv'</span></span><br><span class="line"><span class="comment"># save result in list -> all_filenames</span></span><br><span class="line">extension = <span class="string">'csv'</span></span><br><span class="line">all_filenames = [i <span class="keyword">for</span> i <span class="keyword">in</span> glob.glob(<span class="string">'*.{}'</span>.<span class="built_in">format</span>(extension))]</span><br><span class="line"><span class="comment"># print(all_filenames)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># combine all files in the list, encoding need to change for yourself actual </span></span><br><span class="line">combined_csv = pd.concat([pd.read_csv(f, encoding=<span class="string">'ANSI'</span>)</span><br><span class="line"> <span class="keyword">for</span> f <span class="keyword">in</span> all_filenames]) </span><br><span class="line"></span><br><span class="line"><span class="comment"># combine all files in the list</span></span><br><span class="line"><span class="comment"># combined_xlsx = pd.read_excel</span></span><br><span class="line"><span class="comment"># export to csv</span></span><br><span class="line">combined_csv.to_csv(<span class="string">"combined_csv.csv"</span>, index=<span class="literal">False</span>, encoding=<span class="string">'utf-8-sig'</span>)</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ol>
<h4 id="合并多个xlsx"><a href="#合并多个xlsx" class="headerlink" title="合并多个xlsx"></a>合并多个xlsx</h4><p>这个就没有找到cmd的操作方案了,不过pandas依旧yyds</p>
<p>祭出代码</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> glob</span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"></span><br><span class="line">os.chdir(<span class="string">"xlsx_1"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">extension = <span class="string">'xlsx'</span></span><br><span class="line">all_filenames = [i <span class="keyword">for</span> i <span class="keyword">in</span> glob.glob(<span class="string">'*.{}'</span>.<span class="built_in">format</span>(extension))]</span><br><span class="line"></span><br><span class="line">combined_csv = pd.concat(</span><br><span class="line"> [</span><br><span class="line"> pd.read_excel(f)</span><br><span class="line"> <span class="keyword">for</span> f <span class="keyword">in</span> all_filenames</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">combined_csv.to_excel(<span class="string">"combined_result.xlsx"</span>, index=<span class="literal">False</span>)</span><br></pre></td></tr></table></figure>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2023/02/27/merge-multiple-csv-or-xlsx/" data-id="cltdpes11004454dkhud8fr9k" data-title="merge-multiple-csv-or-xlsx" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/csv-xlsx/" rel="tag">csv, xlsx</a></li></ul>
</footer>
</div>
</article>
<article id="post-encryption" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2023/02/21/encryption/" class="article-date">
<time class="dt-published" datetime="2023-02-21T09:16:00.000Z" itemprop="datePublished">2023-02-21</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2023/02/21/encryption/">encryption</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h3 id="加密方式"><a href="#加密方式" class="headerlink" title="加密方式"></a>加密方式</h3><p>介绍加密方式。</p>
<h4 id="AES"><a href="#AES" class="headerlink" title="AES"></a>AES</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">CryptoJS</span> = <span class="built_in">require</span>(<span class="string">'crypto-js'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> key = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(<span class="string">'xxxxxxxxxxx'</span>) <span class="comment">//十六位十六进制数作为密钥</span></span><br><span class="line"><span class="keyword">const</span> iv = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(<span class="string">'xxxxxxxxxxxxx'</span>) <span class="comment">//十六位十六进制数作为密钥偏移量</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Encrypt</span>(<span class="params">word</span>) {</span><br><span class="line"> <span class="keyword">let</span> srcs = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>.<span class="title function_">parse</span>(word)</span><br><span class="line"> <span class="keyword">let</span> encrypted = <span class="title class_">CryptoJS</span>.<span class="property">AES</span>.<span class="title function_">encrypt</span>(srcs, key, {</span><br><span class="line"> <span class="attr">iv</span>: iv,</span><br><span class="line"> <span class="attr">mode</span>: <span class="title class_">CryptoJS</span>.<span class="property">mode</span>.<span class="property">CBC</span>,</span><br><span class="line"> <span class="attr">padding</span>: <span class="title class_">CryptoJS</span>.<span class="property">pad</span>.<span class="property">Pkcs7</span>,</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">return</span> encrypted.<span class="property">ciphertext</span>.<span class="title function_">toString</span>().<span class="title function_">toUpperCase</span>()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Decrypt</span>(<span class="params">word</span>) {</span><br><span class="line"> <span class="keyword">let</span> encryptedHexStr = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Hex</span>.<span class="title function_">parse</span>(word)</span><br><span class="line"> <span class="keyword">let</span> srcs = <span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Base64</span>.<span class="title function_">stringify</span>(encryptedHexStr)</span><br><span class="line"> <span class="keyword">let</span> decrypt = <span class="title class_">CryptoJS</span>.<span class="property">AES</span>.<span class="title function_">decrypt</span>(srcs, key, {</span><br><span class="line"> <span class="attr">iv</span>: iv,</span><br><span class="line"> <span class="attr">mode</span>: <span class="title class_">CryptoJS</span>.<span class="property">mode</span>.<span class="property">CBC</span>,</span><br><span class="line"> <span class="attr">padding</span>: <span class="title class_">CryptoJS</span>.<span class="property">pad</span>.<span class="property">Pkcs7</span>,</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">let</span> decryptedStr = decrypt.<span class="title function_">toString</span>(<span class="title class_">CryptoJS</span>.<span class="property">enc</span>.<span class="property">Utf8</span>)</span><br><span class="line"> <span class="keyword">return</span> decryptedStr.<span class="title function_">toString</span>()</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="RSA"><a href="#RSA" class="headerlink" title="RSA"></a>RSA</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><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">NodeRSA</span> = <span class="built_in">require</span>(<span class="string">'node-rsa'</span>)</span><br><span class="line"><span class="keyword">const</span> publicKey = <span class="string">'xxxxxxxxxxxxxx'</span></span><br><span class="line"><span class="keyword">const</span> privateKey = <span class="string">'xxxxxxxxxxxxxxxxx'</span></span><br><span class="line"><span class="comment">// 加密</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">encrypted</span>(<span class="params">str</span>) {</span><br><span class="line"> <span class="keyword">const</span> publicKeyObj = <span class="keyword">new</span> <span class="title class_">NodeRSA</span>(publicKey)</span><br><span class="line"> publicKeyObj.<span class="title function_">setOptions</span>({ <span class="attr">encryptionScheme</span>: <span class="string">'pkcs1'</span> })</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> encrypted = publicKeyObj.<span class="title function_">encrypt</span>(str, <span class="string">'base64'</span>, <span class="string">'utf8'</span>)</span><br><span class="line"> <span class="keyword">return</span> encrypted</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 解密</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">decrypted</span>(<span class="params">str</span>) {</span><br><span class="line"> <span class="keyword">const</span> privateKeyObj = <span class="keyword">new</span> <span class="title class_">NodeRSA</span>(privateKey)</span><br><span class="line"> privateKeyObj.<span class="title function_">setOptions</span>({ <span class="attr">encryptionScheme</span>: <span class="string">'pkcs1'</span> })</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> decrypted = privateKeyObj.<span class="title function_">decrypt</span>(str, <span class="string">'utf8'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="title class_">JSON</span>.<span class="title function_">parse</span>(decrypted)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2023/02/21/encryption/" data-id="cltdpes0k002e54dkck2s7bjc" data-title="encryption" class="article-share-link">Share</a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/encryption/" rel="tag">encryption</a></li></ul>
</footer>
</div>
</article>
<nav id="page-nav">
<span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><span class="space">…</span><a class="page-number" href="/page/10/">10</a><a class="extend next" rel="next" href="/page/2/">Next »</a>
</nav>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">Tags</h3>
<div class="widget">
<ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/33-js-concepts/" rel="tag">33-js-concepts</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Css/" rel="tag">Css</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ES6/" rel="tag">ES6</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Html/" rel="tag">Html</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/PackingTools/" rel="tag">PackingTools</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Product/" rel="tag">Product</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/React/" rel="tag">React</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Thoughts/" rel="tag">Thoughts</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Tools/" rel="tag">Tools</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/XMLHttpRequest/" rel="tag">XMLHttpRequest</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/api/" rel="tag">api</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/authCode-auth/" rel="tag">authCode, auth</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/canvas/" rel="tag">canvas</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/components/" rel="tag">components</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/csv-xlsx/" rel="tag">csv, xlsx</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/encryption/" rel="tag">encryption</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gitTools/" rel="tag">gitTools</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/http/" rel="tag">http</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/introduce/" rel="tag">introduce</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javascript/" rel="tag">javascript</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jwt/" rel="tag">jwt</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mvvm/" rel="tag">mvvm</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/network/" rel="tag">network</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/" rel="tag">nginx</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/node/" rel="tag">node</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/other/" rel="tag">other</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/regexp/" rel="tag">regexp</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/shell/" rel="tag">shell</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/wechat/" rel="tag">wechat</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xlsx/" rel="tag">xlsx</a></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Tag Cloud</h3>
<div class="widget tagcloud">
<a href="/tags/33-js-concepts/" style="font-size: 20px;">33-js-concepts</a> <a href="/tags/Css/" style="font-size: 17.14px;">Css</a> <a href="/tags/ES6/" style="font-size: 15.71px;">ES6</a> <a href="/tags/Html/" style="font-size: 10px;">Html</a> <a href="/tags/PackingTools/" style="font-size: 11.43px;">PackingTools</a> <a href="/tags/Product/" style="font-size: 11.43px;">Product</a> <a href="/tags/React/" style="font-size: 10px;">React</a> <a href="/tags/Thoughts/" style="font-size: 14.29px;">Thoughts</a> <a href="/tags/Tools/" style="font-size: 12.86px;">Tools</a> <a href="/tags/XMLHttpRequest/" style="font-size: 14.29px;">XMLHttpRequest</a> <a href="/tags/api/" style="font-size: 10px;">api</a> <a href="/tags/authCode-auth/" style="font-size: 10px;">authCode, auth</a> <a href="/tags/canvas/" style="font-size: 11.43px;">canvas</a> <a href="/tags/components/" style="font-size: 10px;">components</a> <a href="/tags/csv-xlsx/" style="font-size: 10px;">csv, xlsx</a> <a href="/tags/encryption/" style="font-size: 10px;">encryption</a> <a href="/tags/gitTools/" style="font-size: 10px;">gitTools</a> <a href="/tags/http/" style="font-size: 10px;">http</a> <a href="/tags/introduce/" style="font-size: 10px;">introduce</a> <a href="/tags/javascript/" style="font-size: 18.57px;">javascript</a> <a href="/tags/jwt/" style="font-size: 10px;">jwt</a> <a href="/tags/mvvm/" style="font-size: 10px;">mvvm</a> <a href="/tags/network/" style="font-size: 10px;">network</a> <a href="/tags/nginx/" style="font-size: 12.86px;">nginx</a> <a href="/tags/node/" style="font-size: 12.86px;">node</a> <a href="/tags/other/" style="font-size: 10px;">other</a> <a href="/tags/regexp/" style="font-size: 10px;">regexp</a> <a href="/tags/shell/" style="font-size: 10px;">shell</a> <a href="/tags/wechat/" style="font-size: 11.43px;">wechat</a> <a href="/tags/xlsx/" style="font-size: 10px;">xlsx</a>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Archives</h3>
<div class="widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2024/03/">March 2024</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2024/02/">February 2024</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2024/01/">January 2024</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2023/03/">March 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2023/02/">February 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2022/11/">November 2022</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2022/04/">April 2022</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/09/">September 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/05/">May 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/03/">March 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/10/">October 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/09/">September 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">June 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/05/">May 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/04/">April 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">March 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/01/">January 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/12/">December 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/09/">September 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/07/">July 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/06/">June 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/05/">May 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/04/">April 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">March 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/02/">February 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/01/">January 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/12/">December 2017</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/11/">November 2017</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/10/">October 2017</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/09/">September 2017</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/08/">August 2017</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/07/">July 2017</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/06/">June 2017</a></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Recent Posts</h3>
<div class="widget">
<ul>
<li>
<a href="/2024/03/03/thirdAPISecret/">thirdAPISecret</a>
</li>
<li>
<a href="/2024/02/21/mvvm-resource-read/">mvvm-resource-read</a>
</li>
<li>
<a href="/2024/02/04/jwt/">jwt</a>
</li>
<li>
<a href="/2024/02/02/auth-code/">auth-code</a>
</li>
<li>
<a href="/2024/01/22/shell-cron-check-process/">shell-cron-check-process</a>
</li>
</ul>
</div>
</div>
</aside>
</div>
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
© 2024 zero<br>
Powered by <a href="https://hexo.io/" target="_blank">Hexo</a>
</div>
</div>
</footer>
</div>
<nav id="mobile-nav">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/archives" class="mobile-nav-link">Archives</a>
</nav>
<script src="/js/jquery-3.4.1.min.js"></script>
<script src="/fancybox/jquery.fancybox.min.js"></script>
<script src="/js/script.js"></script>
</div>
</body>
</html>