-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path3712793328.html
More file actions
1364 lines (1036 loc) · 92 KB
/
Copy path3712793328.html
File metadata and controls
1364 lines (1036 loc) · 92 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
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en" data-default-color-scheme="auto">
<head>
<meta charset="UTF-8">
<link rel="apple-touch-icon" sizes="76x76" href="/img/fluid.png">
<link rel="icon" href="/img/fluid.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="theme-color" content="#2f4154">
<meta name="author" content="FangZhou">
<meta name="keywords" content="Vue,React,Nodejs,blogs,frontend,web,developer,programmer">
<meta name="description" content="计算机网络">
<meta property="og:type" content="article">
<meta property="og:title" content="计算机网络沉淀心得">
<meta property="og:url" content="http://arkpln.github.io/3712793328.html">
<meta property="og:site_name" content="Ark的技术博客">
<meta property="og:description" content="计算机网络">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="http://arkpln.github.io/images/cn.jpg">
<meta property="article:published_time" content="2026-01-26T03:43:02.000Z">
<meta property="article:modified_time" content="2026-02-26T09:18:45.696Z">
<meta property="article:author" content="FangZhou">
<meta property="article:tag" content="network">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="http://arkpln.github.io/images/cn.jpg">
<title>计算机网络沉淀心得 - Ark的技术博客</title>
<link rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css">
<link rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css">
<link rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css">
<!-- 主题依赖的图标库,不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_1749284_5i9bdhy70f8.css">
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_1736178_k526ubmyhba.css">
<link rel="stylesheet" href="/css/main.css">
<link id="highlight-css" rel="stylesheet" href="/css/highlight.css">
<link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css">
<script id="fluid-configs">
var Fluid = window.Fluid || {};
Fluid.ctx = Object.assign({}, Fluid.ctx)
var CONFIG = {"hostname":"arkpln.github.io","root":"/","version":"1.9.8","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":null,"google":{"measurement_id":null},"tencent":{"sid":null,"cid":null},"leancloud":{"app_id":"mEwkD7geCX7RWNO8srhDE2oP-gzGzoHsz","app_key":"4EF76hyiVA1QILHZThVbfoat","server_url":"https://mewkd7ge.lc-cn-n1-shared.com","path":"window.location.pathname","ignore_local":false},"umami":{"src":null,"website_id":null,"domains":null,"start_time":"2024-01-01T00:00:00.000Z","token":null,"api_server":null}},"search_path":"/local-search.xml","include_content_in_search":true};
if (CONFIG.web_analytics.follow_dnt) {
var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
}
</script>
<script src="/js/utils.js"></script>
<script src="/js/color-schema.js"></script>
<meta name="google-site-verification" content="5KfTZvtlydmBIzY97rVo-caP5jljAfmD3Qs3sBzY2Go"><style>ins.adsbygoogle[data-ad-status="unfilled"] { display: none !important; }</style>
<meta name="generator" content="Hexo 7.3.0"></head>
<body>
<header>
<div class="header-inner" style="height: 70vh;">
<nav id="navbar" class="navbar fixed-top navbar-expand-lg navbar-dark scrolling-navbar">
<div class="container">
<a class="navbar-brand" href="/">
<strong>Ark的技术博客</strong>
</a>
<button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<div class="animated-icon"><span></span><span></span><span></span></div>
</button>
<!-- Collapsible content -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ml-auto text-center">
<li class="nav-item">
<a class="nav-link" href="/" target="_self">
<i class="iconfont icon-home-fill"></i>
<span>快乐老家</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/archives/" target="_self">
<i class="iconfont icon-archive-fill"></i>
<span>笔岚档案</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/categories/" target="_self">
<i class="iconfont icon-category-fill"></i>
<span>文以类聚</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/tags/" target="_self">
<i class="iconfont icon-tags-fill"></i>
<span>按标签阅览</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about/" target="_self">
<i class="iconfont icon-user-fill"></i>
<span>联系我</span>
</a>
</li>
<li class="nav-item" id="search-btn">
<a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
<i class="iconfont icon-search"></i>
</a>
</li>
<li class="nav-item" id="color-toggle-btn">
<a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
<i class="iconfont icon-dark" id="color-toggle-icon"></i>
</a>
</li>
</ul>
</div>
</div>
</nav>
<div id="banner" class="banner" parallax="true" style="background: url('/images/cn.jpg') no-repeat center center; background-size: cover;">
<div class="full-bg-img">
<div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
<div class="banner-text text-center fade-in-up">
<div class="h2">
<span id="subtitle" data-typed-text="计算机网络沉淀心得"></span>
</div>
<div class="mt-3">
<span class="post-meta">
<i class="iconfont icon-date-fill" aria-hidden="true"></i>
<time datetime="2026-01-26 11:43" pubdate>
January 26, 2026 am
</time>
</span>
</div>
<div class="mt-1">
<span class="post-meta mr-2">
<i class="iconfont icon-chart"></i>
16k words
</span>
<span class="post-meta mr-2">
<i class="iconfont icon-clock-fill"></i>
136 mins
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
<main>
<div class="container-fluid nopadding-x">
<div class="row nomargin-x">
<div class="side-col d-none d-lg-block col-lg-2">
<aside class="sidebar d-none d-xl-block" style="margin-right:-1rem;z-index:-1"><ins class="adsbygoogle" style="display:flex;justify-content:center;min-width:160px;max-width:300px;width:100%;height:600px;position:sticky;top:2rem" data-ad-client="ca-pub-3240358922862141" data-ad-slot="6522434837"></ins><script> (adsbygoogle = window.adsbygoogle || []).push({}); </script></aside>
</div>
<div class="col-lg-8 nopadding-x-md">
<div class="container nopadding-x-md" id="board-ctn">
<div id="board">
<article class="post-content mx-auto">
<h1 id="seo-header">计算机网络沉淀心得</h1>
<div class="markdown-body">
<h1 id="计算机网络沉淀心得"><a href="#计算机网络沉淀心得" class="headerlink" title="计算机网络沉淀心得"></a>计算机网络沉淀心得</h1><h2 id="OSI七层网络模型"><a href="#OSI七层网络模型" class="headerlink" title="OSI七层网络模型"></a>OSI七层网络模型</h2><h3 id="结构总述"><a href="#结构总述" class="headerlink" title="结构总述"></a>结构总述</h3><ul>
<li><p>网络接口层/数据链路层</p>
<ul>
<li><p>物理层 -> IEEE820.1</p>
</li>
<li><p>数据链路层 -> FDDO,Ethernet,PPP</p>
</li>
</ul>
</li>
<li><p>网络层</p>
<ul>
<li>网络层 -> IP,ICMP,ARP,RIP</li>
</ul>
</li>
<li><p>传输层</p>
<ul>
<li>传输层 ->TCP,UDP</li>
</ul>
</li>
<li><p>应用层</p>
<ul>
<li><p>会话层 ->SSL,TLS</p>
</li>
<li><p>表示层 -> JPEG,ASCII,DECOIC,加密</p>
</li>
<li><p>应用层 -> HTTP,FTP,SNMP,DNS</p>
</li>
</ul>
</li>
</ul>
<h3 id="物理层"><a href="#物理层" class="headerlink" title="物理层"></a>物理层</h3><p>物理层是直接与物理介质打交道的</p>
<p>在这一层<em>光,电,无线电波</em>获取传送信号,电压,转换成数字信号,在这一层主要传输<strong>比特流</strong></p>
<p>物理层设备:</p>
<ul>
<li><p>网卡</p>
</li>
<li><p>网线</p>
</li>
<li><p>集线器,中继器</p>
</li>
<li><p>调制解调器</p>
</li>
</ul>
<p>物理层信道:</p>
<ul>
<li><p>明线(有线导线)</p>
</li>
<li><p>对称电缆</p>
</li>
<li><p>同轴电缆(最广泛)</p>
</li>
<li><p>光纤(光信号传导信号)</p>
</li>
<li><p>无线电波(WiFi,卫星)</p>
</li>
</ul>
<h3 id="数据链路层"><a href="#数据链路层" class="headerlink" title="数据链路层"></a>数据链路层</h3><p><strong>功能:</strong> 建立逻辑连接,进行硬件地址选址,差错检验.将比特组合成字节进而合成帧(<strong>数据帧</strong>),使用MAC地址访问介质,发现错误但不能纠正。</p>
<p><strong>MAC地址:</strong> 每个网卡的唯一标识</p>
<p>设备:</p>
<ul>
<li>交换机</li>
</ul>
<h3 id="网络层"><a href="#网络层" class="headerlink" title="网络层"></a>网络层</h3><p>网络层是最复杂的一层,在这一层就定义了我们的IP。该层控制数据链路层与传输层之间的信息转发,建立、维持和终止网络的连接。具体地说,数据链路层的数据在这一层被转换为数据包,然后通过路径选择、分段组合、顺序、进/出路由等控制,将信息从一个网络设备传送到另一个网络设备</p>
<p><strong>IP网址的原因:</strong></p>
<p>在数据链路层,如果所有的使用互联网的用户在同一个网段中,会产生广播风暴,所以要将用户进行划分,让他们在不同的网段中,自己在自己的小网段中广播。而互联网就是这无数的子网络构成的一个巨型网络。</p>
<p>在网络层中引入了一套新的地址,让我们能够区分不同的网段。这套地址就叫做“网络地址”,简称“网址”。于是,”网络层”出现以后,每台计算机有了两种地址,一种是MAC地址,另一种是网络地址。两种地址之间没有任何联系,MAC地址是绑定在网卡上的,网络地址则是管理员分配的,它们只是随机组合在一起。</p>
<p>网络地址帮助我们确定计算机所在的子网络,MAC地址则将数据包送到该子网络中的目标网卡。因此,从逻辑上可以推断,必定是先处理网络地址,然后再处理MAC地址。</p>
<p><strong>功能:</strong> </p>
<ul>
<li><p>寻址:对网络层而言使用IP地址来唯一标识互联网上的设备,网络层依靠IP地址进行相互通信(类似于数据链路层的MAC地址)</p>
</li>
<li><p>路由:在同一个网络中的内部通信并不需要网络层设备,仅仅靠数据链路层就可以完成相互通信,对于不同的网络之间相互通信则必须借助路由器等三层设备。</p>
</li>
</ul>
<p><strong>设备:</strong></p>
<ul>
<li>路由器</li>
</ul>
<p><strong>协议:</strong></p>
<ul>
<li><p>IPv4</p>
</li>
<li><p>IPv6</p>
</li>
</ul>
<h3 id="传输层"><a href="#传输层" class="headerlink" title="传输层"></a>传输层</h3><p><strong>功能:</strong></p>
<ul>
<li><p>定义端口号</p>
</li>
<li><p>控流</p>
</li>
<li><p>校验</p>
</li>
</ul>
<p><strong>协议:</strong></p>
<ul>
<li><p>TCP:面向连接的可靠协议,三次握手四次挥手</p>
</li>
<li><p>UDP:不可靠协议,但效率更高</p>
</li>
</ul>
<h3 id="会话层"><a href="#会话层" class="headerlink" title="会话层"></a>会话层</h3><p><strong>功能:</strong></p>
<p>会话层,是在发送方和接收方之间进行通信时创建、维持、之后终止或断开连接的地方,与电话通话有点相似。</p>
<p>会话层定义了一种机制,允许发送方和接收方启动或停止请求会话,以及当双方发生拥塞时仍然能保持对话。</p>
<p>会话层包含了一种称为检查点(Checkpoint)的机制来维持可靠会话。</p>
<p>检查点定义了一个最接近成功通信的点,并且定义了当发生内容丢失或损坏时需要回滚以便恢复丢失或损坏数据的点,即断点下载的原理。</p>
<p>这一层经常被叫<strong>报文</strong></p>
<h3 id="表示层"><a href="#表示层" class="headerlink" title="表示层"></a>表示层</h3><p><strong>功能:</strong></p>
<p>安全、压缩、编解码相关的功能和标准。</p>
<ul>
<li><p>ASCII,utf-8</p>
</li>
<li><p>JPEG</p>
</li>
</ul>
<p>这一层经常被叫<strong>报文</strong></p>
<h3 id="应用层"><a href="#应用层" class="headerlink" title="应用层"></a>应用层</h3><p><strong>功能:</strong> 负责为用户和应用程序提供网络服务,直接与用户交互。常见的协议有 HTTP(超文本传输协议)、FTP(文件传输协议)、SMTP(邮件传输协议)等。</p>
<p><strong>协议:</strong></p>
<ul>
<li><p>HTTP/HTTPS</p>
</li>
<li><p>DNS</p>
</li>
<li><p>SMTP</p>
</li>
<li><p>WebSocket</p>
</li>
<li><p>SSH</p>
</li>
</ul>
<h2 id="TCP三次握手"><a href="#TCP三次握手" class="headerlink" title="TCP三次握手"></a>TCP三次握手</h2><p><a target="_blank" rel="external nofollow noopener noreferrer" href="https://imgchr.com/i/pZR9Z7T"><img src="https://s41.ax1x.com/2026/01/26/pZR9Z7T.webp" srcset="/img/loading.gif" lazyload alt="pZR9Z7T.webp"></a></p>
<ol>
<li><p>seq(sequence number),序列号随机生成</p>
</li>
<li><p>ack(acknowledgement number)确认号ack=seq + 1</p>
</li>
<li><p>ACK(acknowledgement)确认序列号有效</p>
</li>
<li><p>SYN(Synchronous)发起新连接</p>
</li>
</ol>
<p><strong>过程:</strong></p>
<ol>
<li><p>首先客户端会发送一个段:<code>SYN</code>报文,想跟<code>服务端</code>进行连接,并且会携带一个序列号<code>seq</code>,下次发送的数据序列号还会进行+1。此时客户端发送<code>SYN = 1 seq=x</code></p>
</li>
<li><p>服务端收到了SYN + seq 字段之后,服务端也会生成一个对应服务端seq序列号,这时候就会携带ACK确认号,表示之前的SYN 收到了,还会有一个小写的ack 把 客户端的seq + 1,此时服务端发送<code>SYN = 1,ACK = 1,seq = y,ack=x+1</code></p>
</li>
<li><p>客户端收到服务端的响应之后会发送一个ACK确定序列号有效,并且还会发送seq,这里的seq会通过算法计算出来是否跟服务端的ack值相等,然后会发送一个新的ack这里的ack是服务端的seq值+1,确保一切正常。此时客户端发送<code>ACK= 1 seq = x+1,ack = y+1</code></p>
</li>
</ol>
<p><strong>总结:</strong></p>
<p>TCP 三次握手用于在数据传输前建立可靠连接,主要目的是确认双方的收发能力并同步初始序列号。<br>第一次握手由客户端发送 SYN,请求建立连接;<br>第二次握手服务器回复 SYN+ACK,确认客户端请求并发送自己的初始序列号;<br>第三次握手客户端发送 ACK,确认服务器的 SYN。<br>至此双方都确认了彼此的发送和接收能力,连接正式建立。</p>
<h2 id="TCP四次挥手"><a href="#TCP四次挥手" class="headerlink" title="TCP四次挥手"></a>TCP四次挥手</h2><p><a target="_blank" rel="external nofollow noopener noreferrer" href="https://imgchr.com/i/pZRCgqx"><img src="https://s41.ax1x.com/2026/01/26/pZRCgqx.webp" srcset="/img/loading.gif" lazyload alt="pZRCgqx.webp"></a></p>
<ol>
<li><p>seq(sequence number),序列号随机生成</p>
</li>
<li><p>ack(acknowledgement number)确认号ack = seq + 1</p>
</li>
<li><p>ACK(acknowledgement)确认序列号有效</p>
</li>
<li><p>SYN(synchronous)发起新连接</p>
</li>
<li><p>FIN(FINISH)完成</p>
</li>
<li><p>断开连接服务端和客户端都可以主动发起我们拿客户端举例,客户端进行断开操作先发送<code>FIN</code>包生成客户端的<code>seq</code>序列号随后进入<code>wait1</code>状态,这是第一次挥手。客户端发送<code>FIN=1 seq=u</code></p>
</li>
<li><p>服务端收到FIN包表示自己进入了关闭等待状态,然后向客户端使用ack验证,验证成功打上ACK标记,随后生成服务端的<code>seq值</code>发送给客户端,这是第二次挥手,服务端此时还可以发送未完成的数据。服务端发送<code>ACK=1 ack=u+1</code></p>
</li>
<li><p>等待服务端所有任务操作完成之后服务端开始进入最后确认状态,向客户端发送<code>FIN包</code>,并且验证ack,使用客户端第一次的<code>seq + 1</code>去验证,验证成功打上ACK标记,并且生成一个新的序列号seq发送给客户端,这是第三次挥手。客户端发送<code>FIN seq=v ack=u+1</code></p>
</li>
<li><p>客户端收到之后进入超时等待状态<code>2MSL(1-4分钟)</code>,经过等到后客户端关闭连接,而服务端收到信息验证完成ack成功之后打上<code>ACk</code>标记随后将关闭连接。服务端发送<code>ACK=1 seq=u+1 ack=v+1 </code></p>
</li>
</ol>
<p><strong>TIME_WAIT 的两个核心作用</strong></p>
<ol>
<li>确保最后一个 ACK 能被服务器接收</li>
</ol>
<ul>
<li><p>如果服务器没收到 ACK,会重发 FIN</p>
</li>
<li><p>客户端在 TIME_WAIT 状态仍能正确响应</p>
</li>
</ul>
<ol start="2">
<li>防止旧连接的报文污染新连接</li>
</ol>
<ul>
<li><p>等待网络中所有“旧报文”自然消失</p>
</li>
<li><p>时间长度 = <strong>2 × MSL(最大报文生存时间)</strong></p>
</li>
</ul>
<p><strong>总结:</strong></p>
<p>TCP 四次挥手用于可靠地释放连接。由于 TCP 是全双工协议,连接的两个方向需要分别关闭。<br>主动关闭方首先发送 FIN 表示不再发送数据;被动关闭方回复 ACK 确认;待其数据发送完毕后再发送 FIN;最后主动关闭方发送 ACK 确认。<br>主动关闭方进入 TIME_WAIT 状态,以确保连接可靠关闭并防止旧报文干扰新连接。</p>
<h2 id="浏览器输入url后发生了什么"><a href="#浏览器输入url后发生了什么" class="headerlink" title="浏览器输入url后发生了什么"></a>浏览器输入url后发生了什么</h2><h3 id="URL-统一资源定位符"><a href="#URL-统一资源定位符" class="headerlink" title="URL(统一资源定位符)"></a>URL(统一资源定位符)</h3><p><code>http:</code>:访问协议</p>
<p><code>www.server.com</code>:服务器名称/域名</p>
<p><code>/dir1/</code>:路径名,目录名</p>
<p><code>file1.html</code>:文件名</p>
<h3 id="DNS解析"><a href="#DNS解析" class="headerlink" title="DNS解析"></a>DNS解析</h3><p>DNS将IP地址与域名进行映射,便于用户记忆和访问.</p>
<p>浏览器自身DNS->操作系统DNS->本地host文件->向域名服务器发送请求</p>
<p><strong>过程:</strong></p>
<ol>
<li><p>请求发起后浏览器首先会解析这个域名,首先查看本地硬盘的hosts文件,查看是否存在这个域名对应的规则,如果有的话,就直接使用hosts文件里面的IP地址</p>
</li>
<li><p>如果在本地的hosts文件中没有找到对应的IP地址,浏览器会发出一个DNS请求到本地DNS服务器,本地DNS服务器一般由ISP(网络接入服务商)提供。</p>
</li>
<li><p>查询你输入的网址的DNS请求到达本地DNS服务器后,本地DNS服务器会首先查询它的缓存记录,如果缓存命中则直接返回结果,此过程是递归方式进行查询,如果没有,本地服务器还需要向DNS根服务器进行查询。</p>
</li>
<li><p>根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器可以到域服务器上继续查询,并给出域服务器的地址,这个过程是迭代的过程。</p>
</li>
</ol>
<blockquote>
<p>一、核心概念:什么是 OPTIONS 请求?<br><code>OPTIONS 是 HTTP 的一种请求方法,用于获取服务器支持的通信选项。</code></p>
<p>在浏览器 <strong>CORS(跨域资源共享)</strong> 场景中,OPTIONS 被用作 “预检请求”(Preflight Request)</p>
<p>预检请求的目的是为了确保实际请求对目标服务器是安全的,发送预请求可以得知服务器是否允许跨域请求以及运行那些字段和HTTP方法。<br>二、两种 CORS 请求类型</p>
<hr>
<table>
<thead>
<tr>
<th>类型</th>
<th>英文</th>
</tr>
</thead>
<tbody><tr>
<td><strong>简单请求</strong></td>
<td>Simple Request</td>
</tr>
<tr>
<td><strong>复杂请求</strong></td>
<td>Complex Request / Preflighted Request</td>
</tr>
</tbody></table>
<h2 id="三、简单请求的判定标准(必须同时满足)"><a href="#三、简单请求的判定标准(必须同时满足)" class="headerlink" title="三、简单请求的判定标准(必须同时满足)"></a>三、简单请求的判定标准(<strong>必须同时满足</strong>)</h2><ol>
<li>方法限制</li>
</ol>
<p>只能是以下之一:</p>
<ul>
<li><p><code>GET</code></p>
</li>
<li><p><code>HEAD</code></p>
</li>
<li><p><code>POST</code></p>
<ol start="2">
<li>头部限制</li>
</ol>
</li>
</ul>
<p>只能包含 <strong>CORS 安全列出的头部</strong>:</p>
<ul>
<li><p><code>Accept</code></p>
</li>
<li><p><code>Accept-Language</code></p>
</li>
<li><p><code>Content-Language</code></p>
</li>
<li><p><code>Content-Type</code>(但值受限,见下)</p>
</li>
</ul>
<ol start="3">
<li>Content-Type 限制(如果是 POST)</li>
</ol>
<p>只能是:</p>
<ul>
<li><p><code>application/x-www-form-urlencoded</code></p>
</li>
<li><p><code>multipart/form-data</code></p>
</li>
<li><p><code>text/plain</code></p>
</li>
</ul>
<ol start="4">
<li>无自定义头部</li>
</ol>
<p>不能添加如 <code>X-Custom-Header</code>、<code>Authorization</code> 等自定义头部</p>
<ol start="5">
<li>无 ReadableStream 对象</li>
</ol>
<p>请求中不能使用 <code>ReadableStream</code></p>
<p>普通表单提交、简单的 GET 请求<br>四、复杂请求(触发预检的场景)</p>
<hr>
<p>只要 <strong>违反上述任一条件</strong>,就是复杂请求:</p>
<table>
<thead>
<tr>
<th>场景</th>
<th>示例</th>
</tr>
</thead>
<tbody><tr>
<td>使用非简单方法</td>
<td><code>PUT</code>、<code>DELETE</code>、<code>PATCH</code></td>
</tr>
<tr>
<td>发送 JSON 数据</td>
<td><code>Content-Type: application/json</code></td>
</tr>
<tr>
<td>携带自定义头部</td>
<td><code>Authorization: Bearer token</code></td>
</tr>
<tr>
<td>使用特殊头部</td>
<td><code>X-Requested-With</code> 等</td>
</tr>
</tbody></table>
</blockquote>
<h3 id="协商缓存"><a href="#协商缓存" class="headerlink" title="协商缓存"></a>协商缓存</h3><h4 id="强制缓存"><a href="#强制缓存" class="headerlink" title="强制缓存"></a>强制缓存</h4><p><strong>浏览器强制缓存服务端提供的资源</strong></p>
<p>通过配置响应头的<code>cache-control</code>字段的<code>max-age</code>和<code>Expires</code>字段来决定</p>
<table>
<thead>
<tr>
<th>头部</th>
<th>语法</th>
<th>特点</th>
<th>状态码</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Expires</strong></td>
<td><code>Expires: Wed, 21 Oct 2026 07:28:00 GMT</code></td>
<td>HTTP/1.0 产物,绝对时间,受本地时间影响</td>
<td>200 (from disk cache)</td>
</tr>
<tr>
<td><strong>Cache-Control</strong></td>
<td><code>Cache-Control: max-age=31536000</code></td>
<td>HTTP/1.1 标准,相对时间(秒),更可靠</td>
<td>200 (from memory/disk cache)</td>
</tr>
</tbody></table>
<h4 id="协商缓存-1"><a href="#协商缓存-1" class="headerlink" title="协商缓存"></a>协商缓存</h4><p>当服务端发现资源最后修改时间<code>Last-Modified</code>和<code>If-modified-since</code>值相等,代表资源从该时间后再未改变过。</p>
<p>服务端于是返回304(Not Modified)状态码,表示资源没有改变,并且响应体为空。浏览器拿到后,就知道原本可能过期的缓存其实还可以继续使用。</p>
<p>如果资源改变了,就会返回200,且响应体带上最新资源。Etag 的值没有规定一般是文件hash,当然你也可以设置版本号之类的去对比 </p>
<p>E-Tag一般规定为文件hash,也可以设置版本号。</p>
<table>
<thead>
<tr>
<th>头部</th>
<th>语法</th>
<th>验证方式</th>
<th>精度</th>
<th>状态码</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Last-Modified</strong></td>
<td><code>Last-Modified: Tue, 15 Nov 2024 12:45:26 GMT</code></td>
<td>对比修改时间</td>
<td>秒级</td>
<td>304 / 200</td>
</tr>
<tr>
<td><strong>ETag</strong></td>
<td><code>ETag: "33a64df5-8d5c-4c7a-9c3f-2e1b8d6f5a4c"</code></td>
<td>对比内容指纹(哈希)</td>
<td>毫秒级</td>
<td>304 / 200</td>
</tr>
</tbody></table>
<h4 id="缓存规则"><a href="#缓存规则" class="headerlink" title="缓存规则"></a>缓存规则</h4><p> 先强制,后协商;<br> 强制不过期,直接本地拿;<br> 强制过期问服务器,ETag 优先来比对;<br> ETag 相同 304,不同就下新资源。</p>
<h3 id="HTML渲染"><a href="#HTML渲染" class="headerlink" title="HTML渲染"></a>HTML渲染</h3><ol>
<li><p>HTML解析器把超文本和标签通过AST解析为DOM树</p>
</li>
<li><p>把CSS样式表转化为浏览器可以理解的styleSheet,属性值标准化,再处理集成和层叠,成为CSSOM的构建过程计算出DOM节点的样式</p>
</li>
</ol>
<h3 id="回流与重绘"><a href="#回流与重绘" class="headerlink" title="回流与重绘"></a>回流与重绘</h3><p>当<code>Render Tree</code>z中部分或全部元素的尺寸、结构或某些属性发生改变的时候,浏览器重新渲染部分或全部文档的过程称之为<strong>回流</strong>。</p>
<h4 id="触发回流的操作"><a href="#触发回流的操作" class="headerlink" title="触发回流的操作"></a>触发回流的操作</h4><ul>
<li><p>页面首次渲染</p>
</li>
<li><p>浏览器窗口大小发生改变</p>
</li>
<li><p>元素尺寸或位置发生改变</p>
</li>
<li><p>元素内容变化</p>
</li>
<li><p>元素字体大小变化</p>
</li>
<li><p>添加或删除可见的DOM元素</p>
</li>
<li><p>激活CSS伪类</p>
</li>
<li><p>查询某些属性或调用方法</p>
</li>
</ul>
<p>常用且会导致回流的属性和方法:</p>
<p>会导致回流的属性和方法</p>
<ul>
<li><p><code>clientWidth/Height/Top/Left</code>:元素的<strong>可视区域尺寸</strong></p>
</li>
<li><p><code>offsetWidth/Height/Top/Left</code>:元素的<strong>完整尺寸</strong></p>
</li>
<li><p><code>scrollWidth/Height/Top/Left</code>:元素的<strong>实际内容尺寸</strong>(包括由于溢出而不可见的部分)</p>
</li>
<li><p><code>scrollIntoView()</code>:将元素滚动到视口中使其可见</p>
</li>
<li><p><code>scrollIntoViewIfNeeded()</code>:非标准方法(仅WebKit/Blink支持)</p>
</li>
<li><p><code>getComputedStyle()</code>:返回元素的所有CSS属性的计算值</p>
</li>
<li><p><code>getBoundingClientRect()</code>:返回元素的大小及其相对于视口的位置,返回一个包含<code>left</code>, <code>top</code>, <code>right</code>, <code>bottom</code>, <code>width</code>, <code>height</code>的DOMRect对象</p>
</li>
<li><p><code>scrollTo()</code>:将元素或窗口滚动到指定位置</p>
</li>
</ul>
<h4 id="触发重绘的操作"><a href="#触发重绘的操作" class="headerlink" title="触发重绘的操作"></a>触发重绘的操作</h4><p>当页面中元素样式的改变并不影响它在文档流中的位置时<code>color</code>,<code>background-color</code>,<code>visibility</code>等</p>
<h4 id="为什么transform-opacity不触发回流"><a href="#为什么transform-opacity不触发回流" class="headerlink" title="为什么transform/opacity不触发回流"></a>为什么<code>transform/opacity</code>不触发回流</h4><ul>
<li><p><strong>回流/重排(Reflow)</strong>: 发生在布局阶段</p>
</li>
<li><p><strong>重绘(Repaint)</strong>: 发生在绘制阶段</p>
</li>
<li><p><strong>合成(Composite)</strong>: 发生在合成阶段</p>
</li>
</ul>
<p>浏览器会为这些属性创建独立的<strong>合成层</strong>:</p>
<ul>
<li><p>元素被提升到自己的图层(layer)</p>
</li>
<li><p>图层由GPU直接处理,不依赖CPU的布局计算</p>
</li>
<li><p>图层可以独立于其他图层进行变换</p>
</li>
</ul>
<p>浏览器自动创建合成层的情况:</p>
<ul>
<li><p>3D/透视变换(perspective, transform3d)</p>
</li>
<li><p>使用will-change: transform/opacity</p>
</li>
<li><p>视频、canvas、iframe元素</p>
</li>
<li><p>有3D上下文或加速2D上下文的canvas</p>
</li>
<li><p>具有opacity动画的过渡元素</p>
</li>
</ul>
<h4 id="如何避免回流"><a href="#如何避免回流" class="headerlink" title="如何避免回流"></a>如何避免回流</h4><p>1. <strong>开发阶段原则</strong></p>
<ul>
<li><p>优先使用CSS动画而非JavaScript动画</p>
</li>
<li><p>使用transform/opacity实现视觉变化</p>
</li>
<li><p>避免直接操作内联样式</p>
</li>
<li><p>批量读取和写入DOM属性</p>
</li>
<li><p><code>requestAnimationFrame()</code>将DOM操作安排在浏览器重绘之前</p>
</li>
</ul>
<p>2. <strong>架构设计原则</strong></p>
<ul>
<li><p>实现虚拟列表/无限滚动</p>
</li>
<li><p>采用组件懒加载</p>
</li>
<li><p>实现代码分割和按需加载</p>
</li>
</ul>
<h2 id="CDN"><a href="#CDN" class="headerlink" title="CDN"></a>CDN</h2><p>如果配置了CDN,DNS会将最终的域名解析权交给CNAME(别名指向)指向的CDN专用DNS服务器。</p>
<h2 id="浏览器跨域"><a href="#浏览器跨域" class="headerlink" title="浏览器跨域"></a>浏览器跨域</h2><h3 id="为什么会有跨域"><a href="#为什么会有跨域" class="headerlink" title="为什么会有跨域?"></a>为什么会有跨域?</h3><p><strong>同源策略:</strong> 相同网址的请求,其协议、域名、端口都应该相同,否则均属于跨域。</p>
<p>1. <strong>防止跨站脚本攻击(XSS)</strong></p>
<p>如果没有同源策略,恶意网站可以:</p>
<ul>
<li><p>通过iframe加载银行网站</p>
</li>
<li><p>使用JavaScript读取银行页面的DOM内容</p>
</li>
<li><p>窃取用户的登录凭证、账户信息</p>
</li>
</ul>
<p>2. <strong>防止跨站请求伪造(CSRF)</strong></p>
<p>同源策略限制了<strong>跨域读取响应</strong>,使得CSRF攻击虽然能发送请求,但攻击者无法读取响应内容。</p>
<p>3. <strong>保护用户会话状态</strong></p>
<ul>
<li><p>浏览器为每个源维护独立的cookie存储</p>
</li>
<li><p>防止恶意网站读取或修改其他网站的cookie</p>
</li>
<li><p>确保会话隔离,用户在不同网站的登录状态互不干扰</p>
</li>
</ul>
<p>4. <strong>防止恶意数据窃取</strong></p>
<ul>
<li><p>阻止恶意网站读取其他网站的本地存储(localStorage、sessionStorage)</p>
</li>
<li><p>防止IndexedDB等客户端数据库被跨域访问</p>
</li>
<li><p>保护用户的浏览历史、缓存等敏感信息</p>
</li>
</ul>
<h3 id="跨域解决方案"><a href="#跨域解决方案" class="headerlink" title="跨域解决方案"></a>跨域解决方案</h3><h4 id="前后端协商JSONP"><a href="#前后端协商JSONP" class="headerlink" title="前后端协商JSONP"></a>前后端协商JSONP</h4><p><strong>原理:</strong> Script标签的src不受同源策略的限制,可以跨域访问请求数据,但只能发送get请求</p>
<p><strong>缺点:</strong> 只能发送GET请求,不安全,不容易维护</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">html</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">head</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"CORS"</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">head</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">body</span>></span><br><br> <span class="hljs-tag"></<span class="hljs-name">body</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="language-javascript"></span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> <span class="hljs-title function_">jsonp</span> = (<span class="hljs-params">name</span>) =>{</span><br><span class="language-javascript"> <span class="hljs-keyword">let</span> script = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">'script'</span>);</span><br><span class="language-javascript"> script.<span class="hljs-property">src</span> = <span class="hljs-string">`http://localhost:3000/jsonp?callback=<span class="hljs-subst">${name}</span>`</span>;</span><br><span class="language-javascript"> <span class="hljs-variable language_">document</span>.<span class="hljs-property">body</span>.<span class="hljs-title function_">appendChild</span>(script);</span><br><span class="language-javascript"> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>)=></span>{</span><br><span class="language-javascript"> <span class="hljs-variable language_">window</span>[name] = <span class="hljs-function">(<span class="hljs-params">data</span>) =></span>{</span><br><span class="language-javascript"> <span class="hljs-title function_">resolve</span>(data)</span><br><span class="language-javascript"> }</span><br><span class="language-javascript"> })</span><br><span class="language-javascript"> }</span><br><span class="language-javascript"> <span class="hljs-title function_">jsonp</span>(<span class="hljs-string">`callback<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime()}</span>`</span>).<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">data</span>=></span>{</span><br><span class="language-javascript"> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(data);</span><br><span class="language-javascript"> })</span><br><span class="language-javascript"> </span><span class="hljs-tag"></<span class="hljs-name">script</span>></span><br><span class="hljs-tag"></<span class="hljs-name">html</span>></span><br></code></pre></td></tr></table></figure>
<p><strong>后端:</strong></p>
<figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span><span class="hljs-string">'express'</span><br><br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'/jsonp'</span>,<span class="hljs-function">(<span class="hljs-params">req,res</span>)=></span>{<br> <span class="hljs-keyword">const</span> {callback} = req.<span class="hljs-property">query</span><br><br> res.<span class="hljs-title function_">send</span>(<span class="hljs-string">`<span class="hljs-subst">${callback}</span>(<span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify({message:<span class="hljs-string">'Hello, JSONP!'</span>})}</span>)`</span>)<br><br>})<br><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">3000</span>,<span class="hljs-function">()=></span>{<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'JSONP server running on http://localhost:3000'</span>)})<br><br></code></pre></td></tr></table></figure>
<h4 id="前端代理"><a href="#前端代理" class="headerlink" title="前端代理"></a>前端代理</h4><p>使用Vite,Webpac配置Proxy</p>
<figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-comment">// vite.config.ts</span><br><br><br><span class="hljs-keyword">import</span> {defineConfig} <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span><br><br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title function_">defineConfig</span>({<br> <span class="hljs-attr">server</span>:{<br> <span class="hljs-attr">proxy</span>:{<br> <span class="hljs-string">'/api'</span>:{<br> <span class="hljs-attr">target</span>:<span class="hljs-string">'http://localhost:3000'</span>,<br> <span class="hljs-attr">changeOrigin</span>:<span class="hljs-literal">true</span>,<br> <span class="hljs-comment">// rewrite...</span><br>}<br>}<br>}<br>})<br></code></pre></td></tr></table></figure>
<h4 id="后端配置请求头"><a href="#后端配置请求头" class="headerlink" title="后端配置请求头"></a>后端配置请求头</h4><ol>
<li><p><strong>Access-Control-Allow-Origin</strong>:控制哪些源可以访问</p>
</li>
<li><p><strong>Access-Control-Allow-Credentials</strong>:是否允许携带凭证</p>
</li>
<li><p><strong>Access-Control-Allow-Methods</strong>:允许的HTTP方法</p>
</li>
<li><p><strong>Access-Control-Allow-Headers</strong>:允许的请求头</p>
</li>
</ol>
<figure class="highlight ts"><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><code class="hljs ts"><br>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'api/json'</span>,<span class="hljs-function">(<span class="hljs-params">res,req</span>)=></span>{<br> res.<span class="hljs-title function_">setHeader</span>(<span class="hljs-string">'Access-Control-Allow-Origin'</span>,<span class="hljs-string">"*"</span>);<br>})<br></code></pre></td></tr></table></figure>
<h4 id="Nginx"><a href="#Nginx" class="headerlink" title="Nginx"></a>Nginx</h4><p>配置Nginx</p>
<figure class="highlight nginx"><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><code class="hljs nginx"><span class="hljs-section">location</span> /api {<br> <span class="hljs-attribute">proxy_pass</span> http://127.0.0.1:3000;<br>}<br></code></pre></td></tr></table></figure>
<h2 id="AJAX"><a href="#AJAX" class="headerlink" title="AJAX"></a>AJAX</h2><p>Ajax(Asynchronous JavaScript And XML)即异步 JavaScript 和 XML,是一组用于在网页上进行异步数据交换的Web开发技术,可以在不刷新整个页面的情况下向服务器发起请求并获取数据,然后将数据插入到网页中的某个位置。这种技术能够实现增量式更新页面,提高用户交互体验,减少响应时间和带宽的消耗。</p>
<p>使用 Ajax 技术,可以通过 JavaScript 和 XMLHttpRequest 对象来向服务器获取数据。在Ajax请求的过程中,可以通过定义回调函数来对请求的结果进行处理,回调函数会在请求完成后执行,通过这种方式可以更新页面内容或者响应用户操作。</p>
<h3 id="GET请求"><a href="#GET请求" class="headerlink" title="GET请求"></a>GET请求</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">html</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">head</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"CORS"</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">head</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">body</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"btn"</span>></span>AJAX GET<span class="hljs-tag"></<span class="hljs-name">button</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"updatedP"</span>></span> It should update.<span class="hljs-tag"></<span class="hljs-name">p</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">body</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="language-javascript"></span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> btn = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'btn'</span>);</span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> <span class="hljs-title function_">sendAjax</span> = (<span class="hljs-params"></span>) =>{</span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> xhr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">XMLHttpRequest</span>();</span><br><span class="language-javascript"> xhr.<span class="hljs-title function_">open</span>(<span class="hljs-string">'GET'</span>,<span class="hljs-string">'http://localhost:3000/api/hello'</span>,<span class="hljs-literal">true</span>);</span><br><span class="language-javascript"> xhr.<span class="hljs-property">onreadystatechange</span> = <span class="hljs-function">() =></span> {</span><br><span class="language-javascript"> <span class="hljs-keyword">if</span>(xhr.<span class="hljs-property">readyState</span> === <span class="hljs-number">4</span> && xhr.<span class="hljs-property">status</span> === <span class="hljs-number">200</span>){</span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> res = xhr.<span class="hljs-property">responseText</span>;</span><br><span class="language-javascript"> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'updatedP'</span>).<span class="hljs-property">innerText</span> = res;</span><br><span class="language-javascript"> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res);</span><br><span class="language-javascript"> }</span><br><span class="language-javascript"> }</span><br><span class="language-javascript"> xhr.<span class="hljs-title function_">send</span>(<span class="hljs-literal">null</span>);</span><br><span class="language-javascript"> }</span><br><span class="language-javascript"> btn.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>,<span class="hljs-function">()=></span>{</span><br><span class="language-javascript"> <span class="hljs-title function_">sendAjax</span>();</span><br><span class="language-javascript"> });</span><br><span class="language-javascript"></span><br><span class="language-javascript"></span><br><span class="language-javascript"> </span><span class="hljs-tag"></<span class="hljs-name">script</span>></span><br><span class="hljs-tag"></<span class="hljs-name">html</span>></span><br></code></pre></td></tr></table></figure>
<h3 id="发送POST请求"><a href="#发送POST请求" class="headerlink" title="发送POST请求"></a>发送POST请求</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> xhr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">XMLHttpRequest</span>();<br>xhr.<span class="hljs-title function_">open</span>(<span class="hljs-string">'POST'</span>, <span class="hljs-string">'http://localhost:3000/api/post'</span>)<br>xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>);<br>xhr.<span class="hljs-property">onload</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">if</span> (xhr.<span class="hljs-property">status</span> === <span class="hljs-number">200</span>) {<br> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#result'</span>).<span class="hljs-property">innerText</span> = xhr.<span class="hljs-property">responseText</span>;<br> }<br> <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Request failed. Returned status of '</span> + xhr.<span class="hljs-property">status</span>);<br> }<br>};<br>xhr.<span class="hljs-title function_">send</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({<span class="hljs-attr">name</span>: <span class="hljs-string">'zhangsan'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">18</span>}));<br><br></code></pre></td></tr></table></figure>
<h3 id="POST-请求-application-x-www-form-urlencoded"><a href="#POST-请求-application-x-www-form-urlencoded" class="headerlink" title="POST 请求 application/x-www-form-urlencoded"></a>POST 请求 application/x-www-form-urlencoded</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> xhr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">XMLHttpRequest</span>();<br>xhr.<span class="hljs-title function_">open</span>(<span class="hljs-string">'POST'</span>, <span class="hljs-string">'http://localhost:3000/api/post'</span>)<br>xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/x-www-form-urlencoded'</span>);<br>xhr.<span class="hljs-property">onload</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">if</span> (xhr.<span class="hljs-property">status</span> === <span class="hljs-number">200</span>) {<br> <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#result'</span>).<span class="hljs-property">innerText</span> = xhr.<span class="hljs-property">responseText</span>;<br> }<br> <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Request failed. Returned status of '</span> + xhr.<span class="hljs-property">status</span>);<br> }<br>};<br>xhr.<span class="hljs-title function_">send</span>(<span class="hljs-string">'name=zhangsan&age=18'</span>);<br><br></code></pre></td></tr></table></figure>
<h3 id="中断请求-和-设置超时时间"><a href="#中断请求-和-设置超时时间" class="headerlink" title="中断请求 和 设置超时时间"></a>中断请求 和 设置超时时间</h3><p>中断请求只需要调用 <code>xhr.abort()</code>; 即可并且会有一个中断的回调。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">xhr.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'abort'</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'我被中断了'</span>); });<br></code></pre></td></tr></table></figure>
<p>超时时间可以设置timeout 参数</p>
<p>xhr.timeout = 3000;</p>
<p>同样有一个超时回调</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">xhr.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'timeout'</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'超时啦'</span>); });<br></code></pre></td></tr></table></figure>
<h3 id="获取进度"><a href="#获取进度" class="headerlink" title="获取进度"></a>获取进度</h3><p>可以监听 progress</p>
<p>在监听器中,我们通过 event.loaded 和 event.total 属性获取已上传数据量和总数据量,并计算上传进度,最后将进度显示在页面上</p>
<h2 id="Fetch-API"><a href="#Fetch-API" class="headerlink" title="Fetch API"></a>Fetch API</h2><p>为什么使用<code>Fetch</code>:</p>
<ul>
<li><p>代码更简单</p>
</li>
<li><p>可维护性好</p>
</li>
</ul>
<h3 id="GET请求-1"><a href="#GET请求-1" class="headerlink" title="GET请求"></a>GET请求</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">html</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">head</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"CORS"</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">head</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">body</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"btn"</span>></span>AJAX GET<span class="hljs-tag"></<span class="hljs-name">button</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"updatedP"</span>></span> It should update.<span class="hljs-tag"></<span class="hljs-name">p</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">body</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="language-javascript"></span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> btn = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'btn'</span>);</span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> <span class="hljs-title function_">sendfetch</span> = (<span class="hljs-params"></span>) =>{</span><br><span class="language-javascript"> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'http://localhost:3000/api/hello'</span>)</span><br><span class="language-javascript"> <span class="hljs-comment">//指定返回方式</span></span><br><span class="language-javascript"> .<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">res</span>=></span>res.<span class="hljs-title function_">text</span>())</span><br><span class="language-javascript"> .<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">data</span>=></span>{</span><br><span class="language-javascript"> <span class="hljs-keyword">const</span> p = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'updatedP'</span>);</span><br><span class="language-javascript"> p.<span class="hljs-property">innerText</span> = data;</span><br><span class="language-javascript"> })</span><br><span class="language-javascript"> }</span><br><span class="language-javascript"> btn.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>,<span class="hljs-function">()=></span>{</span><br><span class="language-javascript"> <span class="hljs-title function_">sendfetch</span>();</span><br><span class="language-javascript"> });</span><br><span class="language-javascript"></span><br><span class="language-javascript"></span><br><span class="language-javascript"> </span><span class="hljs-tag"></<span class="hljs-name">script</span>></span><br><span class="hljs-tag"></<span class="hljs-name">html</span>></span><br></code></pre></td></tr></table></figure>
<h3 id="POST请求"><a href="#POST请求" class="headerlink" title="POST请求"></a>POST请求</h3><figure class="highlight js"><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><code class="hljs js"><br><span class="hljs-title function_">fetch</span>(<span class="hljs-string">'http://localhost:3000/api/post'</span>,{<br> <span class="hljs-attr">method</span>:<span class="hljs-string">'POST'</span>,<br> <span class="hljs-attr">headers</span>:{<br> <span class="hljs-string">'Content-Type'</span>:<span class="hljs-string">'application/json'</span><br> },<br> <span class="hljs-attr">body</span>:<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({<br> <span class="hljs-attr">name</span>:<span class="hljs-string">'zhangsan'</span>,<br> <span class="hljs-attr">age</span>:<span class="hljs-number">18</span><br> })<br>}).<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">res</span> =></span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res);<br> <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">json</span>()<br>}).<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">res</span> =></span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res);<br>})<br><br></code></pre></td></tr></table></figure>
<h3 id="中断请求"><a href="#中断请求" class="headerlink" title="中断请求"></a>中断请求</h3><p>使用 <code>AbortController</code> 的 <code>abort</code>方法中断</p>
<figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> abort = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AbortController</span>()<br><span class="hljs-title function_">fetch</span>(<span class="hljs-string">'http://localhost:3000/api/post'</span>,{<br> <span class="hljs-attr">method</span>:<span class="hljs-string">'POST'</span>,<br> <span class="hljs-attr">headers</span>:{<br> <span class="hljs-string">'Content-Type'</span>:<span class="hljs-string">'application/json'</span><br> },<br> <span class="hljs-attr">signal</span>:abort.<span class="hljs-property">signal</span>,<br> <span class="hljs-attr">body</span>:<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({<br> <span class="hljs-attr">name</span>:<span class="hljs-string">'zhangsan'</span>,<br> <span class="hljs-attr">age</span>:<span class="hljs-number">18</span><br> })<br>}).<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">res</span> =></span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res);<br> <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">json</span>()<br>}).<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">res</span> =></span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(res);<br>})<br><br><span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#stop'</span>).<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =></span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'stop'</span>);<br> abort.<span class="hljs-title function_">abort</span>()<br>})<br><br></code></pre></td></tr></table></figure>
<h3 id="获取进度-1"><a href="#获取进度-1" class="headerlink" title="获取进度"></a>获取进度</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs js"><br><span class="hljs-keyword">const</span> btn = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#send'</span>)<br><span class="hljs-keyword">const</span> <span class="hljs-title function_">sendFetch</span> = <span class="hljs-keyword">async</span> (<span class="hljs-params"></span>) => {<br> <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'http://localhost:3000/api/txt'</span>,{<br> <span class="hljs-attr">signal</span>:abort.<span class="hljs-property">signal</span><br> })<br> <span class="hljs-comment">//fetch 实现进度条</span><br> <span class="hljs-keyword">const</span> response = data.<span class="hljs-title function_">clone</span>()<br> <span class="hljs-keyword">const</span> reader = data.<span class="hljs-property">body</span>.<span class="hljs-title function_">getReader</span>()<br> <span class="hljs-keyword">const</span> contentLength = data.<span class="hljs-property">headers</span>.<span class="hljs-title function_">get</span>(<span class="hljs-string">'Content-Length'</span>)<br> <span class="hljs-keyword">let</span> loaded = <span class="hljs-number">0</span><br> <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {<br> <span class="hljs-keyword">const</span> { done, value } = <span class="hljs-keyword">await</span> reader.<span class="hljs-title function_">read</span>()<br> <span class="hljs-keyword">if</span> (done) {<br> <span class="hljs-keyword">break</span><br> }<br> loaded += value?.<span class="hljs-property">length</span> || <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">const</span> progress = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'#progress'</span>)<br> progress.<span class="hljs-property">innerHTML</span> = (loaded / contentLength * <span class="hljs-number">100</span>).<span class="hljs-title function_">toFixed</span>(<span class="hljs-number">2</span>) + <span class="hljs-string">'%'</span><br> }<br> <span class="hljs-keyword">const</span> text = <span class="hljs-keyword">await</span> response.<span class="hljs-title function_">text</span>()<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(text);<br>}<br>btn.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>, sendFetch)<br><br></code></pre></td></tr></table></figure>
<h3 id="携带Cookie"><a href="#携带Cookie" class="headerlink" title="携带Cookie"></a>携带Cookie</h3><p>设置 <code>credentials:'include'</code></p>
<h2 id="SSE"><a href="#SSE" class="headerlink" title="SSE"></a>SSE</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>SSE(Server-Sent Events)是一种用于实现服务器主动向客户端推送数据的技术,也被称为“事件流”(Event Stream)。它基于 HTTP 协议,利用了其长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。</p>
<h3 id="SSE与WS的区别"><a href="#SSE与WS的区别" class="headerlink" title="SSE与WS的区别"></a>SSE与WS的区别</h3><p>SSE(Server-Sent Events)和 WebSocket 都是实现服务器向客户端实时推送数据的技术,但它们在某些方面还是有一定的区别。</p>
<ol>
<li>技术实现</li>
</ol>
<p>SSE 基于 HTTP 协议,利用了其长连接特性,通过浏览器向服务器发送一个 HTTP 请求,建立一条持久化的连接。而 WebSocket 则是通过特殊的升级协议(HTTP/1.1 Upgrade 或者 HTTP/2)建立新的 TCP 连接,与传统 HTTP 连接不同。</p>
<ol start="2">
<li>数据格式</li>
</ol>
<p>SSE 可以传输文本和二进制格式的数据,但只支持单向数据流,即只能由服务器向客户端推送数据。WebSocket 支持双向数据流,客户端和服务器可以互相发送消息,并且没有消息大小限制。</p>
<ol start="3">
<li>连接状态</li>
</ol>
<p>SSE 的连接状态仅有三种:已连接、连接中、已断开。连接状态是由浏览器自动维护的,客户端无法手动关闭或重新打开连接。而 WebSocket 连接的状态更灵活,可以手动打开、关闭、重连等。</p>
<ol start="4">
<li>兼容性</li>
</ol>
<p>SSE 是标准的 Web API,可以在大部分现代浏览器和移动设备上使用。但如果需要兼容老版本的浏览器(如 IE6/7/8),则需要使用 polyfill 库进行兼容。而 WebSocket 在一些老版本 Android 手机上可能存在兼容性问题,需要使用一些特殊的 API 进行处理。</p>
<ol start="5">
<li>安全性</li>
</ol>
<p>SSE 的实现比较简单,都是基于 HTTP 协议的,与普通的 Web 应用没有太大差异,因此风险相对较低。WebSocket 则需要通过额外的安全措施(如 SSL/TLS 加密)来确保数据传输的安全性,避免被窃听和篡改,否则可能会带来安全隐患。</p>
<p>总体来说,SSE 和 WebSocket 都有各自的优缺点,适用于不同的场景和需求。如果只需要服务器向客户端单向推送数据,并且应用在前端的浏览器环境中,则 SSE 是一个更加轻量级、易于实现和维护的选择。而如果需要双向传输数据、支持自定义协议、或者在更加复杂的网络环境中应用,则 WebSocket 可能更加适合。</p>
<h3 id="API"><a href="#API" class="headerlink" title="API"></a>API</h3><h4 id="EventSource构造函数"><a href="#EventSource构造函数" class="headerlink" title="EventSource构造函数"></a>EventSource构造函数</h4><p><code>EventSource</code> 的构造函数接收一个 URL 参数,通过该 URL 可以建立起与服务器的连接,并开始接收服务器发送的数据。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> eventSource = <span class="hljs-keyword">new</span> <span class="hljs-title class_">EventSource</span>(<span class="hljs-string">'/my-server'</span>);<br></code></pre></td></tr></table></figure>
<h4 id="EventSource-readyState-属性"><a href="#EventSource-readyState-属性" class="headerlink" title="EventSource.readyState 属性"></a>EventSource.readyState 属性</h4><p><code>readyState</code> 属性表示当前 <code>EventSource</code> 对象的状态,它是一个只读属性,它的值有以下几个:</p>
<ul>
<li><code>CONNECTING</code>:表示正在和服务器建立连接。</li>
<li><code>OPEN</code>:表示已经建立连接,正在接收服务器发送的数据。</li>
<li><code>CLOSED</code>:表示连接已经被关闭,无法再接收服务器发送的数据。</li>
</ul>
<h4 id="EventSource-close-方法"><a href="#EventSource-close-方法" class="headerlink" title="EventSource.close() 方法"></a>EventSource.close() 方法</h4><p><code>close()</code> 方法用于关闭 <code>EventSource</code> 对象与服务器的连接,停止接收服务器发送的数据。</p>
<h4 id="EventSource-onopen-事件"><a href="#EventSource-onopen-事件" class="headerlink" title="EventSource.onopen 事件"></a>EventSource.onopen 事件</h4><p><code>onopen</code> 事件表示 <code>EventSource</code> 对象已经和服务器建立了连接,并开始接收来自服务器的数据。当 <code>EventSource</code> 对象建立连接时,触发该事件。</p>
<p><code>eventSource.onopen = function(event) { console.log('连接成功!', event); };</code></p>
<h4 id="EventSource-onerror-事件"><a href="#EventSource-onerror-事件" class="headerlink" title="EventSource.onerror 事件"></a>EventSource.onerror 事件</h4><p><code>onerror</code> 事件表示在建立连接或接收服务器数据时发生了错误。当出现错误时,触发该事件。</p>
<p><code>eventSource.onerror = function(event) { console.log('发生错误:', event); };</code></p>
<h4 id="EventSource-onmessage-事件"><a href="#EventSource-onmessage-事件" class="headerlink" title="EventSource.onmessage 事件"></a>EventSource.onmessage 事件</h4><p><code>onmessage</code> 事件表示已经接收到服务器发送的数据,当接收到数据时,触发该事件。</p>
<p><code>eventSource.onmessage = function(event) { console.log('接收到数据:', event); };</code></p>
<p>以上就是 <code>EventSource</code> 对象的常用 API 介绍,需要注意的是,在使用 <code>EventSource</code> 对象的过程中,如果服务器没有正确地设置响应头信息(如:<code>Content-Type: text/event-stream</code>),可能会导致 <code>EventSource</code> 对象无法接收到服务器发送的数据。</p>
<h2 id="navigator-sendBeacon"><a href="#navigator-sendBeacon" class="headerlink" title="navigator.sendBeacon"></a>navigator.sendBeacon</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>在 web 开发中,我们经常需要将用户行为或性能数据上报到服务器。为了不影响用户体验,开发者通常会在页面卸载时进行数据上报。然而,传统的数据上报方式,如 <code>XMLHttpRequest</code> 或 <code>Fetch API</code>,容易受到页面卸载过程中的阻塞,导致数据丢失。为了解决这个问题,<code>navigator.sendBeacon</code> API 被引入,它可以在页面卸载时安全、可靠地发送数据。</p>
<h3 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h3><ol>
<li><p>发送心跳包,保持服务器长连接</p>
</li>
<li><p>埋点,在页面卸载或关闭时记录用户在线时间,pv uv,以及错误日志上报。</p>
</li>
<li><p>发送用户反馈,发送用户反馈信息。</p>
</li>
</ol>
<h3 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h3><ol>
<li><p>不受页面卸载过程的影响,确保数据可靠发送</p>
</li>
<li><p>异步执行,不阻塞页面关闭或跳转</p>
</li>
<li><p>能够发送跨域请求</p>
</li>
</ol>
<h3 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h3><ol>
<li><p><code>fetch</code>和<code>AJAX</code>都可以发送任意请求,<code>sendBeacon</code>只能发送POST</p>
</li>
<li><p>~可以传输任意字节,<code>sendBeacon</code>只能传输少量数据</p>
</li>
<li><p>~可以定义任意请求头,<code>sendBeacon</code>无法自定义请求头</p>
</li>
<li><p><code>sendBeacon</code>只能传输<code>ArrayBuffer</code>,<code>ArrayBufferView</code>,<code>Blob</code>,<code>DOMString</code>,<code>FormData</code>,<code>URLSearchParams</code>。</p>
</li>
<li><p>处于危险网络环境或开启广告屏蔽插件则无法使用。</p>
</li>
</ol>
<h2 id="HTTP-HTTPS"><a href="#HTTP-HTTPS" class="headerlink" title="HTTP/HTTPS"></a>HTTP/HTTPS</h2><h3 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h3><p>HTTPS,全称为HypertextTransferProtocol Secure,是一种通过加密通道传输数据的安全协议。它是HTTP协议的安全版本,用于在Web浏览器和Web服务器之间进行安全的数据传输。HTTPS在传输过程中使用了 SSL(Secure Sockets Layer)或TLS(TransportLayer Security)协议来加密数据,确保敏感信息在传输过程中不会被窃取或篡改。 </p>
<h3 id="TLS-SSL"><a href="#TLS-SSL" class="headerlink" title="TLS/SSL"></a>TLS/SSL</h3><p>TLS和SSL是用于网络通信协议的安全协议,提供了加密和认证机制,用于确保数据传输的机密性和完整性。该协议位于应用层和传输层之间</p>
<p>主要作用:</p>
<ol>
<li><p>加密通信:使用加密算法加密数据,防止第三方截获和窃听通信内容。</p>
</li>
<li><p>身份认证:提供了身份验证机制,用于确认通信双方的身份,并确保数据只发送到正确的接收方。</p>
</li>
</ol>
<p>SSL是最早实现HTTPS的协议,现已被TLS取代,TLS解决了SSL存在的安全漏洞,改进了算法。</p>
<h3 id="加密"><a href="#加密" class="headerlink" title="加密"></a>加密</h3><ol>
<li><p>对称加密:AES、DES</p>
</li>
<li><p>非对称加密:RSA DSA,公钥可以公开,私钥只能让服务端知道。</p>
</li>
</ol>
<h2 id="JWT-Json-Web-Token"><a href="#JWT-Json-Web-Token" class="headerlink" title="JWT(Json Web Token)"></a>JWT(Json Web Token)</h2><h3 id="组成"><a href="#组成" class="headerlink" title="组成"></a>组成</h3><h4 id="Header"><a href="#Header" class="headerlink" title="Header"></a>Header</h4><p>头部由两部分组成: 令牌类型和签名算法。</p>
<figure class="highlight json"><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><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"alg"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"HS256"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"typ"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"JWT"</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure>
<h4 id="Payload"><a href="#Payload" class="headerlink" title="Payload"></a>Payload</h4><p>Payload包含所要传递的信息,如用户身份、权限等</p>
<figure class="highlight perl"><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><code class="hljs perl">{<br> <span class="hljs-string">"iss"</span>:<span class="hljs-string">"example<span class="hljs-variable">@email</span>.com"</span>,<br> <span class="hljs-string">"exp"</span>: <span class="hljs-string">"..."</span><br>}<br></code></pre></td></tr></table></figure>
<h4 id="Signature"><a href="#Signature" class="headerlink" title="Signature"></a>Signature</h4><p>使用私钥对头部和负载进行加密,用于验证令牌完整性和真实性。</p>
<p><code>_Base64UrlEncode(Header) + "." + Base64UrlEncode(Payload)_</code></p>
</div>
<hr>
<div>
<div class="post-metas my-3">
<div class="post-meta mr-3 d-flex align-items-center">
<i class="iconfont icon-category"></i>
<span class="category-chains">
<span class="category-chain">
<a href="/categories/network/" class="category-chain-item">network</a>
</span>
</span>
</div>
<div class="post-meta">
<i class="iconfont icon-tags"></i>
<a href="/tags/network/" class="print-no-link">#network</a>
</div>
</div>
<div class="license-box my-3">
<div class="license-title">
<div>计算机网络沉淀心得</div>
<div>http://arkpln.github.io/3712793328.html</div>
</div>
<div class="license-meta">
<div class="license-meta-item">
<div>Author</div>
<div>FangZhou</div>
</div>
<div class="license-meta-item license-meta-date">
<div>Posted on</div>
<div>January 26, 2026</div>
</div>