HTTP
一、HTTP简介
Web 使用一种名为 HTTP ( HyperText Transfer Protocol ,超文本传输协议的协议作为规范,完成从客户端到服务器端等一系列运作流程。 HTTP处于计算机网络中的应用层,HTTP是建立在TCP协议之上,所以HTTP协议的瓶颈及其优化技巧都是基于TCP协议本身的特性,例如tcp建立连接的3次握手和断开连接的4次挥手以及每次建立连接带来的RTT延迟时间。HTTP HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。默认HTTP的端口号为80,HTTPS的端口号为443。
HTTP 是一个属于应用层的面向对象的协议,HTTP 协议一共有五大特点:1、支持客户/服务器模式;2、简单快速;3、灵活;4、无连接;5、无状态。
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求并收到客户的应答后即断开连接。采用这种方式可以节省传输时间,可以尽快将资源释放出来服务其他客户端。HTTP1.1及以后出现了Keep-Alive,它可以使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。
无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即我们给服务器发送HTTP请求之后,服务器根据请求会给我们发送数据过来,但是发送完不会记录任何信息。HTTP协议这种特性有优点也有缺点,优点在于解放了服务器,每一次请求“点到为止”不会造成不必要连接占用,缺点在于每次请求会传输大量重复的内容信息。于是两种用于保持HTTP连接状态的技术就应运而生了,一个是Cookie另一个是Session。Cookie可以保持登录信息到用户下次与服务器的会话,下次访问同一网站时,用户会发现不必输入用户名和密码就已经登录了。
二、HTTP的报文结构
用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的空行( CR+LF )来划分。通常并不一定要有报文主体。
HTTP的 请求、响应 报文结构:
URI(统一资源标识符)和URL(统一资源定位符)
URI:一个用于标识某一互联网资源名称的字符串。组成:主机名(含端口号)+相对路径+标识符
URL:对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。组成:协议+主机名(含端口号)+相对路径
区别:URI表示请求资源在互联网上存在的位置,URL在表示请求资源的位置同时还要说明如何访问到这个资源,URL是URI的一个子集。
如http://www.baidu.com:80/login.jsp 其中https为协议,/login.jsp 为相对路径
HTTP的报文头部类型
1 通用首部字段( General Header Fields )请求报文和响应报文两方都会使用的首部。
| 首部字段名 | 说明
| ------------- |:-------------:
| Cache-Control|控制缓存的行为
| Connection|逐跳首部、连接的管理
| Date|创建报文的日期时间
| Pragma|报文指令
| Trailer|报文末端的首部一览
| Transfer-Encoding|指定报文主体的传输编码方式
| Upgrade|升级为其他协议
| Via|代理服务器的相关信息
| Warning|错误通知
2 请求首部字段( Request Header Fields )从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。
3 响应首部字段( Response Header Fields )从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
4 实体首部字段( Entity Header Fields )针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。
| 首部字段名 | 说明
| ------------- |:-------------:
| Allow| 资源可支持的 HTTP 方法
| Content-Encoding| 实体主体适用的编码方式
| Content-Language| 实体主体的自然语言
| Content-Length| 实体主体的大小(单位:字节)
| Content-Location| 替代对应资源的 URI
| Content-MD5| 实体主体的报文摘要
| Content-Range| 实体主体的位置范围
| Content-Type| 实体主体的媒体类型
| Expires| 实体主体过期的日期时间
| Last-Modified| 资源的最后修改日期时间
HTTP方法及状态码
HTTP方法
GET: 请求资源,GET请求可以将参数放入uri中也可以放入body,但不推荐get将参数放入body。
POST: 提交资源,POST将数据放在在body中 。
PUT: 传输文件,替换资源
DELETE: 删除资源
HEAD: 获得报文首部
OPTUIONS: 询问支持的方法
TRACK: 追踪路径,回显服务器收到的请求,用于测试诊断
CONNECT:要求用隧道协议连接代理
GET方法和POST方法的区别:
1)安全性:GET请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,参数将明文出现在URL上,URL信息也可能会被记录到历史纪录中。POST请求是把提交的数据则放置在HTTP包的包体中。
2)数据长度:HTTP协议没有对传输的数据和URL长度进行限制, 但特定浏览器和服务器对URL长度有限制, 因此对于GET提交时,传输数据就会受到URL长度的限制(大部分最多只能有1024字节);由于POST操作不是通过URL传值,理论上数据长度不受限;
3)缓存:GET 用于获取信息,是幂等的,GET请求能够被缓存,以GET请求的URL能够保存为浏览器书签,POST 用于修改服务器上的数据,非幂等,POST请求则都不能
4)数据获取:Get是向服务器发索取数据的一种请求;而Post是向服务器提交数据的一种请求,要提交的数据位于信息头后面的实体中。
HTTP状态码
1XX informational(信息性状态码) 接收的请求正在处理
100——客户必须继续发出请求
101——客户要求服务器根据请求转换HTTP协议版本
2XX Success(成功状态码) 请求正常处理完毕
200——交易成功
201——提示知道新文件的URL
202——接受和处理、但处理未完成
203——返回信息不确定或不完整
204——请求收到,但返回信息为空
205——服务器完成了请求,用户代理必须复位当前已经浏览过的文件
206——服务器已经完成了部分用户的GET请求
3XX Redirection(重定向状态码) 需要进行附加操作已完成请求
300——请求的资源可在多处得到
301——删除请求数据
302——在其他地址发现了请求数据
303——建议客户访问其他URL或访问方式
304——客户端已经执行了GET,但文件未变化
305——请求的资源必须从服务器指定的地址得到
306——前一版本HTTP中使用的代码,现行版本中不再使用
307——申明请求的资源临时性删除
4XX Client Error(客户端错误状态码) 服务器无法处理请求
400——错误请求,如语法错误
401——未授权
402——保留有效ChargeTo头响应
403——禁止访问
404——没有发现文件、查询或URl
405——用户在Request-Line字段定义的方法不允许
406——根据用户发送的Accept拖,请求资源不可访问
407——类似401,用户必须首先在代理服务器上得到授权
408——客户端没有在用户指定的饿时间内完成请求
409——对当前资源状态,请求不能完成
410——服务器上不再有此资源且无进一步的参考地址
411——服务器拒绝用户定义的Content-Length属性请求
412——一个或多个请求头字段在当前请求中错误
413——请求的资源大于服务器允许的大小
414——请求的资源URL长于服务器允许的长度
415——请求资源不支持请求项目格式
416——请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段
417——服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求长。
5XX Server Error(服务器端错误状态码) 服务器处理请求出错
HTTP 500 - 内部服务器错误
Error 501 - 未实现
HTTP 502 - 网关错误
Cookies&Session&token
cookie
cookie是http规范,存储在客户端,当客户端第一次登录服务端的时候,如果服务器需要记录用户状态,服务器会在响应信息中包含一个Set-Cookie的响应头,结构是一个字典,键是根据用户名和密码创建随机的字符串,值是客户端的所有操作的记录和状态,客户端会根据这个响应头存储Cookie信息。再次请求服务器时,客户端会在请求信息中包含一个Cookie请求头,服务器对该凭据进行用户身份、状态等验证,合法时使用户不必输入用户名和密码就可以直接登录。Cookie可以提高用户体验,但会加大网络之间的数据传输量,应尽量在Cookie中仅保存必要的数据。服务端生成cookie时若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口cookie就消失,称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里。若设置了过期时间,浏览器就会把cookie保存在硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。cookie 是不可跨域的,每个cookie都会绑定单一的域名,无法在别的域名下获取使用(foo.com域产生的cookie无法被bar.com域读取),一级域名和二级域名之间是允许共享使用的。
Session
Session是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。session是基于cookie实现的,存储在服务器端。用户第一次请求服务器的时候,服务器会根据用户提交的相关信息创建对应的Session,请求返回时会将此 Session 的唯一标识信息 SessionID 返回给浏览器,浏览器接收到服务器返回的 SessionID 信息后会将此信息存入到 Cookie 中,同时也会此 SessionID 属于哪个域名记录到该 Cookie 中。当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在则自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果找到 Session 证明用户已经登录可执行后面操作。如果没有找到说明用户没有登录或者登录失效。通常情况下,服务端会使用Set-Cookie标头来传递SessionID,这只是其中一种常见的方式,有些应用程序可能会将SessionID作为URL参数传递,或者使用自定义的HTTP头来传递。
token令牌
客户端使用用户名跟密码请求登录,服务端收到请求后去验证用户名与密码,验证成功后服务端通过加密算法签发一个token给客户端,客户端收到token后会把它存储起来,比如放在cookie里或者localStorage里,客户端每次向服务端请求资源的时候需要带着服务端签发的token,服务端收到请求后去验证客户端请求里面带着的 token ,如果验证成功就向客户端返回请求的数据。每一次请求都需要携带 token,需要把 token 放到 HTTP的 Header里。基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库。token完全由应用管理,所以它可以避开同源策略。token默认没有跨域限制。使用token就没有这样的问题。这对于需要向多个服务获取授权的单页面应用程序尤其有用,使用token使得用从myapp.com获取的授权向myservice1.com和myservice2.com获取服务成为可能。当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。token 传参有两种一种是放在请求头里,本质上是跟 cookie 是一样的,只是换个单词而已;另外一种是在 url 请求参数里,这种更直观。通常情况下,服务端会使用Set-Cookie标头来传递包含token的cookie。但并不是唯一的方式,服务端也可以将token直接作为响应体的一部分进行传递,或者使用自定义的HTTP头字段进行传递。
Cookie,Session和Token 的区别
安全性: Token比Session安全,Session比Cookie安全。Session存储在服务器端,Cookie存储在客户端,token存储在客户端。
存取值的类型不同:Cookie 只支持存字符串数据,Session 可以存任意数据类型。客户端发送session和token都要借助cookie。
有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭或者 Session 超时都会失效。
存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于Cookie,但是当访问量过多会占用过多的服务器资源。
cookie格式如下:
Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"其中name=value是必选项,其它都是可选项。Cookie的主要构成如下: name:一个唯一确定的cookie名称。通常来讲cookie的名称是不区分大小写的。 value:存储在cookie中的字符串值。最好为cookie的name和value进行url编码 domain:cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:yq.aliyun.com),也可以不包含它(如:.aliyun.com,则对于aliyun.com的所有子域都有效). path: 表示这个cookie影响到的路径,浏览器跟会根据这项配置,像指定域中匹配的路径发送cookie。 expires:失效时间,表示cookie何时应该被删除的时间戳(也就是何时应该停止向服务器发送这个cookie)。如果不设置这个时间戳,浏览器会在页面关闭时即将删除所有cookie;不过也可以自己设置删除时间。
这个值是GMT时间格式,如果客户端和服务器端时间不一致,使用expires就会存在偏差。 max-age: 与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒),而不是一个固定的时间点。正常情况下,max-age的优先级高于expires。 HttpOnly: 告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见。但在http请求张仍然会携带这个cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器
安装目录中以文件形式存在。这项设置通常在服务器端设置。 secure: 安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息
放cookie就对了服务器端设置
三、HTTP1
HTTP协议永远都是客户端发起请求,服务器回送响应。这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。HTTP协议是一个无状态的协议,同一个客户端的这次请求和上次请求是没有对应关系。HTTP/1.0于1996年5月公布。HTTP/1.1于1997年1月公布。
HTTP通信机制
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤
1. 建立TCP连接 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,HTTP是比TCP更高层次的应用层协议,只有低层协议建立之后才能进行更高层协议的连接,因此首先要建立TCP连接。
2. Web浏览器向Web服务器发送请求命令 一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。例如:GET/sample/hello.jsp HTTP/1.1。
3. Web浏览器发送请求头信息 浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4. Web服务器应答 客户机向服务器发出请求后,服务器会客户机回送应答, HTTP/1.1 200 OK ,应答的第一部分是协议的版本号和应答状态码。
5. Web服务器发送应答头信息 正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6. Web服务器向浏览器发送数据 Web服务器向浏览器发送头信息后,紧接着会发送一个空白行来表示头信息的发送到此为结束,接着,服务器就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。
7. Web服务器关闭TCP连接 一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码:Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。
在上图中,可清晰的看到客户端浏览器(ip为192.168.2.33)与服务器的交互过程:
1)No1:浏览器(192.168.2.33)向服务器(220.181.50.118)发出连接请求。此为TCP三次握手第一步,此时从图中可以看出,为SYN,seq:X (x=0)
2)No2:服务器(220.181.50.118)回应了浏览器(192.168.2.33)的请求,并要求确认,此时为:SYN,ACK,此时seq:y(y为0),ACK:x+1(为1)。此为三次握手的第二步;
3)No3:浏览器(192.168.2.33)回应了服务器(220.181.50.118)的确认,连接成功。为:ACK,此时seq:x+1(为1),ACK:y+1(为1)。此为三次握手的第三步;
4)No4:浏览器(192.168.2.33)发出一个页面HTTP请求;
5)No5:服务器(220.181.50.118)确认;
6)No6:服务器(220.181.50.118)发送数据;
7)No7:客户端浏览器(192.168.2.33)确认;
8)No14:客户端(192.168.2.33)发出一个图片HTTP请求;
9)No15:服务器(220.181.50.118)发送状态响应码200 OK
……
持久连接
HTTP1.0每进行一次HTTP请求就会断开一次TCP连接,连接不能复用。这情况在早期传输文本很小的时候倒也不觉得如何,但是随着时代的进步,所需传输的内容种类越来越多和内容越来越大了,每次连接后都会断开请求就大幅度的增加了通信量的开销了。
HTTP/1.1有了持久连接,新的请求可以在上次请求建立的TCP连接之上发送,连接可以复用。它规定了只要任何一方没有明确的提出断开连接,那么就保持TCP连接状态。而在维持的TCP连接期间,可以多次进行HTTP请求来传输需要的内容。长连接情况下,多个HTTP请求可以复用同一个TCP连接,这就节省了很多TCP连接建立和断开的消耗。
HTTP/1.1默认保持持久连接,在HTTP的头部信息中会有Connection: Keep-alive属性,在响应头设置Connection属性为close即可关闭持久连接。我们也可以通过浏览器开发工具的NetWork面板查看这个属性的状态及HTTP请求信息:
如果你是短连接的话,那你每打开一个网页,基本要建立几个甚至几十个TCP连接,这很浪费资源。但如果是长连接的话,那么这么多次HTTP请求,其实使用的都是一个TCP连接,很显然是可以节省很多消耗的。长连接并不是永久连接的,如果一段时间内(具体的时间长短,是可以在header当中进行设置的,也就是所谓的超时时间),这个连接没有HTTP请求发出的话,那么这个长连接就会被断掉。
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。 而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,如果每个用户都占用一个连接的话,并发量会很大。
HTTP协议中的长轮询和短轮询
短轮询不难理解,比如你现在要做一个电商中商品详情的页面,这个详情界面中有一个字段是库存量。而这个库存量需要实时的变化,保持和服务器里实际的库存一致。这个时候,最简单的一种方式,就是写个死循环,不停的去请求服务器中的库存量是多少,然后刷新到这个页面当中,这其实就是所谓的短轮询。长轮询和短轮询最大的区别是,短轮询去服务端查询的时候,不管库存量有没有变化,服务器就立即返回结果了。而长轮询则不是,在长轮询中,服务器如果检测到库存量没有变化的话,将会把当前请求挂起一段时间(这个时间也叫作超时时间,一般是几十秒)。在这个时间里,服务器会去检测库存量有没有变化,检测到变化就立即返回,否则就一直等到超时为止。而对于客户端来说,不管是长轮询还是短轮询,客户端的动作都是一样的,就是不停的去请求,不同的是服务端,短轮询情况下服务端每次请求不管有没有变化都会立即返回结果,而长轮询情况下,如果有变化才会立即返回结果,而没有变化的话,则不会再立即给客户端返回结果,直到超时为止。
长短轮询和长短连接的区别
第一,一个TCP连接是否为长连接,是通过设置HTTP的Connection Header来决定的,而且是需要两边都设置才有效。而一种轮询方式是否为长轮询,是根据服务端的处理方式来决定的,与客户端没有关系。
第二个区别就是实现的方式,连接的长短是通过协议来规定和实现的。而轮询的长短,是服务器通过编程的方式手动挂起请求来实现的。
HTTP/1.x的缺陷
- 连接无法复用:连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对大量小文件请求影响较大(未达到最大窗口请求就被终止)。
-
- HTTP/1.0传输数据时,每次都需要重新建立连接,增加延迟。
- HTTP/1.1虽然加入keep-alive可以复用一部分连接,但域名分片等情况下仍然需要建立多个connection,耗费资源,给服务器带来性能压力。
-
- 队头阻塞(HOLB):导致带宽无法被充分利用,以及后续健康请求被阻塞。HOLB是指一系列包因为第一个包被阻塞;HOLB会导致在达到最大请求数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。
- HTTP 1.0:下个请求必须在前一个请求返回后才能发出,
request-response
对按序发生。显然,如果某个请求长时间没有返回,那么接下来的请求就全部阻塞了。 - HTTP 1.1:尝试使用 pipeling 来解决,即浏览器可以一次性发出多个请求(同个域名,同一条 TCP 链接)。但 pipeling 要求返回是按序的,那么前一个请求如果很耗时(比如处理大图片),那么后面的请求即使服务器已经处理完,仍会等待前面的请求处理完才开始按序返回。所以,pipeling 只部分解决了 HOLB。
- 协议开销大: HTTP1.x在使用时,header里携带的内容过大,在一定程度上增加了传输的成本,并且每次请求header基本不怎么变化,尤其在移动端增加用户流量。
- 安全因素:HTTP1.x在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性
一条连接上只可发送一个请求。
请求只能从客户端开始。客户端不可以接收除响应以外的指令。
请求 / 响应首部未经压缩就发送。首部信息越多延迟越大。
发送冗长的首部。每次互相发送相同的首部造成的浪费较多。
HTTP/1.1版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。
HTTP/2.0版的头信息,数据体都是二进制。
四、HTTP/2
随着 web 技术的飞速发展。 HTTP 1.1 已经无法满足用户对性能的要求, HTTP/2主要基于 SPDY 协议。HTTP/2标准于2015年5月发表。
HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。 HTTP / 1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
二进制分帧
- 帧(帧):HTTP/2数据通信的最小单位。
- 消息(Message):指 HTTP/2 中逻辑上的 HTTP 消息。例如请求和响应等,消息由一个或多个帧组成。
- 流(流):存在于连接中的一个虚拟通道。流可以承载双向消息,每个流都有一个唯一的整数ID。
HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。
多路复用
多路复用代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP连接并发完成。HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8 的个数限制,如下图,红色圈出来的请求就因域名链接数已超过限制,而被挂起等待了一段时间:
在 HTTP/2 中,有了二进制分帧之后,HTTP/2 不再依赖 TCP 链接去实现多流并行了,在 HTTP/2中:
●同域名下所有通信都在单个连接上完成。
●单个连接可以承载任意数量的双向数据流。
●数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
这一特性,性能会有极大的提升,因为:
●同个域名只需要占用一个 TCP 连接,消除了因多个 TCP 连接而带来的延时和内存消耗。
●单个连接上可以并行交错的请求和响应,之间互不干扰。
●在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。
服务器推送
服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML再发送这些请求。服务端可以主动推送,客户端也有权利选择接收与否。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。
头部压缩
HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,因为它们需要等待带着ACK的响应回来以后才能继续被发送。HTTP/2对消息头采用HPACK(专为http2头部设计的压缩格式)进行压缩传输,能够节省消息头占用的网络的流量。而HTTP/1.x每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。
HTTP 每一次通信都会携带一组头部,用于描述这次通信的的资源、浏览器属性、cookie 等,例如
为了减少这块的开销并提升性能, HTTP/2会压缩这些首部:
●HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
●首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
●每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。
例如:下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销。
我们来看一个实际的例子,下面是用WireShark抓取的访问google首页的包:
上图是是访问https://www.google.com/抓到的第一个请求的头部,可以看到头部的内容,总共占用了437 bytes,我们选中头部的cookie,可以看到cookie总共占用了118 bytes。接下来我们看看第二个请求的头部:
从上图可以看到,得益于头部压缩,第二个请求中cookie只占用了1个字节,我们来看看变化了的Accept字段:
由于Accept字段与请求一中的内容不同,需要发送给服务器,所以占用了29 bytes。
HTTP/2.0核心优势/特性
多路复用:多个请求都是通过一个 TCP 连接并发完成(HTTP/1.1管线化在多个请求之间的响应会被阻塞,HTTP/2.0解决了这问题,并且支持优先级和流量控制)
头部压缩:报文头部压缩处理,数通信量更小
服务端推送:服务端能够更快的把资源推送给客户端
语义改进:采用二进制格式传输数据
五、HTTPS
HTTP是明文传输的,也就意味着,介于发送端和接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。HTTPS全称Hyper Text Transfer Protocol over Secure Socket Layer,直译过来就是通过SSL实现的超文本传输协议,简单来讲就是加密版的HTTP协议,也就是HTTP+SSL/TLS。HTTPS是HTTP运行在SSL/TLS之上,HTTPS使用对称加密和非对称加密相结合的方式来实现内容加密。
SSL/TLS
为了解决HTTP明文传输的风险性,网景公司设计了SSL。SSL目前的版本是3.0,之后IETF对SSL 3.0进行了升级,于是出现了TLS 1.0。简单而言就是TLS是SSL的升级版,现在浏览器一般用的都是TLS。
SSL(Secure Socket Layer,安全套接字层):1994年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。他的版本有:SSL 1.0、SSL 2.0、SSL 3.0
TLS(Transport Layer Security,传输层安全):其前身是 SSL,1999年从 3.1 开始被 IETF 标准化并改名为TLS,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。
SSL3.0和TLS1.0由于存在安全漏洞,已经很少被使用到。目前使用最广泛的是TLS 1.1、TLS 1.2。
两种基本的加解密算法类型:
1)对称加密:密钥只有一个,加密解密为同一个密码,且加解密速度快,典型的对称加密算法有DES、AES等;
2)非对称加密:密钥成对出现,加密解密使用不同密钥(公钥加密需要私钥解密,私钥加密需要公钥解密),相对对称加密速度较慢,典型的非对称加密算法有RSA、DSA等。
HTTPS加密方式介绍
浏览器-->SSL Client Hello(我支持这些加密方式)-->服务器
浏览器<-SLL Server Hello(就用这种加密,然后下面是我的证书)-<--服务器
浏览器-->证书验证ok,拿证书里的公钥加密key,告诉服务器-->服务器
浏览器<--私钥解密,得到key<--服务器
开始以对称密钥的方式,加密通信,密钥即key
HTTPS的优点
从实际出发来看,HTTPS主要有以下优点:
1防止私密信息泄露,防止信息被篡改;
2有助于SEO,百度、谷歌均明确表示会优先收录、展示HTTPS站点的内容;
3完全杜绝运营商HTTP劫持问题;
4有效解决运营商DNS劫持问题,降低网站被劫持的风险;
5HTTPS的小绿锁表示可以提升用户对网站信任程度(当然不是说有小绿锁的都是安全的);
6可以有效防止山寨、镜像网站等;
7为未来升级HTTP/2做准备,HTTP/2必须基于HTTPS部署;
HTTPS的缺点
1服务器性能下降,开启HTTPS会增加内存、CPU、网络带宽的开销,特别是非对称加密这一块;
2访问速度下降,HTTP连接的建立需要3次握手,HTTPS还需要加上ssl的几次握手,当然下降主要是在第一次建立连接的时候,后面正常通信速度一般没啥变化;
3除了握手部分外,所有信息传输之后浏览器和服务器都要进行加密解密,又是一笔额外的开销;
4申请证书需要一笔花费,当然现在免费证书也很容易申请到,这个不算明显缺点;
HTTPS原理
HTTPS主要分为单向认证和双向认证,99%的场景都只需要单向认证。
单向认证
1浏览器访问一个https地址,同时向服务端发送支持的SSL协议版本、支持的加密算法、一个客户端生成的随机数(用于稍后生成"对话密钥")等。
2服务端给客户端返回要使用的SSL协议版本号、加密算法、一个服务器生成的随机数(也同样用于稍后生成"对话密钥"),另外还有一个最重要的,返回服务器端的证书,即公钥证书;
3客户端收到服务器回应以后,首先验证证书是否合法,如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期、或者返回的公钥不能正确解开返回证书中的数字签名,就会向访问者显示一个警告,由其选择是否还要继续通信。如果证书没有问题,客户端就会从证书中取出服务器的公钥继续;
客4户端向服务端发送自己所能支持的对称加密方案(注意是对称加密),供服务器端进行选择;
5服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;
6服务器将选择好的加密方案通过明文方式返回给客户端;
7客户端接收到服务端返回的加密方式后,使用该加密方式生成产生一个随机密钥(后续用作通信过程中对称加密的密钥),然后将该随机数用用证书中的公钥加密发给服务端;
8服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获得最终的对称加密密钥。至此,客户端和服务端都得到一个随机密钥,并且这个密钥别人没法知道;
9在接下来的会话中,服务器和客户端将会使用该密码进行对称加密解密,保证通信过程中信息的安全。
双向认证
双向认证和单向认证原理基本差不多,主要区别是除了客户端需要认证服务端以外,服务端对客户端也需要认证。什么场景下需要验证客户端呢?比如一些银行业务,银行会要求客户必须在电脑上插入它们签发的U盾之类的东西,或者安装什么控件,这里就类似客户端证书的概念,没有这个证书的人无法使用银行提供的业务。
一次完整的HTTPS请求
1.客户端发送Client Hello报文开始SSL通信,报文中包含客户端支持的SSL的指定版本、加密组件列表等
2.服务端可进行SSL通信时,会以Serve rHello报文作为应答
3.服务端发送Certificate报文,报文包含公开密钥证书
4.服务端发送Server Hello Done报文通知客户端,最初阶段的SSL握手协商部分结束
5.SSL第一次握手结束后,客户端以Client Key Exchange报文作为回应,其中包含通信加密中使用的随机密码串
6.客户端发送Change Cipher Spec报文,提示服务端此报文之后的通信采用符合上一步的随机密码串的密钥加密
7.客户端发送Finished报文,其中包含连接至今全部报文的整体校验值
8.服务端发送Change Cipher Spec报文
9.服务端发送Finished报文
10.Finished报文交换完毕后,SSL连接建立完成
11.应用层协议通信,HTTP
12.客户端断开连接,发送close notify
TLS握手过程
在建立TCP连接后,开始建立TLS连接。TSL握手协议如下图所示
(1) client端发起握手请求,会向服务器发送一个ClientHello消息,该消息包括其所支持的SSL/TLS版本、Cipher Suite加密算法列表(告知服务器自己支持哪些加密算法)、sessionID、随机数等内容。
(2) 服务器收到请求后会向client端发送ServerHello消息,其中包括:
SSL/TLS版本;
session ID,因为是首次连接会新生成一个session id发给client;
Cipher Suite,sever端从Client Hello消息中的Cipher Suite加密算法列表中选择使用的加密算法;
Radmon 随机数。
(3) 经过ServerHello消息确定TLS协议版本和选择加密算法之后,就可以开始发送证书给client端了。证书中包含公钥、签名、证书机构等信息。
(4) 服务器向client发送ServerKeyExchange消息,消息中包含了服务器这边的EC Diffie-Hellman算法相关参数。此消息一般只在选择使用DHE 和DH_anon等加密算法组合时才会由服务器发出。
(5) server端发送ServerHelloDone消息,表明服务器端握手消息已经发送完成了。
(6) client端收到server发来的证书,会去验证证书,当认为证书可信之后,会向server发送ClientKeyExchange消息,消息中包含客户端这边的EC Diffie-Hellman算法相关参数,然后服务器和客户端都可根据接收到的对方参数和自身参数运算出Premaster secret,为生成会话密钥做准备。
(7) 此时client端和server端都可以根据之前通信内容计算出Master Secret(加密传输所使用的对称加密秘钥),client端通过发送此消息告知server端开始使用加密方式发送消息。
(8) 客户端使用之前握手过程中获得的服务器随机数、客户端随机数、Premaster secret计算生成会话密钥master secret,然后使用该会话密钥加密之前所有收发握手消息的Hash和MAC值,发送给服务器,以验证加密通信是否可用。服务器将使用相同的方法生成相同的会话密钥以解密此消息,校验其中的Hash和MAC值。
(9) 服务器发送ChangeCipherSpec消息,通知客户端此消息以后服务器会以加密方式发送数据。
(10) sever端使用会话密钥加密(生成方式与客户端相同,使用握手过程中获得的服务器随机数、客户端随机数、Premaster secret计算生成)之前所有收发握手消息的Hash和MAC值,发送给客户端去校验。若客户端服务器都校验成功,握手阶段完成,双方将按照SSL记录协议的规范使用协商生成的会话密钥加密发送数据。