一、HTTP简介
- 传输层使用TCP
- 客户端发起一个与服务器的TCP连接(建立套接字),端口号为80
- 服务器接收客户端的TCP连接
- 在浏览器与Web服务器交换HTTP报文(应用层协议报文)
- TCP连接关闭
- HTTP是无状态的
服务器并不维护关于客户的任何信息 - 维护状态的协议很复杂!
- 必须维护历史信息(状态)
- 如果服务器/客户端死机,它们的状态信息可能不一致,但二者的信息必须一致
- 无状态的服务器能够支持更多的客户端
Web服务器启动后,创建一个守护Socket,监听80号端口,当有客户端浏览器发起请求时,会创建不同的连接Socket,维持会话关系
二、HTTP连接
HTTP1.0(非持久)
- 客户端发起一个到服务器80端口的连接
- HTTP服务器在80端口等待连接,接收连接并通知客户端
- HTTP客户端向TCP连接的套接字发送HTTP请求报文
- HTTP服务器收到请求报文,封装响应报文,并通过套接字向客户端发送
- 客户端断开连接
该请求响应过程中,如果客户端需要向同一个HTTP服务器发送资源请求,则需要建立新的TCP连接
HTTP1.1(持久)
特性:
- 持久化连接以支持连接重用
- 分块传输编码以支持流失响应
- 请求管道以支持并行请求处理
- 字节服务以支持基于范围的资源请求
- 更好的缓存机制
Web请求:
一个普通的Web请求,前三步与HTTP1.0一样,只是客户端在给服务端发送请求后,如果有新的 请求也是发送到同一个HTTP服务器,无需建立新的TCP连接,可以直接复用已经建立的TCP连接; 并且服务器发送完给客户端的两次响应报文后,客户端并不马上关闭连接,如果客户端继续向服务 器发送请求,可以复用第一次请求已经建立起来的TCP连接,复用方式有以下两种:- 流水线方式
第一个请求发出后,拿到服务器响应报文再继续发第二个请求 - 非流水线方式
第一个请求发出后,无需等待服务器响应报文,就继续发第二个请求
- 流水线方式
特性详解:
- HTTP管道
持久HTTP对于多次请求必须满足FIFO的队列顺序:发送请求、等待响应完成,再发送新的请求,对于服务器而言,上一次响应报文的发出到下一次请求的接收这段时间处于空闲状态。
HTTP管道可以让我们把FIFO队列从客户端(请求队列)迁移到服务器(响应队列),HTTP管道允许使用非流水线的方式把请求发送到服务端,服务器可以并行处理这些请求,为这些请求封装响应资源,然后按照响应顺序,把一个个响应报文发送给客户端。
队首阻塞:
在HTTP1.1中,多个请求同时到达服务端时,服务器可以并行处理这些请求,但它只能严格地串行返回响应。特别是,不允许一个连接上地多个响应数据交错到达(多路复用),因而一个响应必须完全返回后,下一个响应才会开始传输。
例子:- 客户端发出HTML和CSS的请求同时到达,但先处理的是HTML请求
- 服务并行处理这两个请求,其中处理HTML耗时50ms,处理CSS用时30ms
- CSS请求处理先处理完成,但被缓存起来以等待HTML响应
- 发送完HTML响应后,再发送服务器缓冲中的CSS响应
在上面的例子中,即使客户端同时发送了两个请求,而且CSS资源先准备就绪,服务器也会先发送HTML响应,然后再交付CSS。这种情况通常称作队首阻塞。
实际中,由于HTTP1.1不可能实现多路复用,HTTP管道会导致HTTP服务、代理和客户端出现很多问题 - 一个慢响就应会阻塞所有后续请求
- 并行处理时,服务器必须缓冲管道中的响应,从而占用服务器资源
- 响应失败可能终止TCP连接,从而强迫客户端端重发对所有后续资源的请求,服务器重复处理
- 如果存在中间代理,检测管道兼容性,确保可靠性很重要。如果中间代理不支持管道,则它可能会中断连接,也可能会把所有请求串联起来
- 使用多个TCP连接
HTTP1.1提供的管道的方式会带来很多额外的问题,实际生产用的比较少,然而通过客户端FIFO队列的形式在实践中太慢,为了解决这个问题,浏览器支持客户端并行打开多个TCP会话,现实中,大多数现在浏览器,包括桌面和移动浏览器都支持每个主机打开6个连接。
多个TCP连接需要的资源:- 客户端可以并行分派最多6个请求
- 服务器可以并行处理最多6个请求
- 第一次往返可以发送的累计分组数量(TCP cwnd)增长为原来的6倍
在没有管道的情况下,最大请求数与打开的连接数相同。对应的,TCP拥塞窗口也要乘以打开的数量,从而允许客户端绕开由TCP慢启动规定的分组限制。这种方法的代价: - 多个套接字会占用客户端、服务器以及代理的资源,包括内存缓冲区和CPU时钟周期
- 并行TCP流之间竞争共享的宽带
- 由于使用多个套接字,实现复杂性更高
- 即使并行TCP流,应用的并行能力也受限制
HTTP2.0
新增特性:
- 支持请求和响应的多路复用
- 压缩HTTP头部字段降低协议开销
- 增加请求优先级
- 支持服务器端主动给客户端推送消息(以前是请求-响应模式)
特性详解: - 二进制分帧层
分帧层指的是在套接字接口和应用可见的高层HTTP API之间的一种新机制:HTTP的语义,包括各种动词、方法、首部都不受影响,不同的是传输期间对它们的编码方式变了。HTTP1.1以换行符作为纯文本大的分隔符,而HTTP2.0将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码
HTTP2.0中的新概念- 流
已建立的连接上的双向字节流,是连接中一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2……n) - 消息
逻辑上的HTTP消息,比如请求、响应等,由一或多个帧组成 - 帧
每个帧包含帧首部,至少也会标识出当前帧所属的流
在HTTP2.0的新概念中,可以把流理解成请求/响应,流的具体内容就是消息(请求/响应报文),而消息又是由一或多个帧组成(将请求/响应报文分成多个帧),这些帧可以乱序发送(同一流中的帧顺序发送),然后再根据每个帧首部的流标识重新组装
建立了HTTP2.0连接之后,客户端与服务器通过交换帧来通信,帧是基于这个新协议通信的最小单位。在同一个流中,所有帧共享一个8字节的首部,启动包含帧的长度、类型、标志,还有一个保留位和一个31位的流标识符。 - 16位的长度意味着一帧大约可以携带64K(2^16)数据,不包括8字节首部
- 8位的类型字段决定如何解释帧区域部分的内容
- 8位的标志字段允许不同的帧类型特定于帧的消息标志(
常用标志位有END_HEADERS 表示头数据结束
) - 1位的保留字段始终为0
- 31位的流标识符唯一标识HTTP2.0的流
HTTP2.0规定了如下帧类型: - DATA:用于传输HTTP消息体(请求体)
- HEADERS:用于传输关于流的额外的首部字段(流的优先值)
- PRIORITY:用于指定或重新指定引用资源的优先级
- RST_STREAM:用于通知流的非正常终止
- SETTINGS:用于通知两端通信方式的配置数据(流量控制,限定推送流的数量)
- PUSH_PROMISE:用于发出创建流和服务器引用资源的要约(服务器资源推送)
- PING:用于计算往返时间,执行“活性”检查
- GOAWAY:用于通知对端停止在当前连接中创建流
- WINDOW_UPDATE:用于针对个别流或个别连接实现流量控制(更新流量控制窗口大小)
- CONTINUATION:用于继续一系列首部块片段
- 客户端通过发送HEADERS帧来发起新流,这个帧里面包含有新流ID的公用首部、可选的31位优先值以及一组HTTP键值对首部(首部块)
- 服务器发送PUSH_PROMISE帧来发送推送流,这个帧与HEADERS帧等效,但它要包含“要约流ID”,没有优先值
以上两种帧的类型用于沟通新流的元数据,静荷会在DATA帧中单独发送。由于两端都可以发起新流,流计数器偏置:客户端发起的流具有奇数ID,服务器发起的流具有偶数ID。这样两端的ID不会冲突,而且各自持有一个简单的计数器,每次发起新流时递增ID即可
发送新流:
在发送数据之前,必须创建一个新流并随之发送响应的元数据,比如流优先级、HTTP首部等,HTTP2.0规定客户端和服务端双方都可以发起新流:
发送应用数据:
创建新流并发送HTTP首部之后,接下来就是利用DATA帧发送应用数据。应用数据可以分为多个DATA帧,最后一帧要翻转帧首部的END_STREAM字段
从技术上说,DATA帧的长度字段决定了每帧的数据净荷最多可达2^16-1(65535)字节。可是,为了减少头部阻塞,HTTP2.0标准要求DATA帧不能超过2^14-1(16383)字节。长度超过这个阈值的数据,就得分帧发送
- 流
- 多向请求与响应
HTTP2.0将消息分解为独立的帧,交错发送,客户端可以向服务器传输帧,与此同时,服务器也可以向客户端乱序发送一系列帧,然后在另一端重新组装,从来带来巨大的性能提升:- 可以并行交错的发送请求,请求之间互不响应
- 可以并行交错的发送响应,响应之间互不影响
- 只使用一个连接即可并行发送多个请求和响应
- 消除不必要的延迟,从而减少页面加载的时间
- 请求优先级
将HTTP消息分解为独立的帧后,可以通过优先值优化这些帧的交错和传输顺序,为了做到这一点,每个流都可以带有一个31比特的优先值- 0 表示最高优先级
- 2^31 -1 表示最低优先级
有了这个优先值,客户端和服务端可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。服务器可以根据流的优先级控制资源分配(CPU、内存、宽带),而在响应数据准备就绪后,优先发送最高优先级的帧到客户端
- 服务器推送
HTTP2.0新增地一个强大的功能就是服务器可以对于一个客户端请求发送多个响应,换句话说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确的请求。
建立HTTP2.0连接后,客户端与服务器交换SETTINGS帧,借此可以限定双向并发的流的最大数量。因此客户端可以限定推送流的数量,或者通过把这个值设置为0而完全禁用服务器推送。
相比于把资源嵌入到文档中推送给客户端,HTTP2.0把这个过程从应用中拿出来,放到了HTTP协议本身来实现,可以带来以下好处:- 客户端可以缓存推送过来的资源
- 客户端可以拒绝推送过来的资源
- 推送资源可以由不同的页面共享
- 服务器可以按照优先级推送资源
所有推送的资源都遵守同源策略。换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行
服务端推送流由PUSH_PROMISE发起,且在返回响应之前发送,它是除了对原始请求的响应之外服务器向客户端发出的有意推送所述资源的信号,PUSH_PROMISE帧中只包含要约(promise)资源的HTTP首部。
客户端收到PUSH_PROMISE帧之后,可以视自身需求拒绝这个流(比如已经缓存了响应资源)。
服务器到底如何确定那些资源可以或应该推送?
HTTP2.0标准没有规定某种算法,所以实现者拥有了解释权。 - 应用在自身代码中确定发起服务器推送,要求与HTTP2.0紧密耦合
- 通过额外的HTTP首部向服务器发送信号,列出它希望推送的资源
- 服务器可以不依赖应用而自动学习相关资源。解析文档,推断出推送的资源,比如服务器可以根据Referer首部收集依赖数据,然后自动向客户端推送关键资源
- 首部压缩
为了减少HTTP首部的开销,HTTP2.0会压缩首部- HTTP2.0会在客户端和服务端使用“首部表”来跟踪和存储
之前发送的
键值对,对于相同的数据,不再通过每次请求和响应发送 - 首部表在HTTP2.0的连接存续期内始终存在,由客户端和服务器共同完成渐进地更新
- 每个新的首部键值对要么被追加在当前表地末尾,要么替换表中之前地值
请求和响应首部地定义在HTTP2.0中基本没有改变,只是所有首部键必须全部小写,而且请求行独立为:method、:shceme、:host和:path这些键值对
- HTTP2.0会在客户端和服务端使用“首部表”来跟踪和存储
三、请求/响应报文
HTTP请求报文
- 两种类型的HTTP报文:请求、响应
- HTTP请求报文组成部分(ASCⅡ编码)
GET /somedir/page.html HTTP/1.1
请求行:GET、POST、HEAD(只请求页面头部)命令
首部行:Host、User-agent(用户代理程序)、Connection、Accept-language
换行回车符:表示报文结束(一个额外的换行回车符)
通用格式
request line:Method|sp|URL|sp|version|cr if
header line:header field name:value |cr if
cr if
Entity Body - 提交表单输入
- Post方式
网页通常包括表单输入
包含在实体主体(Entity Body)中的输入被提交到服务器 - URL方式
方法:Get
输入行通过请求行的URL字段上载(URL+?参数1&参数2)
- Post方式
HTTP响应报文
HTTP/1.1 200 OK\r\n
Connection close\r\n
Date:Thu,06 Aug 2021 9:00:11 GMT\r\n
Server:Apache/1.3.0(Unix) \r\n ——服务端Web服务器及版本
Last-Modified:Mon,22 Jun 2021…\r\n ——服务器资源上一次修改的日期
Content-Length:6821\r\n
Content-Type:text/html \r\n
data data data ——数据,如请求的HTML文件
状态行:协议版本、状态码、相应状态信息
首部行:连接状态、服务器信息、响应报文长度、响应报文格式
响应数据:HTML文件等
大多数主要的门户网站使用cookies
第一次访问某网站时,服务器端生成一个cookie并存储,在响应报文中,把cookie发送给用户端,用户端在本地文件系统进行存储,当下一次再次访问该网站时,在请求头带上cookie信息,服务端就能识别到该客户端,将无状态的HTTP变成了有状态的HTTP
四个组成部分:
- 在HTTP响应报文中有一个cookie的首部行(第一次访问)
- 在HTTP请求报文含有一个cookie的首部行
- 在用户端系统中保留有一个cookie文件,由用户的浏览器管理
- 在Web站点有一个后端数据库,用于存储cookie信息
四、HTTP状态码
服务器返回的响应报文中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。
状态码 | 类别 | 原因短语 |
---|---|---|
1XX | Informational(信息性状态码) | 接收的请求正在处理 |
2XX | Success(成功状态码) | 请求正常处理结束 |
3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4XX | Client Error (客户端错误状态码) | 服务器无法处理请求 |
5XX | Server Error (服务器错误状态码) | 服务器处理请求出错 |
1XX 信息
- 100 Continue:表明当前为止都很正常,客户端可以继续发送请求或者忽略这个响应
2XX 成功
- 200 OK
- 204 No Content:请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用
- 206 Partial Content:表示客户端进行了范围请求。响应报文包含由Content-Range指定范围的实体内容
3XX 重定向
- 301 Moved Permanently:永久性重定向
- 302 Found:临时性重定向
- 303 See Other:和302有着相同的功能,但是303明确要求客户端应该采用GET方法获取资源
注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
- 304 Not Modified:如果请求报文首部包含一些条件,例如:if-Match、If-ModifiedSince、if-None-Match、if-Range、if-Unmodified-Since,如果不满足条件,服务器会返回304状态码
- 307 Temporary Redirect:临时重定向,与302的含义类似,但是307要求浏览器不会把重定向请求的POST方法改成GET方法
4XX 客户端错误
- 400 Bad Request:请求报文中存在语法错误
- 401 Unauthorized:该状态码表示发送的请求需要有认证信息(BASIC认证、DIGEST认证)。如果之前已进行过一次请求,则表示用户认证失败
- 403 Forbidden:请求被拒绝,服务器端没有必要给出拒绝的详细理由
- 404 Not Found
5XX 服务器错误
- 500 Internal Server Error:服务器正在执行请求时发生错误
- 503 Service Unavilable:服务器暂时处于超负载或正在进行停机维护,现在无法处理请求
五、Web缓存
不访问原始服务器,就满足客户的请求(静态资源)
- 用户设置浏览器:通过缓存访问Web(本地缓存)
- 浏览器将所有的HTTP请求发给缓存(代理服务器)
- 在缓存中的资源,缓存直接响应资源
- 如果资源不在缓存中,缓存请求原始服务器,然后再将资源返回给客户端
- 缓存既是客户端又是服务器,通常缓存是由ISP安装
- 为什么使用缓存?
- 降低客户端的请求响应时间
- 可以大大减少一个机构内部网络与Internet接入链路上的流量(在本地区域网添加代理服务器)
- 互联网大量采用了缓存:可以使较弱的ICP也能够有效提供内容
- 缓存服务器与Web服务器数据不同步问题解决方案
HTTP协议有一种机制,允许缓存器证实它的对象是最新的,这种机制就是条件GET(conditional GET)方法。
条件GET方法:1、请求报文使用GET方法 2、请求报文中包含一个“If-Modified-Since:”首部行。那么,这个HTTP请求报文就是一个条件GET请求报文。
条件GET的使用:- 缓存服务器向Web服务器发送资源请求
请求报文:
GET /fruit/kiwi.gif HTTP/1.1
Host:www.baidu.com
响应报文:
HTTP/1.1 200 OK
Date:……
Server:……
Last-Modified:Web,9 Sep 2021 09:29:24
Content-Type:application/json
(data data data data ……)
缓存服务器在将资源发送到请求的浏览器的同时,也在本地缓存了该资源,同时还存储了最后修改时间Last-Modified - 隔了一段时间后,Web服务器端的资源可能发生变更,导致与缓存服务器的数据不一致,此时缓存服务器向Web服务器发送一个条件GET执行最新检查。
请求头:
GET /fruit/kiwi.gif HTTP/1.1
Host:www.baidu.com
If-modified-since:Web,9 Sep 2021 09:29:24
首部行的If-modified-since值等于缓存服务器存储的资源对应Last-Modified的值。该条件GET报文告诉Web服务器缓存服务器中资源上次修改的时候,Web服务器比较本地资源的上次修改时间是否大于缓存服务器中资源的上次修改时间,如果发生了修改,则将修改后的资源响应给缓存服务器;如果没有修改,则响应304状态码:
HTTP/1.1 304 Not Modified
Data:……
Server:……
(empty entity body)- 缓存器:在HTTP请求中指定缓存拷贝的时间
If-modified-since: - 服务器:如果缓存拷贝陈旧(服务器资源没有发生变化),则响应报文没包含对象
HTTP/1.1 304 Not Modified
- 缓存器:在HTTP请求中指定缓存拷贝的时间
- Last-Modified/Last-Modified-Since要配合Cache-control使用
个人理解:如果Cache-control配置了缓存以及缓存时间的时候,Last-Modified/Last-Modified-Since才会有用,当缓存过了有效时间之后,新的请求才会触发条件GET机制
即使浏览器设置了缓存,当用户点击“刷新”按钮时,浏览器会忽略缓存继续向服务器发送请求,这时Last-Modified将能够很好的减少回应开销
Cache-control的常见取值:- no-cache:数据内容被缓存,但每次请求都重新访问服务器做缓存过期校验,若有max-age,则缓存期间不访问服务器
- no-store:禁止缓存
- private(默认):只能在浏览器中缓存,只有在第一次请求的时候才访问服务器,如有max-age,则缓存期间不访问服务器
- public:可以被任何缓存区缓存,如:浏览器、服务器、代理服务器
- max-age:相对过期时间,即以秒为单位的缓存时间
- no-cache,private:打开新窗口时候重新访问服务器,若设置max-age,则缓存期间不访问服务器
- private,正数的max-age:后退时候不访问服务器
- no-cache,正数的max-age:后退时会访问服务器
- 缓存服务器向Web服务器发送资源请求
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112071.html