「查缺补漏」巩固你的HTTP知识体系

前言

此次梳理的篇幅主要是涉及网络部分,包括HTTP等,对巩固本身的网络知识体系也是颇有帮助的,进一步的对性能优化而言也是帮助很大的。html

但更多的是抛砖引玉,但愿对大家有所帮助。node

感谢掘友的鼓励与支持🌹🌹🌹,往期文章都在最后梳理出来了(●'◡'●)git

接下来就以问题的形式展开梳理👇github

谈一谈HTTP协议优缺点

超文本传输协议,HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范web

HTTP 特色

  1. 灵活可扩展。一个是语法上只规定了基本格式,空格分隔单词,换行分隔字段等。另一个就是传输形式上不只能够传输文本,还能够传输图片,视频等任意数据。
  2. 请求-应答模式,一般而言,就是一方发送消息,另一方要接受消息,或者是作出相应等。
  3. 可靠传输,HTTP是基于TCP/IP,所以把这一特性继承了下来。
  4. 无状态,这个分场景回答便可。

HTTP 缺点

  1. 无状态,有时候,须要保存信息,好比像购物系统,须要保留下顾客信息等等,另一方面,有时候,无状态也会减小网络开销,好比相似直播行业这样子等,这个仍是分场景来讲。
  2. 明文传输,即协议里的报文(主要指的是头部)不使用二进制数据,而是文本形式。这让HTTP的报文信息暴露给了外界,给攻击者带来了便利。
  3. 队头阻塞,当http开启长链接时,共用一个TCP链接,当某个请求时间过长时,其余的请求只能处于阻塞状态,这就是队头阻塞问题。

HTTP/1.0 HTTP1.1 HTTP2.0版本之间的差别

HTTP 0.9

  • 1991年,原型版本,功能简陋,只有一个命令GET,只支持纯文本内容,该版本已过期。

HTTP 1.0

  • 任何格式的内容均可以发送,这使得互联网不只能够传输文字,还能传输图像、视频、二进制等文件。
  • 除了GET命令,还引入了POST命令和HEAD命令。
  • http请求和回应的格式改变,除了数据部分,每次通讯都必须包括头信息(HTTP header),用来描述一些元数据。
  • 只使用 header 中的 If-Modified-Since 和 Expires 做为缓存失效的标准。
  • 不支持断点续传,也就是说,每次都会传送所有的页面和数据。
  • 一般每台计算机只能绑定一个 IP,因此请求消息中的 URL 并无传递主机名(hostname)

HTTP 1.1

http1.1是目前最为主流的http协议版本,从1999年发布至今,还是主流的http协议版本。面试

  • 引入了持久链接( persistent connection),即TCP链接默认不关闭,能够被多个请求复用,不用声明Connection: keep-alive。长链接的链接时长能够经过请求头中的 keep-alive 来设置
  • 引入了管道机制( pipelining),即在同一个TCP链接里,客户端能够同时发送多个 请求,进一步改进了HTTP协议的效率。
  • HTTP 1.1 中新增长了 E-tag,If-Unmodified-Since, If-Match, If-None-Match 等缓存控制标头来控制缓存失效。
  • 支持断点续传,经过使用请求头中的 Range 来实现。
  • 使用了虚拟网络,在一台物理服务器上能够存在多个虚拟主机(Multi-homed Web Servers),而且它们共享一个IP地址。
  • 新增方法:PUT、 PATCH、 OPTIONS、 DELETE。

http1.x版本问题

  • 在传输数据过程当中,全部内容都是明文,客户端和服务器端都没法验证对方的身份,没法保证数据的安全性。
  • HTTP/1.1 版本默认容许复用TCP链接,可是在同一个TCP链接里,全部数据通讯是按次序进行的,服务器一般在处理完一个回应后,才会继续去处理下一个,这样子就会形成队头阻塞。
  • http/1.x 版本支持Keep-alive,用此方案来弥补建立屡次链接产生的延迟,可是一样会给服务器带来压力,而且的话,对于单文件被不断请求的服务,Keep-alive会极大影响性能,由于它在文件被请求以后还保持了没必要要的链接很长时间。

HTTP 2.0

  • 二进制分帧 这是一次完全的二进制协议,头信息和数据体都是二进制,而且统称为"帧":头信息帧和数据帧。
  • 头部压缩 HTTP 1.1版本会出现 User-Agent、Cookie、Accept、Server、Range 等字段可能会占用几百甚至几千字节,而 Body 却常常只有几十字节,因此致使头部偏重。HTTP 2.0 使用 HPACK 算法进行压缩。
  • 多路复用 复用TCP链接,在一个链接里,客户端和浏览器均可以同时发送多个请求或回应,且不用按顺序一一对应,这样子解决了队头阻塞的问题。
  • 服务器推送 容许服务器未经请求,主动向客户端发送资源,即服务器推送。
  • 请求优先级 能够设置数据帧的优先级,让服务端先处理重要资源,优化用户体验。

