zoukankan      html  css  js  c++  java
  • [笔记]《HTTP权威指南》- 实体和编码

            HTTP要确保它承载的“货物”满足以下条件:

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

    一、报文是箱子,实体是货物

            如果把HTTP报文想象成因特网货运系统中的箱子,那么HTTP实体就是报文中实际的货物。

            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 这份文档特定实例的唯一验证码。
    • Cahce-Control 指出应该如何缓存该文档。

    1 实体主体

            首部字段以一个空白的CRLF行结束,随后就是实体主体的原始内容。

    二、Content-Length:实体的大小

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

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

    1 检测截尾

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

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

    2 Content-Length与持久连接

            Content-Length首部对于持久连接是必不可少的。如果响应通过持久连接传送,就可能有另一条HTTP响应紧随其后。客户端通过Content-Length首部就可以知道报文在何处结束,下一条报文从何处开始。

    3 内容编码

            Content-Length首部说明的是编码后(encoded)的主体的字节长度,而不是未编码的原始主体的长度。

    4 确定实体主体长度的规则

    • 如果特定的HTTP报文类型中不允许带有主体,就忽略Content-Length首部,它是对(没有实际发送出来的)主体进行计算的。
    • 如果报文中还有描述传输编码的Transfer-Encoding首部(不采用默认的HTTP“恒等”编码),那实体就应由一个称为“零字节块”(zero-byte chunk)的特殊模式结束,除非报文已经因链接关闭而结束。
    • 如果报文中含有Content-Length首部(并且报文类型允许有实体主体),而且没有非恒等的Transfer-Encoding首部字段,那么Content-Length的值就是主体的长度。如果收到的报文中既有Content-Length首部字段又有非恒等的Transfer-Encoding首部字段,那就必须忽略Content-Length,因为传输编码会改变实体主体的表示和传输方式。
    • 如果报文使用了multipart/byterange(多部分/字节范围)媒体类型,并且没有用Content-Length首部指出实体主体的长度,那么多部分报文中的每个部分都要说明它的大小。这种多部分类型是唯一的一种自定界的实体主体类型,因此除非发送方知道接收方可以解析它,否则就不能发送这种媒体类型。
    • 如果上面的规则都不匹配,实体就在连接关闭的时候结束。实际上,只有服务器可以使用连接关闭来指示报文的结束。客户端不能用关闭连接来指示客户端报文的结束,因为这样会使服务器无法响应。

     三、实体摘要

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

    四、媒体类型和字符集

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

    1 文本的字符编码

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

    2 多部分媒体类型

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

    3 多部分表格提交

            HTTP使用Content-Type:multipart/form-data或Content-Type:multipart/mixed这样的首部以及多部分主体来发送这种请求,举例如下:

    Content-Type: multipart/form-data; boundary=[abcdefghijklmnopqrstuvwxyz]

            其中的boundary参数说明了分割主体中不同部分所用的字符串。

    <FORM action="http://server.com/cgi/handle"
        enctype="multipart/form-data"
        method="post">
    <P>
    What is your name?<INPUT type="text" name="submit-name"><BR>
    What files are you sending?<INPUT type="file" name="files"><BR>
    <INPUT type="submit" value="Send"><INPUT type="reset">
    </FORM>

            用户代理可能会发回下面这样的数据:

    Content-Type: multipart/form-data; boundary=AaB03x
    --AzBo3x
    Content-Dispositon: form-data; name="submit-name"
    Sally
    --AaB03x
    Content-Disposition: form-data; name="files"
    Content-Type: multipart/mixed; boundary=BbC04y
    --BbC04y
    Content-Disposition: file; filename="essayfile.txt"
    Content-Type: text/plain
    --BbC04y
    Content-Disposition: file; filename="imagefile.gif"
    Content-Type: image/gif
    ...contents of imagefile.gif...
    --BbC04y
    --AaB03x--

    4 多部分范围响应

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

    五、内容编码

            HTTP应用程序有时在发送之前需要对内容进行编码。

    1 内容编码过程

    • 网站服务器生成原始响应报文,其中有原始的Content-Type和Content-Length首部。
    • 内容编码服务器(也可能是原始的服务器或下行的代理)创建编码后的报文。编码后的报文有同样的Content-Type但Content-Length可能不同(比如本体被压缩了)。内容编码服务器在编码后的报文中增加了Content-Encoding首部,这样接收的应用程序就可以进行解码了。
    • 接收程序得到编码后的报文,进行解码,获得原始报文。

    2 内容编码类型

            HTTP定义了一些标准的内容编码类型,并允许用扩展编码的形式增添更多的编码。Content-Encoding首部就用这些标准化的代号来说明编码时使用的算法。

    3 Accept-Encoding首部

            为了避免服务器使用客户端不支持的编码方式,客户端就把自己支持的内容编码方式列表放在请求的Accept-Encoding首部里发出去。如果HTTP请求中没有包含Accept-Encoding首部,服务器端就可以假设客户端能够接收任何编码方式。

    六、传输编码和分块编码

            传输编码也是作用在实体主体上的可逆变换,但使用它们时由于架构方面的原因,同内容的格式无关。使用传输编码是为了改变报文中的数据在网络上传输的方式。

    1 可靠传输

            在HTTP中,只有少数一些情况下,所传输的报文主体可能会引发问题。其中两种情况如下所述。

            1)未知的尺寸

                    如果不先生成内容,某些网关应用程序和内容编码器就无法确定报文主体的最终大小。通常,这些服务器希望在知道大小之前就开始传输数据。因为HTTP协议要求Content-Length首部必须在数据之前,有些服务器就是用传输编码来发送数据,并用特别的结束脚注表明数据结束。

            2)安全性

                    你可以用传输编码来把报文内容扰乱,然后再共享的传输网络上发送。不过,由于像SSL这样的传输层安全体系的流行,就很少需要靠传输编码来实现安全性了。

    2 Transfer-Encoding首部

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

    • Transfer-Encoding 告知接收方为了可靠地传输报文,已经对其进行了何种编码。
    • TE 用在请求首部中,告知服务器可以使用那些传输编码扩展。

            下面的例子中,请求使用了TE首部来告诉服务器它可以接收分块编码(如果是HTTP/1.1应用程序的话,这就是必须的)并且愿意接受附在分块编码的报文结尾上的拖挂:

    GET /new_products.html HTTP/1.1
    Host: www.joes-hardware.com
    User-Agent: Mozilla/4.61 [en] (WinNT; I)
    TE: trailers, chunked
    ...

            对它的相应中包含Trasfer-Encoding首部,用于告诉接收方已经用分块编码对报文进行了传输编码:

    HTTP/1.1 200 OK
    Transfer-Encoding: chunked
    Server: Apache/3.0
    ...

            在这个起始首部之后,报文的结构就将发生改变。

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

    3 分块编码

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

    七、验证码和新鲜度

    1 新鲜度

            服务器可以用这两个首部之一来提供这种信息:Expires(过期)和Cache-Control(缓存控制)。

            Expires首部规定文档“过期”的具体时间——此后就不应当认为它还是最新的。Expires首部的语法如下:

    Expires: Sun Mar 18 23:59:59 GMT 2001

            客户端和服务器为了能正确使用Expires首部,它们的始终必须同步。

            Cache-Control首部可以用秒数来规定文档最长使用期——从文档离开服务器之后算起的总计时间。使用期不与时钟同步,因此可以给出更精确的结果。

    2 有条件的请求与验证码

            当请求缓存服务器中的副本时,如果它不再新鲜,缓存服务器就需要保证它有一个新鲜的副本。缓存服务器可以向原始服务器获取当前的副本。但在很多情况下,原始服务器上的文档仍然与缓存中已过期的副本相同。如果服务器上的文档和已过期的缓存副本相同,而缓存服务器还是要从原始服务器上取文档的话,那缓存服务器就是在浪费网络带宽,给缓存服务器和原始服务器增加不必要的负载,是所有的事情都变慢了。

            为了避免这种情况,HTTP为客户端提供了一种方法,仅当资源改变时才请求副本,这种特殊请求称为有条件的请求。有条件的请求是标准的HTTP请求报文,但仅当某个特定条件为真时才执行。

    GET /announce.html HTTP/1.0
    If-Modified-Since: Sat, 29 Jun 2002, 14:30:00 GMT

            有条件的请求是通过以“If-”开头的有条件的首部来实现的。

            概括一下,当客户端多次访问同一个资源时,首先需要判断它当前的副本是不是仍然新鲜。如果不再新鲜,它们就必须从服务器获取最新的版本。为了避免在资源没有改变的情况下收到一份相同的副本,客户端可以向服务器发送有条件的请求,说明能唯一标识客户端当前副本的验证码。只在资源和客户端的副本不同的情况下服务器才会发送其副本。

  • 相关阅读:
    placeholder 兼容处理
    扩展 jq 对象方法
    gulp 命令
    v-show、v-if、v-for的使用
    Vue中防抖和节流 --来自官方文档
    Python字符窜取值
    怎么安装redis桌面版?
    Python常用的基本数据类型
    MySQL常用语法
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/SyMind/p/8376311.html
Copyright © 2011-2022 走看看