聊聊http发展史

前言

HTTP(HyperText Transfer Protocal) 是超文本传输协议,http最初被打造出来就是为了传输文本内容,用作学术交流,将html文本布局传来传去,那个时候是没有后端的概念的,数据全是写死的,类似电子书。本期就带大家回顾下http的发展历程,认清咩个版本的优缺点~

HTTP/0.9

  1. 客户端发送get请求,比如请求一个/index.html
  2. 服务端接收请求,读取对应的html文件,以ASCII的字符流返回给客户端

特点

  1. 只有请求行,没有请求头和请求体,因此0.9版本的http也被称之为单行协议
  2. 因此也没有响应头
  3. 传输的内容是以ASCII的字符流

推动0.9到1.0的发展是网景公司,世界上第一款浏览器就是网景公司开发的,自从他推出浏览器后,万维网(World Wide Web)就不再是仅仅做学术交流了,互联网高速发展,万维网联盟(W3C)成立,http工作组同时成立,这个工作组专门致力于http协议的更新,以前查html,css,js就是在w3c上查找,类似现在的mdn

随着互联网需求的增加,0.9不再满足,1.0诞生

0.9只能传文本格式,用户接触浏览器不仅仅要看文本,还需要看图片,音频等格式

HTTP/1.0

  1. 相比较0.9,支持多种类型文件的传输,且不限于ASCII编码方式

  2. 既然多种文件,那么就需要信息告诉浏览器如何加载这些文件,因此引入请求头,响应头来让客户端和服务端更加深入的交流,并且是key-value的形式

为什么有了请求头和响应头就能支持多种文件的数据传输

请求头

accept: text/html 告诉服务端我期望接收到一个html的文件

accept-encoding: gzip, deflate, br 告诉服务端以这种方式压缩

accept-language: zh-CN 告诉服务端以中文的格式返回

响应头

content-encoding: br 告诉浏览器压缩方式是br

content-type: text/html; charset=utf-8 告诉浏览器以这种方式,编码加载

1.0时,比如展示一个页面,用到几个js文件,css文件,用一次就会单独用http请求一次,文件不多还好,但是随着需求增加,一个页面可能会用到很多js文件,以及第三方库,或者说图片资源,展示一个页面会发很多次请求,非常影响性能

HTTP/1.1

  1. 持久连接,一个tcp连接建立,可以传输多个http请求,减少了大量的tcp连接和断开连接带来的开销

    持久连接带来了队头阻塞的问题,这个问题没办法解决

  2. Chunk transfer机制处理动态数据包的长度

1.0时一个页面展示每用到一个js脚本,图片等都需要重新建立一次连接,做无畏的重复,因此1.1推出了持久连接或者长连接来解决这个问题

1.1可以建立一次tcp连接后,发送多个http请求,最后tcp关闭连接,持久连接在1.1是默认开启的,当然你也可以通过改请求头中的Connection字段,Connection: keep-alive || closeclose就是关闭的

实际开发中,页面所有的资源不可能全部一次性请求回来,比如有个按钮,点击后才会发请求,假设我页面初次加载的tcp请求还没有关闭,就点击了按钮,于是就会再次建立一次持久连接,这种建立是有数量限制的,通常为6-8个keep-alive,也就是tcp持久连接

凡事有利有弊,这种方式可以1次tcp连接 n 次http请求,我们设想一个情景,如果 n 个http请求有个http请求的数据很多,造成很慢,后面的http还会过来吗?不能,当年的http请求需要顺序,因此这就导致了http队头阻塞

队头阻塞

  • 管线化:批量化发请求(放弃)

针对这个http队头阻塞问题,http工作组想过一个解决方案,管线化,一次性把http请求全部发出去,这些http请求都会打上顺序标记,保证接收的顺序,谷歌和火狐以前采用过这个方案,但是不清楚出于什么原因放弃了这个方案

后面请求头中增加了一个host字段,这就导致了虚拟机技术的成熟,浏览器的同源策略就是通过host字段判断域名是否一致,虚拟机也会被分配ip,虚拟机和主机的ip是不同的,host当初就是用来区分虚拟机的域名地址的

另外,1.0时,需要在响应头中设置数据的大小,字段content-Length: 1024 比如这个就是1024个字节的大小,但是有时候后端也不清楚自己发送的数据多大,因为数据可能是动态的,这就导致了客户端不清楚自己是否接收完毕,1.1于是推出片段化数据,将数据分割成若干个任意大小的数据块,每个数据块发送时带有自身的长度,最后会发送一个长度为0的数据块来标志发送完毕,这就有点像是柯里化函数,最后不传参数才会执行函数

