在查阅了很多所谓的博文,发现很多文章都是错的,有的甚至就是误人子弟。所以打算自己总结一下在上计算机网络这本课时候的知识点。同时尽量站在前端的角度仔细研究一下前端该掌握的东西。
网络层模型
计算机网络,其实就是学习每个层模型上的协议,明白两台计算机是如何通过网络通讯的。首先计算机网络的模型是这样子的。如下图1-18
计算机是如何进行通讯的
现实的计算机通讯是基于TCP/IP协议的,也就是上图1-18的四层网络协议,到这里,我们一定要首先明白两台计算机的通讯过程,如下图1-19
我以图1-19举个栗子,就以淘宝的买家(主机2)和卖家(主机1)举个例子吧。
首先买家会在淘宝上买东西,下单付款后,卖家就发货了。比如买了一件衣服(data)。
卖家发货的过程
1.拿出一件衣服data,数据。
2.衣服拿什么样的袋子装呢?拿一个透明色的袋子装吧(HTTP协议),然后就变成这样。【HTTP header + data】
3.我发送的衣服要买家确认签收,我才知道完成了这笔交易,所以必须是可靠的。(衣服是一套的?太大了,分开装吧)
【TCP header +【HTTP header + data】】
4.好了衣服包装好了,我需要写上地址,不然快递小哥哥不指定该送到哪里。于是
【IP header +【TCP header +【HTTP header + data】】】
5.这下真包装好了,装上车给快递小哥拿走吧,于是就变成了。
【MAC header + 【IP header +【TCP header +【HTTP header + data】】】】
6.装上车了,开车运输吧
【MAC header + 【IP header +【TCP header +【HTTP header + data】】】】
打包好的衣服就会变成很长比特流0101010111.......进行传输,发车。
买家收货的过程
买家收到货之后,就会一层层的倒着来解开快递包裹,由6-1步慢慢解开快递包裹,确认是不是自己要买的那件衣服(data)。其实所有的网络通讯,都可以看成一个买衣服的通讯过程,只是每个过程需要买的东西(数据data)不一样罢了。
模型抽象总结
我们已经知道,两台计算机之间的通讯,就和淘宝买衣服的买家和卖家一样,一个打包一个解包,直至交易确认完毕。在这个交易的过程中,其实是可以抽象出一个对等层模型解构的,我们来了解一下对等层模型结构传输的到底是什么。
应用层:
应用层是体系结构中的最高层。应用层的任务是通过应用进程间的交互来完成特定网络应用。应用层协议定义的是应用进程间通信和交互的规则。这里的进程就是主机中正在运行的程序。对于不同的网络应用需要不有不同的应用层协议。在互联网的应用层协议很多,如域名DNS,支持万维网应用的HTTP协议,支持电子邮件的SMTP协议,等等。我们把应用层的数据单元称为报文(messgae)。即PDU数据单元。
运输层:
运输层的任务就是负责向两台主机中进程之间的通信提供通用的数据传输服务。应用进程利用该服务穿上那个应用层报文。所谓通用的,是指并不针对某个特定网路应用,而是多种应用可以使用同一个运输层服务。由于一台主机可以同时运行多个进程,因此运输层有复用和分用的功能。复用就是多个应用层进程可同时使用下面运输层的服务,分用和复用相反,是运输层把收到的信息分别交付给上面应用层的相关进程。
运输层主要有下面两种协议:
- 传输控制协议TCP(Transmission Control Protocol)-提供面向连接的、可靠的数据传输服务,其数据传输的单位是报文段(segment)。
- 用户数据报协议 UDP(User Datagram)。 Protocol)-提供无连接的、尽最大努力(best-effort)的数据传输服务(不保证数据传输的可靠性),其数据传输的单位是用户数据报。
网络层:
网络层负责为分组交换网上的不同主机提供通信服务。其实给快递包裹写上地址,就是IP数据报,把有地址的快递包裹送到指定的地点。比如广东省XX市送到浙江省XX市。
数据链路层 && 物理层:
数据链路层和物理层比较底层,一般我们开发应用层的服务,都不需要接触到网络层以下的东西,只需要熟悉应用层和运输层即可。但是我们还是要了解一下数据链路层传输的是帧,将IP数据报封装成帧。而物理层传输的是比特流。
tips:可以总结为下层为上层提供服务,你想一下打包裹的过程?
HTTP
HTTP协议,是我们前端必须掌握的。HTTP是一种不保存状态,即无状态协议。HTTP协议自身不对请求和响应之间的通信状态进行保存,不做持久化处理。所以为了保存状态引入了cookie技术,后面细讲。
HTTP/0.9
HTTP 是基于 TCP/IP 协议的应用层协议。它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口。
最早版本是1991年发布的0.9版。该版本很简单,只有一个GET命令。
命令格式:GET /index.html
这个命令表示,TCP连接建立以后,客户端向服务端请求(request)网页index.html
而协议规定,服务端只能返回HTML格式的字符串,不能回应别的格式。服务器发送完毕,就关闭TCP连接。
HTTP/1.0
1996年5月,发布了1.0的版本,内容也大大的增加了,主要是以下几点。
1.任何格式的内容都可以发送了,包括传输图像、视频、二进制文件等
2.除了GET、还增加了POST、HEAD命令,丰富了浏览器和服务器的互动手段
3.其次,HTTP请求和回应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。
4.其它的新增还包括状态码、权限、缓存、内容编码等。
请求格式:
GET / HTTP/1.0
User-Agent: Mozilla/6.0 XXXX
Accept: */*
可以看到,和0.9的版本变化很大,除了第一行的请求命令以外,后面多行头信息是描述客户端的信息。
User-Agent: 客户端环境,即浏览器版本号等
Accept:*/*: 客户端可以接收的内容类型,*/*代表任何类型
响应格式:
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137481
Expires: Thu, 05 Dec 1998 16:10:10 GMT
Last-Modified: Wed, 5 August 1998 15:55:28 GMT
Server: Apache 0.88
<html>
<body>Hello HTTP</body>
</html>
响应格式的变化也很大,第一行代表“协议版本号 + 状态码 + 状态描述”。
Content-Type:text/html; charset=utf-8 就是我们常见的网页类型,这些数据类型总称为MIME type,可以在后面添加参数。
Content-Encoding:数据的压缩方式,gzip、compress、deflate,客户端在请求时,可以使用Accept-Encoding说明自己可以接收的压缩方法
缺点:
HTTP在1.0和0.9的时候,虽然1.0丰富了网页传输的内容,但是还存在一个致命的缺点,每个TCP连接只能发送一次,发送完毕后,连接就关闭了,如果还要请求其它资源,就必须重新创建连接。TCP的连接成本是非常高的,因为客户端要和服务端三次握手建立连接。
为了解决这个问题,Connection:keep-alive 就粉墨登场了。客户端设置这个字段,告诉服务器不要关闭TCP连接,以便其它请求服用。服务器同样会返回这个字段。
HTTP/1.1
1997年1月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了20年后的今天,直到现在还是最流行的版本。它针对1.0版本的优化主要有以下几个。
1.持久化连接,即TCP默认不关闭,可以被多个请求复用,不用声明Connection:keep-alive客户端或者服务端发现对方有一段时间没有活动,就可以主动关闭TCP连接,不过最好的做法是,客户端在最后一个请求加上Connection:close,主动的关闭TCP连接。
tips:目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。
2.管道机制,即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。(也叫队头阻塞)
3.Content-Length,一个TCP连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是Content-Length字段的作用,说明本次回应的数据长度,不然不知道数据有多大。
4.分块传输,使用Content-Length字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。是采用缓存的策略来完成的。这样就会出现一个情况,服务器要等到这块动态的大数据完成之后,才能继续发送数据。所以,1.1版本可以使用分块代替缓存,只要请求或回应的头信息有 Transfer-Encoding:chunked 字段,就表明回应将由数量未定的数据块组成。每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。
5.在1.1版本还增加了很多命令,PUT、PATCH、HEAD、OPTIONS、DELETE,另外客户端的请求头信息还新增了host字段,用来指定服务器域名或者主机ip。
tips:GET(获取资源)、POST(传输实体主题)、PUT(传输文件)、HEAD(获取报文首部,告知通讯状态)、DELETE(删除文件)、OPTIONS(询问支持的方法)、TRACE(追踪路径)
HTTP/1.1缺点
虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为队头拥塞(Head-of-line blocking)。
为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS代码、域名分片(domain sharding)等等。如果HTTP协议设计得更好一些,这些额外的工作是可以避免的。
HTTP/2
2015年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。我们也来看下2.0版本有哪些改进。
1.二进制协议,HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。
2.多工,HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。这种双向的实时的也叫多工。
3.数据流,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STRAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。
客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
4.头信息压缩,HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie 和 User Agent。一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip 或 compress
5.服务器推送,HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。HTTP在2.0的大版本之前,都是通过轮询的机制发送接收数据,这样的话就很考验网络环境。如果增加服务器推送,通过一定的手段知道什么时间段需要什么信息。就不用再次轮询查数据了。
HTTP/1.1 首部格式
首先要明白一点,我们前端做的优化,在运输层以下能做的事情几乎为零,也就是说只能对应用层上的协议动手脚,做优化。所以,我们很有必要完全学习一下HTTP协议的格式。
tips:直接引用网上的图吧,侵删。
HTTP通用字段:
HTTP请求头字段:
HTTP响应头字段:
HTTPS
通过抓包(我现在电脑没抓包软件了演示不了QAQ,直接网上拿一张图),我们可以很清晰的看出,HTTP协议传输的时候,完全是明文传输的。这太可怕了!!!
总结HTTP缺点:
1.通讯使用明文,不加密,容易被窃听
2.不验证对方的身份,因此有可能遭遇伪装
3.无法验证报文的完整性,所有可能已经被篡改
这时候HTTPS就登场了,什么是HTTPS呢?怎么用呢?
1.HTTPS还是通过HTTP来传输的,但是信息通过 TLS 协议进行了加密了。
2.TLS 协议位于传输层之上,应用层之下。
3.在 TLS 中使用了两种加密技术,对称加密和非对称加密。
1)对称加密:对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。
2)非对称加密:有公钥私钥之分,公钥所有人都可以知道,可以将数据用公钥加密,但是 将数据解密必须使用私钥解密,私钥只有分发公钥的一方才知道。
TLS 握手过程如下图:
- 客户端发送一个随机值,需要的协议和加密方式
- 服务端收到客户端的随机值,自己也产生一个随机值,并根据客户端需求的协议和加密方式来使用对应的方式,发送自己的证书(如果需要验证客户端证书需要说明)
- 客户端收到服务端的证书并验证是否有效,验证通过会再生成一个随机值,通过服务端证书的公钥去加密这个随机值并发送给服务端,如果服务端需要验证客户端证书的话会附带证书
- 服务端收到加密过的随机值并使用私钥解密获得第三个随机值,这时候两端都拥有了三个随机值,可以通过这三个随机值按照之前约定的加密方式生成密钥,接下来的通信就可以通过该密钥来加密解密
通过以上步骤可知,在 TLS 握手阶段,两端使用非对称加密的方式来通信,但是因为非对称加密损耗的性能比对称加密大,所以在正式传输数据时,两端使用对称加密的方式通信。
tips:以上说明的都是 TLS 1.2 协议的握手情况,在 1.3 协议中,首次建立连接只需要一个 RTT,后面恢复连接不需要 RTT 了。
HTTP协议之保存状态
还有一个问题,客户端想和服务端保持状态,常应用的场景就是保持登陆状态,避免频繁的重复登陆,最早的做法就是使用Cookie。Cookie会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie,当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值后发送出去。服务器端根据客户端发过来的cookie对比服务器上的记录,最后得到之前的状态信息。即:
- 请求报文(没有Cookie信息的状态);
- 响应报文(服务端生成Cookie信息);
- 请求报文(自动发送保存着的Cookie信息)。
Cookie属性
NAME=VALUE(赋予Cookie的名称和值,必须项)
expires=DATE(Cookie有效期)
path=PATH(将服务器上的文件目录作为Cookie的适用对象)
domain=域名 (作为Cookie适用对象的域名,不指定则创建Cookie服务器的域名)
Secure(仅在使用HTTPS安全通讯时才会发送Cookie)
HttpOnly(加以限制,使Cookie不能被JS脚本访问)
tips:著名的XSS攻击就是通过JS脚本盗取Cookie,设置HttpOnly也是一种有效的防御手段
因为Cookie存在被盗取的原因,后面就出现了Session ID,干脆把保存的状态放在服务器端,这样虽然更好,但是服务器的压力也就更大了,之后就延伸出token之类的验证技术,保证安全性。同时,Cookie也有大小的限制,后面再加以讨论。
HTTP协议之缓存
缓存是性能优化的重要一环,浏览器缓存机制对前端开发者是非常重要的知识点,结合HTTP分别讲清楚缓存这东西吧。
- 强缓存
- 协商缓存
- 缓存位置
强缓存
浏览器缓存分为两种情况,一种是需要发送HTTP请求的,一种是不需要发送的
首先检查强缓存的时候是不需要发送HTTP请求的。
如何来检查?通过HTTP相应的字段进行检查,但是说起这个字段,就要联系上面HTTP的发展史了。
HTTP/1.0 Expires
Expires,即过期时期,存在于服务器返回的响应头中,告诉浏览器在这个时期之前可以直接从缓存里面获取数据,无需再次请求。比如下面的
Expires: Wed, 22 Nov 2019 08:41:00 GMT
表示资源在2019年11月22号8点41分过期,过期了就得向服务器发送请求
这种方式存在一个问题,就是浏览器的时间和服务器的时间不一致,那服务器返回的这个过期时间可能就是不准确的。因此这种方式很快在后来的HTTP1.1版本中被抛弃了。
HTTP/1.1 Cache-Control
它和 Expires 本质的不同是,它没有采用时间截点,就是具体的过期时间的方式,而是采用过期时长来控制缓存,对应的字段是max-age。比如
Cache-Control:max-age=3600
代表这个响应返回后的3600秒内,也就是一个小时之内,是可以直接使用缓存的。
Cache-Control 不止 max-age一个属性,它还有更多丰富的属性。
private:这种情况就是只有浏览器能缓存了,中间的代理服务器不能缓存。
no-cache:跳过当前的强缓存,发送HTTP请求,即直接进入 协商缓存 阶段
no-store:非常粗暴,不进行任何形式的缓存。
s-maxage:这和max-age很像;但是s-maxage是针对代理服务器的缓存时间。
tips:当Expires和Cache-Control同时出现的时候,会优先使用后者。当强缓存失效之后,就进入协商缓存的阶段。
协商缓存
强缓存失效之后,浏览器在请求头中携带响应的缓存tag来向服务器发起请求,由服务器根据这个tag决定,是否使用缓存,这就是协商缓存。
具体来说,这样的缓存tag分为两种: Last-Modified 和 ETag。这两者各有优劣,并不存在谁对谁有绝对的优势,跟上面强缓存的两个 tag 不一样。
Last-Modified
即最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。
浏览器接收到后,如果再次请求,会在请求头中携带 If-Modified-Since 字段,这个字段的值也就是服务器传来的最后修改时间。
服务器拿到请求头中的 If-Modified-Since 字段后,其实会和这个服务器中 Last-Modified 对比,也就是最后的修改时间对比:
- 如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
- 否则返回304,告诉浏览器直接用缓存。
ETag
ETag是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。服务器通过响应头把这个值给浏览器。
浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。
服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:
- 如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
- 否则返回304,告诉浏览器直接用缓存。
1.在精准度上,ETag 优于 Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:
- 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
- Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。
另外,如果两种方式都支持的话,服务器会优先考虑 ETag。
缓存位置
前面我们已经提到,当强缓存命中或者协商缓存中服务器返回304的时候,我们直接从缓存中获取资源。那这些资源究竟缓存在什么位置呢?
浏览器中的缓存位置一共有四种,按优先级从高到低排列分别是:
- Service Worker
- Memory Cache
- Disk Cache
- Push Cache
Service Worker 借鉴了 Web Worker的 思路,即让 JS 运行在主线程之外,由于它脱离了浏览器的窗体,因此无法直接访问DOM。虽然如此,但它仍然能帮助我们完成很多有用的功能,比如离线缓存、消息推送和网络代理等功能。其中的离线缓存就是 Service Worker Cache。
Memory Cache 和 Disk Cache
Memory Cache是指内存,从效率上讲它是最快的,但是它的存活周期又是最短的,渲染进程结束后,就不存在了。
Disk Cache是指存储在磁盘的缓存,从存取效率上讲是比内存缓存慢的,但是他的优势在于存储容量和存储时长。稍微有些计算机基础的应该很好理解,就不展开了。
好,现在问题来了,既然两者各有优劣,那浏览器如何决定将资源放进内存还是硬盘呢?主要策略如下:
- 比较大的JS、CSS文件会直接被丢进磁盘,反之丢进内存
- 内存使用率比较高的时候,文件优先进入磁盘
Push Cache
即推送缓存,它是 HTTP/2 中的内容,虽然现在应用的并不广泛,但随着 HTTP/2 的推广,它的应用会越来越广泛。
缓存总结:
首先通过 Cache-Control 验证强缓存是否可用
- 如果强缓存可用,直接使用
- 否则进入协商缓存,即发送 HTTP 请求,服务器通过请求头中的 Last-Modified 或者ETag 字段检查资源是否更新
- 若资源更新,返回资源和200状态码
- 否则,返回304,告诉浏览器直接从缓存获取资源
前端经典面试题
在浏览器上输入URL,到页面上加载完成,都经历了些什么?我相信前端的小伙伴,十个是有九个都遇到过这道面试题的。为什么都喜欢问这道面试题呢?因为这道面试题非常的考验前端程序员的基本功,即使是1-3年经验的前端,也未必答得很好。我尝试的作答一下,重点在回答网络方面的知识。
- 首先做 DNS 查询,如何浏览器缓存有DNS对应的IP地址,则使用,否则,则会查询本机的host主机记录,如果没有,则会向上查询,直至查询得到。一般本机没有缓存对应的DNS记录的话,会向外网发起DNS解析,DNS解析使用的是UDP协议。
- 解析到DNS对应的具体IP地址后,接下来是 TCP 握手,应用层会下发数据给传输层包装,这里 TCP 协议会指明两端的端口号,然后下发给网络层包装。网络层中的 IP 协议会确定出目标 IP 地址等信息,并且指示了数据传输中该如何跳转路由器。然后包会再被封装到数据链路层的数据帧结构中,最后到物理层面转换成比特流的传输了。
- TCP 握手结束后,如果协议是HTTPS,则会进行 TLS 握手,否则就直接开始正式的传输数据。
- 数据在进入服务端之前,可能还会先经过负责负载均衡的服务器,它的作用就是将请求合理的分发到多台服务器上,这时假设服务端会响应一个 HTML 文件
- 首先浏览器会判断状态码是什么,如果是 200 那就继续解析,如果 400 或 500 的话就会报错,如果 300 的话会进行重定向,这里会有个重定向计数器,避免过多次的重定向,超过次数也会报错
- 浏览器开始解析文件,如果是 gzip 格式的话会先解压一下,然后通过文件的编码格式知道该如何去解码文件
- 文件解码成功后会正式开始渲染流程,先会根据 HTML 构建 DOM 树,有 CSS 的话会去构建 CSSOM 树。如果遇到
script
标签的话,会判断是否存在async
或者defer
,前者会并行进行下载并执行 JS,后者会先下载文件,然后等待 HTML 解析完成后顺序执行,如果以上都没有,就会阻塞住渲染流程直到 JS 执行完毕。遇到文件下载的会去下载文件,这里如果使用 HTTP 2.0 协议的话会极大的提高多图的下载效率。 - 初始的 HTML 被完全加载和解析后会触发
DOMContentLoaded
事件 - CSSOM 树和 DOM 树构建完成后会开始生成 Render 树,这一步就是确定页面元素的布局、样式等等诸多方面的东西
- 在生成 Render 树的过程中,浏览器就开始调用 GPU 绘制,合成图层,将内容显示在屏幕上了,等待用户的操作。
tips:针对这道题,还可以继续深挖扩展,堪称灵魂拷问。下面针对扩展直接给出连接。
扩展1
TCP三次握手、四次挥手是怎么样的?
为什么连接需要三次握手?断开连接需要四次挥手?
推荐学习链接:juejin.cn/post/684490…
扩展2
HTTPS的握手过程?301 和 302状态码分别代表什么?
推荐学习链接:www.muyiy.cn/question/ne…
扩展3
怎么发起一个请求?什么标签可以发起一个请求?什么是跨域?为什么会跨域?(跨域发生在浏览器端),我们来慢慢解决。
可以发送网络请求的标签有哪些?
1.location.href = 'https://www.baidu.com' (会发生页面跳转,也没办法控制代码)
2.带有href属性的标签,比如a标签。
3.form 表单的action属性。
4.带有src属性的标签。
5.AJAX,阿贾克斯,这是到目前为止,应用得最广泛的请求方式了。
即然都可以发送网络请求,那GET和POST的请求方式有什么区别?
首先,一定要知道是基于什么规范的,很多小伙伴一上来就是巴拉巴拉的一大堆,这是极其不严谨的。如果不基于任何规范,GET和POST是没有什么区别的,只是名字不一样而已。
如果是基于RFC规范的(浏览器已实现),就会有以下我们常见的区别:
1)GET的数据在URL上是可见的,POST不显示在URL中
2)GET对长度有限制(URL长度限制),POST没有
3)GET请求的数据是可以收藏为书签,POST请求的数据不可以收藏为书签
4)GET请求后,按后退按钮、刷新按钮无影响,POST数据会被重新提交
5)GET的编码类型为application/x-www-form-url,POST的编码类型有很多种
6)GET历史参数会被保留在浏览器里,POST不会保留
7)GET只允许发ASCII的编码格式,POST没有限制,允许发送二进制等
8)GET与POST相比,GET安全性较差,因为直接是url的一部分,直接可见
那跨域是什么,怎么样会导致跨域?
1.https://www.baidu.com:80,https就是协议,www.baidu.com就是域名,80是端口号。默认不写就是80
2.即使跨域了,请求也是可以发送出去的
3.服务器端也能接受到请求、正常处理请求、返回请求的数据
4.浏览器也能接受到这些数据
5.接受到数据之后,浏览器会判定当前页面的域和请求域的不同,所以才会判定为跨域
虽然跨域了,但是我们依然需要这个数据怎么办?解决跨域。
解决跨域问题分主要分为两种类型
1.后端(别人家的)配合我们进行跨域
1)JSONP(正常的情况,返回数据都是JSON格式。JSONP是一种特殊的格式)
2)后端设置Access-Control-Allow-Origin属性以支持跨域
2.后端(别人家的后端)不配合我们进行跨域
1)iframe(只能显示,不能控制)
2)通过后端代理(自己的后端,或者常用的webpack的代理)
JSONP原理
前端需要做的:
1.判断请求与当前域是不是同源的,如果是就正常发送AJAX,如果不是生成一个src的标签
2.生成一个随机的callback名字,还得创建一个名字一样的方法,想办法挂载出去,比如直接挂载在window上
3.设置标签的src属性,设置为请求的接口
4.将callback作为参数拼接在后面
后端需要做的:
5.后端接受到请求之后,开始准备返回数据
6.后端拼接数据,将要返回的数据用callback的值和括号包裹起来,
例如:callback = asd123456,要返回的数据为{“a”: 1,“b”: 2}
就要拼接为:asd123456({“a”: 1,“b”: 2});
7.将内容返回
8.浏览器接受到新内容之后,会当JS代码来执行,从而就执行了asd123456这个方法了。
CORS原理
对于cors原理,或者其他的跨域方法,我推荐直接阅读这个链接:www.conardli.top/blog/articl…
总结
未完待续,后面还会继续扩充内容。
前端爬坑不易,很多小伙伴是非科班出身的,或者半路转行的,推荐看下这篇文章:
引用:http://47.98.159.95/my_blog/perform/001.html