谈一谈你对HTTP/2理解

头部压缩

HTTP 1.1版本会出现 User-Agent、Cookie、Accept、Server、Range 等字段可能会占用几百甚至几千字节,而 Body 却常常只有几十字节,因此致使头部偏重。算法

HTTP 2.0 使用 HPACK 算法进行压缩。跨域

那咱们看看HPACK算法吧👇数组

从上面看,咱们能够看到相似于索引表,每一个索引表对应一个值,好比索引为2对应头部中的method头部信息,这样子的话,在传输的时候,不在是传输对应的头部信息了,而是传递索引,对于以前出现过的头部信息,只须要把索引(好比1,2,...)传给对方便可,对方拿到索引查表就好了。浏览器

这种传索引的方式,能够说让请求头字段获得极大程度的精简和复用。

其次是对于整数和字符串进行哈夫曼编码,哈夫曼编码的原理就是先将全部出现的字符创建一张索引表,而后让出现次数多的字符对应的索引尽量短,传输的时候也是传输这样的索引序列,能够达到很是高的压缩率。

多路复用

HTTP 1.x 中,若是想并发多个请求,必须使用多个 TCP 连接,且浏览器为了控制资源,还会对单个域名有 6-8个的TCP连接请求限制。

HTTP2中:

  • 同域名下全部通讯都在单个链接上完成。
  • 单个链接能够承载任意数量的双向数据流。
  • 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间能够乱序发送,由于根据帧首部的流标识能够从新组装,也就是Stream ID,流标识符,有了它,接收方就能从乱序的二进制帧中选择ID相同的帧,按照顺序组装成请求/响应报文。

服务器推送

浏览器发送一个请求,服务器主动向浏览器推送与这个请求相关的资源,这样浏览器就不用发起后续请求。

相比较http/1.1的优点👇

  • 推送资源能够由不一样页面共享
  • 服务器能够按照优先级推送资源
  • 客户端能够缓存推送的资源
  • 客户端能够拒收推送过来的资源

二进制分帧

以前是明文传输,不方便计算机解析,对于回车换行符来讲究竟是内容仍是分隔符,都须要内部状态机去识别,这样子效率低,HTTP/2采用二进制格式,所有传输01串,便于机器解码。

这样子一个报文格式就被拆分为一个个二进制帧,用Headers帧存放头部字段,Data帧存放请求体数据。这样子的话,就是一堆乱序的二进制帧,它们不存在前后关系,所以不须要排队等待,解决了HTTP队头阻塞问题。

在客户端与服务器之间,双方均可以互相发送二进制帧,这样子双向传输的序列,称为,因此HTTP/2中以流来表示一个TCP链接上进行多个数据帧的通讯,这就是多路复用概念。

那乱序的二进制帧,是如何组装成对于的报文呢?

  • 所谓的乱序,值的是不一样ID的Stream是乱序的,对于同一个Stream ID的帧是按顺序传输的。
  • 接收方收到二进制帧后,将相同的Stream ID组装成完整的请求报文和响应报文。
  • 二进制帧中有一些字段,控制着优先级流量控制等功能,这样子的话,就能够设置数据帧的优先级,让服务器处理重要资源,优化用户体验。

介绍一下HTTP 常见状态码

RFC 规定 HTTP 的状态码为三位数,第一个数字定义了响应的类别,被分为五类:

  • 1xx: 表明请求已被接受,须要继续处理。
  • 2xx: 表示成功状态。
  • 3xx: 重定向状态。
  • 4xx: 客户端错误。
  • 5xx: 服务器端错误。

1xx 信息类

接受的请求正在处理,信息类状态码。

2xx 成功

  • 200 OK 表示从客户端发来的请求在服务器端被正确请求。
  • 204 No content,表示请求成功,但没有资源可返回。
  • 206 Partial Content,该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求 响应报文中包含由 Content-Range 指定范围的实体内容。

3xx 重定向

  • 301 moved permanently,永久性重定向,表示资源已被分配了新的 URL,这时应该按 Location 首部字段提示的 URI 从新保存。
  • 302 found,临时性重定向,表示资源临时被分配了新的 URL。
  • 303 see other,表示资源存在着另外一个 URL,应使用 GET 方法获取资源。
  • 304 not modified,当协商缓存命中时会返回这个状态码。
  • 307 temporary redirect,临时重定向,和302含义相同,不会改变method

当 30一、30二、303 响应状态码返回时,几乎全部的浏览器都会把 POST 改为 GET,并删除请求报文内的主体,以后请求会自动再次发送 30一、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时你们都会这么作

