Tiêu đề phạm vi HTTP


81

Tôi đang đọc http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35 và cố gắng tìm cách tiếp tục tải xuống tệp.

Ví dụ: giả sử một tệp có độ dài 100 byte và tôi có tất cả 100 byte. Tuy nhiên, tôi không biết kích thước tệp dự kiến ​​phải là bao nhiêu, vì vậy tôi yêu cầu tệp và chỉ định tiêu đề Phạm vi trông giống như sau:

Range: bytes=100-

Đây có phải là một yêu cầu Phạm vi hợp lệ không?


5
Erm, ví dụ dưới nó trích dẫn 'byte = 9500-' là hợp lệ, vì vậy ....
Wrikken

1
Giới thiệu mới nhất là RFC7233 - httpwg.github.io/specs/rfc7233.html
Mark Nottingham

2
Bạn có thể yêu cầu HEAD trước và kiểm tra độ dài của tệp.
Matheus Rocha

Câu trả lời:


54

Đó là một yêu cầu hợp lệ về mặt cú pháp, nhưng không phải là một yêu cầu thỏa đáng. Nếu bạn nhìn sâu hơn trong phần đó, bạn sẽ thấy:

Nếu một tập hợp byte-phạm vi hợp lệ về mặt cú pháp bao gồm ít nhất một byte-range-spec có byte-pos đầu tiên nhỏ hơn độ dài hiện tại của entity-body hoặc ít nhất một hậu tố-byte-range-spec có - độ dài hậu tố bằng không, thì phạm vi-set-byte là thỏa mãn. Nếu không, bộ-dải-byte không thoả mãn được. Nếu bộ-dải-byte không thoả mãn, máy chủ NÊN trả về phản hồi có trạng thái 416 (Dải ô yêu cầu không thoả mãn) . Nếu không, máy chủ NÊN trả về phản hồi có trạng thái là 206 (Nội dung một phần) chứa các phạm vi thỏa mãn của phần thân thực thể.

Vì vậy, tôi nghĩ trong ví dụ của bạn, máy chủ sẽ trả về 416 vì nó không phải là phạm vi byte hợp lệ cho tệp đó.


Vì vậy, có cách nào khách hàng có thể tiếp tục tải xuống mà không cần thực hiện lệnh gọi HEAD để tìm ra độ dài nội dung trước tiên rồi tính toán và tìm nạp nội dung thực tế không? Ý tôi là một số loại mở địa chỉ như "cho tôi tất cả các byte sau byte như vậy và như vậy ..."
dhruvbird

5
Khách hàng sẽ biết liệu nó có tất cả dữ liệu từ yêu cầu ban đầu hay không - nó phải nhận được tiêu đề Độ dài Nội dung trong phản hồi ban đầu hoặc nếu nó được mã hóa theo từng đoạn, nó sẽ nhận được một đoạn có độ dài bằng 0 để cho biết phản hồi đã hoàn tất. Nếu bạn chưa lưu khỏi trạng thái này và chỉ có một phần byte trên đĩa, thì có, bạn sẽ phải thực hiện yêu cầu HEAD hoặc sử dụng tiêu đề Phạm vi để yêu cầu phạm vi byte và nếu bạn nhận lại được 416 phản hồi mà bạn biết bạn có tất cả các byte.
Marc Novakowski

Tôi nghĩ Expect-Continue cho phép bạn phát trực tuyến nhiều hơn hoặc ít hơn như mong muốn?
MJB

@MarcNovakowski Trên thực tế, hãy xem xét trường hợp wget và sử dụng cờ -c. Vì wget không duy trì bất kỳ siêu dữ liệu nào về việc tệp đã hoàn thành, nên giả sử kích thước của tệp trên đĩa là 99 byte. wget sẽ yêu cầu phạm vi byte "100-" và tôi cảm thấy rằng máy chủ nên trả lời với phản hồi độ dài 0 vì yêu cầu chỉ là 1 quá cuối của tệp.
dhruvbird

147

Như Wrikken đã đề xuất, đó là một yêu cầu hợp lệ. Nó cũng khá phổ biến khi khách hàng yêu cầu phương tiện hoặc tiếp tục tải xuống.

Một máy khách thường sẽ kiểm tra xem máy chủ có xử lý các yêu cầu khác nhau không ngoài việc chỉ tìm kiếm Accept-Rangesphản hồi. Chrome luôn gửi Range: bytes=0-yêu cầu GET đầu tiên cho một video, vì vậy, đó là thứ bạn không thể loại bỏ.

Bất cứ khi nào khách hàng đưa Range:vào yêu cầu của mình, ngay cả khi nó không đúng định dạng, nó sẽ mong đợi một phần nội dung (206) phản hồi. Khi bạn tìm kiếm về phía trước trong khi phát lại video HTML5, trình duyệt chỉ yêu cầu điểm bắt đầu. Ví dụ:

Range: bytes=3744-

Vì vậy, để máy khách phát video đúng cách, máy chủ của bạn phải có khả năng xử lý các yêu cầu phạm vi không đầy đủ này.

Bạn có thể xử lý loại 'phạm vi' mà bạn đã chỉ định trong câu hỏi của mình theo hai cách:

Đầu tiên, Bạn có thể trả lời với điểm bắt đầu được yêu cầu được đưa ra trong phản hồi, sau đó tổng độ dài của tệp trừ đi một (phạm vi byte được yêu cầu được lập chỉ mục bằng 0). Ví dụ:

Yêu cầu:

GET /BigBuckBunny_320x180.mp4 
Range: bytes=100-

Phản ứng:

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

Thứ hai, bạn có thể trả lời với điểm bắt đầu được đưa ra trong yêu cầu và độ dài (kích thước) tệp kết thúc mở. Điều này dành cho webcast hoặc phương tiện khác mà tổng thời lượng không xác định. Ví dụ:

Yêu cầu:

GET /BigBuckBunny_320x180.mp4
Range: bytes=100-

Phản ứng:

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

Lời khuyên:

Bạn phải luôn trả lời với độ dài nội dung đi kèm với phạm vi. Nếu phạm vi hoàn chỉnh, có bắt đầu đến kết thúc, thì độ dài nội dung chỉ đơn giản là sự khác biệt:

Yêu cầu: Phạm vi: byte = 500-1000

Phản hồi: Phạm vi nội dung: byte 500-1000 / 123456

Hãy nhớ rằng phạm vi được lập chỉ mục bằng 0, vì vậy Range: bytes=0-999thực sự yêu cầu 1000 byte, không phải 999, vì vậy hãy trả lời bằng một cái gì đó như:

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

Hoặc là:

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

Tuy nhiên, hãy tránh phương pháp sau nếu có thể vì một số trình phát đa phương tiện cố gắng tìm ra thời lượng từ kích thước tệp. Nếu yêu cầu của bạn dành cho nội dung truyền thông, đó là linh cảm của tôi, thì bạn nên đưa thời lượng của nó vào phản hồi. Điều này được thực hiện với định dạng sau:

X-Content-Duration: 63.23 

Đây phải là một dấu chấm động. Không giống như Content-Length, giá trị này không cần phải chính xác. Nó được sử dụng để giúp người chơi tìm kiếm xung quanh video. Nếu bạn đang phát trực tuyến một webcast và chỉ có ý tưởng chung về thời lượng của nó, tốt hơn là bạn nên bao gồm thời lượng ước tính của mình hơn là bỏ qua hoàn toàn. Vì vậy, đối với một webcast dài hai giờ, bạn có thể bao gồm một số thứ như:

X-Content-Duration: 7200.00 

Với một số loại phương tiện, chẳng hạn như webm, bạn cũng phải bao gồm loại nội dung, chẳng hạn như:

Content-Type: video/webm 

Tất cả những điều này đều cần thiết để phương tiện phát đúng cách, đặc biệt là trong HTML5. Nếu bạn không đưa ra thời lượng, người chơi có thể cố gắng tìm ra thời lượng (để cho phép tìm kiếm) từ kích thước tệp của nó, nhưng điều này sẽ không chính xác. Điều này là tốt và cần thiết cho webcast hoặc phát trực tiếp, nhưng không lý tưởng để phát lại các tệp video. Bạn có thể trích xuất thời lượng bằng phần mềm như FFMPEG và lưu nó vào cơ sở dữ liệu hoặc thậm chí là tên tệp.

X-Content-Durationđang được loại bỏ để ủng hộ Content-Duration, vì vậy tôi cũng sẽ bao gồm điều đó. Một phản hồi cơ bản cho yêu cầu "0-" sẽ bao gồm ít nhất những điều sau:

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

Một điểm nữa: Chrome luôn bắt đầu yêu cầu video đầu tiên với những điều sau:

Range: bytes=0-

Một số máy chủ sẽ gửi một phản hồi 200 thông thường dưới dạng một phản hồi mà nó chấp nhận (nhưng với các tùy chọn phát lại hạn chế), nhưng hãy thử gửi 206 thay thế để hiển thị hơn phạm vi xử lý của máy chủ của bạn. RFC 2616 cho biết có thể chấp nhận bỏ qua các tiêu đề phạm vi.


Bạn sẽ làm gì nếu nội dung là một luồng video trực tiếp không có thời lượng cố định?
Joel Barsotti

@Joel, bạn cần trả lời với một khoảng thời gian ngay cả khi bạn không biết điều đó. Trong trường hợp đó, chỉ cần thử 0.0. Đối với khách hàng, thời lượng không quan trọng vì bạn thường không thể quét một luồng trực tiếp. Nếu 0,0 không hoạt động, chỉ cần thử một cái gì đó thực sự cao như 1000000,00.
Victor Stoddard