浏览器的cookie也是这个时候加入的,cookie虽然是浏览器的存储但是大部分是归于后端负责的,前端可以读取cookie的内容,另外cookie的内容也可以被设置为可读取不可读取,一般为了安全性会设置不可读取,这就是为了防止脚本攻击

HTTP/2.0

1.1的问题

  1. 带宽用不满,多条tcp连接竞争带宽导致每条tcp连接中能被分配的带宽大大降低
  2. tcp的慢启动:拥塞控制导致一定会慢启动,但是会推迟页面关键资源加载时间
  3. http队头阻塞问题,阻塞时会浪费带宽

1.1存在队头阻塞问题,以及6个持久连接,也就是说一个浏览器只能同时存在6个tcp的建立,一个tcp建立有多个http请求,其实这6个持久连接会共享网络速度,假设1000M宽带,网速最终就是1000/6M的效果,也就是说对网速的利用率很低,其实造成网速低的原因还有个就是tcp的慢启动,到达理想速度有个过程,这个慢启动就是为了解决网络拥塞问题

tcp慢启动有个问题就是,对于很小的cssjs文件,就没必要耗时这么久,文件大还好,文件小但是文件又很重要就很难受

多路复用

  1. 一个域名只使用一个tcp长连接
  2. 将每个请求分成一帧一帧的数据进行传输并打上标记,同时发送给服务端,且可以在重要资源请求中标记为加急,服务端接收到带有各种编号的数据帧后,可以区分哪个数据帧加急,优先处理和响应该请求的数据帧(通过引入了二进制分帧层实现多路复用)

首先,tcp的慢启动我们肯定无法进行优化的,只能进行规避,因此我就尽可能的少点tcp的建立连接,2.0的多路复用就是一个域名只使用一个tcp的长连接,6个变1个,这样就不会产生多个keep-alive占用带宽问题,因此网速大大提高

另外,多路复用还将每个请求都划分成一帧一帧的样子,每帧都会标记一些数据,比如标记加急,这样就可以解决http队头阻塞问题,里面就是因为引入了二进制分帧层

2.0同时引入了https

HTTP/HTTPS

首先一个请求行大概如下这样

GET /image/logo.png HTTP/1.1

这里提到get,顺带带大家认清getpost的区别

GET vs POST

getpost本质上没有很多区别,真要说区别需要从用法上来说

get没有加密效果!

要从用法上说就得扯上 副作用幂等

  • 副作用:对服务器上的资源有变更

    比如,搜索是不会对数据发生变更的,注册会有

  • 幂等:注册10次和20次不是幂等,新增了数据,但是更改文章10次和20次是幂等,改来改去还是那么多数据

get多作用于无副作用,幂等的场景,比如搜索

post多作用于有副作用,无幂等的场景,比如注册

从技术角度来说,get请求能缓存,post不能缓存

浏览器浏览页面会有历史页面的,历史页面就有urlget请求的数据放在url中,因此,get请求会被浏览器缓存住

要说安全,post请求确实是会安全一点,post请求放在请求体中,get请求拼接在url中

另外url的长度是有限的,所以get请求数据有限制,而post不会

post请求支持更多的编码类型,并且不对数据类型做限制

用过koa的小朋友都清楚,koa默认是不支持post的,需要另外安装依赖,就是因为post的数据类型太多了,不支持

总结

  1. get用于无副作用幂等的场景,post用于有副作用不幂等的场景
  2. get请求能缓存,post不能
  3. post相对安全一点,post的参数是在请求体中,get的参数是拼接在url
  4. url的长度有限制,所以get请求会受影响
  5. post支持更多的编码类型,且不对数据类型做限制

这里也顺带放下面试官喜欢问你的状态码

http状态码

200 请求成功,请求在服务端被正确处理

204 响应成功,没有数据

205 服务器处理成功,浏览器应重置文档视图

206 服务器成功处理了部分get请求

301 资源永久重定向 资源 后端换地方不作任何操作就是404

302 资源临时重定向

303 让你查看其他地址

304 请求的资源没有修改,服务端不会返回任何资源

400 请求语法错误,服务器看不懂

401 请求没有携带信息,比如token认证失败

403 请求被拒绝 敏感词

404 找不到资源

500 服务器内部错误,无法完成请求

501 服务器不支持当前请求所需的功能

503 服务器系统维护或者超载,暂时无法处理客户端的请求

回到http/https的比较

https是加密后的http,这个s就是TLS

因此https = http + tls

TLS位于传输层之上,应用层之下,TLS中包含了对称加密非对称加密

对称加密

对称加密需要客户端,服务端双方都知道加密的方式,以及解密的方式,或者说双方都有相同的密钥,都知道如何加密和解密

对称加密有个很大问题,双方如何清楚共同的密钥?通过传输的方式,密钥也是通过网络传输,这个过程要是被截取就完蛋了

非对称加密