4XX 客户端错误

  • 400 bad request,请求报文存在语法错误。
  • 401 unauthorized,表示发送的请求须要有经过 HTTP 认证的认证信息。
  • 403 forbidden,表示对请求资源的访问被服务器拒绝。
  • 404 not found,表示在服务器上没有找到请求的资源。
  • 405 Method Not Allowed,服务器禁止使用该方法,客户端能够经过options方法来查看服务器容许的访问方法,以下 👇
Access-Control-Allow-Methods →GET,HEAD,PUT,PATCH,POST,DELETE
复制代码

5XX 服务器错误

  • 500 internal sever error,表示服务器端在执行请求时发生了错误。
  • 502 Bad Gateway,服务器自身是正常的,访问的时候出了问题,具体啥错误咱们不知道。
  • 503 service unavailable,代表服务器暂时处于超负载或正在停机维护,没法处理请求。

DNS如何工做的

DNS 协议提供的是一种主机名到 IP 地址的转换服务,就是咱们常说的域名系统。是应用层协议,一般该协议运行在UDP协议之上,使用的是53端口号。

咱们经过一张图来看看它的查询过程吧👇

这张图很生动的展现了DNS在本地DNS服务器是如何查询的,通常向本地DNS服务器发送请求是递归查询的

本地 DNS 服务器向其余域名服务器请求的过程是迭代查询的过程👇

DNS查询
DNS查询

递归查询和迭代查询

  • 递归查询指的是查询请求发出后,域名服务器代为向下一级域名服务器发出请求,最后向用户返回查询的最终结果。使用递归 查询,用户只须要发出一次查询请求。

  • 迭代查询指的是查询请求后,域名服务器返回单次查询的结果。下一级的查询由用户本身请求。使用迭代查询,用户须要发出 屡次的查询请求。

因此通常而言,本地服务器查询是递归查询,而本地 DNS 服务器向其余域名服务器请求的过程是迭代查询的过程

DNS缓存

缓存也很好理解,在一个请求中,当某个DNS服务器收到一个DNS回答后,它可以回答中的信息缓存在本地存储器中。返回的资源记录中的 TTL 表明了该条记录的缓存的时间。

DNS实现负载平衡

它是如何实现负载均衡的呢?首先咱们得清楚DNS 是能够用于在冗余的服务器上实现负载平衡。

**缘由:**这是由于通常的大型网站使用多台服务器提供服务,所以一个域名可能会对应 多个服务器地址。

举个例子来讲👇

  • 当用户发起网站域名的 DNS 请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合
  • 在每一个回答中,会循环这些 IP 地址的顺序,用户通常会选择排在前面的地址发送请求。
  • 以此将用户的请求均衡的分配到各个不一样的服务器上,这样来实现负载均衡。

总结

  • DNS域名系统,是应用层协议,运行UDP协议之上,使用端口43。
  • 查询过程,本地查询是递归查询,依次经过浏览器缓存 —>> 本地hosts文件 —>> 本地DNS解析器 —>>本地DNS服务器 —>> 其余域名服务器请求。 接下来的过程就是迭代过程。
  • 递归查询通常而言,发送一次请求就够,迭代过程须要用户发送屡次请求。

DNS 为何使用 UDP 协议做为传输层协议?

DNS 使用 UDP 协议做为传输层协议的主要缘由是为了不使用 TCP 协议时形成的链接时延。

  • 为了获得一个域名的 IP 地址,每每会向多个域名服务器查询,若是使用 TCP 协议,那么每次请求都会存在链接时延,这样使 DNS 服务变得很慢。
  • 大多数的地址查询请求,都是浏览器请求页面时发出的,这样会形成网页的等待时间过长。

介绍一下Connection:keep-alive

什么是keep-alive

咱们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每一个请求/应答客户和服务器都要新建一个链接,完成 以后当即断开链接(HTTP协议为无链接的协议);

当使用Keep-Alive模式(又称持久链接、链接重用)时,Keep-Alive功能使客户端到服 务器端的链接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了创建或者从新创建链接。

为何要使用keep-alive

keep-alive技术的建立目的,能在屡次HTTP以前重用同一个TCP链接,从而减小建立/关闭多个 TCP 链接的开销(包括响应时间、CPU 资源、减小拥堵等),参考以下示意图(来源:维基百科):

客户端如何开启

在HTTP/1.0协议中,默认是关闭的,须要在http头加入"Connection: Keep-Alive”,才能启用Keep-Alive;

Connection: keep-alive
复制代码

http 1.1中默认启用Keep-Alive,若是加入"Connection: close “,才关闭。

Connection: close
复制代码

目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的链接请求了,因此是否能完成一个完整的Keep- Alive链接就看服务器设置状况。


介绍HTTP 缓存策略

这个跟以前的浏览器缓存原理同样,我直接拿我以前梳理过的吧。

