HTTP:实体和编码

HTTP可以传输任何东西,比如图形、文本、实体、软件等等。HTTP还会确保它的报文能被正确的传输、识别、提取以及使得处理。具体来说,HTTP要确保它所承载的“货物”满足下面条件:

  • 可以被正确的识别(通过Content-Type首部说明媒体格式,Content-Language首部说明语言),以便浏览器和其他客户单能够正确处理内容
  • 可以被正确的解包(通过Content-Length首部和Content-Encoding首部)
  • 是最新的(通过实体验证码和缓存过期控制)
  • 符号用户的需要(基于Accept系列的内容协商首部)
  • 在网络上可以快速有效的传输(通过范围请求、差异编码以及其他数据压缩方法)
  • 完整到达、未被篡改(通过传输编码首部和Content-MD5校验和首部)

为了实现这些目标,HTTP使用了完善的标签来描述承载内容的实体

报文是箱子,实体是货物

可以把HTTP报文看成是网络货运系统的箱子,那么HTTP实体就是货物。看个例子:
在这里插入图片描述
实体首部指出这是一个纯文本文档(Content-Type:text/plain),它只有18个字节长(Content-Length:18)。和往常一样,一个空白行(CRLF)把首部字段同主体的开始部分分隔开来。

HTTP实体首部描述了HTTP报文中的内容。HTTP/1.1版定义了如下10个基本实体首部字段:

  • Content-Type 实体中所承载对象的类型。
  • Content-Length 所传送实体主体的长度或大小。
  • Content-Language 与所传送对象最相配的人类语言。
  • Content-Encoding 对象数据所做的任意变换(比如,压缩)。
  • Content-Location 一个备用位置,请求时可通过它获得对象。
  • Content-Range 如果这是部分实体,这个首部说明它是整体的哪个部分。
  • Content-MD5 实体主体内容的校验和。
  • Last-Modified 所传输内容在服务器上创建或最后修改的日期时间。
  • Expires 实体数据将要失效的日期时间。
  • Allow 该资源所允许的各种请求方法,例如,GET和HEAD。
  • ETag 这份文档特定实例(参见15.7节)的唯一验证码。ETag首部没有正式定义为实体首部,但它对许多涉及实体的操作来说,都是一个重要的首部。
  • Cache-Control 指出应该如何缓存该文档。和ETag首部类似,Cache-Control首部也没有正式定义为实体首部。

实体主体

实体主体就是原始货物。任何其他描述性的信息都包含在首部中。因为货物(也就是实体主体)只是原始数据,所以需要实体首部来描述数据的意义。比如,Content-Type实体首部告诉我们如何去解释数据(是图像还是文本),而Content-Encoding实体首部告诉我们数据是不是已被压缩或者重编码。

首部字段以一个空白的CRLF行结束,随后就是实体主体的原始内容。不管内容是什么,都紧随这个CRLF之后
在这里插入图片描述

Content-Length:实体的大小

Content-Length首部指示出报文中实体主体的字节大小。这个大小是包含了所有内容编码的。比如,对文本文件进行了gzip压缩的话,Content-Length首部就是压缩后的大小,而不是原始大小。

除非使用了分块编码,否则Content-Length首部就是带有实体主体的报文必须使用的。使用Content-Length首部是为了能够检测出服务器崩溃而导致的报文截尾,并对共享持久连接的多个报文进行正确分段

检测截尾

HTTP的早期版本采用关闭连接的方法来划定报文的结束。但是,没有Content-Length的话,客户端无法区分到底是报文结束时正常的连接关闭,还是报文传输中由于服务器崩溃而导致的连接关闭。客户端需要通过Content-Length来检测报文截尾。

报文截尾的问题对缓存代理服务器来说尤其严重。如果缓存服务器收到被截尾的报文却没有识别出截尾的话,它可能会存储不完整的内容并多次使用它来提供服务。缓存代理服务器通常不会为没有显式Content-Length首部的HTTP主体做缓存,以此来减小缓存已截尾报文的风险

错误的Content-Length

错误的Content-Length比缺少Content-Length还要糟糕。因为某些早期的客户端和服务器在Content-Length计算上存在一些众所周知的错误,有些客户端、服务器以及代理中就包含了特别的算法,用来检测和纠正与有缺陷服务器的交互过程。HTTP/1.1规定用户Agent代理应该在接收且检测到无效长度时通知用户。

