JavaScript面试考点之HTTP
1、HTTP 的请求方法
1)GET: 通常用来获取资源。
2)POST: 提交数据,即上传数据。
3)PUT: 修改数据。
4)HEAD: 获取资源的元信息。
5)DELETE: 删除资源(几乎用不到)。
6)CONNECT: 建立连接隧道,用于代理服务器。
7)OPTIONS: 列出可对资源实行的请求方法,用来跨域请求。
8)TRACE: 追踪请求-响应的传输路径。
GET 和 POST 的区别:
从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
从TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。
2、URI
URI, 全称为(Uniform Resource Identifier), 也就是统一资源标识符。URI包含了URN和URL两个部分。 URL就是我们常说的网址。
1)scheme 表示协议名,比如http, https, file等等。后面必须和://连在一起。
2)user:passwd@ 表示登录主机时的用户信息,不过很不安全,不推荐使用,也不常用。
3)host:port表示主机名和端口。
4)path表示请求路径,标记资源所在位置。
5)query表示查询参数,为key=val这种形式,多个键值对之间用&隔开。
6)fragment表示 URI 所定位的资源内的一个锚点,浏览器可以根据这个锚点跳转到对应的位置。
3、 HTTP 状态码
RFC 规定 HTTP 的状态码为三位数,被分为五类:
1xx: 表示目前是协议处理的中间状态,还需要后续操作。
2xx: 表示成功状态。
3xx: 重定向状态,资源位置发生变动,需要重新请求。
4xx: 请求报文有误。
5xx: 服务器端发生错误。
常见状态码:
200 OK是见得最多的成功状态码。通常在响应体中放有数据。
301 Moved Permanently即永久重定向,对应着302 Found,即临时重定向。
304 Not Modified: 当协商缓存命中时会返回这个状态码。
403 Forbidden: 这实际上并不是请求报文出错,而是服务器禁止访问,原因有很多,比如法律禁止、信息敏感。
404 Not Found: 资源未找到,表示没在服务器上找到相应的资源。
405 Method Not Allowed: 请求方法不被服务器端允许。
406 Not Acceptable: 资源无法满足客户端的条件。
408 Request Timeout: 服务器等待了太长时间。
409 Conflict: 多个请求发生了冲突。
413 Request Entity Too Large: 请求体的数据过大。
414 Request-URI Too Long: 请求行里的 URI 太大。
429 Too Many Request: 客户端发送的请求过多。
431 Request Header Fields Too Large请求头的字段内容太大。
500 Internal Server Error: 仅仅告诉你服务器出错了。
501 Not Implemented: 表示客户端请求的功能还不支持。
502 Bad Gateway: 服务器自身是正常的,但访问的时候出错了,啥错误咱也不知道。
503 Service Unavailable: 表示服务器当前很忙,暂时无法响应服务。
4、Accept 系列字段
Accept系列字段分为四个部分: 数据格式、压缩方式、支持语言和字符集。
1)数据格式
针对于发送端而言,Content-Type这个字段,接收端想要收到特定类型的数据,也可以用Accept字段。,这两个字段的取值可以分为下面几类:
a、text:text/html, text/plain, text/css 等
b、image: image/gif, image/jpeg, image/png 等
c、audio/video: audio/mpeg, video/mp4 等
d、application: application/json, application/javascript, application/pdf, application/octet-stream
2)压缩方式
一般数据都是会进行编码压缩的,采取什么样的压缩方式就体现在了发送方的Content-Encoding字段上, 同样的,接收什么样的压缩方式体现在了接受方的Accept-Encoding字段上。
a、gzip: 当今最流行的压缩格式
b、deflate: 另外一种著名的压缩格式
c、br: 一种专门为 HTTP 发明的压缩算法
3)字符集
在接收端对应为Accept-Charset,指定可以接受的字符集,而在发送端并没有对应的Content-Charset, 而是直接放在了Content-Type中,以charset属性指定。
3)支持语言
Content-Language字段,在需要实现国际化的方案当中,可以用来指定支持的语言,在接受方对应的字段为Accept-Language。
5、从输入URL地址到看到页面
第一步:URL解析
对URL的编码:处理空格中文等
encodeURI / decodeURI
主要对传递的参数信息进行编码
encodeURIComponent / decodeURIComponent
第二步:缓存检查
先检查是否存在强缓存?有且未失效,走强缓存;如果没有或失效,检查是否存在协商缓存,有走协商缓存,没有,获取最新数据。
缓存的位置:Memory Cache 内存缓存;Disk Cache 硬盘缓存。
打开网页:查找 disk cache 中是否有匹配,如有则使用,如没有则发送网络请求
普通刷新 (F5):因TAB没关闭,因此memory cache是可用的,会被优先使用,其次才是disk cache
强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache,服务器直接返回 200 和最新内容
1)强缓存 Expires / Cache-Control
浏览器对于强缓存的处理:根据第一次请求资源时返回的响应头来确定的
Expires:缓存过期时间,用来指定资源到期的时间(HTTP/1.0)。
Cache-Control:cache-control: max-age=2592000第一次拿到资源后的2592000秒内(30天),再次发送请求,读取缓存中的信息(HTTP/1.1)。
Cache-Control 还拥有多个值:
no-cache 不直接使用缓存,也就是跳过强缓存。
no-store 禁止浏览器缓存数据,每次请求资源都会向服务器要完整的资源。
public 可以被所有用户缓存,包括终端用户和 CDN 等中间件代理服务器。
private 只允许终端用户的浏览器缓存,不允许其他中间代理服务器缓存。
no-cache和no-store的区别:no-cache是跳过强缓存,还是会走协商缓存的步骤,而no-store是真正的完全不走缓存,所有资源都不会缓存在本地
两者同时存在的话,Cache-Control优先级高于Expires。
如何来确定本地缓存资源为最新的的呢?
a、服务器更新资源后,让资源名称不一样,这样页面导入的全新的资源。例如webpack打包文件名字用hash值。
b、在HTML导入时,文件后面加一个时间戳
c、协商缓存。
2)协商缓存 Last-Modified / ETag
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。
协商缓存需要配合强缓存使用,使用协商缓存需要先设置Cache-Control:no-cache或者pragma:no-cache来告诉浏览器不走强缓存
第一次向服务器发送请求,协商缓存没有,向服务器发送请求(没有传递任何的标识)。服务器收到请求,准备内容。数据中会包含标识:Last-Modified (HTTP/1.0)资源的最后更新时间/ ETag(HTTP/1.1)记录的是一个标识,也是根据资源文件更新生成的,每一次资源更新都会重新生成一个ETag。客户端拿到数据然后渲染,把信息和标识缓存到本地。
第二次想服务器发请求时,会带着标识。if-Modified-Since:Last-Modified (HTTP/1.0,只精确到秒,如果1秒内资源请求,和新资源更新,则无法识别) / If-None-Match:ETag(HTTP/1.1)。服务器来判断资源信息是否更新,没有更新返回304,从本地缓存获取,若丢失查询请求服务器;更新了返回200及最新资源。
3)数据缓存
第三步:DNS解析
1)递归查询
2)迭代查询
每一次DNS解析时间预计在20~120毫秒
a、减少DNS请求次数(把资源放在一个服务器,但真实不是的)
b、DNS预获取(DNS Prefetch)
但是我们我们通常会分服务器存储:web服务器、数据服务器、图片服务器。根据数据选择不同的服务器。
服务器拆分的优势
a、资源的合理利用
b、抗压能力加强
c、提高HTTP并发
第四步:TCP三次握手,建立连接通道
seq序号,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记
ack确认序号,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1
标志位
a、ACK:确认序号有效
b、RST:重置连接
c、SYN:发起一个新连接
e、FIN:释放一个连接
最开始双方都属于CLOSED状态。然后服务器开始监听某个端口,进入LISTEN状态。
a、客户端注重发起连接,发送SYN,自己变成了SYN-SENT状态
c、服务端收到,返回SYN和ACK(对应客户端发来的SYN),自己变成了SYN-RECD
d、客户端再发送ACK给服务端,自己变成ESTAB-LISHED(established)状态;服务端收到ACK之后,也变成这个状态。
三次握手为什么不用两次,或者四次?
建立TCP链接是为了保证稳定有序的收发数据,那么就要保证双发的发送和接收功能都是OK的。 三次握手三次是客户端和服务端都让 "对方" 知道自己发送和接收能力都OK的最小次数。
第一次:client—>server (服务端确认了客户端的发送功能)
第二次:setver—>client (客户端确认了服务端的发送功能和接收功能)
第三次:client—>server (服务端确认了客户端的接收功能);
TCP连接建立。
两次无法保证,四次会多余。
TCP作为一种可靠传输控制协议,其核心思想:既要保证数据可靠传输,又要提高传输的效率!
如果两次,无法确认客户端的接收能力。可能出现的问题是,两次握手,服务端只要接收到然后发送相应的数据包,就默认连接了 ,但是事实上现在客户端可能已经断开连接了,这样也就带来了连接资源的浪费,服务器并不知道客户端收到传到的确认。
因为三次已经足够确认双方的发送和接收的能力了,如果四次,客户端还需再发确认。
为什么要传回 SYN?传了 SYN,为什么还要传 ACK?
接收端传回发送端所发送的 SYN 是为了告诉发送端,我接收到的信息确实就是你所发送的信号了。
双方通信无误必须是两者互相发送信息都无误。传了 SYN,证明发送方到接收方的通道没有问题,但是接收方到发送方的通道还需要 ACK 信号来进行验证。
SYN 泛洪攻击
TCP 只有经过三次握手才能连接,而 SYN 泛洪攻击就是针对 TCP 握手过程进行攻击:
a、攻击者发送大量的 SYN 包给服务器(第一次握手成功)
b、服务器回应(SYN + ACK)包(第二次握手成功)
c、但是攻击者不回应 ACK 包(第三次握手不进行)
导致服务器存在大量的半开连接,这些半连接可以耗尽服务器资源,使被攻击服务器无法再响应正常 TCP 连接,从而达到攻击的目的。
一种称为 SYN cookie 的有效防御现在已部署在大多数主要的操作系统中:
在客户端发送 SYN 报文给服务器(第一次握手),服务端收到连接请求报文段后,服务器不会为此SYN创建半开连接,而是生成一个序列号(所谓的 cookie)一起发送给客户端(第二次握手),在这个阶段,服务器不会为该连接分配任何资源。
客户端返回 ACK 报文给服务器(第三次握手),服务器会验证这个 cookie 值,只有验证成功才创建 TCP 连接,分配资源。
如果客户端没有返回 ACK 报文给服务器,也不会对服务器造成任何的伤害,因为服务器没有分配任何资源给它。
第五步:数据传输
HTTP报文:请求报文 响应报文
响应状态码
200 OK
202 Accepted :服务器已接受请求,但尚未处理(异步)
204 No Content:服务器成功处理了请求,但不需要返回任何实体内容
206 Partial Content:服务器已经成功处理了部分 GET 请求(断点续传 Range/If-Range/Content-Range/Content-Type:”multipart/byteranges”/Content-Length….)
301 Moved Permanently
302 Move Temporarily
304 Not Modified
305 Use Proxy
400 Bad Request : 请求参数有误
401 Unauthorized:权限(Authorization)
404 Not Found
405 Method Not Allowed
408 Request Timeout
500 Internal Server Error
503 Service Unavailable
505 HTTP Version Not Supported
……
第六步:TCP四次挥手
首先客户端主动关闭,向服务器发FIN报文
a、服务端接收后通知应用进程并向客户端发送ACK确认
b、服务端处理完后被动关闭再次向客户端发送FIN以及ACK,进入LAST-ACK状态,
c、客户端收到服务端发来的FIN后,发送 ACK 给服务端。再等待2MSL后进入CLOSED状态。客户端需要等待2个 MSL(Maximum Segment Lifetime,报文最大生存时间),在这段时间内如果客户端没有收到服务端的重发请求,那么表示 ACK成功到达,挥手结束,否则客户端重发 ACK。
为什么客户端最后还要等待2MSL?
保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端
1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
服务器端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文
但关闭连接时,当服务器端收到FIN报文时,很可能并不会立即关闭链接,所以只能先回复一个ACK报文,告诉客户端:”你发的FIN报文我收到了”,只有等到服务器端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送,故需要四步握手。
HTTP 如何实现长连接?在什么时候会超时?
通过在头部(请求和响应头)设置Connection: keep-alive,可以保证TCP通道建立完成后不关闭。HTTP1.0协议支持,但是默认关闭,从HTTP1.1协议以后,连接默认都是长连接,默认是开启的。
所谓长连接,即在 HTTP 请求建立 TCP 连接时,请求结束,TCP 连接不断开,继续保持一段时间(timeout),在这段时间内,同一客户端向服务器发送请求都会复用该 TCP 连接,并重置 timeout 时间计数器,在接下来 timeout 时间内还可以继续复用 TCP 。这样无疑省略了反复创建和销毁 TCP 连接的损耗。
timeout 时间到了之后,TCP会立即断开连接吗?
若两小时(timeout)没有收到客户的数据,服务器就发送一个探测报文段,以后则每隔 75 秒发送一次。若一连发送 10 个探测报文段后仍无客户的响应,服务器就认为客户端出了故障,接着就关闭这个连接。 ——摘自谢希仁《计算机网络》
HTTP 一般会有 httpd 守护进程,里面可以设置 keep-alive timeout,当 tcp 链接闲置超过这个时间就会关闭,也可以在 HTTP 的 header 里面设置超时时间。
http长连接的keepalive_time和tcp连接的keepalive_timeout不同:
a、http keep-alive是为了让tcp活得更久一点,以便在同一个连接上传送多个http,提高socket的效率。而tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制。
keepalive是TCP保鲜定时器,当网络两端建立了TCP连接之后,闲置idle(双方没有任何数据流发送往来)了tcp_keepalive_time后,服务器内核就会尝试向客户端发送侦测包,来判断TCP连接状况(有可能客户端崩溃、强制关闭了应用、主机不可达等等)。如果没有收到对方的回答(ack包),则会在 tcp_keepalive_intvl后再次尝试发送侦测包,直到收到对对方的ack,如果一直没有收到对方的ack,一共会尝试 tcp_keepalive_probes次,每次的间隔时间在这里分别是15s, 30s, 45s, 60s, 75s。如果尝试tcp_keepalive_probes,依然没有收到对方的ack包,则会丢弃该TCP连接。TCP连接默认闲置时间是2小时,一般设置为30分钟足够了。
SO_KEEPALIVE的三个参数详细解释:
tcp_keepalive_intvl,保活探测消息的发送频率。默认值为75s。发送频率tcp_keepalive_intvl乘以发送次数tcp_keepalive_probes,就得到了从开始探测直到放弃探测确定连接断开的时间,大约为11min。
tcp_keepalive_probes,TCP发送保活探测消息以确定连接是否已断开的次数。默认值为9(次)。注意:只有设置了SO_KEEPALIVE套接口选项后才会发送保活探测消息。
tcp_keepalive_time,在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测消息的时间,即允许的持续空闲时间。默认值为7200s(2h)。
第七步:页面渲染
6、HTTP1.0 VS HTTP1.1 VS HTTP2.0
HTTP1.0和HTTP1.1的一些区别:
1)缓存处理,HTTP1.0中主要使用 Last-Modified,Expires 来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略:ETag,Cache-Control…
2)带宽优化及网络连接的使用,HTTP1.1支持断点续传,即返回码是206(Partial Content)
3)错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除…
4)Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)
5)长连接,HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
在HTTP/1.0 中每一次请求都需要建立一个 TCP 连接,请求结束后立即断开连接。
在HTTP/1.1 中,每一个连接都默认是长连接 (persistent connection)。对于同一个 tcp 连接,允许一次发送多个 http1.1 请求,也就是说,不必等前一个响应收到,就可以发送下一个请求。这样就解决了 http1.0 的客户端的队头阻塞,而这也就是HTTP/1.1中管道机制 (Pipeline)的概念了。
但是,http1.1 规定,服务器端的响应的发送要根据请求被接收的顺序排队,也就是说,先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送,这也会造成队头阻塞。可见,http1.1 的队首阻塞是发生在服务器端。
HTTP2.0和HTTP1.X相比的新特性:
为了解决HTTP/1.1中的服务端队首阻塞,HTTP/2采用了二进制分帧 和 多路复用 等方法。
1)新的二进制格式(Binary Format),二进制分帧。HTTP1.x的解析是基于文本,基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合,基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。原来Headers + Body的报文格式如今被拆分成了一个个二进制的帧,用Headers帧存放头部字段,Data帧存放请求体数据。分帧之后,服务器看到的不再是一个个完整的 HTTP 请求报文,而是一堆乱序的二进制帧。二进制帧不存在先后关系,因此也就不会排队等待,也就没有了 HTTP 的队头阻塞问题。
通信双方都可以给对方发送二进制帧,这种二进制帧的双向传输的序列,也叫做流(Stream)。HTTP/2 用流来在一个 TCP 连接上来进行多个数据帧的通信,这就是多路复用的概念。
所谓的乱序,指的是不同 ID 的 Stream 是乱序的,但同一个 Stream ID 的帧一定是按顺序传输的。二进制帧到达后对方会将 Stream ID 相同的二进制帧组装成完整的请求报文和响应报文。
2)头部压缩,HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小
3)服务端推送(server push),服务器已经不再是完全被动地接收请求,响应请求,它也能新建 stream 来给客户端发送消息。例如浏览器请求一个 HTML 文件,服务器就可以在返回 HTML 的基础上,将 HTML 中引用到的其他资源文件一起返回给客户端,减少客户端的等待。再比如我的网页有一个sytle.css的请求,在客户端收到sytle.css数据的同时,服务端会将sytle.js的文件推送给客户端,当客户端再次尝试获取sytle.js时就可以直接从缓存中获取到,不用再发请求了
我们前端在做性能优化的时候,很多时候会提到的一点就是“HTTP 1.1 的队头阻塞问题”,具体来说 就是 HTTP2 解决了 HTTP1.1 中的队头阻塞问题,但是为什么 HTTP1.1 有队头阻塞问题,HTTP2 究竟怎么解决的这个问题,很多人都不清楚。
其实队头阻塞是一个专有名词,不仅仅在 HTTP 有,交换器等其他地方也都涉及到了这个问题。实际上引起这个问题的根本原因是使用了队列这种数据结构。
协议规定, 对于同一个 tcp 连接,所有的 http1.0 请求放入队列中,只有前一个请求的响应收到了,才能发送下一个请求,这个时候就发生了阻塞,并且这个阻塞主要发生在客户端。
总结:HTTP/1.x keep-alive 与 HTTP/2 多路复用区别
HTTP/1.x 是基于文本的,只能整体去传;HTTP/2 是基于二进制流的,可以分解为独立的帧,交错发送。
HTTP/1.x keep-alive 必须按照请求发送的顺序返回响应;HTTP/2 多路复用不按序响应。
HTTP/1.x keep-alive 为了解决队头阻塞,将同一个页面的资源分散到不同域名下,开启了多个 TCP 连接;HTTP/2 同域名下所有通信都在单个连接上完成。
HTTP/1.x keep-alive 单个 TCP 连接在同一时刻只能处理一个请求(两个请求的生命周期不能重叠);HTTP/2 单个 TCP 同一时刻可以发送多个请求和响应。
7、性能优化
8、HTTP和HTTPS的区别
HTTP的优点:
灵活可扩展。一个是语义上的自由,只规定了基本格式。另一个是传输形式的多样性,不仅仅可以传输文本,还能传输图片、视频等任意数据,非常方便;
可靠传输。HTTP 基于 TCP/IP,请求-应答模式;
无状态。这里的状态是指通信过程的上下文信息,而每次 http 请求都是独立、无关的,默认不需要保留状态信息。
HTTP的缺点:
无状态也成为了一个缺点。在需要长连接的场景中,需要保存大量的上下文信息,以免传输大量重复的信息;另外一些应用仅仅只是为了获取一些数据,不需要保存连接上下文信息,无状态反而减少了网络开销。很矛盾。
明文传输,即协议里的报文(主要指的是头部)不使用二进制数据,而是文本形式。让 HTTP 的报文信息暴露给了外界,给攻击者也提供了便利。
队头阻塞问题,当 http 开启长连接时,共用一个 TCP 连接,同一时刻只能处理一个请求,那么当前请求耗时过长的情况下,其它的请求只能处于阻塞状态。
解决HTTP 明文传输不安全的问题:
由于HTTP的不安全引出HTTPS,HTTPS就是在HTTP的基础上增加了一层SSL(Secure Sockets Layer 安全套接字协议)的加密协议。如下图所示,传输层安全TLS(Transport Layer Security,TLS)是SSL的升级版,它们的作用都是进行加密的连接。
加密方式,分别是对称加密和非对称加密。
1)对称加密
靠一个密钥来加密数据,使用相同的一个密钥来解密数据。首先用户需要把自己的一把钥匙给送给服务器,用户用这把钥匙加密数据,然后服务器待会拿这把相同的钥匙去解密用户接下来发送的数据。
缺点:每个用户的密钥都要先发给服务器,给服务器增加了太多太多的负荷;第一次发送密钥给服务器的时候,此次发送是明文发送的,此刻可以在中间截取到了我们的密钥。
优点:该加密方式计算量小,加密和解密的速度比较快,适合加密比较大的数据。
2)非对称加密
有一个公钥和一个私钥,公钥加密只能私钥解密,私钥加密只能公钥解密。因为解密和加密使用不同的钥匙,所以称为非对称加密。公钥和私钥都放在服务器上,公钥是可以随便传输的,私钥是绝对不会暴露的,数据传输是安全的。
首先服务器端把公钥传给客户端,客户端拿到公钥后对数据进行加密,然后客户端发送使用公钥加密过的数据到服务器,服务器收到加密后的数据后使用私钥对数据进行解密。
优缺点:该加密方式数据传输虽然安全,但是计算量大,加密和解密的速度比较慢。
3)HTTPS加密、解密及验证过程
HTTPS将对称加密与非对称加密结合起来,充分利用两者各自的优势。在交换密钥环节使用非对称加密方式,之后的建立通信交换报文阶段则使用对称加密方式。
HTTPS的通信步骤如下:
a、客户使用https url访问服务器,则要求web 服务器建立ssl链接。
b、web服务器接收到客户端的请求之后,会将网站的证书(证书中包含了公钥),返回或者说传输给客户端。
c、客户端和web服务器端开始协商SSL链接的安全等级,也就是加密等级。客户端浏览器通过双方协商一致的安全等级,建立会话密钥,然后通过网站的公钥来加密会话密钥,并传送给网站。
d、 web服务器通过自己的私钥解密出会话密钥。 web服务器通过会话密钥加密与客户端之间的通信。
假如服务器端存有一个公钥777和一个私钥888,首先,浏览器发出一个https请求,如https://www.baidu.com,服务器端响应请求,返回一个SSL数字证书给客户端,SSL数字证书包括了公钥和服务器的身份标识信息,客户端收到SSL数字证书之后,验证该数字证书是否有效,如无效,则浏览器会发出不安全警告,如有效,就会先生成一个随机码如6666,然后使用公钥777对这个随机码进行加密,然后传输该加密后的随机码到服务器,服务器使用私钥888进行解密,得到客户端的随机码为6666。
客户端和服务器都同时拥有了该随机码6666,然后,把这个随机码6666用作对称加密的密钥,用密钥6666对userName和passWord的信息进行加密,发送到服务器端,服务器端同样使用相同的密钥6666对数据进行解密,最后得到userName和passWord的信息。以上为整个HTTPS加密、解密及验证的过程。
解决HTTP 队头阻塞问题:
并发连接,对于一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其它所有任务。
域名分片,域名下可以分出非常多的二级域名,而它们都指向同样的一台服务器,能够并发的长连接数更多了。
总结:
http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议
https: 是以安全为目标的HTTP通道。在HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
1)HTTP 是明文传输协议,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全,用到SSL证书(HTTPS是安装SSL的服务器,HTTP是未安装SSL的服务器)。
2)端口也不同,HTTPS标准端口443,HTTP标准端口80;
3)HTTPS基于传输层,HTTP基于应用层;
9、HTTP 如何处理大文件的传输?
对于几百 M 甚至上 G 的大文件来说,如果要一口气全部传输过来显然是不现实的,会有大量的等待时间,严重影响用户体验。因此,HTTP 针对这一场景,采取了范围请求的解决方案,允许客户端仅仅请求一个资源的一部分。
前提是服务器要支持范围请求,要支持这个功能,就必须加上这样一个响应头(Accept-Ranges)。
Range 字段拆解。对于客户端而言,它需要指定请求哪一部分,通过Range这个请求头字段确定,格式为bytes=x-y。
a、0-499表示从开始到第 499 个字节。
b、500- 表示从第 500 字节到文件终点。
c、-100表示文件的最后100个字节。
服务器收到请求之后,首先验证范围是否合法,如果越界了那么返回416错误码,否则读取相应片段,返回206状态码。
同时,服务器需要添加Content-Range字段,这个字段的格式根据请求头中Range字段的不同而有所差异。请求单段数据和请求多段数据,响应头是不一样的。
对于单段数据的请求,返回的响应如下:
Content-Range字段,0-9表示请求的返回,100表示资源的总大小。
多段数据:
这个时候出现了一个非常关键的字段Content-Type: multipart/byteranges;boundary=00000010101,它代表了信息量是这样的:请求一定是多段数据请求;响应体中的分隔符是 00000010101。
在响应体中各段数据之间会由这里指定的分隔符分开,而且在最后的分隔末尾添上--表示结束。
10、HTTP 与 TCP 区别
TCP 协议对应于传输层,而 HTTP 协议对应于应用层,从本质上来说,二者没有可比性:
HTTP 对应于应用层,TCP 协议对应于传输层
HTTP 协议是在 TCP 协议之上建立的,HTTP 在发起请求时通过 TCP 协议建立起连接服务器的通道,请求结束后,立即断开 TCP 连接
HTTP 是无状态的短连接,而 TCP 是有状态的长连接
TCP是传输层协议,定义的是数据传输和连接方式的规范,HTTP是应用层协议,定义的是传输数据的内容的规范
11、WebSocket
WebSocket是HTML5中的协议,支持持久连续,http协议不支持持久性连接。Http1.0和HTTP1.1都不支持持久性的链接,HTTP1.1中的keep-alive,将多个http请求合并为1个。
HTTP的生命周期通过Request来界定,也就是Request一个Response,那么在Http1.0协议中,这次Http请求就结束了。在Http1.1中进行了改进,是的有一个connection:Keep-alive,也就是说,在一个Http连接中,可以发送多个Request,接收多个Response。但是必须记住,在Http中一个Request只能对应有一个Response,而且这个Response是被动的,不能主动发起。
WebSocket是基于Http协议的,或者说借用了Http协议来完成一部分握手,在握手阶段与Http是相同的。
12、fetch发送2次请求的原因
我们所说的发送2次请求,其实就是在跨域请求时,编写了带预检请求的代码导致多了一次名为OPTIONS的尝试请求。
发送2次请求需要满足以下2个条件:
a、必须要在跨域的情况下
b、除GET、HEAD和POST(content-type: application/x-www-form-urlencoded, multipart/form-data, text/plain Content-Type)以外的跨域请求(我们可以称为预检(Preflighted)的跨域请求)。
之所以会发送2次请求(分别为OPTIONS请求与POST请求),那是因为我们使用了带预检(Preflighted)的跨域请求。该请求会在发送真实的请求之前发送一个类型为OPTIONS的预检请求。预检请求会检测服务器是否支持我们的真实请求所需要的跨域资源,唯有资源满足条件才会发送真实的请求。