我在我以前的那一篇中已经详细的说过了,点这里传送门聊一聊浏览器缓存

咱们来梳理一下吧👇

强缓存

强缓存两个相关字段,ExpiresCache-Control

强缓存分为两种状况,一种是发送HTTP请求,一种不须要发送。

首先检查强缓存,这个阶段**不须要发送HTTP请求。**经过查找不一样的字段来进行,不一样的HTTP版本因此不一样。

  • HTTP1.0版本,使用的是Expires,HTTP1.1使用的是Cache-Control

Expires

Expires即过时时间,时间是相对于服务器的时间而言的,存在于服务端返回的响应头中,在这个过时时间以前能够直接从缓存里面获取数据,无需再次请求。好比下面这样:

Expires:Mon, 29 Jun 2020 11:10:23 GMT
复制代码

表示该资源在2020年7月29日11:10:23过时,过时时就会从新向服务器发起请求。

这个方式有一个问题:服务器的时间和浏览器的时间可能并不一致,因此HTTP1.1提出新的字段代替它。

Cache-Control

HTTP1.1版本中,使用的就是该字段,这个字段采用的时间是过时时长,对应的是max-age。

Cache-Control:max-age=6000
复制代码

上面表明该资源返回后6000秒,能够直接使用缓存。

固然了,它还有其余不少关键的指令,梳理了几个重要的👇

注意点:

  • 当Expires和Cache-Control同时存在时,优先考虑Cache-Control。
  • 固然了,当缓存资源失效了,也就是没有命中强缓存,接下来就进入协商缓存👇

协商缓存

强缓存失效后,浏览器在请求头中携带响应的缓存Tag来向服务器发送请求,服务器根据对应的tag,来决定是否使用缓存。

缓存分为两种,Last-ModifiedETag。二者各有优点,并不存在谁对谁有绝对的优点,与上面所讲的强缓存两个Tag所不一样。

Last-Modified

这个字段表示的是最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。

浏览器接收到后,若是再次请求,会在请求头中携带If-Modified-Since字段,这个字段的值也就是服务器传来的最后修改时间。

服务器拿到请求头中的If-Modified-Since的字段后,其实会和这个服务器中该资源的最后修改时间对比:

  • 若是请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程同样。
  • 不然返回304,告诉浏览器直接使用缓存。

ETag

ETag是服务器根据当前文件的内容,对文件生成惟一的标识,好比MD5算法,只要里面的内容有改动,这个值就会修改,服务器经过把响应头把该字段给浏览器。

浏览器接受到ETag值,会在下次请求的时候,将这个值做为If-None-Match这个字段的内容,发给服务器。

服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对👇

  • 若是二者同样的话,直接返回304,告诉浏览器直接使用缓存
  • 若是不同的话,说明内容更新了,返回新的资源,跟常规的HTTP请求响应的流程同样

二者对比

  • 性能上,Last-Modified优于ETagLast-Modified记录的是时间点,而Etag须要根据文件的MD5算法生成对应的hash值。
  • 精度上,ETag优于Last-ModifiedETag按照内容给资源带上标识,能准确感知资源变化,Last-Modified在某些场景并不能准确感知变化,好比👇
    • 编辑了资源文件,可是文件内容并无更改,这样也会形成缓存失效。
    • Last-Modified 可以感知的单位时间是秒,若是文件在 1 秒内改变了屡次,那么这时候的 Last-Modified 并无体现出修改了。

最后,若是两种方式都支持的话,服务器会优先考虑ETag

缓存位置

接下来咱们考虑使用缓存的话,缓存的位置在哪里呢?

浏览器缓存的位置的话,能够分为四种,优先级从高到低排列分别👇

  • Service Worker
  • Memory Cache
  • Disk Cache
  • Push Cache

Service Worker

这个应用场景好比PWA,它借鉴了Web Worker思路,因为它脱离了浏览器的窗体,所以没法直接访问DOM。它能完成的功能好比:离线缓存消息推送网络代理,其中离线缓存就是Service Worker Cache

Memory Cache

指的是内存缓存,从效率上讲它是最快的,从存活时间来说又是最短的,当渲染进程结束后,内存缓存也就不存在了。

Disk Cache

存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,优点在于存储容量和存储时长。

Disk Cache VS Memory Cache

二者对比,主要的策略👇

内容使用率高的话,文件优先进入磁盘

比较大的JS,CSS文件会直接放入磁盘,反之放入内存。

Push Cache

推送缓存,这算是浏览器中最后一道防线吧,它是HTTP/2的内容。具体我也不是很清楚,有兴趣的能够去了解。

总结

  • 首先检查Cache-Control, 尝鲜,看强缓存是否可用
  • 若是可用的话,直接使用
  • 不然进入协商缓存,发送HTTP请求,服务器经过请求头中的If-Modified-Since或者If-None-Match字段检查资源是否更新
  • 资源更新,返回资源和200状态码。
  • 不然,返回304,直接告诉浏览器直接从缓存中去资源。