Content-Length与持久连接

Content-Length首部对于持久连接是必不可少的。如果响应通过持久连接传送,就可能有另一条响应紧随其后。客户端通过Content-Length首部就可以通知报文在何处关闭,下一条报文在何处开始。因为连接是持久的,客户端无法依赖连接关闭来判别报文的结束。如果没有Content-Length首部,HTTP应用程序就不知道某个实体主体在哪里结束,下一条报文从哪里开始。

有一种情况下,使用持久连接时可以没有Content-Length首部,即采用**分块编码(chunked encoding)**时。在分块编码的情况下,数据是分为一系列的块来发送的,每块都有大小说明。哪怕服务器在生成首部的时候不知道整个实体的大小(通常是因为实体是动态生成的),仍然可以使用分块编码传输若干已知大小的块

内容编码

HTTP运行对实体主体的内容进行编码,比如可以使之更安全或者进行压缩以节省空间。如果主体进行了内容编码,Content-Length首部说明的就是编码后的主体的字节长度,而不是未编码的原始主体的长度

确定实体主体长度的规则

下面列出的规则说明了在若干不同的情况下如何正确计算主体的长度和结束位置。这些规则应当按照顺序使用,谁先匹配就用谁。

  • 如果特定的HTTP报文不允许带有主体,就忽略Content-Length首部,它是对(没有实际发送出来的)主体进行计算的。此时,Content-Length首部是提示性的,并不说明实体的主体长度
    • 最重要的例子就是HEAD响应。HEAD方法请求服务器发送等价的GET请求中会出现的首部,但不要包括主体。因为对GET的响应会带有Content-Length首部,所以HEAD响应里面也有。但与GET响应不同的是,HEAD响应中不会有主体。
    • 1XX,204以及304响应也可以有提示性的Content-Length首部,但是也都没有实体主体
    • 那些规定不能带有实体主体的报文,不管带有什么首部字段,都必须在首部之后的第一个空行终止
  • 如果报文中含有描述传输编码的Transfer-Encoding首部(不采用默认的HTTP"恒等"编码),那实体就应由一个称为零字节块(Zero-byte chunk)的特殊模块结束,除非报文已经因连接关闭而借宿
  • 如果报文中含有Content-Length首部(并且报文类型允许有实体主体),而且没有非恒等的Transfer-Encoding首部字段,那么Content-Length的值就是主体的长度。
  • 如果收到的报文中既有Content-Length首部(并且报文类型允许有实体主体),又有非恒等的Transfer-Encoding首部字段,那就必须忽略Content-Length,因为传输编码会改变实体主体的表示和传输方式(因此可能就会改变传输的字节数)
  • 如果报文使用了multipart/byteranges(多部分/字节范围)媒体类型,并且没有用Content-Length首部指出实体主体的长度,那么多部分报文中的每个部分都要说明它自己的大小,那么多部分报文中的每个部分都要说明它自己的大小。这种多部分类型是唯一的一种自定界的实体主体类型,因此除非发送方知道接收方可以解析它,否则就不能发送这种媒体类型
  • 如果上面的规则都不逼迫,实体就在连接关闭的时候结束。实际上,只有服务器可以使用连接关闭来指示报文的结束。客户端不能用关闭连接来指示客户端报文的结束,因为这样会使服务器无法发回响应(客户端使用半关闭,也就是只把连接的输出端关闭,但很多服务器应用程序设计并没有考虑到处理这种情况,会把半关闭当中客户端要从服务器断开连接来处理。HTTP没有对连接管理进行良好的规范)。

为了和使用HTTP/1.0的应用程序兼容,任何带有实体主体的HTTP/1.1请求都必须带有正确的Content-Length首部字段。

HTTP/1.1规范中建议对于带有主体但没有Content-Length首部的请求,服务器如果无法确定报文的长度,就应当发送400 Bad Request响应或者411 Length Required响应,后一种情况表明服务器要求收到正确的Content-Length首部

实体摘要

