HTTP(HyperText Transfer Protocol)
HTTP协议定义了浏览器(即万维网客户进程)怎样向万维网服务器请求万维网文档,以及服务器怎样把文档传送给浏览器,从层次的角度看,HTTP是面向事务的(transaction-oriented)应用层协议,它是万维网上能够可靠地交换文件(包括文本、声音、图像等各种多媒体文件)的重要基础。 HTTP规定在HTTP客户与HTTP服务器之间的每次交互,都由一个ASCII码串构成的请求和一个类似的通用因特网邮件扩充,即"类MIME(MIME-like)"的响应组成。HTTP报文通常都使用TCP连接传送。 HTTP协议是无状态的(stateless)。服务器并不记得曾经访问过的用户,不记录通信过程的上下文信息,每次Http请求都是独立的、无关的。无状态简化了服务器的设计,使服务器更容易支持大量并发的HTTP请求。 用户点击鼠标链接某个万维网文档时,HTTP协议首先要和服务器建立TCP连接。需要使用三次握手。当三次握手的前两部分完成后(即经过一个RTT时间后),万维网客户就把HTTP请求报文作为三次握手的第三个报文的数据发送给万维网服务器。服务器收到HTTP请求报文后,就把所请求的文档作为响应报文返回给用户。
请求一个万维网文档所需的时间 HTTP/1.0的主要缺点,每请求一个文档就要有两倍RTT的开销。另一种开销就是万维网客户和服务器为每一次建立新的TCP连接都要分配缓存和变量,特别是万维网服务器往往要同时服务于大量客户的请求,所以这种非持续连接会使万维网服务器的负担很重。浏览器能提供5~10个并行的TCP连接,每一个TCP连接处理客户一个请求。 HTTP/1.1协议较好地解决了上面的这个问题,它使用持续连接(persistent connection)。所谓持续连接就是万维网服务器在发送响应后仍然在一段时间内保持这条连接,使同一个客户(浏览器进程)和该服务器可以持续在这条连接上传送后续HTTP请求报文和响应报文。这并不局限于传送同一个页面上链接的文档,而是只要这些文档都在同一个服务器上就行。 HTTP/1.1协议的持续连接有两种工作方式,即非流水线方式(without pipelining)和流水线方式(with pipelining) 非流水线方式的特点,是客户在收到前一个响应后才能发送下一个请求。因此,在TCP连接已建立后,客户每访问一次对象都要用去一个往返时间RTT。这比非持续连接要用去两倍RTT的开销,节省了建立TCP连接所需要的一个RTT时间。但非流水线方式还是有缺点的,因为服务器在发送完一个对象后,其TCP连接就处于空闲状态,浪费了服务器资源。 流水线方式的特点,是客户在收到HTTP的响应报文之前就能够接着发送新的请求报文,于是一个接一个的请求报文到达服务器后,服务器就可持续发回响应报文。因此,使用流水线方式时,客户访问所有对象只需花费一个RTT时间。流水线工作方式使TCP连接中的空闲时间减少,提高了下载文档效率。
代理服务器
代理服务器的作用
HTTP报文结构
HTTP有两类报文:
- 请求报文–从客户向服务器发送请求报文。
- 响应报文–从服务器到客户的回答。
由于HTTP是面向文本的(text-oriented),因此在报文中的每一个字段都是一些ASCII码串,因而各个字段的长度都是不确定的。
HTTP的报文格式 这两种报文格式的区别就是开始行不同
- 开始行,用于区分是请求报文还是响应报文。在请求报文中的开始行叫做请求行(Request-Line),而在响应报文中的开始行叫做状态行(Status–Line)。在开始行的三个字段之间都以空格分隔开,最后的“CR”和“LF"分别代表"回车"和”换行“
- 首部行,用来说明浏览器、服务器或报文主题的一些信息。首部可以有好几行,但也可以不适用。在每一个首部行中都有首部字段名和它的值,每一行在结束的地方都要有”回车“和”换行“。整个首部行结束时,还有一空行将首部行和后面的实体主体分开。
- 实体主体(entity body),在请求报文中一般都不用这个字段,而在响应报文中也可能没有这个字段。
请求报文的第一行”请求行“只有三个内容,即方法,请求资源的URL,以及HTTP的版本。”方法“就是对所请求的对象进行的操作,这些方法实际上也就是一些命令。
在服务器上存放用户信息
当用户张三浏览某个使用Cookie的网站时,该网站的服务器就为张三产生一个唯一的识别码,并以此作为索引在服务器的后端数据库中产生一个项目。接着在给张三的HTTP响应报文中添加一个叫做Set-cookie的首部行。”首部字段名“就是“Set-cookie”,而后面的“值”就是赋予该用户的“识别码”。当张三收到这个响应时,其浏览器就在它管理的特定Cookie文件中添加一行,其中包括这个服务器的主机名和Set-cookie后面给出的识别码。当张三继续浏览这个网站时,每法送一个HTTP请求报文,其浏览器就会从其Cookie文件中取出这个网站的识别码,并放到HTTP请求报文的Cookie首部行中:Cookie:123456,于是,这个网站就能够跟踪用户123456(张三)在该网站的活动。
HTTP各版本对比
- HTTP/0.9:1991年发布,极其简单,只有一个get命令
- HTTP/1.0:1996年5月发布,增加了大量内容
- HTTP/1.1:1997年1月发布,进一步完善HTTP协议,是目前最流行的版本
- SPDY :2009年谷歌发布SPDY协议,主要解决HTTP/1.1效率不高的问题
- HTTP/2 :2015年借鉴SPDY的HTTP/2发布
HTTP/1.0和HTTP1.1的区别
- 缓存处理:HTTP/1.0 使用 Pragma:no-cache + Last-Modified/If-Modified-Since来作为缓存判断的标准;HTTP/1.1 引入了更多的缓存控制策略:Cache-Control、Etag/If-None-Match等
- 错误状态管理:HTTP/1.1新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
- 范围请求:HTTP/1.1在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接,支持断点续传
- Host头:HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础
- 持久连接:HTTP/1.1 最大的变化就是引入了持久连接(persistent connection),在HTTP/1.1中默认开启 Connection: keep-alive,即TCP连接默认不关闭,可以被多个请求复用
HTTP/1.1的缺点 HTTP/1.1 的持久连接和管道机制允许复用TCP连接,在一个TCP连接中,也可以同时发送多个请求,但是所有的数据通信都是按次序完成的,服务器只有处理完一个回应,才会处理下一个回应。比如客户端需要A、B两个资源,管道机制允许浏览器同时发出A请求和B请求,但服务器还是按照顺序,先回应A请求,完成后再回应B请求,这样如果前面的回应特别慢,后面就会有很多请求排队等着,这称为"队头阻塞(Head-of-line blocking)" 管线技术部分解决了请求并发的问题,仍存在队头阻塞的问题 - 请求可以并行发出,但是响应必须串行返回。
- 前一个响应未及时返回,后面的响应就会被阻塞,这就是对头阻塞问题。
HTTP1.1容易触发浏览器TCP连接数限制,对于同一个域名,浏览器最多只能同时创建 6~8 个 TCP 连接 (不同浏览器不一样)。因为一个tcp连接一次承载一个请求,也就是说一个时刻最多只能发起6-8个请求,这就是上文说到的只能同时发起 6 个视频请求的问题。为了解决这个限制,行业内惯用域名分区的方案,即将资源分散到不同域名下 (比如二级子域名),这样就可以针对不同域名创建连接并请求。但多域名随之而来的是更多的 dns 查询耗时,以及 更多 tcp 连接开销。
HTTP/2
HTTP/2以Google发布的SPDY协议为基础,于2015年发布。它不叫HTTP/2.0,因为标准委员会不打算再发布子版本了,下一个新版本将是HTTP/3。HTTP/2协议只在HTTPS环境下才有效,升级到HTTP/2,必须先启用HTTPS HTTP/2解决了HTTP/1.1的性能问题,主要特点如下:
- 二进制分帧:HTTP/1.1的头信息是文本(ASCII编码),数据体可以是文本,也可以是二进制;HTTP/2 头信息和数据体都是二进制,统称为“帧”:头信息帧和数据帧;
- 多路复用(双工通信):通过单一的 HTTP/2 连接发起多重的请求-响应消息,即在一个连接里,客户端和浏览器都可以同时发送多个请求和响应,而不用按照顺序一一对应,这样避免了“队头堵塞”。HTTP/2 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息。说白了就是一个TCP连接上完成所有的HTTP请求,首先在原来的应用层和传输层之间,加入一层二进制分帧层。HTTP1.x是基于文本传输,但是文本解析复杂耗时,因此改为二进制。而在传输数据结构上,引入了帧和流的概念,一个流由多个帧组成,一个TCP连接上可以有个流同时传输,从而解决了HTTP1.x在一个TCP连接上只有一个HTTP请求的问题。HTTP2.0将每个HTTP请求切割为更小的帧,有header帧和body帧等,并且给同一个请求的帧分配相同的sreamId,模拟实现了流的传输。HTTP2通过多路复用解决了HTTP1.x队头阻塞和TCP连接数的问题。
- http2 把原来http所传输的信息划分为多个粒度更小的帧,并对其进行二进制编码,然后将其映射到属
于特定流的消息。 在一个 TCP 连接上,我们可以向对方不断发送帧,每帧的 stream identifier 的标明这一帧属于哪个流,然后在对方接收时,根据 stream identifier 拼接每个流的所有帧组成一整块数据。我们可以把每个请求或者响应都当作一个流,那么多个请求变成多个流,这不同流的数据被分成多个帧,在一个连接中交错地发送给对方,这就是 http2 中的多路复用 多路复用依赖一个关键技术点:二进制分帧 二进制分帧层指示如何在客户端和服务器之间封装和传输http消息。它会将所有传输的信息分割为粒度更小的帧,首部信息则被封装到Headers帧,body则封装到Data帧里面。每个帧都以固定的9字节首部开始,里面会至少标明其所属的流。一个流则是一个请求或者响应。正是基于帧和流,且来自不同流的帧可以交错发送,才使多路复用可以实现。 - 数据流:因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。HTTP/1.1取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
- 首部压缩:HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息压缩后再发送(SPDY 使用的是通用的DEFLATE 算法,而 HTTP/2 则使用了专门为首部压缩而设计的 HPACK 算法)。;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
首先是在服务器和客户端之间建立哈希表,将用到的字段存放在这张表中,那么在传输的时候对于之前出现过的值,只需要把索引(比如0,1,2,…)传给对方即可,对方拿到索引查表就行了。这种传索引的方式,可以说让请求头字段得到极大程度的精简和复用。 其次是对于整数和字符串进行哈夫曼编码,哈夫曼编码的原理就是先将所有出现的字符建立一张索 引表,然后让出现次数多的字符对应的索引尽可能短,传输的时候也是传输这样的索引序列,可以 达到非常高的压缩率 - 服务端推送:HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
HTTP缓存
HTTP缓存机制是根据HTTP报文的缓存标识进行的。HTTP缓存分为强缓存和协商缓存。优先级最高的是 强缓存,在命中强缓存失败的情况下,才会走协商缓存。
强缓存
当缓存数据库中已有所请求的数据时。客户端直接从缓存数据库中获取数据。当缓存数据库中没有所请 求的数据时,客户端的才会从服务端获取数据。 对于强制缓存,服务器响应的header中会用两个字段来表明——Expires和Cache-Control。
Expires
Exprires的值为服务端返回的数据到期时间。Expires是一个时间戳,接下来如果我们试图再次向服务器 请求资源,浏览器就会先对比本地时间和expires的时间戳,如果本地时间小于expires设定的过期时 间,就直接从缓存中获取这个资源。 当再次请求时的请求时间小于返回的此时间,则直接使用缓存数据。但由于服务端时间和客户端时间可 能有误差,这也将导致缓存命中的误差,另一方面,Expires是HTTP1.0的产物,故现在大多数使用 Cache-Control替代。
Cache-Control
在HTTP/1.1中,增加了一个字段Cache-control,该字段表示资源缓存的最大有效时间,在该时间内, 客户端不需要向服务器发送请求
- public:表明响应可以被任何对象(包括:发送请求的客户端、代理服务器等等)缓存。
- private:表明响应只能被客户端缓存。
- no-cache:跳过强缓存,直接进入协商缓存阶段。
- no-store:表示当前请求资源禁用缓存
- max-age=:设置缓存存储的最大时间,超过这个时间缓存被认为过期(单位秒)
- s-maxage=:覆盖max-age或者Expires头。如果s-maxage未过期,则向代理服务器请求其缓存内
容。
协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是 否使用缓存的过程,主要有以下两种情况
- 协商缓存生效,返回304和Not Modified
- 协商缓存生效 ,返回200和请求结果
控制协商缓存的字段分别有:Last-Modified和Etag
Last-Modified
浏览器在第一次访问资源时,服务器返回资源的同时,在 response header 中添加 Last-Modified 的header,值是这个资源在服务器上的最后修改时间,浏览器接收后缓存文件和header 浏览器下一次请求这个资源,浏览器检测到有 Last-Modified 这个 header ,于是添加 If-ModifiedSince 这个header,值就是 Last-Modified 中的值;服务器再次收到这个资源请求,会根据 IfModified-Since 中的值与服务器中这个资源的最后修改时间对比,如果没有变化,返回304和空的响应 体,直接从缓存读取,如果 If-Modified-Since 的时间小于服务器中这个资源的最后修改时间,说明文 件有更新,于是返回新的资源文件和200 但是 Last-Modified 存在一些弊端: 如果本地打开缓存文件,即使没有对文件进行修改,但还是会造成 Last-Modified 被修改,服务端不 能命中缓存导致发送相同的资源 因为 Last-Modified 只能以秒计时,如果在不可感知的时间内修改完成 文件,那么服务端会认为资源还是命中了,不会返回正确的资源 既然根据文件修改时间来决定是否缓存尚有不足,能否可以直接根据文件内容是否修改来决定缓存策 略?所以在 HTTP / 1.1 出现了 ETag 和 If-None-Match
Etag
Etag: 服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务 器决定),只要资源有变化,Etag就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将 上一次返回的Etag值放到request header里的If-None-Match里,服务器只需要比较客户端传来的IfNone-Match跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改 过了。
- 不同,说明资源被改动过,则响应整个资源内容,返回状态码200。
- 相同,说明资源无心修改,则响应header,浏览器直接从缓存中获取数据信息。返回状态码304.
Etag 的优先级高于 Last-Modified
小结
首先通过cache-control验证强制缓存是否可用
- 如果强制缓存可用,直接使用
- 否则进入协商缓存,即发送HTTP请求,服务器通过请求头中If-Modified-Since或者If-None-Match这些条件请求字段检查资源是否更新
- 若资源更新,返回资源和200状态码
- 否则,返回304,告诉浏览器直接从缓存获取资源
缓存的优点
- 减少了冗余的数据传递,节省带宽流量
- 减少了服务器的负担,大大提高了网站性能
- 加快了客户端加载网页的速度
不同刷新的请求执行过程 4. 浏览器地址栏中写入URL,回车之后浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿(最快)。 5. F5:F5告诉浏览器,去服务器看看这个文件是否有过期了。于是浏览器发送一个请求带上If-Modify-Since 6. Ctrl+F5:告诉浏览器,把缓存中的这个文件删了,然后再去服务器请求完整的资源文件下来,于是客户端就完成了强行更新的操作。
HTTP状态码
RFC 规定 HTTP 的状态码为三位数,被分为五类: 1xx: 表示目前是协议处理的中间状态,还需要后续操作。 2xx: 表示成功状态。 3xx: 重定向状态,资源位置发生变动,需要重新请求。 4xx: 请求报文有误。 5xx: 服务器端发生错误。 200 – 请求成功 301 – 资源(网页等)被永久转移到其它URL 304 -Not Modified当协商缓存命中时会返回这个状态码 404 – 请求的资源(网页等)不存在 500 – 内部服务器错误
HTTP断点续传
断点续传:指的是在上传/下载时,将任务(一个文件或压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传/下载,如果碰到网络故障,可以从已经上传/下载的部分开始继续上传/下载未完成的部分,而没有必要从头开始上传/下载。可以节省时间,提高速度。 HTTP1.1 协议(RFC2616)开始支持获取文件的部分内容,这为并行下载以及断点续传提供了技术支持。它通过在 Header 里两个参数实现的,客户端发请求时对应的是 Range ,服务器端响应时对应的是 Content-Range。 Range,用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:Range:(unit=first byte pos)-[last byte pos] Range 头部的格式有以下几种情况:
Range: bytes=0-499 表示第 0-499 字节范围的内容
Range: bytes=500-999 表示第 500-999 字节范围的内容
Range: bytes=-500 表示最后 500 字节的内容
Range: bytes=500- 表示从第 500 字节开始到文件结束部分的内容
Range: bytes=0-0,-1 表示第一个和最后一个字节
Range: bytes=500-600,601-999 同时指定几个范围
Content-Range 用于响应头中,在发出带 Range 的请求后,服务器会在 Content-Range 头部返回当前接受的范围和文件总大小。一般格式:Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth] 例如:Content-Range: bytes 0-499/22400 0-499 是指当前发送的数据的范围,而 22400 则是文件的总大小。而在响应完成后,返回的响应头内容也不同:
HTTP/1.1 200 Ok(不使用断点续传方式)
HTTP/1.1 206 Partial Content(使用断点续传方式)
增强校验
在实际场景中,会出现一种情况,即在终端发起续传请求时,URL 对应的文件内容在服务器端已经发生变化,此时续传的数据肯定是错误的。如何解决这个问题了?显然此时需要有一个标识文件唯一性的方法。 在 RFC2616 中也有相应的定义,比如实现 Last-Modified 来标识文件的最后修改时间,这样即可判断出续传文件时是否已经发生过改动。同时 FC2616 中还定义有一个 ETag 的头,可以使用 ETag 头来放置文件的唯一标识。
Last-Modified
If-Modified-Since,和 Last-Modified 一样都是用于记录页面最后修改时间的 HTTP 头信息,只是 Last-Modified 是由服务器往客户端发送的 HTTP 头,而 If-Modified-Since 则是由客户端往服务器发送的头,可以看到,再次请求本地存在的 cache 页面时,客户端会通过 If-Modified-Since 头将先前服务器端发过来的 Last-Modified 最后修改时间戳发送回去,这是为了让服务器端进行验证,通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回新的内容,如果是最新的,则返回 304 告诉客户端其本地 cache 的页面是最新的,于是客户端就可以直接从本地加载页面了,这样在网络上传输的数据就会大大减少,同时也减轻了服务器的负担。
Etag
Etag(Entity Tags)主要为了解决 Last-Modified 无法解决的一些问题。
- 一些文件也许会周期性的更改,但是内容并不改变(仅改变修改时间),这时候我们并不希望客户端认为这个文件被修改了,而重新 GET。
- 某些文件修改非常频繁,例如:在秒以下的时间内进行修改(1s 内修改了 N 次),If-Modified-Since 能检查到的粒度是 s 级的,这种修改无法判断(或者说 UNIX 记录 MTIME 只能精确到秒)。
- 某些服务器不能精确的得到文件的最后修改时间。
为此,HTTP/1.1 引入了 Etag。Etag 仅仅是一个和文件相关的标记,可以是一个版本标记,例如:v1.0.0;或者说 “627-4d648041f6b80” 这么一串看起来很神秘的编码。但是 HTTP/1.1 标准并没有规定 Etag 的内容是什么或者说要怎么实现,唯一规定的是 Etag 需要放在 “” 内。
If-Range
用于判断实体是否发生改变,如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。一般格式:
If-Range: Etag | HTTP-Date
也就是说,If-Range 可以使用 Etag 或者 Last-Modified 返回的值。当没有 ETage 却有 Last-modified 时,可以把 Last-modified 作为 If-Range 字段的值。 例如:
If-Range: “627-4d648041f6b80”
If-Range: Fri, 22 Feb 2013 03:45:02 GMT
If-Range 必须与 Range 配套使用。如果请求报文中没有 Range,那么 If-Range 就会被忽略。如果服务器不支持 If-Range,那么 Range 也会被忽略。 如果请求报文中的 Etag 与服务器目标内容的 Etag 相等,即没有发生变化,那么应答报文的状态码为 206。如果服务器目标内容发生了变化,那么应答报文的状态码为 200。 用于校验的其他 HTTP 头信息:If-Match/If-None-Match、If-Modified-Since/If-Unmodified-Since。
工作原理
Etag 由服务器端生成,客户端通过 If-Range 条件判断请求来验证资源是否修改。请求一个文件的流程如下: 第一次请求:
- 客户端发起 HTTP GET 请求一个文件。
- 服务器处理请求,返回文件内容以及相应的 Header,其中包括 Etag(例如:627-4d648041f6b80)(假设服务器支持 Etag 生成并已开启了 Etag)状态码为 200。
第二次请求(断点续传): - 客户端发起 HTTP GET 请求一个文件,同时发送 If-Range(该头的内容就是第一次请求时服务器返回的 Etag:627-4d648041f6b80)。
- 服务器判断接收到的 Etag 和计算出来的 Etag 是否匹配,如果匹配,那么响应的状态码为 206;否则,状态码为 200。
检测服务器是否支持断点续传
CURL 实现检测:
[root@localhost ~]# curl -i --range 0-9 http://www.baidu.com/img/bdlogo.gif HTTP/1.1 206 Partial Content Date: Mon, 21 Nov 2016 05:26:29 GMT Server: Apache P3P: CP=" OTI DSP COR IVA OUR IND COM " Set-Cookie: BAIDUID=0CD0E23B4D4F739954DFEDB92BE6CE03:FG=1; expires=Tue, 21-Nov-17 05:26:29 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1 Last-Modified: Fri, 22 Feb 2013 03:45:02 GMT ETag: “627-4d648041f6b80” Accept-Ranges: bytes Content-Length: 10 Cache-Control: max-age=315360000 Expires: Thu, 19 Nov 2026 05:26:29 GMT Content-Range: bytes 0-9/1575 Connection: Keep-Alive Content-Type: image/gif
GIF89a[root@localhost ~]# 能够找到 Content-Range,则表明服务器支持断点续传。有些服务器还会返回 Accept-Ranges,输出结果 Accept-Ranges: bytes ,说明服务器支持按字节下载。 https://www.cnblogs.com/findumars/p/5745345.html
HTTPS
QUIC协议
|