说一说HTTP 的请求方法?

  • HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法
  • HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT

http/1.1规定了如下请求方法(注意,都是大写):

  • GET: 请求获取Request-URI所标识的资源
  • POST: 在Request-URI所标识的资源后附加新的数据
  • HEAD: 请求获取由Request-URI所标识的资源的响应消息报头
  • PUT: 请求服务器存储一个资源,并用Request-URI做为其标识(修改数据)
  • DELETE: 请求服务器删除对应所标识的资源
  • TRACE: 请求服务器回送收到的请求信息,主要用于测试或诊断
  • CONNECT: 创建链接隧道,用于代理服务器
  • OPTIONS: 列出可对资源实行的请求方法,用来跨域请求

谈一谈GET 和 POST 的区别

本质上,只是语义上的区别,GET 用于获取资源,POST 用于提交资源。

想装逼请参考 https://zhuanlan.zhihu.com/p/22536382

具体差异👇

  • 从缓存角度看,GET 请求后浏览器会主动缓存,POST 默认状况下不能。
  • 从参数角度来看,GET请求通常放在URL中,所以不安全,POST请求放在请求体中,相对而言较为安全,可是在抓包的状况下都是同样的。
  • 从编码角度看,GET请求只能经行URL编码,只能接受ASCII码,而POST支持更多的编码类型且不对数据类型限值。
  • GET请求幂等,POST请求不幂等,幂等指发送 M 和 N 次请求(二者不相同且都大于1),服务器上资源的状态一致。
  • GET请求会一次性发送请求报文,POST请求一般分为两个TCP数据包,首先发 header 部分,若是服务器响应 100(continue), 而后发 body 部分。

从应用场景角度来看,Get 多用于无反作用,幂等的场景,例如搜索关键字。Post 多用于反作用,不幂等的场景,例如注册。


options 方法有什么用?

  • OPTIONS 请求与 HEAD 相似,通常也是用于客户端查看服务器的性能。

  • 这个方法会请求服务器返回该资源所支持的全部 HTTP 请求方法,该方法会用'*'来代替资源名称,向服务器发送 OPTIONS 请求,能够测试服务器功能是否正常。

  • JS 的 XMLHttpRequest对象进行 CORS 跨域资源共享时,对于复杂请求,就是使用 OPTIONS 方法发送嗅探请求,以判断是否有对指定资源的访问权限。


谈一谈你对URL理解

统一资源定位符的简称,Uniform Resource Locator,经常被称为网址,是因特网上标准的资源地址。

组成

通用的格式:scheme://host[:port]/path/…/?query#anchor

名称 功能
scheme 访问服务器以获取资源时要使用哪一种协议,好比:http,https 和 FTP 等
host HTTP 服务器的 IP 地址或者域名
port HTTP 服务器的默认端口是 80,HTTPS默认端口是443,这种状况下端口号能够省略,若是使用了别的端口,必须指明。不一样的端口,你能够认为是不一样的应用程序。
path 访问资源的路径
query-string 发给 http 服务器的数据
anchor 锚点

举个例子👇

https://www.baidu.com/s?tn=baidu&bar=&wd=TianTian
复制代码

这个URL中,https就是协议,www.baidu.com就是域名,默认端口是443,/s就是请求的path,tn=baidu&bar=&wd=TianTian这个就是query

URL 编码

  • URL 只能使用 ASCII 字符集来经过因特网进行发送。
  • 因为 URL 经常会包含 ASCII 集合以外的字符,URL 必须转换为有效的 ASCII 格式。
  • URL 编码使用 "%" 其后跟随两位的十六进制数来替换非 ASCII 字符。
  • URL 不能包含空格。URL 编码一般使用 + 来替换空格。

举个例子👇

每天转换为有效的ASCII格式就是%CC%EC%CC%EC


谈一谈队头阻塞问题

什么是队头阻塞?

对于每个HTTP请求而言,这些任务是会被放入一个任务队列中串行执行的,一旦队首任务请求太慢时,就会阻塞后面的请求处理,这就是HTTP队头阻塞问题。

有什么解决办法吗👇

并发链接

咱们知道对于一个域名而言,是容许分配多个长链接的,那么能够理解成增长了任务队列,也就是说不会致使一个任务阻塞了该任务队列的其余任务,在RFC规范中规定客户端最多并发2个链接,不过实际状况就是要比这个还要多,举个例子,Chrome中是6个。

域名分片

顾名思义,咱们能够在一个域名下分出多个二级域名出来,而它们最终指向的仍是同一个服务器,这样子的话就能够并发处理的任务队列更多,也更好的解决了队头阻塞的问题。