尽管HTTP通常都是在像TCP/IP这样的可靠传输协议之上实现的,但仍有很多因素会导致报文的一部分在传输过程中被修改,比如有不兼容的转码代理,或者中间代理有误,等等。为检测实体主体的数据是否被不经意(或不希望有)的修改,发送方可以在生成初始的主体时,生成一个数据的校验和,这样接收方就可以通过检查这个校验和来捕获所有意外的实体被修改了。

服务器使用Content-MD5首部发送对实体主体运行MD5算法的结果。只有产生响应的原始服务器可以计算并发送Content-MD5首部,中间代理和缓冲不应当修改或者添加这个首部,否则就会与验证端到端完整性的这个最终目的相冲突。Content-MD5首部是在内容做了所有需要的内容编码之后,还没有做任何传输编码之前,计算出来的。为了验证报文的传输之前,客户端必须先进行传输编码的解压,然后计算所得到的没有进行传输编码的实体主体的MD5。比如说,如果一份文档使用gzip算法进行压缩,然后用分开编码发送,那么就对整个经gzip压缩的主体进行MD5计算。

除了检查报文的完整性之外,MD5还可以当做散列表的关键字,用来快速定位文档并消除不必要的重复内容存储。除了这些可能的用法,一般不常用到Content-MD5首部。

作为对HTTP的扩展,在IETF的草案中提出了其他一些摘要算法。这些扩展建议增加新的Want-Digest首部,它允许客户端说明期望响应中使用的摘要类型,并使用质量值来建议多种摘要算法并说明优先顺序。

媒体类型和字符集

Content-Type首部字段说明了实体主体的MIME类型。MIME类型是标准化名字,用以说明作为货物运载实体的基本媒体类型(比如HTML文件等)。客户端应用程序使用MIME类型来解释和处理其内容。

Content-Type的值是标准化的MIME类型,都在互联网号码分配机构中注册。MIME类型由一个主媒体类型后跟一个斜线以及一个子类型组成,子类型用于进一步说明其媒体类型。举个例子:text/html

要注意的是,Content-Type首部说明的是原始主体的媒体类型。比如,如果实体经过内容编码的话,Content-Type首部说明的仍是编码之前的实体主体的类型

文本的字符编码

Content-Type首部还支持可选的参数来进一步说明内容的类型。charset(字符集)就是个例子,它说明把实体中的比特转换为文本文件中的字符的方法。比如:

Content-Type: text/html; charset=iso-8859-4

多部分媒体类型

MIME中的multipart(多部分)电子邮件报文中包含多个报文,它们合在一起作为单一的复杂报文发送。每一部分都是独立的,有各自的描述其内容的集:不同的部分之间用分界字符串连接在一起。

HTTP也支持多部分主体,不过,通常只用于下列两种情形之一:

  • 提交填写号的表格
  • 作为承载若干文档片段的范围响应

多部分表格提交

当提交填写的HTTP表格时,变长的文本字段和上传的对象都作为多部分主体里面独立的部分发送,这样表格中就可以填写各种不同类型和长度的值。

HTTP使用Content-Type:multipart/form-dataContent-Type:multipart/mixed这样的首部以及多部分主体来发送这种请求,举例如下:
在这里插入图片描述
其中的boundary参数说明了分隔主体中不同部分所用的字符串。

多部分范围响应

HTTP对范围请求的响应也可以是多部分的。这样的响应中有Content-Type: multipart/byteranges首部和带有不同范围的多部分主体。

内容编码

HTTP应用程序有时在发送之前需要对内容进行编码。比如,在把很大的HTML文档发送给通过慢速连接上来的客户端之前,服务器可能会对它进行压缩,这样有助于减少传输实体的时间。服务器还可以把内容加密,以此防止未经授权的第三方看到文档的内容。

这种类型的编码是发送方应用到内容之上的。当内容经过内容编码之后,编好码的数据就放在实体主体中,像往常一样发送给接收方

内容编码过程

如下图:

  • 网站服务请求生成原始响应报文,其中有原始的Content-Type和Content-Length首部
  • 内容编码服务器创建编码后的报文,编码后的报文有着同样的Content-Type但Content-Length可能不同。内容编码服务器在编码后的报文中增加Content-Encoding首部,这样接收到的应用程序就可以进行解码了
  • 接收程序得到编码后的报文,进行解码,获得原始报文。
    在这里插入图片描述
    下面给出的响应片段是另一个编码响应的例子(一个压缩的图像):
    在这里插入图片描述
    注意,Content-Type首部可以且还应当出现在报文中。它说明了实体的原始格式,一旦实体被解码,要显示的时候,可能还是需要该信息才行。记住,Content-Length首部现在代表的是编码之后的主体长度

