HTTP Range标头


81

我正在阅读http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35, 并试图弄清楚如何继续文件下载。

例如,假设一个文件的长度为100个字节,而我拥有所有100个字节。但是,我不知道预期的文件大小应该是多少,所以我要文件并指定一个看起来像这样的Range标头:

Range: bytes=100-

这是有效的范围请求吗?


5
Erm,其下的示例引用了“ bytes = 9500-”为有效,因此....
Wrikken 2010年

1
最新的裁判是RFC7233 - httpwg.github.io/specs/rfc7233.html
马克诺丁汉

2
您可以先发出HEAD请求,然后检查文件长度。
Matheus Rocha

Answers:


54

这是语法上有效的请求,但不是可满足的请求。如果您在该部分中进一步查看,则会看到:

如果在语法上有效的字节范围集包括至少一个字节范围规范,且其第一个字节位置小于实体主体的当前长度,则至少一个后缀字节范围规范具有非-后缀长度为零,则可满足字节范围设置。否则,字节范围设置将无法满足。如果字节范围设置不令人满意,则服务器应返回状态为416的响应(请求范围不令人满意)。否则,服务器应该返回状态206(部分内容)的响应,其中包含实体主体的可满足范围。

因此,我认为在您的示例中,服务器应返回416,因为它不是该文件的有效字节范围。


那么,客户有什么方法可以在不进行HEAD调用的情况下恢复下载,而HEAD无需先计算内容长度,然后进行数学运算并获取实际内容?我的意思是某种开放式地址,例如“给我这样的字节之后的所有字节...”
dhruvbird

5
客户端将已经知道它是否具有来自原始请求的所有数据-它应该已经在原始响应中接收到Content-Length标头,或者如果它被分块编码,则它将接收到零长度的分块以指示回应已完成。如果尚未保存此状态,而磁盘上只有一部分字节,那么是的,您将必须执行HEAD请求或使用Range标头来请求字节范围,如果返回416您知道自己拥有所有字节。
Marc Novakowski

我认为Expect-Continue可以让您像期望的那样或多或少地进行流式处理?
MJB

@MarcNovakowski实际上,考虑wget的情况并使用-c标志。由于wget不会维护有关文件完整的任何元数据,因此假设磁盘上文件的大小为99字节。wget将请求字节范围“ 100-”,并且我认为服务器应以0长度的响应进行响应,因为该请求仅比文件末尾晚1。
dhruvbird 2014年

147

正如Wrikken所建议的,这是一个有效的请求。当客户端请求媒体或恢复下载时,这也很常见。

客户端通常会进行测试,以查看服务器是否仅在寻找Accept-Ranges响应之外还处理远程请求。Chrome始终会Range: bytes=0-向其发送第一个GET请求以发送视频,因此您无法忽略它。

每当客户端Range:在其请求中包括该请求时,即使该请求的格式有误,也希望得到部分内容(206)的响应。在HTML5视频播放期间向前搜索时,浏览器仅请求起点。例如:

Range: bytes=3744-

因此,为了使客户端正确播放视频,您的服务器必须能够处理这些不完整的范围请求。

您可以通过两种方式处理在问题中指定的“范围”类型:

首先,您可以使用响应中给出的请求起始点进行回复,然后用文件的总长度减去一(请求的字节范围为零索引)进行响应。例如:

请求:

GET /BigBuckBunny_320x180.mp4 
Range: bytes=100-

响应:

206 Partial Content
Content-Type: video/mp4
Content-Length: 64656927
Accept-Ranges: bytes
Content-Range: bytes 100-64656926/64656927

其次,您可以使用请求中给出的起点和开放式文件长度(大小)进行答复。这是用于网络广播或其他总长度未知的媒体。例如:

请求:

GET /BigBuckBunny_320x180.mp4
Range: bytes=100-

响应:

206 Partial Content
Content-Type: video/mp4
Content-Length: 64656927
Accept-Ranges: bytes
Content-Range: bytes 100-64656926/*

提示:

您必须始终以范围内包含的内容长度作为响应。如果范围是完整的,并且从开始到结束,那么内容长度就是区别:

请求:范围:字节= 500-1000

响应:内容范围:字节500-1000 / 123456

请记住,该范围是零索引的,因此Range: bytes=0-999实际上是请求1000个字节,而不是999个字节,因此请响应以下内容:

Content-Length: 1000
Content-Range: bytes 0-999/123456

要么:

Content-Length: 1000
Content-Range: bytes 0-999/*

但是,如果可能,请避免使用后一种方法,因为某些媒体播放器会尝试从文件大小中确定持续时间。如果您的要求是媒体内容,这是我的直觉,那么您应该在响应中包括其持续时间。使用以下格式完成此操作:

X-Content-Duration: 63.23 

这必须是一个浮点数。与不同Content-Length,此值不一定是准确的。它用于帮助播放器在视频中寻找。如果您正在流播网络广播,并且只大致了解其持续时间,则最好包括估计的持续时间,而不要完全忽略它。因此,对于两个小时的网络广播,您可以包含以下内容:

X-Content-Duration: 7200.00 

对于某些媒体类型,例如webm,您还必须包括内容类型,例如:

Content-Type: video/webm 

所有这些都是媒体正常播放所必需的,尤其是在HTML5中。如果您不指定持续时间,播放器可能会尝试从文件大小中找出持续时间(以便进行查找),但这并不准确。很好,这对于网络广播或实时流媒体来说是必需的,但对于播放视频文件而言并不理想。您可以使用FFMPEG之类的软件提取持续时间,并将其保存在数据库或文件名中。

X-Content-Duration正在逐步淘汰Content-Duration,因此我也将其包括在内。对“ 0-”请求的基本响应至少包括以下内容:

HTTP/1.1 206 Partial Content
Date: Sun, 08 May 2013 06:37:54 GMT
Server: Apache/2.0.52 (Red Hat)
Accept-Ranges: bytes
Content-Length: 3980
Content-Range: bytes 0-3979/3980
Content-Type: video/webm
X-Content-Duration: 2054.53
Content-Duration: 2054.53

还有一点:Chrome始终会通过以下内容开始其第一个视频请求:

Range: bytes=0-

某些服务器会发送常规的200响应作为答复,它会接受(但播放选项有限),但尝试发送206来代替服务器处理范围。RFC 2616表示可以忽略范围标头。


如果内容是没有固定持续时间的实时视频流,该怎么办?
乔尔·巴索蒂

@Joel,即使您不知道,也需要提供一定的回复时间。在这种情况下,只需尝试0.0。对于客户端而言,持续时间并不重要,因为您通常无法扫描实时流。如果0.0无效,则尝试尝试很高的值,例如1000000.00。
维克多·斯托达德

@VictorStoddard可以将分块流应用到客户端请求中不存在Range标头的常规文件下载吗?在这种情况下,服务器应如何响应?
gkiko

@gkiko除了在块传输编码中使用Transfer-Encoding标头而不是Content-Length之外,没有太大区别。块可以来自单个文件,服务器可以设置块大小。客户端应在收到大块时对其进行缓冲和拼凑。另外,HTTP流使用媒体文件的预先记录的段,将它们作为单独的部分(ts文件)保存在服务器上。使用从索引文件获得的常规HTTP文件GET请求为这些段提供服务。我发现分段非常棘手,但这是几年前的事。
维克多·斯托达德

Content-Length:64656927 Accept-Ranges:字节Content-Range:字节100-64656926为什么Content-Length不是'64656827'?
iwind

7

与Mark Novakowski的答案相反,由于某些原因,答案被很多人支持,是的,这是一个有效且可满足的请求。

实际上,正如Wrikken指出的那样,该标准就是一个例子。在实践中,Firefox会按预期方式(使用206代码)响应此类请求,而这正是我用来实现渐进式下载的方式,即,仅获得长日志文件的尾部,该日志文件随轮询而实时增长。


2
请再次阅读Marc Novakowki的答案。他引用了RFC中“可满足”的特殊含义。此请求无法满足,因为请求的字节超出了文件的长度。
Scott Lamb 2015年

1
Firefox不是响应请求的软件元素,它是http服务器
Colin D

是的,对不起,我的意思是阿帕奇
FrancescoPotortì

5

对于在2019年绊倒Victor Stoddard的上述答案并变得充满希望和关注的人们,请注意:

a)在Firefox 41中删除了对X-Content-Duration的支持:https : //developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/41#HTTP

b)我认为Firefox仅支持.ogg音频和.ogv视频,而不支持其他任何类型。

c)我看不到Chrome曾经完全支持它,但这可能只是我缺乏研究。但是,到目前为止,对于Chrome浏览器71中的webm或ogv视频,它的存在与否似乎没有任何影响。

d)我找不到“ Content-Duration”替换为“ X-Content-Duration”的任何地方,我认为“ X-Content-Duration”没有生存足够长的时间来提供后继标头名称。

我认为这意味着,从今天开始,如果您要向Webm或ogv容器提供包含不知道其持续时间(例如ffpeg管道输出)的流到Chrome或FF的流,并且希望它们可在HTML 5视频元素,您可能不走运。无论您是否通过范围请求进行服务,Firefox 64.0都竭尽全力地使这些可擦写的内容变得可疑,但如果您查找的次数超出其认为合适的次数,它就会感到困惑并抛出混乱,直到流被完全下载为止。Chrome甚至不会尝试,它只会停止工作,直到整个流播放完毕后,您才可以彻底擦洗。


这是FF开发人员的一长串讨论支持此类文件的话题。 bugzilla.mozilla.org/show_bug.cgi?id=657791
克里斯·麦克唐纳
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.