举个例子,好比TianTian.com,能够分出不少二级域名,好比Day1.TianTian.comDay2.TianTian.com,Day3.TianTian.com,这样子就能够有效解决队头阻塞问题。


谈一谈HTTP数据传输

大概遇到的状况就分为定长数据不定长数据的处理吧。

定长数据

对于定长的数据包而言,发送端在发送数据的过程当中,须要设置Content-Length,来指明发送数据的长度。

固然了若是采用了Gzip压缩的话,Content-Length设置的就是压缩后的传输长度。

咱们还须要知道的是👇

  • Content-Length若是存在而且有效的话,则必须和消息内容的传输长度彻底一致,也就是说,若是太短就会截断,过长的话,就会致使超时。
  • 若是采用短连接的话,直接能够经过服务器关闭链接来肯定消息的传输长度。
  • 那么在HTTP/1.0以前的版本中,Content-Length字段无关紧要,由于一旦服务器关闭链接,咱们就能够获取到传输数据的长度了。
  • 在HTTP/1.1版本中,若是是Keep-alive的话,chunked优先级高于Content-Length,如果非Keep-alive,跟前面状况同样,Content-Length无关紧要。

那怎么来设置Content-Length

举个例子来看看👇

const server = require('http').createServer();
server.on('request', (req, res) => {
  if(req.url === '/index') {
   // 设置数据类型
    res.setHeader('Content-Type''text/plain');
    res.setHeader('Content-Length', 10);
    res.write("你好,使用的是Content-Length设置传输数据形式");
  }
})

server.listen(3000, () => {
  console.log("成功启动--TinaTian");
})

复制代码

不定长数据

如今采用最多的就是HTTP/1.1版本,来完成传输数据,在保存Keep-alive状态下,当数据是不定长的时候,咱们须要设置新的头部字段👇

Transfer-Encoding: chunked
复制代码

经过chunked机制,能够完成对不定长数据的处理,固然了,你须要知道的是

  • 若是头部信息中有Transfer-Encoding,优先采用Transfer-Encoding里面的方法来找到对应的长度。
  • 若是设置了Transfer-Encoding,那么Content-Length将被忽视。
  • 使用长链接的话,会持续的推送动态内容。

那咱们来模拟一下吧👇

const server = require('http').createServer();
server.on('request', (req, res) => {
  if(req.url === '/index') {
   // 设置数据类型
    res.setHeader('Content-Type''text/html; charset=utf8');
    res.setHeader('Content-Length', 10);
    res.setHeader('Transfer-Encoding''chunked');
    
    res.write("你好,使用的是Transfer-Encoding设置传输数据形式");
    setTimeout(() => {
      res.write("第一次传输数据给您<br/>");
    }, 1000);
    res.write("骚等一下");
    setTimeout(() => {
      res.write("第一次传输数据给您");
      res.end()
    }, 3000);
  }
})

server.listen(3000, () => {
  console.log("成功启动--TinaTian");
})

复制代码

上面使用的是nodejs中http模块,有兴趣的小伙伴能够去试一试,以上就是HTTP对定长数据不定长数据传输过程当中的处理手段。


介绍一下HTTPS和HTTP区别

HTTPS 要比 HTTPS 多了 secure 安全性这个概念,实际上, HTTPS 并非一个新的应用层协议,它其实就是 HTTP + TLS/SSL 协议组合而成,而安全性的保证正是 SSL/TLS 所作的工做。

SSL

安全套接层(Secure Sockets Layer)

TLS

(传输层安全,Transport Layer Security)

如今主流的版本是 TLS/1.2, 以前的 TLS1.0、TLS1.1 都被认为是不安全的,在不久的未来会被彻底淘汰。

HTTPS 就是身披了一层 SSL 的 HTTP

HTTP与HTTPS区别
HTTP与HTTPS区别

那么区别有哪些呢👇

  • HTTP 是明文传输协议,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
  • HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,谷歌、百度优先索引HTTPS网页。
  • HTTPS标准端口443,HTTP标准端口80。
  • HTTPS须要用到SSL证书,而HTTP不用。

我以为记住如下两点HTTPS主要做用就行👇

  1. 对数据进行加密,并创建一个信息安全通道,来保证传输过程当中的数据安全;
  2. 对网站服务器进行真实身份认证。

介绍一个HTTPS工做原理

上一节来看,咱们能够把HTTPS理解成HTTPS = HTTP + SSL/TLS

TLS/SSL 的功能实现主要依赖于三类基本算法:散列函数对称加密非对称加密,其利用非对称加密实现身份认证和密钥协商,对称加密算法采用协商的密钥对数据加密,基于散列函数验证信息的完整性。

对称加密