内容编码类型

HTTP定义了一些标准编码类型,并允许用扩展编码的形式增添更多的编码。由互联网号码分配机构对各种编码进行标准化,它给每个内容编码算法分配了唯一的代号。Content-Encoding首部就用这些标准化的代号来说明编码时使用的算法。

下表列出了一些常用的内容编码代号:
在这里插入图片描述
gzip、compress以及deflate编码都是无损压缩算法,用于减少传输报文的大小,不会导致信息损失。这些算法中,gzip通常是效率最高的,使用最为广泛。

Accept-Encoding首部

毫无疑问,我们不希望服务器用客户端无法解码的方式来对内容进行编码。为了避免服务器使用客户端不支持的编码方式,客户端就把自己支持的内容编码方式列表放在请求的Accept-Encoding首部中发出去。如果HTTP请求中没有包含Accept-Encoding首部,服务器就可以假设客户端能够接受任何编码方式(等价于Accept-Encoding:*)
在这里插入图片描述

Accept-Encoding字段包含用,分隔的支持编码的列表,下面给出了一些例子:

在这里插入图片描述
客户端可以给每种编码附加Q(质量)值参数来说明编码的优先级。Q值的范围从0.0到1.0,0.0说明客户端不想接受所说明的编码,1.0则表明最希望使用的编码。*表示"任何其他方法"。

identity编码代码只能在Accept-Encoding首部中出现。客户端用它来说明相对于其他内容编码算法的优先级。

传输编码和分块编码

前一节讨论的内容编码,是对报文的主体进行的可逆变换。内容编码是和内容的具体格式细节紧密相关的。比如,你可能会用gzip压缩文本文件,但不是jpeg文件,因为jpeg这类东西用gzio压缩的不够好

传输编码也是作用在实体主体上的可逆变换,但使用它们是由于架构方面的原因,同内容的格式无关。如下图所示,使用传输编码是为了改变报文中的数据在网络上传输的方式。
在这里插入图片描述

可靠传输

在HTTP协议中,因为底层是TCP/IP,所以只有在少数情况下,所传输的报文主体可能会引发问题。其中两种情况如下:

  • 未知的尺寸:如果不先生成内容,某些网关应用程序和内容编码器就无法确定报文主体的最终大小。通常,这些服务器希望在知道大小之前就开始传输数据。因为HTTP协议要求Content-Length首部必须在数据之前,有些服务器就使用传输编码来发送数据,并用特别的结束脚注来表明数据结束(尽管可以用关闭连接作为报文结束的信号,但是这种方法不能用于持久连接)。
  • 安全性:你可以用传输编码来把报文内容扰乱,然后在共享的传输网络上发送。不过,由于像SSL这样的传输层安全体系的流行,就很少需要靠传输编码来实现安全性了。

Transfer-Encoding首部

HTTP协议中只定义了下面两个首部来描述和控制传输编码:

  • Transer-Encoding:告知接收方为了可靠的传输报文,已经对其进行了何种编码
  • TE:用在请求首部中,告知服务器可以使用哪些传输编码扩展.(Accept-Transer-Encoding)

下面的例子中,请求使用了TE首部来告诉服务器它可以接收分块编码并且原因接收附在分块编码的报文结尾上的拖挂:

在这里插入图片描述
对它的响应中包含Transfer-Encoding首部,用于告诉接收方已经用分开编码对报文进行了传输编码:
在这里插入图片描述
在这个起始首部之后,报文的结构就将发生改变。

传输编码的值都是大小写无关的。HTTP/1.1规定在TE首部和Transfer-Encoding首部中使用传输编码值。最新的HTTP规范只定义了一种传输编码,就是分块编码

与Accept-Encoding首部类似,TE首部也可以使用Q值来说明传输编码的优先顺序。不过,HTTP/1.1规范中禁止将分块编码关联的Q值设为0.0

分块编码

分块编码把报文分隔为若干个大小已知的块。块之间是紧挨着发送的,这样就不需要在发送之前知道整个报文的大小了。