@VictorStoddard có thể áp dụng tính năng phát trực tuyến theo từng đoạn để tải xuống tệp thông thường khi không có tiêu đề Phạm vi trong yêu cầu của khách hàng không? Máy chủ nên phản hồi như thế nào trong trường hợp đó?
gkiko

@gkiko Không có nhiều sự khác biệt ngoài việc sử dụng tiêu đề Mã hóa truyền thay vì Độ dài nội dung trong Mã hóa truyền phân đoạn. Các phân đoạn có thể đến từ một tệp duy nhất và máy chủ có thể đặt kích thước phân đoạn. Khách hàng nên đệm và ghép các phần lại với nhau khi chúng nhận được. Ngoài ra, HTTP Streaming sử dụng các phân đoạn được ghi sẵn của tệp phương tiện, nơi chúng được lưu trên máy chủ dưới dạng các phần riêng lẻ (tệp ts). Các phân đoạn này được phục vụ bằng cách sử dụng tệp HTTP thông thường các yêu cầu GET thu được từ tệp chỉ mục. Tôi thấy việc phân đoạn là khó nhưng đó là cách đây nhiều năm.
Victor Stoddard

Nội dung-Độ dài: 64656927 Phạm vi chấp nhận: byte Nội dung-Phạm vi: byte 100-64656926 Tại sao Độ dài nội dung không phải là '64656827'?
iwind

7

Trái ngược với câu trả lời của Mark Novakowski, vì một số lý do đã được nhiều người ủng hộ, vâng, đó là một yêu cầu hợp lệ và thỏa đáng.

Trên thực tế, tiêu chuẩn, như Wrikken đã chỉ ra, chỉ là một ví dụ như vậy. Trên thực tế, Firefox phản hồi các yêu cầu như mong đợi (với mã 206) và đây chính xác là những gì tôi sử dụng để triển khai tải xuống liên tục, tức là chỉ lấy phần đuôi của một tệp nhật ký dài phát triển theo thời gian thực với tính năng thăm dò.


2
Hãy đọc lại câu trả lời của Marc Novakowki. "thỏa mãn" có một ý nghĩa cụ thể trong RFC, mà ông đã trích dẫn. Yêu cầu này không được đáp ứng vì các byte được yêu cầu vượt quá độ dài của tệp.
Scott Lamb

1
Firefox không phải là yếu tố phần mềm để đáp ứng các yêu cầu, nó là một máy chủ http
Colin D

Vâng, xin lỗi, ý tôi là Apache
Francesco Potortì

5

Đối với những người đang tình cờ gặp câu trả lời của Victor Stoddard ở trên vào năm 2019 và trở nên hy vọng và tinh mắt, hãy lưu ý rằng:

a) Hỗ trợ cho X-Content-Duration đã bị xóa trong Firefox 41: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/41#HTTP

b) Tôi nghĩ rằng nó chỉ được hỗ trợ trong Firefox cho âm thanh .ogg và video .ogv, không cho bất kỳ loại nào khác.

c) Tôi không thể thấy rằng nó đã từng được hỗ trợ trong Chrome, nhưng đó có thể chỉ là sự thiếu nghiên cứu của tôi. Nhưng sự hiện diện hay vắng mặt của nó dường như không ảnh hưởng theo cách này hay cách khác đối với video webm hoặc ogv kể từ ngày hôm nay trong Chrome 71.

d) Tôi không thể tìm thấy bất kỳ nơi nào mà 'Content-Duration' thay thế 'X-Content-Duration' cho bất kỳ thứ gì, tôi không nghĩ rằng 'X-Content-Duration' tồn tại đủ lâu để có tên tiêu đề kế thừa.

Tôi nghĩ điều này có nghĩa là, kể từ hôm nay, nếu bạn muốn cung cấp vùng chứa webm hoặc ogv có chứa các luồng không biết thời lượng của chúng (ví dụ: đầu ra của đường ống ffpeg) cho Chrome hoặc FF và bạn muốn chúng có thể xóa được trong phần tử video HTML 5, bạn có thể không gặp may. Firefox 64.0 thực hiện một nỗ lực nửa vời để làm cho những thứ này có thể xóa được cho dù bạn có phân phát qua các yêu cầu phạm vi hay không, nhưng nó bị nhầm lẫn và ném một bánh xe quay cho đến khi luồng được tải xuống hoàn toàn nếu bạn tìm kiếm nhiều hơn vài lần so với mức nó cho là phù hợp. Chrome thậm chí không cố gắng, nó chỉ nopes ra và sẽ không cho phép bạn chà ở tất cả cho đến khi toàn bộ dòng là thành chơi .


Đây là một chủ đề dài từ các nhà phát triển FF nói về việc hỗ trợ các loại tệp này. bugzilla.mozilla.org/show_bug.cgi?id=657791
Chris McDonough
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.