加密和解密用同一个秘钥的加密方式叫作对称加密。Client客户端和Server端共用一套密钥,这样子的加密过程彷佛很让人理解,可是随之会产生一些问题。

问题一: WWW万维网有许许多多的客户端,不可能都用秘钥A进行信息加密,这样子很不合理,因此解决办法就是使用一个客户端使用一个密钥进行加密。

问题二:既然不一样的客户端使用不一样的密钥,那么对称加密的密钥如何传输? 那么解决的办法只能是一端生成一个秘钥,而后经过HTTP传输给另外一端,那么这样子又会产生新的问题。

问题三: 这个传输密钥的过程,又如何保证加密?若是被中间人拦截,密钥也会被获取, 那么你会说对密钥再进行加密,那又怎么保存对密钥加密的过程,是加密的过程?

到这里,咱们彷佛想明白了,使用对称加密的方式,行不通,因此咱们须要采用非对称加密👇

非对称加密

经过上面的分析,对称加密的方式行不通,那么咱们来梳理一下非对称加密。采用的算法是RSA,因此在一些文章中也会看见传统RSA握手,基于如今TLS主流版本是1.2,因此接下来梳理的是TLS/1.2握手过程

非对称加密中,咱们须要明确的点是👇

  • 有一对秘钥,公钥私钥
  • 公钥加密的内容,只有私钥能够解开,私钥加密的内容,全部的公钥均可以解开,这里说的公钥均可以解开,指的是一对秘钥
  • 公钥能够发送给全部的客户端,私钥只保存在服务器端。

主要工做流程

梳理起来,能够把TLS 1.2 握手过程分为主要的五步👇

图片内容来自浪里行舟

步骤(1)

Client发起一个HTTPS请求,链接443端口。这个过程能够理解成是请求公钥的过程

步骤(2)

Server端收到请求后,经过第三方机构私钥加密,会把数字证书(也能够认为是公钥证书)发送给Client。

步骤(3)

  • 浏览器安装后会自动带一些权威第三方机构公钥,使用匹配的公钥对数字签名进行解密。
  • 根据签名生成的规则对网站信息进行本地签名生成,而后二者比对。
  • 经过比对二者签名,匹配则说明认证经过,不匹配则获取证书失败。

步骤(4)

在安全拿到服务器公钥后,客户端Client随机生成一个对称密钥,使用服务器公钥(证书的公钥)加密这个对称密钥,发送给Server(服务器)。

步骤(5)

Server(服务器)经过本身的私钥,对信息解密,至此获得了对称密钥,此时二者都拥有了相同的对称密钥

接下来,就能够经过该对称密钥对传输的信息加密/解密啦,从上面图举个例子👇

  • Client用户使用该对称密钥加密'明文内容B',发送给Server(服务器)
  • Server使用该对称密钥进行解密消息,获得明文内容B。

接下来考虑一个问题,若是公钥被中间人拿到纂改怎么办呢?

如下图片来自leocoder

中间人获取公钥
中间人获取公钥

客户端可能拿到的公钥是假的,解决办法是什么呢?

第三方认证

客户端没法识别传回公钥是中间人的,仍是服务器的,这是问题的根本,咱们是否是能够经过某种规范可让客户端和服务器都遵循某种约定呢?那就是经过第三方认证的方式

在HTTPS中,经过 证书 + 数字签名来解决这个问题。

这里惟一不一样的是,假设对网站信息加密的算法是MD5,经过MD5加密后,而后经过第三方机构的私钥再次对其加密,生成数字签名

这样子的话,数字证书包含有两个特别重要的信息👉某网站公钥+数字签名

咱们再次假设中间人截取到服务器的公钥后,去替换成本身的公钥,由于有数字签名的存在,这样子客户端验证发现数字签名不匹配,这样子就防止中间人替换公钥的问题。

那么客户端是如何去对比二者数字签名的呢?

  • 浏览器会去安装一些比较权威的第三方认证机构的公钥,好比VeriSign、Symantec以及GlobalSign等等。
  • 验证数字签名的时候,会直接从本地拿到相应的第三方的公钥,对私钥加密后的数字签名进行解密获得真正的签名。
  • 而后客户端利用签名生成规则进行签名生成,看两个签名是否匹配,若是匹配认证经过,不匹配则获取证书失败。

数字签名做用

数字签名:将网站的信息,经过特定的算法加密,好比MD5,加密以后,再经过服务器的私钥进行加密,造成加密后的数字签名

第三方认证机构是一个公开的平台,中间人能够去获取。

若是没有数字签名的话,这样子能够就会有下面状况👇

从上面咱们知道,若是只是对网站信息进行第三方机构私钥加密的话,仍是会受到欺骗。

由于没有认证,因此中间人也向第三方认证机构进行申请,而后拦截后把全部的信息都替换成本身的,客户端仍然能够解密,而且没法判断这是服务器的仍是中间人的,最后形成数据泄露。

