zoukankan      html  css  js  c++  java
  • HTTP

    一、HTTP简介

    Web 使用一种名为 HTTP ( HyperText Transfer Protocol ,超文本传输协议的协议作为规范,完成从客户端到服务器端等一系列运作流程。本文探讨的是HTTP/1.1版本。这仍然是大多数网站采用的HTTP协议

    IP

    IP 协议的作用是把各种数据包传送给对方。而要保证确实传送到对方那里,则需要满足各类条件。其中两个重要的条件是 IP 地址和 MAC地址( Media Access Control Address )。IP 地址指明了节点被分配到的地址, MAC 地址是指网卡所属的固定地址。 IP 地址可以和 MAC 地址进行配对。 IP 地址可变换,但 MAC地址基本上不会更改。IP使用 ARP 协议凭借 MAC 地址进行通信

    TCP(确保可靠性的协议)

    按层次分, TCP 位于传输层,提供可靠的字节流服务。所谓的字节流服务( Byte Stream Service )是指,为了方便传输,将大块数据分割成以报文段( segment )为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠地传给对方。

    TCP连接的3次握手

    为了准确无误地将数据送达目标处, TCP 协议采用了三次握手( three-way handshaking )策略。
    握手过程中使用了 TCP 的标志( flag ) —— SYN ( synchronize ) 和ACK ( acknowledgement )。发送端首先发送个带 SYN 标志的数据包给对方。接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,代表 “ 握手 ” 结束。若在握手过程中某个阶段莫名中断, TCP 协议会再次以相同的顺序发送相同的数据包。整个过程如下图所示

    为什么需要3次握手

    为什么需要3次握手,如果面试中问到了TCP相关知识,那么这个问题也几乎是必问的,为什么是3次,而不是1次,2次或者4次,5次??

    首先我们知道不管是客户端或者服务端发送数据都会消耗网络流量,还会造成许多不必要的通信开销,浪费资源,所以我们在保证TCP可靠性的前提下所经历的通信次数自然越少越好。

    TCP的可靠性含义我们上面已经说了,那我们就从3次握手分析,如果只有1次握手,客户端只向服务端发送数据,那么就谈不上可靠性了,因为服务端都没有回复,那么我们来看只有2次握手行不行,如果只有2次握手,客户端只向服务端发送数据,服务器也向客户端回复我收到数据了,但是考虑此时如果发送数据的过程中数据丢失了,服务端认为连接建立了(数据我已经发出去了),可是客户端没有收到数据,客户端认为连接没有建立,就会重复请求,而这对与服务端来说就又是一个全新的连接。一言以蔽之:第三次握手是为了防止:如果客户端迟迟没有收到服务器返回确认报文,这时会放弃连接,重新启动一条连接请求,但问题是:服务器不知道客户端没有收到,所以他会收到两个连接,浪费连接开销。如果每次都是这样,就会浪费多个连接开销。

    二、HTTP的报文结构

    用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的空行( CR+LF )来划分。通常,并不一定要有报文主体。

    HTTP的请求以及响应报文结构

    HTTP的报文头部

    下面的是请求某网站时,请求报文以及响应报文的首部信息。

    请求报文首部

    Host: hackr.jp
    User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    Accept-Encoding: gzip, deflate
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1

    响应报文首部

    HTTP/1.1 200 OK
    Date: Thu, 23 Aug 2018 08:17:43 GMT
    Server: Apache
    Last-Modified: Tue, 08 Jan 2013 08:53:29 GMT
    ETag: "25e-4d2c3145df440-gzip"
    Accept-Ranges: bytes
    Vary: Accept-Encoding,User-Agent
    Content-Encoding: gzip
    Content-Length: 379
    Keep-Alive: timeout=15, max=100
    Connection: Keep-Alive
    Content-Type: text/html

    由上可知HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号 “:” 分隔。

    HTTP的报文头部类型

    HTTP 首部字段根据实际用途被分为以下 4 种类型。

    通用首部字段( General Header Fields )请求报文和响应报文两方都会使用的首部。
    | 首部字段名 | 说明
    | ------------- |:-------------:
    | Cache-Control|控制缓存的行为
    | Connection|逐跳首部、连接的管理
    | Date|创建报文的日期时间
    | Pragma|报文指令
    | Trailer|报文末端的首部一览
    | Transfer-Encoding|指定报文主体的传输编码方式
    | Upgrade|升级为其他协议
    | Via|代理服务器的相关信息
    | Warning|错误通知

    请求首部字段( Request Header Fields )从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
    | 首部字段名 | 说明
    | ------------- |:-------------:
    | Accept| 用户代理可处理的媒体类型
    | Accept-Charset| 优先的字符集
    | Accept-Encoding| 优先的内容编码
    | Accept-Language| 优先的语言(自然语言)
    | Authorization| Web 认证信息
    | Expect| 期待服务器的特定行为
    | From| 用户的电子邮箱地址
    | Host| 请求资源所在服务器
    | If-Match| 比较实体标记( ETag )
    | If-Modified-Since| 比较资源的更新时间
    | If-None-Match| 比较实体标记(与 If-Match 相反)
    | If-Range| 资源未更新时发送实体 Byte 的范围请求
    | If-Unmodified-Since| 比较资源的更新时间(与 If-Modified-Since 相反)
    | Max-Forwards| 最大传输逐跳数
    | Proxy-Authorization| 代理服务器要求客户端的认证信息
    | Range| 实体的字节范围请求
    | Referer| 对请求中 URI 的原始获取方
    | TE| 传输编码的优先级
    | User-Agent| HTTP 客户端程序的信息

    响应首部字段( Response Header Fields )从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
    | 首部字段名 | 说明
    | ------------- |:-------------:
    | Accept-Ranges| 是否接受字节范围请求
    | Age| 推算资源创建经过时间
    | ETag| 资源的匹配信息
    | Location| 令客户端重定向至指定 URI
    | Proxy-Authenticate| 代理服务器对客户端的认证信息
    | Retry-After| 对再次发起请求的时机要求
    | Server| HTTP 服务器的安装信息
    | Vary| 代理服务器缓存的管理信息
    | WWW-Authenticate| 服务器对客户端的认证信息

    实体首部字段( Entity Header Fields )针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。
    | 首部字段名 | 说明
    | ------------- |:-------------:
    | Allow| 资源可支持的 HTTP 方法
    | Content-Encoding| 实体主体适用的编码方式
    | Content-Language| 实体主体的自然语言
    | Content-Length| 实体主体的大小(单位:字节)
    | Content-Location| 替代对应资源的 URI
    | Content-MD5| 实体主体的报文摘要
    | Content-Range| 实体主体的位置范围
    | Content-Type| 实体主体的媒体类型
    | Expires| 实体主体过期的日期时间
    | Last-Modified| 资源的最后修改日期时间

    HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分成 2 种类型

    1. 端到端首部( End-to-end Header )
      分在此类别中的首部会转发给请求 / 响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。
    2. 逐跳首部( Hop-by-hop Header )
      分在此类别中的首部只对单次转发有效,会因通过缓存或代理而不再转发。 HTTP/1.1 和之后版本中,如果要使用 hop-by-hop 首部,需提供 Connection 首部字段。

    下面列举了 HTTP/1.1 中的逐跳首部字段。除这 8 个首部字段之外,其他所有字段都属于端到端首部

    • Connection
    • Keep-Alive
    • Proxy-Authenticate
    • Proxy-Authorization
    • Trailer
    • TE
    • Transfer-Encoding
    • Upgrade

    关于各个首部命令的详细参数可参见HTTP Headers

    三、HTTP进阶

    如果这篇文章到上面为止,那跟手册貌似没有什么区别,之前听到过一位大神说的话,掌握一门技术,不仅需要知道这门技术能做到什么,也要知道它不能做到什么,在掌握一门技术的边界之后,便对一门技术游刃有余了,毕竟技术那么多,推陈换代那么快,对于大多数人来说没有精力貌似也不是十分必要去记忆技术的每一个细节(即使记忆了,有许多细节是我们平常用不到的,也就渐渐遗忘了)。在我们掌握边界以后,遇到问题时,我们知道这个问题能依靠该项技术解决,至于怎么解决,那时我们在去查相应手册即可。

    那对于本篇的HTTP来说,我们就从以下两方面进行分析

    HTTP能做到什么

    我们下面结合实际工作中的所遇到的HTTP的应用场景分为两大方面

    访问大数据(图片,视频,大文件)时

    在访问这些大数据时,我们往往会遇到以下问题
    1. 如何请求部分数据?
    2. 假设已请求了某资源的部分数据,程序终止了,服务器更新了该资源,客户端如何做,即已缓存的数据是否可信?

    我们通常在做下载功能的时候往往需要断点续传甚至多线程断点续传,那么上面的问题就肯定会遇到。下面我们一一解答
    1.使用Range来请求某个资源的部分数据

    Range: bytes=bytes=200-1000, 2000-6576, 19000-
    表示请求获取从第 200 字节至第1000 ,2000-6576,19000之后所有字节的资源。
    在一个  Range 首部中,可以一次性请求多个部分,服务器会以 multipart 文件的形式将其返回。
    如果服务器返回的是范围响应,需要使用 206 Partial Content 状态码。
    假如所请求的范围不合法,那么服务器会返回  416 Range Not Satisfiable 状态码,表示客户端错误。
    

    2.ETag以及If-Match If-None-Match If-Range

    响应首部字段ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag值。另外,当资源更新时, ETag 值也需要更新。生成 ETag 值时,并没有统一的算法规则,而仅仅是由服务器来分配。

    ETag 中有强 ETag 值和弱 ETag 值之分。
    强 ETag 值,不论实体发生多么细微的变化都会改变其值。ETag: "1234"
    弱 ETag 值,只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时,会在字段值最开始处附加 W/。ETag: W/"1234"

    请求首部字段If-Match If-None-Match If-Range
    形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。
    If-Match ,它会告知服务器匹配资源所用的实体标记( ETag )值。这时的服务器无法使用弱 ETag 值。服务器会比对 比If-Match 的字段值和资源的 ETag 值,仅当两者一致时,才会执行请求。反之,则返回状态码 412 Precondition Failed 的响应。还可以使用星号( * )指定 If-Match 的字段值。针对这种情况,服务器将会忽略 ETag 的值,只要资源存在就处理请求。

    If-None-Match 只有在 If-None-Match 的字段值与 ETag 值不一致时,可处理该请求。与 If-Match 首部字段的作用相反

    If-Range 浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。浏览器通过发送请求对象的ETag 或者自己所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。总是跟 Range 头部一起使用。

    使用形式如下

    If-Range: Wed, 21 Oct 2015 07:28:00 GMT
    Range: bytes=bytes=200-1000
    
    If-Range: "1234"
    Range: bytes=bytes=200-1000
    

    If-Range 头字段通常用于断点续传的下载过程中,用来自从上次中断后,确保下载的资源没有发生改变。

    通常情况下的HTTP请求与响应

    我们现在的服务器大多是符合RESTFUL规范的,作为客户端(网页、Android、IOS)来说,我们与服务器的通常交互是数据量比较小的操作,增删改查,传递以及解析显示JSON数据。这是我们通常使用HTTP的场景。这种场景下所常用的HTTP头部字段是包含上述访问大数据(图片,视频,大文件)时的请求字段的,这些首部字段各有含义,见HTTP Headers

    HTTP不能做到什么(缺陷)

    • 一条连接上只可发送一个请求。
    • 请求只能从客户端开始。客户端不可以接收除响应以外的指令。
    • 请求 / 响应首部未经压缩就发送。首部信息越多延迟越大。
    • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多。

    备注:由于上述HTTP/1.1协议的缺陷,SPDY 和 WebSocket 等协议纷纷出现,还有HTTP/2.0版本,这些协议的出现在一定程度上弥补了HTTP/1.1协议的缺陷。感兴趣的同学可以深入了解。

    四、HTTP1.1
    HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。HTTP HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。默认HTTP的端口号为80,HTTPS的端口号为443。
    HTTP协议永远都是客户端发起请求,服务器回送响应。这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。HTTP协议是一个无状态的协议,同一个客户端的这次请求和上次请求是没有对应关系。

    HTTP/1.0于1996年5月公布,该协议至今仍被广泛用在服务器端。
    HTTP/1.1于1997年1月公布,是目前主流的HTTP协议版本。
    HTTP/2.0正在制定中。

    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
    ……

    TCP/IP通信传输流程(http举例)
    首先作为发送端的客户端在应用层(http协议)发出一个想看某个web页面的http请求。接着,为了传输的方便,在传输层(tcp协议)把从应用层处收到的数据(http请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。在网络层(ip协议)增加作为通信目的地的MAC地址后转发给链路层。这样,发往网络的通信请求就齐全了。

    HTTP/1.0 每次请求都需要建立新的TCP连接,连接不能复用。HTTP/1.1 新的请求可以在上次请求建立的TCP连接之上发送,连接可以复用。优点是减少重复进行TCP三次握手的开销,提高效率。在同一个TCP连接中,新的请求需要等上次请求收到响应后,才能发送。
    与HTTP协议密切相关的协议/服务:IP,TCP,DNS
    IP协议负责数据包的传送,当然,这需要配合IP地址和MAC地址,IP间的通信依赖MAC地址,这就涉及到用以解析地址的ARP协议了。
    DNS服务负责解析域名
    TCP提供了可靠的字节流服务,对要发送的大块数据进行分割成小数据包以易于传输,并且该协议可确认数据包是否送达到目的方。
    1)异步
    报文发送和接收是分开的,相互独立的,互不影响。这种方式又分两种情况:
    (1)异步双工:接收和发送在同一个程序中,由两个不同的子进程分别负责发送和接收
    (2)异步单工:接收和发送是用两个不同的程序来完成。
    2)同步
    报文发送和接收是同步进行,即报文发送后等待接收返回报文。 同步方式一般需要考虑超时问题,即报文发出去后不能无限等待,需要设定超时时间,超过该时间发送方不再等待读返回报文,直接通知超时返回。
    在长连接中一般是没有条件能够判断读写什么时候结束,所以必须要加长度报文头。读函数先是读取报文头的长度,再根据这个长度去读相应长度的报文。

    3)TCP三次握手

    在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接,完成三次握手,客户端与服务器开始传送数据。
    (1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
    (2)第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
    (3)第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。

    由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。采用四次握手释放一个连接,
    (1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
    (2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
    (3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
    (4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
    为了释放一个连接,任何一方都可以发送一个设置了FIN位的TCP数据段,这表示它已经没有数据要发送了。当FIN数据段被确认的时候,这个方向上就停止传送新数据。另一个方向上可能还在继续无限制地传送数据。当两个方向都停止的时候,连接才被释放。通常情况下,为了释放一个连接,需要4个TCP数据段:每个方向上一个FIN和一个ACK。然而,第一个ACK和第二个FIN有可能被包含在同一个数据段中,从而将总数降低到3个。

    URI(统一资源标识符)和URL(统一资源定位符)
    URI:一个用于标识某一互联网资源名称的字符串。组成:主机名(含端口号)+相对路径+标识符
    URL:对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。组成:协议+主机名(含端口号)+相对路径
    区别:URI表示请求资源在互联网上存在的位置,URL在表示请求资源的位置同时还要说明如何访问到这个资源,URL是URI的一个子集。
    通过请求和响应的交换达成通信
    请求报文是由请求方法、请求URI、协议版本、可选的请求头部字段和内容实体构成的。

    响应报文基本上是由协议版本、状态码、用以解释状态码的原因短语、可选的响应首部字段及实体主体构成。


    Cookies
    HTTP协议用于客户端和服务端之间通过请求和响应的交换所达成的通信,并且它是一种无状态的协议,不会对请求和响应之间的通信状态进行保存(无法根据前一次请求对这次请求做出处理),但为了能够有保存状态的功能,引入了cookies技术。


    Cookie和Session
    Cookie和Session都为了用来保存状态信息,都是保存客户端状态的机制,它们都是为了解决HTTP无状态的问题而所做的努力。
    Session可以用Cookie来实现,也可以用URL回写的机制来实现。用Cookie来实现的Session可以认为是对Cookie更高级的应用。

    Cookie和Session有以下明显的不同点:
    1)Cookie将状态保存在客户端,Session将状态保存在服务器端;
    2)Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。Cookie最早在RFC2109中实现,后续RFC2965做了增强。网络服务器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些cookies。Session并没有在HTTP的协议中定义;
    3)Session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是哪个用户session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用cookie时,这个值也可能设置为由get来返回给服务器;
    4)就安全性来说:当你访问一个使用session 的站点,同时在自己机子上建立一个cookie,建议在服务器端的SESSION机制更安全些.因为它不会任意读取客户存储的信息。

    Session机制
    Session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
    当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个 session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session id将被在本次响应中返回给客户端保存。

    Session的实现方式
    1)使用Cookie来实现
    服务器给每个Session分配一个唯一的JSESSIONID,并通过Cookie发送给客户端。
    当客户端发起新的请求的时候,将在Cookie头中携带这个JSESSIONID。这样服务器能够找到这个客户端对应的Session。
    流程如下图所示:

    2)使用URL回显来实现
    URL回写是指服务器在发送给浏览器页面的所有链接中都携带JSESSIONID的参数,这样客户端点击任何一个链接都会把JSESSIONID带会服务器。
    如果直接在浏览器输入服务端资源的url来请求该资源,那么Session是匹配不到的。
    Tomcat对Session的实现,是一开始同时使用Cookie和URL回写机制,如果发现客户端支持Cookie,就继续使用Cookie,停止使用URL回写。如果发现Cookie被禁用,就一直使用URL回写。jsp开发处理到Session的时候,对页面中的链接记得使用response.encodeURL() 。
    3.1.3在J2EE项目中Session失效的几种情况
    1)Session超时:Session在指定时间内失效,例如30分钟,若在30分钟内没有操作,则Session会失效,例如在web.xml中进行了如下设置:
    <session-config>
    <session-timeout>30</session-timeout> //单位:分钟
    </session-config>
    2)使用session.invalidate()明确的去掉Session。
    3.1.4与Cookie相关的HTTP扩展头
    1)Cookie:客户端将服务器设置的Cookie返回到服务器;
    2)Set-Cookie:服务器向客户端设置Cookie;
    3)Cookie2 (RFC2965)):客户端指示服务器支持Cookie的版本;
    4)Set-Cookie2 (RFC2965):服务器向客户端设置Cookie。

    Cookie的流程
    服务器在响应消息中用Set-Cookie头将Cookie的内容回送给客户端,客户端在新的请求中将相同的内容携带在Cookie头中发送给服务器。从而实现会话的保持。
    流程如下图所示:

     

    持久连接
    HTTP初始版本时,每进行一次HTTP请求就会断开一次TCP连接,这情况在早期传输文本很小的时候倒也不觉得如何,但是随着时代的进步,所需传输的内容种类越来越多和内容越来越大了,每次连接后都会断开请求就大幅度的增加了通信量的开销了。幸好,自HTTP/1.1和部分HTTP/1.0来,有了持久连接这么个神奇的东西,它规定了只要任何一方没有明确的提出断开连接,那么就保持TCP连接状态。而在维持的TCP连接期间,可以多次进行HTTP请求来传输需要的内容。
    得益于持久连接,HTTP实现了管线化,能够做到同时并行发送多个请求,而无需一个接一个的等待响应。

    HTTP/1.1默认保持持久连接,在HTTP的头部信息中会有Connection: Keep-alive属性,我们也可以通过浏览器开发工具的NetWork面板查看这个属性的状态及HTTP请求信息:

    如何关闭持久连接:在响应头设置Connection属性为close.

    HTTP请求的内容结构
    HTTP协议交互的信息称为HTTP报文,HTTP报文大致可分为报文首部和报文主体两块,两者有最初出现的空行来划分,通常并不一定要有报文主体。通过下面的图来看看HTTP报文的结构:

    除却空行(回车符、换行符),大致分为报文首部和报文主体。报文首部包含请求行(请求的方法、URI、HTTP版本)和状态行(响应状态码、原因短语、HTTP版本),首部字段(请求和响应的条件和属性),其他(未定义的首部)。
    请求行:包含用于请求的方法,请求URI和HTTP版本
    状态行:包含响应结果的状态码,原因短语和HTTP版本
    首部字段:首部字段规定了客户端如何处理请求和服务端如何处理响应,根据用途可分为四种:请求首部(请求报文使用的首部),响应首部(响应报文使用的首部),通用首部(请求和响应通用的首部),实体首部(报文实体部分使用的首部)。
    HTTP/1.1首部字段列表
    通用首部字段
    首部字段名 说明
    1 Cache-Control 控制缓存的行为
    2 Connection 逐跳首部、连接的管理
    3 Date 创建报文的日期时间
    4 Pragma 报文指令
    5 Trailer 报文末端的首部一览
    6 Transfer-Encoding 指定报文主体的传输编码方式
    7 Upgrade 升级为其他协议
    8 Via 代理服务器的相关信息
    9 Warning 错误通知

    请求首部字段
    首部字段名 说明
    1 Accept 用户代理可处理的媒体类型/浏览器可接受的MIME类型
    2 Accept-Charset 浏览器可接受的字符集
    3 Accept-Encoding 浏览器能够进行解码的数据编码方式,比如gzip。
    4 Accept-Language 浏览器所希望的语言种类(如中文)
    5 Authorization 授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中
    6 Connection: 表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,它就是持久连接;
    7 Content-Length: 表示请求消息正文的长度;
    8 Cookie: 这是最重要的请求头信息之一;
    9 Expect 期待服务器的特定行为
    10 From 用户的电子邮箱地址
    11 Host 初始URL中的主机和端口
    12 if-Match 比较实体标记(ETag)
    13 if-Modified-Since 比较资源的更新时间
    14 if-None-Match 比较实体标记(与if-Match相反)
    15 if-Range 资源未更新时发送实体Byte的范围请求
    16 if-Unmodified-Since 比较资源的更新时间(与if-Modified-Since相反)
    17 Max-Forwards 最大传输逐跳数
    18 Proxy-Authorization 代理服务器要求客户端的认证信息
    19 Range 实体的字节范围请求
    20 Referer 对请求中URI的原始获取方法
    21 TE 传输编码的优先级
    22 User-Agent HTTP客户端程序的信息

    响应首部字段
    首部字段名 说明
    1 Accept-Ranges 是否接受字节范围请求
    2 Age 推算资源创建经过时间
    3 ETag 资源的匹配信息
    4 Location 令客户端重定向至指定URI
    5 Proxy-Authenticate 代理服务器对客户端的认证信息
    6 Reter-After 对再次发起请求的时机要求
    7 Server HTTP服务器的安装信息
    8 Vary 代理服务器缓存的管理信息
    9 WWW-Authenticate 服务器对客户端的认证信息

    实体首部字段

    首部字段名 说明
    1 Allow 资源可支持的HTTP方法
    2 Content-Encoding 实体主体的适用的编码方式,gzip,见“响应首部”
    3 Content-Language 实体主体的内容语言类型,例如:zh-cn
    4 Content-Length 实体主体的内容长度,eg:80(单位:字节)
    5 Content-Location 替代对应资源的URI
    6 Content-MD5 实体主体的报文摘要,用作校验和。发送方和接受方都计算MD5摘要,接受方将其计算的值与此头标中传递的值进行比较
    7 Content-Range 实体主体的位置范围,也标明此实体的总长度
    8 Content-Type 实体主体的媒体类型
    9 Expires 实体主体过期的日期时间,为0证明不缓存
    10 Last-Modified 资源的最后修改日期时间


    传输编码
    HTTP传输数据的时候可以传输原数据,也可以在传输过程中编码以提升传输速率。通过传输时的编码处理,能有效的处理大量的访问请求。常用的内容编码有以下几种
    · gzip(GUN zip)
    · compress(UNIX系统的标准压缩)
    · deflate(zlib)
    · identity(不进行编码)
    多部分对象集合
    HTTP协议中采纳了多部分对象集合,允许发送的报文主体内可含有多类型实体。多用于上传文件或者图片时使用,可以设置Content-Type属性对其进行规定。如以下几种常见的形式:
    Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的
    Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据
    Application:用于传输应用程序数据或者二进制数据
    ContentType
    用于定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件。ContentType属性指定响应的 HTTP内容类型。在请求服务器端的响应时, 对于每一种返回类型规范的做法是要在服务端指定response的contentType 的.当然,不指定绝大多数情况下也没什么问题尤其是返回"非xml"的时候。如果未指定 ContentType,默认为TEXT/HTML。

    常见的媒体格式类型如下:
    Content-Type=text/html :服务端需要返回一段HTML代码给客户端
    Content-Type=text/plain :服务端需要返回一段普通文本给客户端
    Content-Type=text/xml : 服务端需要返回一段XML代码给客户端
    Content-Type= image/gif :gif图片格式
    Content-Type=image/jpeg :jpg图片格式
    Content-Type=image/png:png图片格式
    Content-Type=text/javascript 服务端需要返回一段javascript代码给客户端

    以application开头的媒体格式类型:
    Content-Type=application/xhtml+xml :XHTML格式
    Content-Type=application/xml : XML数据格式
    Content-Type=application/atom+xml :Atom XML聚合格式
    Content-Type=application/json :服务端需要返回一段json串给客户端
    Content-Type=application/pdf :pdf格式
    Content-Type=application/msword : Word文档格式
    Content-Type=application/octet-stream : 二进制流数据(如常见的文件下载)
    Content-Type=application/x-www-form-urlencoded :FORM元素的enctype属性指定了表单数据向服务器提交时所采用的编码类型
    Content-Type=application/javascript服务端需要返回一段javascript代码给客户端

    范围请求
    执行范围请求时,会用到首部字段Range来指定资源的byte范围,如:一份1000字节大小的文件,想取300-3000字节范围内的资源,可以设置Range:bytes=300-3000;想取300-3000字节和5000字节到最后的资源,可以设置Range:bytes=300-3000,5000-
    内容协商
    内容协商机制是指客户端和服务端就响应资源内容进行交涉,然后提供给客户最为适合的资源,内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。涉及到以下首部字段:
    · Accept
    · Accept-Charset
    · Accept-Encoding
    · Accept-Language
    · Content-Language

    内容协商技术又分为三种类型
    服务器驱动协商:服务端以请求的首部字段作为参考,在服务端处理并且返回对应资源。
    客户端驱动协商:用户通过浏览器提供的可选列表进行手动选择,或者利用js脚本在web页面上自行选择。
    透明协商:服务器驱动协商和代理驱动协商的结合体,当一个缓存被提供了构成响应的一系列可得的表现形式,并且维度的差异能完全被缓存理解,那么此缓存变得有能力代表源服务器为那个资源的后续请求去执行服务器驱动协商

    HTTP方法及状态码
    HTTP方法
    HTTP中也包含了一些方法,用于指定请求的资源按期望产生某种行为。对于这些方法,其中用的最多的是get和post。
    GET方式:是以实体的方式得到由请求URI所指定资源的信息,如果请求URI只是一个数据产生过程,那么最终要在响应实体中返回的是处理过程的结果所指向的资源,而不是处理过程的描述。
    POST方式:用来传输实体的主体,向目的服务器发出请求,要求它接受被附在请求后的实体,并把它当作请求队列中请求URI所指定资源的附加新子项,Post被设计成用统一的方法实现下列功能:1:对现有资源的解释;2:向电子公告栏、新闻组、邮件列表或类似讨论组发信息;3:提交数据块;4:通过附加操作来扩展数据库 。

    GET方法和POST方法的区别:
    1)安全性:GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,参数将明文出现在URL上,容易被他人看到,URL信息也可能会被记录到历史纪录中。POST请求是把提交的数据则放置在是HTTP包的包体中。

    2)数据长度:HTTP协议没有对传输的数据和URL长度进行限制, 但特定浏览器和服务器对URL长度有限制, 因此对于GET提交时,传输数据就会受到URL长度的限制(大部分最多只能有1024字节);
    由于POST操作不是通过URL传值,理论上数据长度不受限;

    3)缓存:GET请求能够被缓存,以GET请求的URL能够保存为浏览器书签,而POST请求则都不能

    4)数据获取:Get是向服务器发索取数据的一种请求;而Post是向服务器提交数据的一种请求,要提交的数据位于信息头后面的实体中。

    HTTP-GET的处理特征如下:
    。将数据添加到URL
    。利用一个问号(”?”)代表URL地址的结尾与数据的开端。
    。每一个数据的元素以 名称/值 (name/value) 的形式出现。
    。利用一个分号(“;”)来区分多个数据元素。
    HTTP-POST的处理特征如下:
    。将数据包括在HTTP主体中。
    。同样的,数据的元素以 名称/值 (name/value) 的形式出现。
    。但是每一个数据元素分别占用主体的一行。

    以下其他方法均不常用
    PUT:传输文件 HEAD:获得报文首部 DELETE:删除文件 OPTUIONS:询问支持的方法 TRACK:追踪路径 CONNECT:要求用隧道协议连接代理

    HTTP状态码
    HTTP状态码表示客户端HTTP请求的返回结果,通过状态码,用户可以知道HTTP请求是否出现问题,问题出在哪,下面简单罗列一些HTTP状态码:
    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 - 网关错误

    HTTP代理及缓存
    代理
    代理指的是具有转发功能的应用程序,接收客户端的请求转发给服务端,也接收服务端的响应转发给客户端。代理不会改变请求的URI,会直接发送给持有资源的服务器。转发时需要附加Via首部字段以标记出经过的主机信息。
    在HTTP通信过程中可以级联多台代理服务器,并且转发时需要附加Via首部字段以标记经过的主机信息。


    缓存
    缓存是代理服务器或客户端本地磁盘内保存的资源副本,利用缓存来减少对源服务器的访问以便于节省通信流量和通信时间,也可以达到更好的交互体验。
    请求的资源如果已经被缓存则直接由缓存服务器返回给客户端,或者客户端直接从本地磁盘读取。缓存可以设置有效时间,当判断缓存过期后,客户端/缓存服务器可像源服务器重新请求新资源。
    断点续传和多线程下载的实现原理
    HTTP协议的GET方法,支持只请求某个资源的某一部分;
    Range 请求的资源范围;
    Content-Range 响应的资源范围;

    断点续传原理:
    对资源进行分块,然后分块请求资,
    Eg1:Range: bytes=306302- :请求这个资源从306302个字节到末尾的部分;
    Eg2:Content-Range: bytes 306302-604047/604048:响应中指示携带的是该资源的第306302-604047的字节,该资源共604048个字节;
    客户端通过并发的请求相同资源的不同片段,来实现对某个资源的并发分块下载。

    多线程下载的原理:
    下载工具开启多个发出HTTP请求的线程;每个http请求只请求资源文件的一部分:Content-Range: bytes 20000-40000/47000;合并每个线程下载的文件。


    HTTP的缺点
    · 通信使用明文(未经加密),内容可能被窃听
    · 不验证通信方的身份,请求/响应会遭伪装
    · 无法证明报文的完整性,存在被篡改的可能

    针对明文传输这点,也可以对报文主体(传输内容)进行加密处理
    针对身份验证这点,可通过在本地安装证书,存储身份认证信息等
    针对确保信息完整性,MD5/SHA-1的散列值校验,数字签名等

    HTTP不带加密机制,但可以通过和SSL(安全 套接层...标注下阅读时的停顿)或TLS(安全层传输协议)的组合使用,用SSL建立安全通信线路后,就可以在这条线路上欢快的进行HTTP通信了。由于结合了SSL,HTTP升级成为HTTPS(或者 HTTP over SSL),然而这还不能说是个完整的HTTPS。
    完整的HTTPS = HTTP + 加密 + 认证 + 完整性保护

    HTTP协议中的长连接和短连接
    HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP连接就结束了,或者更准确的说,是本次HTTP请求就结束了,根本没有长连接这一说。那么自然也就没有短连接这一说了。之所以说HTTP分为长连接和短连接,其实本质上是说的TCP连接。TCP连接是一个双向的通道,它是可以保持一段时间不关闭的,因此TCP连接才有真正的长连接和短连接这一说。HTTP协议说到底是应用层的协议,而TCP才是真正的传输层协议,只有负责传输的这一层才需要建立连接。“HTTP连接”这个词就不应该出现,它只是一个应用层的协议,根本就没有所谓的连接这一说,就像FTP也是应用层的协议,但是你有听说过FTP连接吗?(其实所谓的FTP连接,严格来说,依旧是TCP连接)。
    短链接:连接->传输数据->关闭连接 。HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。 也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。

    长连接其实是指的TCP连接,只要设置Connection为keep-alive就算是长连接,但要服务器和客户端都设置。我们平时用的是长连接。(现在用的基本上都是HTTP1.1协议,你观察一下就会发现,基本上Connection都是keep-alive。而且HTTP协议文档上也提到了,HTTP1.1默认是长连接,也就是默认Connection的值就是keep-alive)长连接 :连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。 长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。

    长连接是为了复用。那既然长连接是指的TCP连接,也就是说复用的是TCP连接,长连接情况下,多个HTTP请求可以复用同一个TCP连接,这就节省了很多TCP连接建立和断开的消耗。如果你是短连接(也就是每次都要重新建立TCP连接)的话,那你每打开一个网页,基本要建立几个甚至几十个TCP连接,这很浪费资源。但如果是长连接的话,那么这么多次HTTP请求,其实使用的都是一个TCP连接,很显然是可以节省很多消耗的。长连接并不是永久连接的。如果一段时间内(具体的时间长短,是可以在header当中进行设置的,也就是所谓的超时时间),这个连接没有HTTP请求发出的话,那么这个长连接就会被断掉。HTTP连接分为“长连接”和“短连接”,HTTP1.0协议不支持长连接,从HTTP1.1协议以后,连接默认都是长连接。而我们现在常用的都是HTTP1.1,因此我们用的都是长连接。

    什么时候用长连接和短连接
    长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。 而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。 总之,长连接和短连接的选择要视情况而定。

    HTTP协议中的长轮询和短轮询
      短轮询不难理解,比如你现在要做一个电商中商品详情的页面,这个详情界面中有一个字段是库存量。而这个库存量需要实时的变化,保持和服务器里实际的库存一致。这个时候,最简单的一种方式,就是写个死循环,不停的去请求服务器中的库存量是多少,然后刷新到这个页面当中,这其实就是所谓的短轮询。
      这种方式有明显的坏处,那就是你很浪费服务器和客户端的资源。客户端还好点,现在PC机配置高了,你不停的请求还不至于把用户的电脑整死,但是服务器就不同了。如果有1000个人停留在某个商品详情页面,那就是说会有1000个客户端不停的去请求服务器获取库存量,这显然是不合理的。
    长轮询和短轮询最大的区别是,短轮询去服务端查询的时候,不管库存量有没有变化,服务器就立即返回结果了。而长轮询则不是,在长轮询中,服务器如果检测到库存量没有变化的话,将会把当前请求挂起一段时间(这个时间也叫作超时时间,一般是几十秒)。在这个时间里,服务器会去检测库存量有没有变化,检测到变化就立即返回,否则就一直等到超时为止。
      而对于客户端来说,不管是长轮询还是短轮询,客户端的动作都是一样的,就是不停的去请求,不同的是服务端,短轮询情况下服务端每次请求不管有没有变化都会立即返回结果,而长轮询情况下,如果有变化才会立即返回结果,而没有变化的话,则不会再立即给客户端返回结果,直到超时为止。 
      这样一来,客户端的请求次数将会大量减少,而且也解决了服务端一直疲于接受请求的窘境。但是长轮询也是有坏处的,因为把请求挂起同样会导致资源的浪费,假设还是1000个人停留在某个商品详情页面,那就很有可能服务器这边挂着1000个线程,在不停检测库存量,这依然是有问题的。因此,不管是长轮询还是短轮询,都不太适用于客户端数量太多的情况,因为每个服务器所能承载的TCP连接数是有上限的,这种轮询很容易把连接数顶满。

    长短轮询和长短连接的区别
    第一,一个TCP连接是否为长连接,是通过设置HTTP的Connection Header来决定的,而且是需要两边都设置才有效。而一种轮询方式是否为长轮询,是根据服务端的处理方式来决定的,与客户端没有关系。
    第二个区别就是实现的方式,连接的长短是通过协议来规定和实现的。而轮询的长短,是服务器通过编程的方式手动挂起请求来实现的。

    五、HTTP/2
    1996 年定义了HTTP 1.0 规范,今天HTTP 1.1 已经变成互联网中主要的协议。随着 web 技术的飞速发展。 HTTP 1.1 已经无法满足用户对性能的要求, HTTP/2(原名HTTP/2.0)主要基于 SPDY 协议。HTTP/2标准于2015年5月以RFC 7540正式发表。

    二进制分帧
    先来理解几个概念:
    帧(帧):HTTP/2数据通信的最小单位。
    消息(Message):指 HTTP/2 中逻辑上的 HTTP 消息。例如请求和响应等,消息由一个或多个帧组成。
    流(流):存在于连接中的一个虚拟通道。流可以承载双向消息,每个流都有一个唯一的整数ID。
    HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。
    HTTP/1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
    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。

    WebSocket 和 http/2.0
    WebSocket
    WebSocket实现了再Web客户端和服务端之间的全双工通信,一旦Web服务端与客户端之间建立WebSocket协议的通信连接,之后的所有通信都依赖这个专用协议进行。
    WebSocket具有推送功能,服务端可直接向客户端推送数据,不必等待客户端的请求;由于WebSocket一直保持连接状态,并且首部信息小,使得通信量也相应的减少。
    为了实现WebSocket通信。需要用到前面说到的HTTP首部字段Upgrade,达到告知服务端通信协议发生改变,当成功握手确立WebSocket连接之后,通信时不再使用HTTP的数据帧,而采用WebSocket独立的数据帧。
    使用浏览器进行双全工通信的WebSocket协议主要特点:
    a支持由服务器向客户端推送数据功能
    b减少通信量,不但每次连接总开销减少,而且首部信息也很少
    为了实现WebSocket通信需要将Http的Upgrade首部字段值设为websocket,对于之前的握手请求,返回状态码101 Switching Proticols.成功握手确立WebSocket连接之后,不再使用HTTP的数据帧,而采用WebSocket独立数据帧


    HTTP/2.0
    核心优势/特性
    多路复用:多个请求都是通过一个 TCP 连接并发完成(HTTP/1.1管线化在多个请求之间的响应会被阻塞,HTTP/2.0解决了这问题,并且支持优先级和流量控制)
    头部压缩:报文头部压缩处理,数通信量更小
    服务端推送:服务端能够更快的把资源推送给客户端
    语义改进:采用二进制格式传输数据

    六、HTTPS
    HTTP是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。https是HTTP运行在SSL/TLS之上,SSL/TLS运行在TCP之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。此外客户端可以验证服务器端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份。安全传输层协议(TLS)用于在两个通信应用程序之间提供保密性和数据完整性。该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)。较低的层为 TLS 记录协议,位于某个可靠的传输协议(例如 TCP)上面,与具体的应用无关,所以,一般把TLS协议归为传输层安全协议。TLS、SSL其实是类似的东西,SSL是个加密套件,负责对HTTP的数据进行加密。TLS是SSL的升级版。现在提到HTTPS,加密套件基本指的是TLS。
    HTTPS全称Hyper Text Transfer Protocol over Secure Socket Layer,直译过来就是通过SSL实现的超文本传输协议,简单来讲就是加密版的HTTP协议,也就是HTTP+SSL/TLS。
    我们都知道,HTTP是明文传输的,因此使用HTTP协议传输隐私信息非常不安全,很容易在传输过程中被窃取,或者通信内容被人篡改冒充,使用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。

    https的实现原理
    有两种基本的加解密算法类型:
    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的几次握手(具体是几次没去考究,有说是9次),当然下降主要是在第一次建立连接的时候,后面正常通信速度一般没啥变化;
    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握手过程
    TSL握手协议如下图所示

    在建立TCP连接后,开始建立TLS连接。下面抓包分析TLS握手过程,抓包图片来源于传输层安全协议抓包分析之SSL/TLS (自己没抓到这么完整的包,只能搬运过来了,摔)


    (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记录协议的规范使用协商生成的会话密钥加密发送数据。

  • 相关阅读:
    向值栈放List集合
    向值栈放对象
    向值栈放数据
    wsgi初探
    python_swift_project_swift使用
    python_swift_project_middleware
    ubuntu 安装 swift
    20140905
    eventlet
    resource
  • 原文地址:https://www.cnblogs.com/tester-l/p/8560141.html
Copyright © 2011-2022 走看看