要注意的是,分块编码是一种传输编码,因此是报文的属性,而不是主体的属性。

分块与持久连接

如果客户端和服务器之间不是持久连接,客端就不需要知道它正在读取的主体的长度,而只需要读到服务器关闭主体连接为止

当使用持久连接时,在服务器写主体之前,必须知道它的大小并在Content-Length首部中发送。如果服务器动态创建内容,就可能在发送之前无法知道主体的长度。

分块编码为这种困难提供了解决方案,只要允许服务器把主体逐块发送,说明每块的大小就可以了。因为主体是动态创建的,服务器可以缓冲它的一部分,发送其大小和相应的块,然后在主体发送完之前重复这个过程。服务器可以用大小为0的块作为主体结束的信号,这样就可以继续保持连接,为下一个响应做准备。

分块编码是相当简单的。下图展示了一个分块编码报文的基本结构。它由起始的HTTP响应首部块开始,随后就是一系列分块。每个分块包含一个长度值和该分块的数据。长度值是16进制形式并将CRLF与数据分隔开。分块中的数据的大小以字节计算,不包括长度值和数据之间的CRLF序列以及分块结尾的CRLF序列。最后一个块有些特别,它的长度值为0,表示“主体结束”。

客户端也可以发送分块的数据给服务器。因为客户端事先不知道服务器是否接受分块编码(这时因为服务器不会在给客户端的响应中发送TE首部),所以客户端必须做好服务器用411 Length Required(需要Content-Length首部)响应来拒绝分块请求的准备。

在这里插入图片描述

分块报文的拖挂

如果客户单的TE首部说明它可以接受拖挂(trailer)的话,就可以在分块的报文最后加上拖挂。产生原始响应的服务器也可以在分块的报文最后加上拖挂。拖挂的内容是可选的,客户端可以忽略并丢弃拖挂中的内容。

拖挂中可以包含附带的首部字段,它们的值在报文开始的时候可能是无法确定的。Content-MD5首部就是一个可以在拖挂中发送的首部,因为在文档生成之前,很难算出它的MD5。上图1展示了拖挂的使用方式。报文首部中包含一个Trailer首部,列出了跟在分块报文之后的首部列表。在Trailer首部中列出的首部就紧接在最后一个分块之后。

除了Transfer-EncodingTrailer以及Content-Length首部之外,其他HTTP首部都可以作为拖挂发送。

内容编码和传输编码的结合

内容编码可以与出书编码同时使用,看个例子:
在这里插入图片描述

传输编码的规则

对报文主体使用传输编码时,必须遵守如下规则:

  • 传输编码集合中必须包括“分块”。唯一的例外就是使用关闭连接来结束报文
  • 当使用分块传输编码时,它必须是最后一个作用到报文主体之上的
  • 分块传输编码不能多次作用到一个报文主体上。

这些规则使得接收方能够确定报文的传输长度。

传输编码是HTTP/1.1版引入的一个相对较新的特性。实现传输编码的服务器必须特别注意不要把经传输编码后的报文发送给非HTTP/1.1的应用程序。同样的,如果服务器收到无法理解的经过传输编码的报文,它应当用501 Unimplemented状态码来回复。不过,所有的HTTP/1.1应用程序至少都必须支持分块编码

随时间变化的实例

网站对象不是静态的。同样的URL会随着时间编号而指向对象的不同版本。以CNN的主页为例,同一天里多次访问http://www.cnn.com,可能每次得到的返回页面都略有不同。

可以把CNN的主页当做一个对象来考虑,其不同的版本就可以看作这个对象的不同实例(如下图)。在图中,客户单多次请求同一个资源(URL),但得到的是该资源的不同实例,因为它是随时间变化的。在时间a和时间b具有相同的实例,而时间c则是不同的实例
在这里插入图片描述
HTTP协议规定了实例操控(instance manipulations)的一系列请求和响应操作,用以操控对象的实例。两个主要的实例操控方法是范围请求和差异编码。这两种方法都要求客户端能够标识它所拥有(如果有的话)的资源的特定副本,并在一定的条件下请求新的实例

验证码和新鲜度