总结

  • HTTPS就是使用SSL/TLS协议进行加密传输
  • 大体流程:客户端拿到服务器的公钥(是正确的),而后客户端随机生成一个对称加密的秘钥,使用该公钥加密,传输给服务端,服务端再经过解密拿到该对称秘钥,后续的全部信息都经过该对称秘钥进行加密解密,完成整个HTTPS的流程。
  • 第三方认证,最重要的是数字签名,避免了获取的公钥是中间人的。

SSL 链接断开后如何恢复?

一共有两种方法来恢复断开的 SSL 链接,一种是使用 session ID,一种是 session ticket。

经过session ID

使用 session ID 的方式,每一次的会话都有一个编号,当对话中断后,下一次从新链接时,只要客户端给出这个编号,服务器若是有这个编号的记录,那么双方就能够继续使用之前的秘钥,而不用从新生成一把。目前全部的浏览器都支持这一种方法。可是这种方法有一个缺点是,session ID 只可以存在一台服务器上,若是咱们的请求经过负载平衡被转移到了其余的服务器上,那么就没法恢复对话。

经过session ticket

另外一种方式是 session ticket 的方式,session ticket 是服务器在上一次对话中发送给客户的,这个 ticket 是加密的,只有服务器可以解密,里面包含了本次会话的信息,好比对话秘钥和加密方法等。这样无论咱们的请求是否转移到其余的服务器上,当服务器将 ticket 解密之后,就可以获取上次对话的信息,就不用从新生成对话秘钥了。

短轮询、长轮询和 WebSocket 间的区别?

短轮询

短轮询的基本思路:

  • 浏览器每隔一段时间向浏览器发送 http 请求,服务器端在收到请求后,不管是否有数据更新,都直接进行 响应。
  • 这种方式实现的即时通讯,本质上仍是浏览器发送请求,服务器接受请求的一个过程,经过让客户端不断的进行请求,使得客户端可以模拟实时地收到服务器端的数据的变化。

优缺点👇

  • 优势是比较简单,易于理解。

  • 缺点是这种方式因为须要不断的创建 http 链接,严重浪费了服务器端和客户端的资源。当用户增长时,服务器端的压力就会变大,这是很不合理的。

长轮询

长轮询的基本思路:

  • 首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将 这个请求挂起,而后判断服务器端数据是否有更新。

  • 若是有更新,则进行响应,若是一直没有数据,则到达必定的时间限制才返回。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,从新创建链接。

优缺点👇

  • 长轮询和短轮询比起来,它的优势是明显减小了不少没必要要的 http 请求次数,相比之下节约了资源。

  • 长轮询的缺点在于,链接挂起也会致使资源的浪费。

WebSocket

  • WebSocket 是 Html5 定义的一个新协议,与传统的 http 协议不一样,该协议容许由服务器主动的向客户端推送信息。
  • 使用 WebSocket 协议的缺点是在服务器端的配置比较复杂。WebSocket 是一个全双工的协议,也就是通讯双方是平等的,能够相互发送消息。

说一说正向代理和反向代理

正向代理

咱们常说的代理也就是指正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求。

反向代理

这种代理模式下,它隐藏了真实的服务端,当咱们向一个网站发起请求的时候,背后可能有成千上万台服务器为咱们服务,具体是哪一台,咱们不清楚,咱们只须要知道反向代理服务器是谁就行,并且反向代理服务器会帮咱们把请求转发到真实的服务器那里去,通常而言反向代理服务器通常用来实现负载平衡。

负载平衡的两种实现方式?

  • 一种是使用反向代理的方式,用户的请求都发送到反向代理服务上,而后由反向代理服务器来转发请求到真实的服务器上,以此来实现集群的负载平衡。

  • 另外一种是 DNS 的方式,DNS 能够用于在冗余的服务器上实现负载平衡。由于如今通常的大型网站使用多台服务器提供服务,所以一个域名可能会对应多个服务器地址。当用户向网站域名请求的时候,DNS 服务器返回这个域名所对应的服务器 IP 地址的集合,但在每一个回答中,会循环这些 IP 地址的顺序,用户通常会选择排在前面的地址发送请求。以此将用户的请求均衡的分配到各个不一样的服务器上,这样来实现负载均衡。这种方式有一个缺点就是,因为 DNS 服务器中存在缓存,因此有可能一个服务器出现故障后,域名解析仍然返回的是那个 IP 地址,就会形成访问的问题。

参考

❤️ 感谢你们

若是你以为这篇内容对你挺有有帮助的话:

  1. 点赞支持下吧,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
  2. 欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。
  3. 以为不错的话,也能够阅读TianTian近期梳理的文章(感谢掘友的鼓励与支持🌹🌹🌹):
相关文章
相关标签/搜索