非对称加密不同,非对称加密会有个公钥私钥,公钥用于加密,私钥用于解密,比如服务端发送一个公钥给客户端,客户端会用这个公钥进行加密,创建一个密钥,用公钥来加密这个密钥,给到服务端,服务端用独有的私钥进行解密得到密钥,两个过程都不怕被截取

tls是先用非对称加密让双方都有密钥,再对称加密进行数据传输

http2.0本身是没有问题的,问题主要存在tcp身上,因为这些版本的http都是基于tcptcp自身就有慢启动问题,不够高效

HTTP/3.0

http2.0的问题在于tcp,因为tcp有个慢启动问题,其实tcp还有个问题就是tcp的队头阻塞,因为tcp需要保证数据包传输的顺序,数据在传输的过程会出现丢包的问题,tcp有个超时重传的机制,为保证顺序就需要等待,这个过程就导致了队头阻塞

因此2.0的问题就是tcp的慢启动和``队头阻塞`

这个时候你肯定想,既然tcp有问题就去解决tcp的问题,实则不行,因为tcp作用于物理层,比如交换机就是物理层,里面的tcp要是变更了,全球的交换机就需要淘汰掉,就像是jsnull被当做obj一样,改不了了

像是这种tcp的问题无法解决,被称之为tcp僵化

其实导致tcp僵化的原因还有一点是操作系统,tcp协议是通过操作系统的内核实现的,应用程序只能使用不能修改

因此http工作组非常无奈,想要解决这些问题就只能不用tcp协议了

3.0基于的协议是QUIC协议

quic协议同样面临着tcp同样的挑战,因为quic协议需要硬件的支持,比较麻烦,但是又比更新tcp好,因为新增个quic协议至少不会让设备崩掉,更新tcp会很麻烦

这也就是为何3.0目前还没有普及的原因

QUIC协议

quic协议不是从0打造的,它是基于udp协议,udp的特点是高效,虽然不可靠,quic协议在udp上实现了类似于tcp的多路复用,可靠性传输等功能

  1. 实现了类似于tcp的流量控制和可靠性传输
  2. 集成了TLS加密
  3. 实现了HTTP2中的多路复用

缺点:需要浏览器,服务器,操作系统支持quic协议,普及开还需要一段时间

最后

一段话总结下http发展史:

0.9是最初版本,此时的http被称之为单行协议,因为只有请求行,没有请求头请求体,以ASCII码的形式传输,只能支持html文件类型,后面随着文件类型的增加,1.0诞生,可以支持多种文件类型的传输,并且不仅仅只支持ASCII这一种编码,引入了请求头响应头,因为里面的字段信息才可以区分文件类型等操作,但是1.0有个缺陷就是一个文件对应一个tcp的建立,后面1.1诞生,推出了keep-alive长连接,一个tcp的建立与断开之间可以有多个http请求,但是keep-alive的数量有限,6-8个,并且keep-alive带来了http队头阻塞的问题,就是一个http请求万一很慢,会阻塞后面的http请求,以前推出过管线化方法去解决,但是因为某些原因不采用了,至今无果,此时1.1还推出了host字段,导致后面虚拟机技术的成熟,并且1.0时的数据包会包含content-Length字段,但是有时候后端的数据是动态的,因此1.1推出Chunk transfer机制来处理动态数据,它是通过切片的形式进行传输,最终发送一个长度为0的数据块来标志发送完毕,因为1.1的队头阻塞问题,以及6个keep-alive共同占用网速的原因,对带宽的利用率很低,2.0诞生,2.0的多路复用,将6个keep-alive变成了一个,有效提高宽带利用率,并且通过二进制分帧层实现了对数据帧的传输顺序管理,解决了http队头阻塞问题,但是由于tcp僵化问题,比如无法解决它的慢启动和队头阻塞问题,3.0摒弃了tcp协议,采用了quic协议,这个协议基于udp,udp高效但是不可靠,于是quic又实现了类似于tcp的流量控制可靠性传输,并且还有加密,实现了多路复用,总之很强大,只是目前还没有普及开

如果你对春招感兴趣,可以加我的个人微信:Dolphin_Fung,我和我的小伙伴们有个面试群,可以进群讨论你面试过程中遇到的问题,我们一起解决

另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请"点赞+评论+收藏"一键三连,感谢支持!

相关推荐
丁总学Java14 分钟前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
懒羊羊大王呀25 分钟前
CSS——属性值计算
前端·css
睡觉然后上课34 分钟前
c基础面试题
c语言·开发语言·c++·面试
无咎.lsy1 小时前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec1 小时前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
fishmemory7sec1 小时前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
豆豆2 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建
twins35203 小时前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
邵泽明3 小时前
面试知识储备-多线程
java·面试·职场和发展
qiyi.sky3 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js