上图中,客户端起初没有该资源的副本,因此它发送请求给服务器要求得到一份。服务器用该资源的版本1给以响应。客户端现在可以缓存这份副本,但是要缓存多长时间呢?

当文档“过期”之后(也就是说,客户端不再认为该副本有效),客户端必须从服务器请求一份新的副本。不过,如果该文档在服务器上并未发生改变,客户端也就不需要再接收一次了------继续使用缓存的副本即可。

这种特殊的请求,称为有条件的请求(conditional request),要求客户端使用验证码(validotor)来告知服务器它当前拥有的版本号,并仅当它的当前副本不再有效时才要求发送新的副本。

新鲜度

服务器应当告知客户端能够将内容缓存多长时间,在这个时间之内就是新鲜的。服务器可以用这两个首部之一来提供这种信息:Expires(过期)和Cache-Control(缓存控制)

Expires首部规定文档"过期"的具体时间—此后就不应当认为它还是最新的。语法如下:
在这里插入图片描述
客户端和服务器为了能正确使用Expires首部,它们的时钟必须同步,但是这并不容易。因此推荐使用Cache-Control

实际上,Cache-Control首部功能很强大。服务器和客户端都可以用它来说说明新鲜度,并且除了使用期和过期时间之外,还有很多指令可用。下表给出了一些常用指令:

在这里插入图片描述

有条件的请求和验证码

当请求缓存服务器中的副本时,如果它不再新鲜,缓存服务器就需要保证它有一个新鲜的副本,此时缓存服务器可以向原始服务器获取当前的副本。但是很多情况下,原始服务器上的文档仍然与缓存中已过期的副本相同。此时,如果还是从原始服务器获取,那么会浪费带宽,使得所有事件都变慢。

为了避免这种情况,HTTP为客户端提供了一种方法,仅当资源改变时才请求副本,这种特殊请求称为有条件的请求(有条件的请求都是通过If-开头的有条件的首部来实现的)。有条件的请求是标准的HTTP请求报文,但仅当某个特定条件为真时才执行(如果提交不满足,服务器就返回一个HTTP错误码)。比如,某个缓存服务器可能发送下面有条件的GET报文给服务器,仅当文件/announce.html从2002年6月29日之后发生改变的情况下才发送它。
在这里插入图片描述
每个有条件的请求都通过特定的验证码来发挥作用。验证码是文档实例的一个特殊属性,用它来测试条件是否为真。从概念上来说,你可以把验证码看作是文档的序列号、版本号、最后修改时间
在这里插入图片描述
HTTP把验证码分为两类:弱验证码强验证码

  • 弱验证码不一定能唯一标识字段的一个实例
  • 强验证码必须能唯一标识字段的一个实例

弱验证码的一个例子是对象的大小字节数,有可能资源的内容改变了,而大小还保存不变。资源的加密校验和(比如MD5)就是强验证码,当文档改变时它总是会改变。

弱验证码的令一个例子是最后修改时间,因为尽管它说明了资源最后被修改的时间,但是它的最大精度是1s,而资源在1s内可以改变很多次

ETag首部是强验证码,因为每当资源改变时,服务器都可以在ETag首部放置不同的值。版本号的摘要校验和都是很好的ETag首部候选,但它们不能带有任意的文本。Etag首部很灵活,它可以带上任意的文本值(以标记的形式),这样就可以用来设计出各种各样的客户端和服务器验证策略。

有时,客户端和服务器可能需要采用不那么精确的实体标记验证方法。比如,某服务器可能想对一个很大、被广泛缓存的文档进行一些美化修饰,但不想在缓存服务器在验证时产生很大的传输流量。此时,该服务器可以在标记前面加上"W/"前缀要广播一个"弱"实体标记。对于弱实体标记来说,只有当关联的实体在语义上发生了重大改变时,标记才会发生变化。而强实体标记则不管关联的实体发生了什么性质的变化,标记都一定会发生改变。

下面的例子展示了客户端如何用弱实体标记向服务器请求再验证。服务器仅当文档的内容从版本4.0算起发生了显著的变化时,才返回主体:
在这里插入图片描述
总结:当客户端多次访问同一个资源时,首先需要判断它当前的副本是不是仍然新鲜。如果不再新鲜,它们就必须从服务器获取最新的版本。为了避免在资源没有改变的情况下收到一份相同的副本,客户端可以向服务器发送有条件的请求,说明能唯一标识客户端当前副本的验证码。只有在资源和客户端的副本不同的情况下服务器才会发送其副本。

