之前曾经写过一篇 一文搞懂页面请求至渲染的过程 (小白版),算是把前端的网络知识梳理一遍,不过没有把相关概念详细探讨,还有一些网络概念没有记下来。希望通过这篇文章,一口气把所有重要的网络概念总结。
UDP
UDP是TCP/IP协议中传输层中其中一种常见的协议,它是面向无连接的,无状态,也就是说,它不关心到底对方有没有收到数据包,反正知道IP地址和端口号,发送就是啦。 UDP主要应用场景:
- 需要资源少,在网络情况比较好的内网,或者对于丢包不敏感的应用。
- 不需要一对一沟通,建立连接,而是可以广播的应用。
- 需要处理速度快,时延低,可以容忍少数丢包,但是要求即便网络拥塞,也毫不退缩,一往无前的时候。
例如在视频或网游中就使用UDP。
TCP
相比UDP,TCP复杂多了,因为它是面向连接的,它需要确认服务端和客户端都连接,双方的状态,要确认传输的数据包没有丢失等。放一张图描述一下包的结构:
三次握手
TCP协议中,建立连接需要 "三次握手",即 “请求 -> 应答 -> 应答之应答”。之所以不能一问一答建立连接,是因为不能保证是否真的连接,通常情况下三次基本可以确定。 基本连接过程我直接引用极客时间的趣谈网络协议:
一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。然后客户端主动发起连接 SYN,之后处于 SYN-SENT 状态。服务端收到发起的连接,返回 SYN,并且 ACK 客户端的 SYN,之后处于 SYN-RCVD 状态。客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK,之后处于 ESTABLISHED 状态,因为它一发一收成功了。服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也一发一收了
用一张图总结:
除了需要用三次握手建立连接外,TCP还需要考虑顺序性问题,由於不是每次通知对方保证一定接收到,所以需要用序号确定,客户端先生成一个序号,当服务端收到时,把它加一,作为接收序号送出,表示回应已经接收之前送来的包,与此同时自己也生成序号。
四次挥手
也用一张图概括四次挥手的过程:
为什麽是四次不是三次? 其实挥多少次手都可以,只是四次通常可以确定双方要终结连接。 另外,有可能挥手中途发生其中一方 “跑路”的情况,因此TCP协议中有MSL (Maximum Segment Lifetime),报文生存最长时间,它是指报文在网络中最长生存时间。如服务端发送报文,过了一MSL後客户端依然收不到,客户端即使後来收到,也把报文当作无效。
以上就是三次握手,四次挥手的介绍,前端基本上知道上述就足够,但不等於TCP只有上述内容。
Http
Http是应用层协议,也是前端最常接触的协议,即面试最常问的内容 (^_^)。
当客户端与服务端基於传输层建立连接後,它们通常使用Http进行通信。
Http协议格式可以直接在浏览器看到,打开 检查 -> 网络,可以看到http协议:
先看请求行的主要内容。General里的url是要访问的地址,method是访问的方法,有get,post,put,delete,通常比较常用是前两个,一个用来获取内容,另一个是提交表单,但不等於get只能获取,它也可以提交的,例如我现在用youtube听歌,url的地址是 www.youtube.com/watch?v=xaj… ,问号後面的就是我提交的内容,get提交的内容须在url显示,所以不能用来提交重要或私隐内容。
接下来看请求头,它是 键:值
来表示的,我们依然可以在浏览器看它的内容。例如,Accept-Charset,表示客户端可以接受的字符集。防止传过来的是另外的字符集,从而导致出现乱码。再如,Content-Type 是指正文的格式。例如,我们进行 POST 的请求,如果正文是 JSON,那么我们就应该将这个值设置为 JSON。
常用的http请求头及响应头,这里有篇文章总结得不错,分享一下:
http特点
一个面试常问的问题,也可以从中了解http的发展。
最初面世的版本是Http/0.9,它所包含的内容很简单,就是请求报文内容只有 1 行,为 GET 加上请求的文件路径。服务端收到请求后返回一个以 ASCII 字符流编码的 HTML 文档。
随着互联网发展,一方面传输的内容不仅是html文本,一方面是要应对的情况越来越多,所以Http/1.0誔生,其中最核心的改变是增加了头部设定,头部内容以键值对的形式设置。请求头部通过 Accept 字段来告诉服务端可以接收的文件类型,响应头部再通过 Content-Type 字段来告诉浏览器返回文件的类型。
然而Http/1.0也有些问题,就是它是一条url对应一个连接,如果页面需要依赖大量外部文件,就需要不断建立连接,而Http/1.1改进这个问题,主要实现通过在请求头新增 Connection:keep-alive,它表示当一个连接传输完成时,并不是马上进行关闭,而是继续复用它传输其他请求的数据,这个连接保持到浏览器或者服务器要求断开连接为止。
随着互联网发展,Http/2.0誔生了,通信速度比以前更快了,一方面是它把头部文件压缩了,另一方面它改为二进制数据传输。客户端在发送请求时会将每个请求的内容封装成不同的带有编号的二进制帧,然后将这些帧同时发送给服务端。服务端接收到数据之后,会将相同编号的帧合并为完整的请求信息。同样,服务端返回结果丶客户端接收结果也遵循这个帧的拆分与组合的过程。
Http/2.0的细节可以看 http2 简介
Https
Https是为了传输重要信息而生的协议。了解它之前,要先了解一些加密的知识。
加密分为对称和非对称加密。在对称加密算法中,加密和解密使用的密钥是相同的。也就是说,加密和解密使用的是同一个密钥。因此,对称加密算法要保证安全性的话,密钥要做好保密。只能让使用的人知道,不能对外公开。 在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的。一把是作为公开的公钥,另一把是作为谁都不能给的私钥。公钥加密的信息,只有私钥才能解密。私钥加密的信息,只有公钥才能解密。
对称加密因为加密和解密的密钥都一样,所以效率比较高。
即使加密了,也不能保证一定是安全。对称加密的问题是怎样才能安全把密钥传给对方; 非对称加密的问题可以想像一个情景:
一个网站把公钥公开,而私钥自己拿着,用户用公钥加密信息,这时只有拥有私钥的网站才能解密。然而,如果它要回应,它必须要用私钥才能加密,它不能用公钥,因为用户没有私钥,如果现在有黑客中途拦截信息,他可以直接用公钥打开。所以如果使用非对称通信,客户端必得要有一对公私钥,服务端可以用对方的公钥来加密,只有客户端才能解密。最大的问题是,怎样能保证对方的密钥不是假的? 因此需要第三方权威介入。
第三方权威的作用是颁发证书,从而保证不可伪造性。首先要先给权威机构证书,请求它签名。证书里面有什么呢?当然应该有公钥,这是最重要的,用来给对方加解密用,还有证书的所有者;另外还有证书的发布机构和证书的有效期。
第三方权威会用它的私钥签名,这个签名是一个不可逆的hash值,即仅凭hash值不能倒推原本的信息,最後它把证书颁发给申请者。
在传输过程中,发送的不再是公钥,而是证书,当对方收方证书时,他知道权威机构是谁,用它的公钥解密签名,从而知道信息是真的,然後用传来的公钥进行通信。
权威机构是层层背书的,即它也需要上一级签名来保证它的权威。
了解了上述概念後,基本上可以了解https的工作原理。把极客时间搬来的图来概括:
一方面通信双方互相把证书和随机数给对方,然後用双方的随机数来生成对称密钥,用它来进行通信。
缓存
看到掘金有一篇写得挺好,分享下:
跨域
另一个前端面试常问的问题。要想理解跨域,首先要理解同源。
源是由协议,主机名 (域名)和端口号组成,同源指的是两个url都是相同的协议,主机名 (域名)和端口号组成。例如:
www.lagou.com/ www.lagou.com/zhaopin/jia… 它们是同源的。如果是
www.lagou.com/ (不同的协议) www.helloworld.com/zhaopin/jia… (不同域名)
则是不同源。如果一个网站要访问不同源的资源,则称为跨域,或叫跨源更准确。 浏览器本身是有同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。同源指:协议丶域名丶端口号必须一致。但由於前端工程化,很多时候需要访问不同源的资源,所以需要用一些方法解决跨域限制。
对于浏览器请求跨域,常用的有下面 4 种方法。
跨域资源共享 (CORS)
这是常用最简单的方法。引用下拉勾教育的前端高手进阶的讲解:
跨域资源共享(CORS,Cross-Origin Resource Sharing)是浏览器为 AJAX 请求设置的一种跨域机制,让其可以在服务端允许的情况下进行跨域访问。主要通过 HTTP 响应头来告诉浏览器服务端是否允许当前域的脚本进行跨域访问。
跨域资源共享将 AJAX 请求分成了两类:简单请求和非简单请求。其中简单请求符合下面 2 个特征。
请求方法为 GET丶POST丶HEAD。
请求头只能使用下面的字段:Accept(浏览器能够接受的响应内容类型)丶Accept-Language(浏览器能够接受的自然语言列表)丶Content-Type (请求对应的类型,只限于 text/plain丶multipart/form-data丶application/x-www-form-urlencoded)丶Content-Language(浏览器希望采用的自然语言)丶Save-Data(浏览器是否希望减少数据传输量)。
任意一条要求不符合的即为非简单请求。
对于简单请求,处理流程如下:
浏览器发出简单请求的时候,会在请求头部增加一个 Origin 字段,对应的值为当前请求的源信息;
当服务端收到请求后,会根据请求头字段 Origin 做出判断后返回相应的内容。
浏览器收到响应报文后会根据响应头部字段 Access-Control-Allow-Origin 进行判断,这个字段值为服务端允许跨域请求的源,其中通配符“*”表示允许所有跨域请求。如果头部信息没有包含 Access-Control-Allow-Origin 字段或者响应的头部字段 Access-Control-Allow-Origin 不允许当前源的请求,则会抛出错误。
当处理非简单的请求时,浏览器会先发出一个预检请求(Preflight)。这个预检请求为 OPTIONS 方法,并会添加了 1 个请求头部字段 Access-Control-Request-Method,值为跨域请求所使用的请求方法。
下图是一个预检请求的请求报文和响应报文。因为添加了不属于上述简单请求的头部字段,所以浏览器在请求头部添加了 Access-Control-Request-Headers 字段,值为跨域请求添加的请求头部字段 authorization。
预检请求头部信息
在服务端收到预检请求后,除了在响应头部添加 Access-Control-Allow-Origin 字段之外,至少还会添加 Access-Control-Allow-Methods 字段来告诉浏览器服务端允许的请求方法,并返回 204 状态码。
在上面的例子中,服务端还根据浏览器的 Access-Control-Request-Headers 字段回应了一个 Access-Control-Allow-Headers 字段,来告诉浏览器服务端允许的请求头部字段。
浏览器得到预检请求响应的头部字段之后,会判断当前请求服务端是否在服务端许可范围之内,如果在则继续发送跨域请求,反之则直接报错。
JSONP
一种比较hack的方法,利用script的src没有跨域限制,进行跨域访问。方法如下:
- 首先在页面的script里添加回调函数fn:
fn(){...}
2.创建一个url,把回调函数作为参数引入:
http://hello.com?callback=fn...
- 创建script标签:
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = url;
document.body.appendChild(script);
- 服务端返回一个脚本,把url传来的参数作为回调函数的参数,里面执行回调函数:
fn({params...})
Jsonp有它的缺点:
只能发送 GET 请求,限制了参数大小和类型;
请求过程无法终止,导致弱网络下处理超时请求比较麻烦;
无法捕获服务端返回的异常信息。
WebSocket
一种应用层协议,可以进行客户端与服务端双方的通信。详情可看这篇文章:
www.html5rocks.com/en/tutorial…
代理
代理分为正向代理与反向代理,正反的方向是以客户端为基准。
正向代理有我们常见的VPN。正向代理的原理是客户端与服务端中间有一个代理服务器,客户端所有的请求都会经过它,它去向目标服务端通信,再把获取的资源返回给客户端。
而反向代理则是客户端与服务端之间有一个代理服务器,客户端一直都是与它进行通信,而不知道原始服务器,客户端与原始服务器的通信都是经过代理服务器进行。
利用反向代理,就可以解决浏览器的同源策略限制,因为服务器本身是没有同源策略限制,它可以进行跨域请求,通过同源域名映射,浏览器则认为自己在同源访问。
例如浏览器现在访问 www.helloworld.com ,当它访问至 www.helloworld.com/gg 时,服务器则把则路径映射至 www.bye.com 。