HTTP协议
2019-01-31 18:38:09 0 举报
AI智能生成
HTTP协议一览
作者其他创作
大纲/内容
HTTP协议
前置知识
计算机网络体系结构分层
OSI与TCP/IP协议族
HTTP应用通信流
首先作为发送端的客户端在应用层(HTTP 协议)发出一个想看某个 Web 页面的 HTTP 请求;接着,为了传输方便,在传输层(TCP 协议)把从应用层处收到的数据(HTTP 请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层;在网络层(IP 协议),增加作为通信目的地的 MAC 地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了;接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的 HTTP请求。
TCP/IP协议
DNS协议
URI
实用工具
Chrome插件
HTTP/2 and SPDY indicator
Wireshark
参考资料
来自 HTTPbis 小组的 HTTP/2 标准草案和其相关文档
HTTP/2官网
RFC1945(HTTP/1.0)
RFC2616(HTTP/1.1)
RFC7230(HTTP/1.1)
RFC7540(HTTP/2)
RFC2045(MIME)
HTTP/2实现
Nodejs范例
HTTP趋势数据
HTTP/2介绍
HTTP/3介绍
High PerformanceBrowser Networking
详解HTTP协议
HTTP协议入门
HTTP站点趋势
每个URL里的连接数在不断增长
图
每个URL里加载的资源尺寸越来越大
概述
前言
设计初衷:
为了提供一种发布和接收HTML页面的方法
简介:
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。HTTP是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。在Internet上的Web服务器上存放的都是超文本信息,客户机需要通过HTTP协议传输所要访问的超文本信息。HTTP包含命令和传输信息,不仅可用于Web访问,也可以用于其他因特网/内联网应用系统之间的通信,从而实现各类应用资源超媒体访问的集成。我们在浏览器的地址栏里输入的网站地址叫做URL (Uniform Resource Locator,统一资源定位符)。就像每家每户都有一个门牌地址一样,每个网页也都有一个Internet地址。当你在浏览器的地址框中输入一个URL或是单击一个超级链接时,URL就确定了要浏览的地址。浏览器通过超文本传输协议(HTTP),将Web服务器上站点的网页代码提取出来,并翻译成漂亮的网页。
LOGO
HTTP之父:Ted Nelson
HTTP基础
1)通过请求和响应的交换达成通信
应用 HTTP 协议时,必定是一端担任客户端角色,另一端担任服务器端角色。仅从一条通信线路来说,服务器端和客服端的角色是确定的。HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。
2)HTTP 是不保存状态的协议
HTTP 是一种无状态协议。协议自身不对请求和响应之间的通信状态进行保存。也就是说在 HTTP 这个级别,协议对于发送过的请求或响应都不做持久化处理。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把 HTTP 协议设计成如此简单的。
随着 Web 的不断发展,很多业务都需要对通信状态进行保存。于是引入了 Cookie 技术。有了 Cookie 再用 HTTP 协议通信,就可以管理状态了。
3)使用 Cookie 的状态管理
Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
4)请求 URI 定位资源
HTTP 协议使用 URI 定位互联网上的资源。正是因为 URI 的特定功能,在互联网上任意位置的资源都能访问到。
5)告知服务器意图的 HTTP 方法
工作过程
在一次完整的 HTTP 通信过程中,客户端与服务器之间将完成下列7个步骤
1)建立 TCP 连接
在HTTP工作开始之前,客户端首先要通过网络与服务器建立连接,该连接默认是通过 TCP 来完成的,该协议与 IP 协议共同构建 Internet,即著名的 TCP/IP 协议族,因此 Internet 又被称作是 TCP/IP 网络。HTTP 是比 TCP 更高层次的应用层协议,根据规则,只有低层协议建立之后,才能进行高层协议的连接,因此,首先要建立 TCP 连接,一般 TCP 连接的端口号是80
2)客户端向服务器发送请求命令
一旦建立了TCP连接,客户端就会向服务器发送请求命令
例如:GET/sample/hello.jsp HTTP/1.1;
3)客户端发送请求头信息
客户端发送其请求命令之后,还要以头信息的形式向服务器发送一些别的信息,之后客户端发送了一空白行来通知服务器,它已经结束了该头信息的发送
4)服务器应答
客户端向服务器发出请求后,服务器会客户端返回响应
例如: HTTP/1.1 200 OK
5)服务器返回响应头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同响应向用户发送关于它自己的数据及被请求的文档
6)服务器向客户端发送数据
服务器向客户端发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以 Content-Type 响应头信息所描述的格式发送用户所请求的实际数据
7)服务器关闭连接
一般情况下,一旦服务器向客户端返回了请求数据,它就要关闭 TCP 连接,如果客户端或者服务器在其头信息加入了这行代码 Connection:keep-alive ,TCP 连接在发送后将仍然保持打开状态,于是,客户端可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽
历史发展
HTTP/0.9
特点
极其简单,只有一个方法,请求和响应内容都精简到了极致
请求:GET /index.html
响应:<html> <body>Hello World</body></html>
缺陷
1)只有1个方法:GET,功能比较局限
2)服务器响应只能返回HTML格式的字符串,不支持其他格式
HTTP/1.0
1)任何格式的内容都可以传输,如文字、传输图像、视频、二进制文件等等
2)引入了POS和HEAD方法,丰富了浏览器与服务器的互动手段
3)引入了HTTP header,用来描述一些元数据。新增状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等功能。
每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。TCP连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。
优化策略
为了解决这个问题,有些浏览器在请求时,用了一个非标准的Connection字段。Connection: keep-alive这个字段要求服务器不要关闭TCP连接,以便其他请求复用。服务器同样回应这个字段。Connection: keep-alive一个可以复用的TCP连接就建立了,直到客户端或服务器主动关闭连接。
缺点
Connection不是标准字段,不同实现的行为可能不一致
HTTP/1.1
1)持久连接
HTTP/1.0以前,每进行一个 HTTP 通信都要断开一次 TCP 连接。比如使用浏览器浏览一个包含多张图片的 HTML 页面时,在发送请求访问 HTML 页面资源的同时,也会请求该 HTML 页面里包含的其他资源。因此,每次的请求都会造成无畏的 TCP 连接建立和断开,增加通信量的开销。
示例1
示例2
为了解决上述 TCP 连接的问题,HTTP/1.0 后期增加了持久连接的方法。其特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。旨在建立一次 TCP 连接后进行多次请求和响应的交互。在 HTTP/1.1 中,所有的连接默认都是持久连接。
示例
2)管线化
持久连接使得多数请求以管线化方式(Pipelining)发送成为可能。以前发送请求后需等待并接收到响应,才能发送下一个请求。管线化技术出现后,不用等待亦可发送下一个请求。这样就能做到同时并行发送多个请求,而不需要一个接一个地等待响应了。
比如,当请求一个包含多张图片的 HTML 页面时,与挨个连接相比,用持久连接可以让请求更快结束。而管线化技术要比持久连接速度更快。请求数越多,时间差就越明显。
先进先出
并行处理
3)分块编码
分块编码是一种传输编码,是报文的属性。HTTP/1.1 的传输编码方式仅对分块传输编码有效。分块编码把报文分割成若干已知大小的块。块之间是紧挨着发送的,这样就不需要在发送之前知道整个报文的大小了。
起因
若客户端与服务器端之间不是持久连接,客户端就不需要知道它在读取的主体的长度,而只需要读取到服务器关闭主体连接为止。当使用持久连接时,在服务器写主体之前,必须知道它的大小并在 Content-Length 首部中发送。如果服务器动态创建内容,就可能在发送之前无法知道主体的长度。
优势
分块编码为上述困难提供了解决方案,只要允许服务器把主体分块发送,说明每块的大小就可以了。因为主体是动态创建的,服务器可以缓冲它的一部分,发送其大小和相应的块,然后在主体发送完之前重复这个过程。服务器可以用大小为 0 的块作为主体结束的信号,这样就可以继续保持连接,为下一个响应做准备。
4)更多功能
新增了Host字段,用来指定服务器的域名。例如:Host: www.example.com有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。
1)过于庞大
HTTP刚诞生的时候只被当作是一个相对简单直观的协议,但时间证明这种初始设计并不如意。定义HTTP 1.0规范的RFC 1945共有60页,发布于1996年。仅仅3年之后,定义HTTP 1.1规范的RFC 2616却一下增长到了176页。HTTP 1.1包含了太多细节和可选的部分,这让它变得过于庞大。
2)过多的可选项
HTTP 1.1不仅包含了非常多的细枝末节,还为将来的扩展预留的很多选项。这种事无巨细的风格导致在现在的软件生态中,几乎没有任何实现真正实现了协议中提及的所有细节,甚至要弄清楚“所有细节”到底包括哪些细节都非常困难。正因为如此,很多最初不常用的功能在后来的实现中很少会被支持,而有些最初实现了的功能,却又很少被使用。随着时间推移,这些当初看似被边缘化的功能逐渐被用上,客户端和服务器的互用性(interoperability)问题就被暴露了出来。HTTP管线化(HTTP Pipelining)就是一个非常好的例子。
3)未能被充分利用的TCP
HTTP 1.1很难榨干TCP协议所能提供的所有性能。HTTP客户端和浏览器必须要另辟蹊径的去找到新的解决方案来降低页面载入时间。与此同时,人们也尝试去用新的协议来替代TCP,但结果证明这也非常困难。无奈之下,人们只能尝试同时改进TCP协议本身和基于TCP的上层协议。简言之,通过更好的利用TCP来减少传输过程中的暂停,并充分挖掘利用那些本可以用于发送/接受更多数据的时间。
4)恼人的延迟
HTTP 1.1对网络延迟非常敏感。部分原因是HTTP Pipelining还有很多问题,所以对大部分用户来说是默认关闭的。
虽然近几年来网络带宽增长非常快,但是与此相对的是,我们并没有看到网络延迟有对应程度的降低。在高延迟的网络上(比如移动设备),即使拥有高连接速率,也很难获得优质快速的网络体验。另外一个需要低延迟的场景是某些视频服务,如视频会议、游戏和一些类似无法预生成待发送数据流的服务。
5)线头阻塞
HTTP 1.1虽然允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为\"线头堵塞\"(Head-of-line blocking)
当然,你可以在选择队伍时候就做好功课,去排一个你认为最快的队伍,或者甚至另起一个新的队伍(即新建一个TCP连接)。但不管怎么样,你总归得先选择一个队伍,而且一旦选定之后,就不能更换队伍。但是,另起新队伍会导致资源耗费和性能损失(新建 TCP 连接的开销非常大)。这种另起新队伍的方式只在新队伍数量很少的情况下有作用,因此它并不具备可扩展性。所以针对此问题并没有完美的解决方案。
1)Spriting
Spriting是一种将很多较小的图片合并成一张大图,再用JavaScript或者CSS将小图重新“切割”出来的技术。网站可以用该技术来提速:在HTTP 1.1里,下载一张大图比下载100张小图快得多。
雪碧图
当某些页面只需要显示其中几张小图时,这种方案的缺点就凸显出来了:它必须将整张大图都从cache里取出,而不能将最频繁使用的那些图片保留在cache里。
2)内联(Inlining)
内联是另外一种防止发送很多小图请求的技巧,它将图片的原始数据嵌入在CSS文件里面的URL里
与Spriting类似
3)拼接(Concatenation)
大型网站往往会包含大量的JavaScript文件。一些前端工具能帮助开发人员将这些文件合并为一个大的文件,从而让浏览器能通过一个请求下载完,而不是发无数请求来分别下载那些小的JavaScript。
如果某页面只需要其中一小部分代码,它也必须下载完整的那份。而一个小小的文件改动也会造成大量数据的重载。这种手段给开发者造成了很大的不便。
4)分片(Sharding)
顾名思义,分片就是把你的服务分散在尽可能多的主机上。这种方案乍一听比较奇怪,但是实际上在它背后却有非常深刻的道理!最初的HTTP 1.1规范提到一个客户端最多只能对同一主机建立两个TCP连接。因此,为了不和规范冲突,一些聪明的网站使用了新的主机名。这样的话,用户就能和网站建立更多的连接,从而降低载入时间。后来,两个连接的限制被取消了,现在的客户端可以轻松地和每个主机建立6-8个连接。但连接的上限却是依然存在的,所以网站依然会用这种技术来提升连接的数量。随着资源个数的提升(上面章节的图例),网站需要更多的连接来保证HTTP协议的效率,从而提升载入速度。在现今的网站上,使用50甚至100个连接来打开一个页面并不罕见。
另外一个将图片或者其他资源分发到不同主机的理由是可以不使用cookies,毕竟现今cookies的大小已经非常可观了。无cookies的图片服务器意味着更小的HTTP请求和更好的性能!
每个新增域名都会增加额外的DNS查询,对socket通信双方都造成额外的资源,最糟糕的是,这要求网站开发者手动管理如何将资源分片(当然,浏览器连接池限制的对象是域名,而不是IP,因此可以通过一台机器绑定多个域名来解决)。此外,TCP慢启动,TLS握手的往返延迟等不可忽视而又客观存在的问题,常常会让Sharding陷入困境,没有解决此道经验的开发者,使用Sharding恐怕是个灾难。
5) Limit HTTP Headers
HTTP1.1将HTTP Header标准化,虽然非常有利于HTTP应用功能的扩展,但限于无状态的特性,Cookies的支持,大多数请求里都会包含许多无用的headers与cookie。RFC 2616规范虽然不对headers的大小做限制,但许多服务器和代理都尝试强行限制它的最大值为8k或16k。
上图中,发送15个字符,报文里却额外包含了352字节的headers,相当于一次HTTP会话里,有96%的数据是冗余的,而且尚未不包含cookies。
要精确控制Headers的使用,开发者必须得对HTTP协议了解得特别细致,否则一个小小的属性缺失,就可能会造成一次灾难
HTTP/2
背景
1)目标:主要解决HTTP/1.1的缺陷
降低协议对延迟的敏感
修复pipelining和head of line blocking的问题
防止主机需求更高的连接数量
2)需求
它必须维持HTTP的范式。毕竟它只是一个让客户端发送请求到服务器的基于TCP的协议。
不能改变http://和https://这样的URL,也不能对其添加新的结构。使用这类URL的网站太多了,没法指望他们全部改变。
HTTP1的服务器和客户端依然会存在很久,所以我们必须提供HTTP1到http2服务器的代理。
要让这种代理能够将http2的功能一对一的映射到HTTP 1.1的客户端。
删除或者减少协议里面那些可选的部分。虽然这并不是一个大的需求,但是SPDY和Google的团队会非常喜欢这点。让协议里所有部分都成为强制要求的,就能防止人们在实现的时候偷懒,从而避免将来的问题。
不再使用小版本号。服务器和客户端都必须确定自己是否完整兼容http2或者彻底不兼容。如果将来该协议需要被扩充更变,那么新的协议将会是http3,而不是http 2.x。
3)观念
http2和现有的URI结构
现有的URI结构正在被HTTP 1.x使用而不能改变,所以http2也必须沿用该结构。正因如此才必须找到一种方式将协议升级至http2,或者让服务器使用http2来彻底替代旧的协议。HTTP 1.1本身就有制定“升级”的方案:提供一个头,让服务器在收到旧协议请求的时候,向客户端发送新协议的响应。这样做的代价是需要一次往返通信。这个往返通信的代价是SPDY团队不能接受的。因为他们只实现了基于TLS的SPDY,所以他们也只开发了一个TLS的扩展来简化协议的协商。这个扩展被称作NPN(Next Protocol Negotiation),通过它,服务器通知客户端所有他支持的协议,从而让客户端从中选择一个合适的。
为https://所准备的http2
足够的关注使得http2在TLS上得以正常运作,SPDY只支持TLS,所以按理说TLS也应成为http2 必需的组件,但出乎意料的是http2仅将TLS作为可选部分。然而,全球两大浏览器领导者 - Firefox和Chrome明确地表示,他们只实现基于TLS的http2.只选择TLS的原因包括了保护用户隐私,早期的评估结果表明,将新的协议建立在TLS上更可能成功。这也是因为所有来自80端口的流量都会被当作HTTP 1.1或者是其某个变种,而不是另外一个种全新的协议。类似地,还有一个激烈而长期的辩论,即当使用TLS时http2是否应该强制规定密码列表,或者应该建立一个黑名单,或者它根本就不需要从TLS层得到任何东西,而由TLS工作组来解决。最后规范指定TLS最低版本是1.2,并且有加密组的限制。
基于TLS之上的http2协商
Next Protocol Negotiation (NPN)是一个用来在TLS服务器上协商SPDY的协议。IETF将这个非正式标准进行规范,从而变成了ALPN(Application Layer Protocol Negotiation)。ALPN被推广用于http2,而SPDY客户端和服务器仍然使用NPN。由于NPN先诞生,而ALPN还经历了一些标准化过程。所以许多早期的http2客户端和服务器在协商http2时同时实现了这两者的扩展。并且,由于SPDY使用NPN,不少服务器同时提供SPDY和http2来支持NPN和APLN。ALPN和NPN的主要区别在于谁持有会话协议的决定权,ALPN是由客户端给服务器发送一个协议优先级列表,由服务器最终选择一个合适的。而NPN则正好相反,是客户端有最终决定权。
为http://所准备的http2
对于纯文本的HTTP1.1来说,协商http2的方法就是给服务器发送一个带升级头部的报文。如果服务器支持http2,它将回复“101 Switching”状态码,并从此开始在该连接上使用http2。也许你很容易就发现这个升级流程会造成一个完整的往返时延开销,但好处是http2连接相比HTTP1可以被更大限度地重用和保持。
1)二进制帧层(Binary Framing Layer)
http2是一个二进制协议。二进制的http2可以使成帧更便捷。在HTTP1.1和其他基于文本的协议中,识别帧的起始和结束相当复杂。而在移除掉可选的空白符和其他冗余后,实现这些会变得更容易。另一方面,从帧结构中分离出协议本身的部分也变得更容易。而在HTTP1中,各个部分相互交织,一团乱麻。协议的压缩特点和其经常运行在TLS之上的事实让纯文本的属性值变得毫无作用,毕竟也无法从数据流上看到文本。我们需要习惯于使用类似Wireshark的工具来从协议层面对http2一探究竟。调试这样的协议将需要curl这样的工具,要进一步地分析网络数据流需要类似Wireshark的http2解析器。
HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为\"帧\
2)多路复用的流(Request and Response Multiplexing)
Stream Identifier定义了二进制帧的格式,http2连接上传输的每个帧都关联到一个“流”。流是一个逻辑上的联合,一个独立的,双向的帧序列。这一系列帧在客户端和服务器中通过http2连接进行交换。每个单独的http2连接都可以包含多个并发的流,这些流中交错的包含着来自两端的帧。流既可以被客户端/服务器端单方面的建立和使用,也可以被双方共享,或者被任意一边关闭。在流里面,每一帧发送的顺序非常关键。接收方会按照收到帧的顺序来进行处理。
流的多路复用意味着在同一连接中来自各个流的数据包被混合在一起。两个(或者更多)独立的“数据列车”被拼凑到了一辆列车上,最终在终点站被分开。在http2里面,很容易可以看到10个甚至100个同时并存的流。创建一个新的流的代价也非常低。
两列“数据火车”
两列火车通过多路复用的方式被组装到了同一列火车上。
3)优先级和依赖性(Stream Prioritization)
每个流都包含一个优先级,优先级被用来告诉对端哪个流更重要。优先级的工作机制在协议中被改变多次,至今仍在讨论。重点在于要让客户端能指定哪个流更重要,并且提供一个依赖参数来指定流的依赖关系。优先级能动态的被改变。这样当用户滚动一个全是图片的页面的时候,浏览器能够指定哪个图片有更高的优先级。或者是在你切换标签页的时候,浏览器可以提升新切换到页面所包含流的优先级。
4)头压缩(Header Compression)
HTTP是无状态协议。简而言之,这意味着每个请求必须要携带服务器需要的所有细节,而不是让服务器保存住之前请求的元数据。因为http2没有改变这个范式,所以它也需要这样(携带所有细节)。这也保证了HTTP可重复性。当一个客户端从同一服务器请求一些资源(例如页面的图片)的时候,这些请求看起来几乎是一致的。而这些大量一致的东西正好值得被压缩。当每个页面资源的个数上升的时候,cookies和请求的大小都会增加,而每个请求都会包含的cookie几乎是一模一样的。HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,这会严重拖累发送请求的速度。因为它们需要等待带着ACK的响应回来以后,才能继续被发送。这也是需要压缩的理由。
HPACK[RFC7541],HTTP/2头部压缩,顾名思义它是一个专为http2头部设计的压缩格式。确切的讲,它甚至被制定写入在另外一个单独的RFC里。新的格式同时引入了一些其他对策让破解压缩变得困难,例如采用帧的可选填充和用一个bit作为标记,来让中间人不压缩指定的头部。HPACK旨在提供一个一致性的实现使信息量的损失尽可能少,使编解码快速而方便,使接收方能控制压缩文本的大小,允许代理重新建立索引(如,通过代理在前后端共享状态),以及对哈夫曼编码串的更快速比较。
5)重置(Stream Reset)
HTTP 1.1的有一个缺点是:当一个含有确切值的Content-Length的HTTP消息被送出之后,你就很难中断它了。当然,通常你可以断开整个TCP链接(但也不总是可以这样),但这样导致的代价就是需要重新通过三次握手建立一个新的TCP连接。一个更好的方案是只终止当前传输的消息并重新发送一个新的。在http2里面,我们可以通过发送RST_STREAM帧来实现这种需求,从而避免浪费带宽和中断已有的连接。
6)服务器推送(Server Push)
这个功能通常被称作“缓存推送”。主要的思想是:当一个客户端请求资源X,而服务器知道它很可能也需要资源Z的情况下,服务器可以在客户端发送请求前,主动将资源Z推送给客户端。这个功能帮助客户端将Z放进缓存以备将来之需。服务器推送需要客户端显式的允许服务器提供该功能。但即使如此,客户端依然能自主选择是否需要中断该推送的流。如果不需要的话,客户端可以通过发送一个RST_STREAM帧来中止。
7)流量控制(Flow Control)
http2上面每个流都拥有自己的公示的流量窗口,它可以限制另一端发送数据,跟SSH的工作原理非常相似。对于每个流来说,两端都必须告诉对方自己还有更多的空间来接受新的数据,而在该窗口被扩大前,另一端只被允许发送这么多数据。只有数据帧受流量控制
8)单连接(One Connection Per Origin)
对于http2来说,每个域名只需要建立一个连接,所有通信都通过多路复用流来达成目的,这对于HTTPS来说,能减少更多的TLS握手时间,更好地复用session。
1)TCP队头阻塞(head of line blocking)
HTTP/2是基于TCP实现的。相比之前的版本,HTTP/2使用的TCP连接数少了很多。TCP是一个可靠的传输协议,基本上,你可以将它视为在两台计算机间建立的一个虚拟链路,由一端放到网络上的内容,最终总会以相同的顺序出现在另一端。(或者遭遇连接中断)
采用HTTP/2时,浏览器一般会在单个TCP连接中创建并行的几十个乃至上百个传输。如果HTTP/2连接双方的网络中有一个数据包丢失,或者任何一方的网络出现中断,整个TCP连接就会暂停,丢失的数据包需要被重新传输。因为TCP是一个按序传输的链条,因此如果其中一个点丢失了,链路上之后的内容就都需要等待。
如右图所示,我们一个用链条来表现一个连接上发送的两个流(传输),红色的与绿色的数据流:
这种单个数据包造成的阻塞,就是TCP上的队头阻塞(head of line blocking)。随着丢包率的增加,HTTP/2的表现越来越差。在2%的丢包率(一个很差的网络质量)中,测试结果表明HTTP/1用户的性能更好,因为HTTP/1一般有六个TCP连接,哪怕其中一个连接阻塞了,其他没有丢包的连接仍然可以继续传输。在限定的条件下,在TCP下解决这个问题相当困难
HTTP/3
基于QUIC的HTTP/2
用TCP还是UDP
如果我们无法解决TCP内的队头阻塞问题,那么按道理,我们应该在网络栈中发明一个UDP和TCP之外的新型传输层协议。或者我们应该用IETF在RFC 4960中标准化的SCTP传输层协议,它也有多个我们所需的特征。但在近些年来,因为在互联网上部署遭遇很大的困难,创造新型传输层协议的努力基本上都失败了。用户与服务器之间要经过许多防火墙、NAT(地址转换)、路由器和其他中间设备(middle-box),这些设备有很多只认TCP和UDP。如果使用另一种传输层协议,那么就会有N%的连接无法建立,这些中间设备会认为除TCP和UDP协议以外的协议都是不安全或者有问题的。如此高的的失败率一般被认为不值得再做出努力。另外,网络栈中的传输层协议改动一般意味着操作系统内核也要做出修改。更新和部署新款操作系统内核的过程十分缓慢,需要付出很大的努力。由IETF标准化的许多TCP新特性都因缺乏广泛支持而没有得到广泛的部署或使用。
为什么不基于UDP使用SCTP
SCTP是一个支持数据流的可靠的传输层协议,而且在WebRTC上已有基于UDP的对它的实现。这看上去很好,但与QUIC相比还不够好,它:没有解决数据流的队头阻塞问题连接建立时需要决定数据流的数量没有稳固的TLS/安全性支持建立连接时候需要4次握手,而QUIC一次都不用(0-RTT)QUIC是类TCP的字节流,而SCTP是信息流(message-based)QUIC连接支持IP地址迁移,SCTP不行
QUIC
安全性
QUIC始终保证安全性。QUIC协议没有明文的版本,所以想要建立一个QUIC连接,就必须通过TLS 1.3来安全地建立一个加密连接。如上文所说,加密可以避免协议僵化等拦截和特殊处理。这也使QUIC具有了Web用户所期望的所有的HTTPS安全特性。QUIC只在加密协议协商时会发送几个明文传送的初始握手报文。
减少延迟
与TCP的3次握手相比,QUIC提供了0-RTT和1-RTT的握手,这减少了协商和建立新连接时所需的时间。除此之外,QUIC提供了提早传输更多数据的“早期数据”(early data)特性,并且它的使用比TCP快速打开(TCP Fast Open)更加简便。因为数据流概念的引入,客户端不用等待前一个连接结束,便可以与同一个主机建立另一个逻辑连接。
有序交付
QUIC的单个数据流可以保证有序交付,但多个数据流之间可能乱序。这意味着单个数据流的传输是按序的,但是多个数据流中接收方收到的顺序可能与发送方的发送顺序不同!举个例子:服务器传送流A和B到客户端。流A先启动,然后是流B。在QUIC中,丢包只会影响该包所处的流。如果流A发生了一次丢包,而流B没有,流B将继续传输直到结束,而流A将会进行丢包重传过程。而在HTTP/2中这不可能发生。
快速握手
QUIC提供0-RTT和1-RTT的连接建立,这意味着QUIC在最佳情况下不需要任何的额外往返时间便可建立新连接。其中更快的0-RTT仅在两个主机之间建立过连接且缓存了该连接的“秘密”(secret)时可以使用。
基于UDP
QUIC是基于UDP在用户空间实现的传输协议。如果不观察细节,你会觉得QUIC跟UDP报文差不多。基于UDP意味着它使用UDP端口号来识别指定机器上的特定服务器。目前已知的所有QUIC实现都位于用户空间,这使它能得到更快速的迭代(相较于内核空间中的实现)
对比HTTP/2的优势
得益于QUIC的0-RTT握手,HTTP/3可以提供更好的早期数据支持,而TCP快速打开和TLS通常只能传输更少的数据,且经常存在问题。
得益于QUIC,HTTP/3的握手速度比TCP+TLS快得多。
HTTP/3不存在明文的不安全版本。尽管在互联网上很少见,HTTP/2还是可以不配合HTTPS来实现和使用
通过ALPN拓展,HTTP/2可以直接在TLS握手时进行协商。HTTP/3基于QUIC,所以需要凭借响应中的 Alt-Svc: 头部来向客户端宣告。
报文
简介
报文是网络中交换和传输的数据单元,即站点一次性要发送的数据块。报文包含了将要发送的完整的数据信息,其长短很不一致,长度不限且可变
用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的 HTTP 报文叫做请求报文;响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。
结构
HTTP 报文大致可分为报文首部和报文主体两部分。两者由最初出现的空行(CR+LF)来划分。通常,并不一定有报文主体。
构成
报文首部
服务器端或客户端需处理的请求或响应的内容及属性
首行
内容
请求行
包含用于请求的方法、请求 URI 和 HTTP 版本
请求方法
方法描述
HTTP版本
状态行
包含表明响应结果的状态码、原因短语和 HTTP 版本
状态码&原因短语
1XX:信息,服务器收到请求,需要请求者继续执行操作
100 Continue
服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求。
101 Switching Protocols
服务器转换协议:服务器将遵从客户的请求转换到另外一种协议。
2XX:成功,操作被成功接收并处理
200 OK
请求成功(其后是对GET和POST请求的应答文档。)
201 Created
请求被创建完成,同时新的资源被创建。
202 Accepted
供处理的请求已被接受,但是处理未完成。
203 Non-authoritative Information
文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝。
204 No Content
没有新文档。浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的。
205 Reset Content
没有新文档。但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容。
206 Partial Content
客户发送了一个带有Range头的GET请求,服务器完成了它。
3XX:重定向,需要进一步的操作以完成请求
300 Multiple Choices
多重选择。链接列表。用户可以选择某链接到达目的地。最多允许五个地址。
301 Moved Permanently
所请求的页面已经转移至新的url。
302 Found
所请求的页面已经临时转移至新的url。
303 See Other
所请求的页面可在别的url下被找到。
304 Not Modified
未按预期修改文档。客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
305 Use Proxy
客户请求的文档应该通过Location头所指明的代理服务器提取。
306 Unused
此代码被用于前一版本。目前已不再使用,但是代码依然被保留。
307 Temporary Redirect
被请求的页面已经临时移至新的url。
4XX:客户端错误,请求包含语法错误或无法完成请求
400 Bad Request
服务器未能理解请求。
401 Unauthorized
被请求的页面需要用户名和密码。
401.1
登录失败。
401.2
服务器配置导致登录失败。
401.3
由于 ACL 对资源的限制而未获得授权。
401.4
筛选器授权失败。
401.5
ISAPI/CGI 应用程序授权失败。
401.7
访问被 Web 服务器上的 URL 授权策略拒绝。这个错误代码为 IIS 6.0 所专用。
402 Payment Required
此代码尚无法使用。
403 Forbidden
对被请求页面的访问被禁止。
403.1
执行访问被禁止。
403.2
读访问被禁止。
403.3
写访问被禁止。
403.4
要求 SSL。
403.5
要求 SSL 128。
403.6
IP 地址被拒绝。
403.7
要求客户端证书。
403.8
站点访问被拒绝。
403.9
用户数过多。
403.10
配置无效。
403.11
密码更改。
403.12
拒绝访问映射表。
403.13
客户端证书被吊销。
403.14
拒绝目录列表。
403.15
超出客户端访问许可。
403.16
客户端证书不受信任或无效。
403.17
客户端证书已过期或尚未生效。
403.18
在当前的应用程序池中不能执行所请求的 URL。这个错误代码为 IIS 6.0 所专用。
403.19
不能为这个应用程序池中的客户端执行 CGI。这个错误代码为 IIS 6.0 所专用。
403.20
Passport 登录失败。这个错误代码为 IIS 6.0 所专用。
404 Not Found
服务器无法找到被请求的页面。
404.0
(无)–没有找到文件或目录。
404.1
无法在所请求的端口上访问 Web 站点。
404.2
Web 服务扩展锁定策略阻止本请求。
404.3
MIME 映射策略阻止本请求。
405 Method Not Allowed
请求中指定的方法不被允许。
406 Not Acceptable
服务器生成的响应无法被客户端所接受。
407 Proxy Authentication Required
用户必须首先使用代理服务器进行验证,这样请求才会被处理。
408 Request Timeout
请求超出了服务器的等待时间。
409 Conflict
由于冲突,请求无法被完成。
410 Gone
被请求的页面不可用。
411 Length Required
\"Content-Length\" 未被定义。如果无此内容,服务器不会接受请求。
412 Precondition Failed
请求中的前提条件被服务器评估为失败。
413 Request Entity Too Large
由于所请求的实体的太大,服务器不会接受请求。
414 Request-url Too Long
由于url太长,服务器不会接受请求。当post请求被转换为带有很长的查询信息的get请求时,就会发生这种情况。
415 Unsupported Media Type
由于媒介类型不被支持,服务器不会接受请求。
416 Requested Range Not Satisfiable
服务器不能满足客户在请求中指定的Range头。
417 Expectation Failed
服务器无法满足Expect的请求头信息。
423
锁定的错误。
5XX:服务器错误,服务器在处理请求的过程中发生了错误
500 Internal Server Error
请求未完成。服务器遇到不可预知的情况。
500.12
应用程序正忙于在 Web 服务器上重新启动。
500.13
Web 服务器太忙。
500.15
不允许直接请求 Global.asa。
500.16
UNC 授权凭据不正确。这个错误代码为 IIS 6.0 所专用。
500.18
URL 授权存储不能打开。这个错误代码为 IIS 6.0 所专用。
500.100
内部 ASP 错误。
501 Not Implemented
请求未完成。服务器不支持所请求的功能。
502 Bad Gateway
请求未完成。服务器从上游服务器收到一个无效的响应。
502.1
CGI 应用程序超时。
502.2
CGI 应用程序出错。
503 Service Unavailable
由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 Gateway Timeout
网关超时。
505 HTTP Version Not Supported
服务器不支持请求中指明的HTTP协议版本。
首部字段
包含表示请求的各种条件和属性的各类首部
用途
使用首部字段是为了给客服端和服务器端提供报文主体大小、所使用的语言、认证信息等内容
说明
首部字段是由首部字段名和字段值构成的,中间用冒号“:”分隔
字段值对应单个 HTTP 首部字段可以有多个值
当 HTTP 报文首部中出现了两个或以上具有相同首部字段名的首部字段时,这种情况在规范内尚未明确,根据浏览器内部处理逻辑的不同,优先处理的顺序可能不同,结果可能并不一致
类型
通用首部字段
请求报文和响应报文都会使用的首部
Cache-Control
请求
响应
Connection
Upgrade
在客户端发送请求和服务器返回响应中,使用 Connection 首部字段,可控制不再转发给代理的首部字段,即删除后再转发(即Hop-by-hop首部)。
close
HTTP/1.1 版本的默认连接都是持久连接。当服务器端想明确断开连接时,则指定 Connection 首部字段的值为 close。
Keep-Alive
HTTP/1.1 之前的 HTTP 版本的默认连接都是非持久连接。为此,如果想在旧版本的 HTTP 协议上维持持续连接,则需要指定 Connection 首部字段的值为 Keep-Alive。
Date
Pragma
no-cache
Pragma 首部字段是 HTTP/1.1 版本之前的历史遗留字段,仅作为与 HTTP/1.0 的向后兼容而定义。
该首部字段属于通用首部字段,但只用在客户端发送的请求中,要求所有的中间服务器不返回缓存的资源。
所有的中间服务器如果都能以 HTTP/1.1 为基准,那直接采用 Cache-Control: no-cache 指定缓存的处理方式最为理想。但是要整体掌握所有中间服务器使用的 HTTP 协议版本却是不现实的,所以,发送的请求会同时包含下面两个首部字段:Cache-Control: no-cachePragma: no-cache
Trailer
Expires
首部字段 Trailer 会事先说明在报文主体后记录了哪些首部字段。可应用在 HTTP/1.1 版本分块传输编码时
Transfer-Encoding
规定了传输报文主体时采用的编码方式。HTTP/1.1 的传输编码方式仅对分块传输编码有效。
内容编码是对报文的主体进行的可逆变换,是和内容的具体格式细节紧密相关的。传输编码也是作用在实体主体上的可逆变换,但使用它们是由于架构方面的原因,同内容的格式无关。使用传输编码是为了改变报文中的数据在网络上传输的方式。
用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。
Via
为了追踪客户端和服务器端之间的请求和响应报文的传输路径。报文经过代理或网关时,会现在首部字段 Via 中附加该服务器的信息,然后再进行转发。首部字段 Via 不仅用于追踪报文的转发,还可避免请求回环的发生。例子:Via: 1.1 a1.sample.com(Squid/2.7)
Warning
该首部字段通常会告知用户一些与缓存相关的问题的警告。Warning 首部字段的格式如下:Warning:[警告码][警告的主机:端口号] \"[警告内容]\"([日期时间])最后的日期时间可省略。HTTP/1.1 中定义了7种警告,警告码对应的警告内容仅推荐参考,另外,警告码具备扩展性,今后有可能追加新的警告码
请求首部字段
从客户端向服务器发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息
Accept
Accept-Charset
Accept-Encoding
Accept-Language
Authorization
告知服务器用户代理的认证信息(证书值)。通常,想要通过服务器认证的用户代理会在接收到返回的 401 状态码响应后,把首部字段 Authorization 加入请求中。共用缓存在接收到含有 Authorization 首部字段的请求时的操作处理会略有差异。示例:Authorization: Basic ldfKDHKfkDdasSAEdasd==
Expect
告知服务器客户端期望出现的某种特定行为。示例:Expect: 100-continue
From
告知服务器使用用户代理的电子邮件地址。 示例:From: Deeson_Woo@163.com
Host
告知服务器,请求的资源所处的互联网主机和端口号。Host 首部字段是 HTTP/1.1 规范内唯一一个必须被包含在请求内的首部字段。若服务器未设定主机名,那直接发送一个空值即可 Host: 。示例:www.baidu.com
If-Match
形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。
首部字段 If-Match,属附带条件之一,它会告知服务器匹配资源所用的实体标记(ETag)值。这时的服务器无法使用弱 ETag 值。服务器会比对 If-Match 的字段值和资源的 ETag 值,仅当两者一致时,才会执行请求。反之,则返回状态码 412 Precondition Failed 的响应。还可以使用星号(*)指定 If-Match 的字段值。针对这种情况,服务器将会忽略 ETag 的值,只要资源存在就处理请求。
示例:If-Match: \"123456\"
If-Modified-Since
首部字段 If-Modified-Since,属附带条件之一,用于确认代理或客户端拥有的本地资源的有效性。它会告知服务器若 If-Modified-Since 字段值早于资源的更新时间,则希望能处理该请求。而在指定 If-Modified-Since 字段值的日期时间之后,如果请求的资源都没有过更新,则返回状态码 304 Not Modified 的响应。
If-None-Match
首部字段 If-None-Match 属于附带条件之一。它和首部字段 If-Match 作用相反。用于指定 If-None-Match 字段值的实体标记(ETag)值与请求资源的 ETag 不一致时,它就告知服务器处理该请求。
示例:If-None-Match: \"123456\"
If-Range
首部字段 If-Range 属于附带条件之一。它告知服务器若指定的 If-Range 字段值(ETag 值或者时间)和请求资源的 ETag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。思考一下不使用首部字段 If-Range 发送请求的情况:服务器端的资源如果更新,那客户端持有资源中的一部分也会随之无效,当然,范围请求作为前提是无效的。这时,服务器会暂且以状态码 412 Precondition Failed 作为响应返回,其目的是催促客户端再次发送请求。这样一来,与使用首部字段 If-Range 比起来,就需要花费两倍的功夫。
示例:If-Range: \"123456\"
If-Unmodified-Since
首部字段 If-Unmodified-Since 和首部字段 If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码 412 Precondition Failed 作为响应返回
Max-Forwards
通过 TRACE 方法或 OPTIONS 方法,发送包含首部字段 Max-Forwards 的请求时,该字段以十进制整数形式指定可经过的服务器最大数目。服务器在往下一个服务器转发请求之前,Max-Forwards 的值减 1 后重新赋值。当服务器接收到 Max-Forwards 值为 0 的请求时,则不再进行转发,而是直接返回响应。
示例:Max-Forwards: 10
Proxy-Authorization
接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段 Proxy-Authorization 的请求,以告知服务器认证所需要的信息。这个行为是与客户端和服务器之间的 HTTP 访问认证相类似的,不同之处在于,认证行为发生在客户端与代理之间。
示例:Proxy-Authorization: Basic dGlwOjkpNLAGfFY5
Range
对于只需获取部分资源的范围请求,包含首部字段 Range 即可告知服务器资源的指定范围。接收到附带 Range 首部字段请求的服务器,会在处理请求之后返回状态码为 206 Partial Content 的响应。无法处理该范围请求时,则会返回状态码 200 OK 的响应及全部资源。
示例:Range: bytes=5001-10000
假设你正在下载一个很大的文件,已经下了四分之三,忽然网络中断了,那下载就必须重头再来一遍。为了解决这个问题,需要一种可恢复的机制,即能从之前下载中断处恢复下载。要实现该功能,这就要用到范围请求。
有了范围请求, HTTP 客户端可以通过请求曾获取失败的实体的一个范围(或者说一部分),来恢复下载该实体。当然这有一个前提,那就是从客户端上一次请求该实体到这一次发出范围请求的时间段内,该对象没有改变过。例如:GET /bigfile.html HTTP/1.1Host: [url=http://www.sample.com]www.sample.com[/url]Range: bytes=20224-···
Referer
首部字段 Referer 会告知服务器请求的原始资源的 URI。 示例:Referer: http://www.sample.com/index.html
TE
首部字段 TE 会告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段 Accept-Encoding 的功能很相像,但是用于传输编码。首部字段 TE 除指定传输编码之外,还可以指定伴随 trailer 字段的分块传输编码的方式。应用后者时,只需把 trailers 赋值给该字段值。TE: trailers
User-Agent
首部字段 User-Agent 会将创建请求的浏览器和用户代理名称等信息传达给服务器。由网络爬虫发起请求时,有可能会在字段内添加爬虫作者的电子邮件地址。此外,如果请求经过代理,那么中间也很可能被添加上代理服务器的名称。
示例:User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101
响应首部字段
从服务端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息
Accept-Ranges
首部字段 Accept-Ranges 是用来告知客户端服务器是否能处理范围请求,以指定获取服务器端某个部分的资源。可指定的字段值有两种,可处理范围请求时指定其为 bytes,反之则指定其为 none。
示例:Accept-Ranges: bytes
Age
首部字段 Age 能告知客户端,源服务器在多久前创建了响应。字段值的单位为秒。若创建该响应的服务器是缓存服务器,Age 值是指缓存后的响应再次发起认证到认证完成的时间值。代理创建响应时必须加上首部字段 Age。
示例:Age: 1200
ETag
首部字段 ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag 值。另外,当资源更新时,ETag 值也需要更新。生成 ETag 值时,并没有统一的算法规则,而仅仅是由服务器来分配。ETag 中有强 ETag 值和弱 ETag 值之分。强 ETag 值,不论实体发生多么细微的变化都会改变其值;弱 ETag 值只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时,会在字段值最开始处附加 W/: ETag: W/\"usagi-1234\"。
示例:ETag: \"usagi-1234\"
Location
使用首部字段 Location 可以将响应接收方引导至某个与请求 URI 位置不同的资源。基本上,该字段会配合 3xx :Redirection 的响应,提供重定向的 URI。几乎所有的浏览器在接收到包含首部字段 Location 的响应后,都会强制性地尝试对已提示的重定向资源的访问。
示例:Location: http://www.sample.com/sample.html
Proxy-Authenticate
首部字段 Proxy-Authenticate 会把由代理服务器所要求的认证信息发送给客户端。它与客户端和服务器之间的 HTTP 访问认证的行为相似,不同之处在于其认证行为是在客户端与代理之间进行的。
示例:Proxy-Authenticate: Basic realm=\"Usagidesign Auth\"
Retry-After
示例:Retry-After: 180
Server
首部字段 Server 告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息。不单单会标出服务器上的软件应用名称,还有可能包括版本号和安装时启用的可选项。
示例:Server: Apache/2.2.6 (Unix) PHP/5.2.5
Vary
首部字段 Vary 可对缓存进行控制。源服务器会向代理服务器传达关于本地缓存使用方法的命令。从代理服务器接收到源服务器返回包含 Vary 指定项的响应之后,若再要进行缓存,仅对请求中含有相同 Vary 指定首部字段的请求返回缓存。即使对相同资源发起请求,但由于 Vary 指定的首部字段不相同,因此必须要从源服务器重新获取资源。
示例:Vary: Accept-Language
WWW-Authenticate
首部字段 WWW-Authenticate 用于 HTTP 访问认证。它会告知客户端适用于访问请求 URI 所指定资源的认证方案(Basic 或是 Digest)和带参数提示的质询(challenge)。
示例:WWW-Authenticate: Basic realm=\"Usagidesign Auth\"
实体首部字段
针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息
Allow
首部字段 Allow 用于通知客户端能够支持 Request-URI 指定资源的所有 HTTP 方法。当服务器接收到不支持的 HTTP 方法时,会以状态码 405 Method Not Allowed 作为响应返回。与此同时,还会把所有能支持的 HTTP 方法写入首部字段 Allow 后返回。
Content-Encoding
首部字段 Content-Encoding 会告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩。主要采用 4 种内容编码的方式。
HTTP 应用程序有时在发送之前需要对内容进行编码。例如,在把很大的 HTML 文档发送给通过慢速连接上来的客户端之前,服务器可能会对其进行压缩,这样有助于减少传输实体的时间。服务器还可以把内容搅乱或加密,以此来防止未授权的第三方看到文档的内容。这种类型的编码是在发送方应用到内容之上的。当内容经过内容编码后,编好码的数据就放在实体主体中,像往常一样发送给接收方。
示例:Content-Encoding: gzip
Content-Language
首部字段 Content-Language 会告知客户端,实体主体使用的自然语言(指中文或英文等语言)。
示例:Content-Language: zh-CN
Content-Length
首部字段 Content-Length 表明了实体主体部分的大小(单位是字节)。对实体主体进行内容编码传输时,不能再使用 Content-Length首部字段。
示例:Content-Length: 15000
Content-Location
首部字段 Content-Location 给出与报文主体部分相对应的 URI。和首部字段 Location 不同,Content-Location 表示的是报文主体返回资源对应的 URI。
示例:Content-Location: http://www.sample.com/index.html
Content-MD5
首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达。
示例:Content-MD5: OGFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==
Content-Range
针对范围请求,返回响应时使用的首部字段 Content-Range,能告知客户端作为响应返回的实体的哪个部分符合范围请求。字段值以字节为单位,表示当前发送部分及整个实体大小。
示例:Content-Range: bytes 5001-10000/10000
Content-Type
首部字段 Content-Type 说明了实体主体内对象的媒体类型。和首部字段 Accept 一样,字段值用 type/subtype 形式赋值。参数 charset 使用 iso-8859-1 或 euc-jp 等字符集进行赋值。
示例:Content-Type: text/html; charset=UTF-8
首部字段 Expires 会将资源失效的日期告知客户端。缓存服务器在接收到含有首部字段 Expires 的响应后,会以缓存来应答请求,在 Expires 字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。源服务器不希望缓存服务器对资源缓存时,最好在 Expires 字段内写入与首部字段 Date 相同的时间值。
Last-Modified
首部字段 Last-Modified 指明资源最终修改的时间。一般来说,这个值就是 Request-URI 指定资源被修改的时间。但类似使用 CGI 脚本进行动态数据处理时,该值有可能会变成数据最终修改时的时间。
其他首部字段
RFC里未定义的首部如 Cookie 等
Set-Cookie
expires
Cookie 的 expires 属性指定浏览器可发送 Cookie 的有效期。当省略 expires 属性时,其有效期仅限于维持浏览器会话(Session)时间段内。这通常限于浏览器应用程序被关闭之前。另外,一旦 Cookie 从服务器端发送至客户端,服务器端就不存在可以显式删除 Cookie 的方法。但可通过覆盖已过期的 Cookie,实现对客户端 Cookie 的实质性删除操作
path
Cookie 的 path 属性可用于限制指定 Cookie 的发送范围的文件目录。
domain
通过 Cookie 的 domain 属性指定的域名可做到与结尾匹配一致。比如,当指定 example.com 后,除example.com 以外,www.example.com 或 www2.example.com 等都可以发送 Cookie。因此,除了针对具体指定的多个域名发送 Cookie 之 外,不指定 domain 属性显得更安全。
secure
Cookie 的 secure 属性用于限制 Web 页面仅在 HTTPS 安全连接时,才可以发送 Cookie。
HttpOnly
Cookie 的 HttpOnly 属性是 Cookie 的扩展功能,它使 JavaScript 脚本无法获得 Cookie。其主要目的为防止跨站脚本攻击(Cross-site scripting,XSS)对 Cookie 的信息窃取。通过上述设置,通常从 Web 页面内还可以对 Cookie 进行读取操作。但使用 JavaScript 的 document.cookie 就无法读取附加 HttpOnly 属性后的 Cookie 的内容了。因此,也就无法在 XSS 中利用 JavaScript 劫持 Cookie 了。
Cookie
首部字段 Cookie 会告知服务器,当客户端想获得 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个 Cookie 时,同样可以以多个 Cookie 形式发送。
示例:Cookie: status=enable
补充说明:HTTP 首部字段是可以自行扩展的。所以在 Web 服务器和浏览器的应用上,会出现各种非标准的首部字段。以下是最为常用的首部字段
X-Frame-Options
说明:
属于 HTTP 响应首部,用于控制网站内容在其他 Web 网站的 Frame 标签内的显示问题。其主要目的是为了防止点击劫持(clickjacking)攻击
值:
DENY
拒绝
SAMEORIGIN
仅同源域名下的页面(Top-level-browsing-context)匹配时许可。(比如,当指定 http://sample.com/sample.html 页面为 SAMEORIGIN 时,那么 sample.com 上所有页面的 frame 都被允许可加载该页面,而 example.com 等其他域名的页面就不行了)
X-XSS-Protection
属于 HTTP 响应首部,是针对跨站脚本攻击(XSS)的一种对策,用于控制浏览器 XSS 防护机制的开关
0
将 XSS 过滤设置成无效状态
1
将 XSS 过滤设置成有效状态
P3P
HTTP 响应首部,通过利用 P3P(The Platform for Privacy Preferences,在线隐私偏好平台)技术,可以让 Web 网站上的个人隐私变成一种仅供程序可理解的形式,以达到保护用户隐私的目的
CP=\"CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND\"
注意:要进行 P3P 的设定,需按以下操作步骤进行
步骤 1:创建 P3P 隐私
步骤 2:创建 P3P 隐私对照文件后,保存命名在 /w3c/p3p.xml
步骤 3:从 P3P 隐私中新建 Compact policies 后,输出到 HTTP 响应中
DNT
属于 HTTP 请求首部,其中 DNT 是 Do Not Track 的简称,意为拒绝个人信息被收集,是表示拒绝被精准广告追踪的一种方法。由于首部字段 DNT 的功能具备有效性,所以 Web 服务器需要对 DNT做对应的支持
同意被追踪
拒绝被追踪
空行(CR + LF)
CR:
Carriage Return,回车符
16进制,0x0d
LF:
Line Feed,换行符
16进制,0x0a
报文主体
应被发送的数据
实体
作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成
右图中深红色框的内容就是报文的实体部分,而蓝色框的两部分内容分别就是实体首部和实体主体。而左图中粉红框内容就是报文主体。
通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。
多部分媒体类型
MIME 中的 multipart(多部分)电子邮件报文中包含多个报文,它们合在一起作为单一的复杂报文发送。每一部分都是独立的,有各自的描述其内容的集,不同部分之间用分界字符串连接在一起。相应得,HTTP 协议中也采纳了多部分对象集合,发送的一份报文主体内可包含多种类型实体。[RFC2045]
多部分对象集合包含的对象
multipart/form-data:在 Web 表单文件上传时使用
multipart/byteranges:状态码 206 Partial Content 响应报文包含了多个范围的内容时使用
请求报文结构图
请求报文示例
响应报文结构图
响应报文示例
协作应用与Web服务器
代理
HTTP 代理服务器是 Web 安全、应用集成以及性能优化的重要组成模块。代理位于客户端和服务器端之间,接收客户端所有的 HTTP 请求,并将这些请求转发给服务器(可能会对请求进行修改之后再进行转发)。对用户来说,这些应用程序就是一个代理,代表用户访问服务器。出于安全考虑,通常会将代理作为转发所有 Web 流量的可信任中间节点使用。代理还可以对请求和响应进行过滤,安全上网或绿色上网。
Agent 代理
Agent 代理是代表用户发起 HTTP 请求的客户端应用程序。所有发器 Web 请求的应用程序都是 HTTP Agent 代理。
网关
网关是一种特殊的服务器,作为其他服务器的中间实体使用。通常用于将 HTTP 流量转换成其他的协议。网关接收请求时就好像自己是资源的源服务器一样。客户端可能并不知道自己正在跟一个网关进行通信。
隧道
隧道是会在建立起来之后,就会在两条连接之间对原始数据进行盲转发的 HTTP 应用程序。HTTP 隧道通常用来在一条或多条 HTTP 连接上转发非 HTTP 数据,转发时不会窥探数据。HTTP 隧道的一种常见用途就是通过 HTTP 连接承载加密的安全套接字层(SSL)流量,这样 SSL 流量就可以穿过只允许 Web 流量通过的防火墙了。
缓存
Web 缓存或代理缓存是一种特殊的 HTTP 代理服务器,可以将经过代理传输的常用文档复制保存起来。下一个请求同一文档的客户端就可以享受缓存的私有副本所提供的服务了。客户端从附近的缓存下载文档会比从远程 Web 服务器下载快得多。
浏览器第一次请求
浏览器再次请求
0 条评论
下一页