范围请求

范围请求:它允许客户单实际上只请求文档的一部分,或者说某个范围。

假设你正下载某个软件,已经下了3/4,这时一个网络故障,连接中断了。通过范围请求就可以避免重新再来。

有了范围请求,HTTP客户端可以通过请求曾获取失败的实体的一个范围(或者说一部分)来恢复下载该实体。当然这有一个前提,那就是从客户端上一次请求该实体到这次发出范围请求的时段内,该对象没有改变过。比如:
在这里插入图片描述
在本例中,客户端请求的是文档开头4000字节之后的部分(不必给出结尾字节数,因为请求方可能不知道文档的大小)。在客户端收到了开头的4000字节之后就失败的情况下,可以使用这种形式的范围请求。还可以用Range首部来请求多个范围(这些范围可以按任意顺序给出,也可以相互重叠)。比如,假设客户端同时连接到多个服务器,为了加速下载文档而从不同的服务器下载同一个文档的不同部分。对于客户端在一个请求内请求多个不同范围的情况,返回的也是单个实体,它有一个多部分主体以及Content-Type:multipart/byteranges首部

并不是所有服务器都接受范围请求,但很多服务器可以。服务器可以通常在响应中包含Accept-Range首部的形式向客户端说明可以接受的范围请求。这个首部的值是计算范围的单位,通常是以字节计算的。比如:
在这里插入图片描述
在这里插入图片描述
Range首部在流行的点对点(P2P)文件共享客户端软件中得到广泛的应用,它们从不同的对等实体同时下载多媒体文件的不同部分。

注意,范围请求也属于一类实体操控,因为它们是在客户端和服务器之间针对特定的对象实例来交换信息的。也就是说,客户端的范围请求仅当客户端和服务器拥有文档的同一个版本是才有意义

差异编码

如果一个网页只有部分信息发生了改变,客户端可以使用差异编码请求值接受页面发生改变的部分。差异编码是HTTP协议的一个扩展,它通过交换对象改变的部分而不是完整的对象来优化传输性能。差异编码也是一种实例操控,因为它依赖客户端与服务器之间针对特定的对象实例来交换信息。
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于计算机专业的学生而言,参加各类比赛能够带来多方面的益处,具体包括但不限于以下几点: 技能提升: 参与比赛促使学生深入学习和掌握计算机领域的专业知识与技能,如编程语言、算法设计、软件工程、网络安全等。 比赛通常涉及实际问题的解决,有助于将理论知识应用于实践中,增强问题解决能力。 实践经验: 大多数比赛都要求参赛者设计并实现解决方案,这提供了宝贵的动手操作机会,有助于积累项目经验。 实践经验对于计算机专业的学生尤为重要,因为雇主往往更青睐有实际项目背景的候选人。 团队合作: 许多比赛鼓励团队协作,这有助于培养学生的团队精神、沟通技巧和领导能力。 团队合作还能促进学生之间的知识共享和思维碰撞,有助于形成更全面的解决方案。 职业发展: 获奖经历可以显著增强简历的吸引力,为求职或继续深造提供有力支持。 某些比赛可能直接与企业合作,提供实习、工作机会或奖学金,为学生的职业生涯打开更多门路。 网络拓展: 比赛是结识同行业人才的好机会,可以帮助学生建立行业联系,这对于未来的职业发展非常重要。 奖金与荣誉: 许多比赛提供奖金或奖品,这不仅能给予学生经济上的奖励,还能增强其成就感和自信心。 荣誉证书或奖状可以证明学生的成就,对个人品牌建设有积极作用。 创新与研究: 参加比赛可以激发学生的创新思维,推动科研项目的开展,有时甚至能促成学术论文的发表。 个人成长: 在准备和参加比赛的过程中,学生将面临压力与挑战,这有助于培养良好的心理素质和抗压能力。 自我挑战和克服困难的经历对个人成长有着深远的影响。 综上所述,参加计算机领域的比赛对于学生来说是一个全面发展的平台,不仅可以提升专业技能,还能增强团队协作、沟通、解决问题的能力,并为未来的职业生涯奠定坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值