下載 PartialContent.zip - 2 KB
------------------------------------------分割線------------------------------------------
免費下載地址在 http://linux.linuxidc.com/
用戶名與密碼都是www.linuxidc.com
具體下載目錄在 /2014年資料/9月/12日/Node.js 中實現 HTTP 206 內容分片
下載方法見 http://www.linuxidc.com/Linux/2013-07/87684.htm
------------------------------------------分割線------------------------------------------
介紹
分部份內容的簡要介紹
開始用Node.js進行實現
對實現進行測試
總結
在本文中,我會闡述HTTP狀態206 分部分內容 的基礎概念,並使用Node.js一步步地實現它. 我們還將用一個基於它用法最常見場景的示例來測試代碼:一個能夠在任何時間點開始播放視頻文件的HTML5頁面.
HTTP 的 206 Partial Content 狀態碼和其相關的消息頭提供了讓浏覽器以及其他用戶代理從服務器接收部分內容而不是全部內容,這樣一種機制. 這一機制被廣泛使用在一個被大多數浏覽器和諸如Windows Media Player和VLC Player這樣的播放器所支持視頻文件的傳輸上.
基礎的流程可以用下面這幾步描述:
浏覽器請求內容.
服務器告訴浏覽器,該內容可以使用 Accept-Ranges 消息頭進行分部分請求.
浏覽器重新發送請求,用 Range 消息頭告訴服務器需要的內容范圍.
服務器會分如下兩種情況響應浏覽器的請求:
如果范圍是合理的,服務器會返回所請求的部分內容,並帶上 206 Partial Content 狀態碼. 當前內容的范圍會在 Content-Range 消息頭中申明.
如果范圍是不可用的(例如,比內容的總字節數大), 服務器會返回 416 請求范圍不合理 Requested Range Not Satisfiable 狀態碼. 可用的范圍也會在 Content-Range 消息頭中聲明.
讓我們來看看這幾個步驟中的每一個關鍵消息頭.
Accept-Ranges: 字節(bytes)
這是會有服務器發送的字節頭,展示可以被分部分發送給浏覽器的內容. 這個值聲明了可被接受的每一個范圍請求, 大多數情況下是字節數 bytes.
Range: 字節數(bytes)=(開始)-(結束)
這是浏覽器告知服務器所需分部分內容范圍的消息頭. 注意開始和結束位置是都包括在內的,而且是從0開始的. 這個消息頭也可以不發送兩個位置,其含義如下:
如果結束位置被去掉了,服務器會返回從聲明的開始位置到整個內容的結束位置內容的最後一個可用字節.
如果開始位置被去掉了,結束位置參數可以被描述成從最後一個可用的字節算起可以被服務器返回的字節數.
Content-Range:字節數(bytes)=(開始)-(結束)/(總數)
這個消息頭將會跟隨 HTTP 狀態碼 206 一起出現. 開始和結束的值展示了當前內容的范圍. 跟 Range 消息頭一樣, 兩個值都是包含在內的,並且也是從零開始的. 總數這個值聲明了可用字節的總數.
Content-Range: */(總數)
這個頭信息和上面一個是一樣的,不過是用另一種格式,並且僅在返回HTTP狀態碼416時被發送。其中總數代表了正文總共可用的字節數。
這裡有一對有2048個字節文件的例子。注意省略起點和重點的區別。
請求開始的1024個字節
浏覽器發送:
GET /dota2/techies.mp4 HTTP/1.1
Host: localhost:8000
Range: bytes=0-1023
服務器返回:
HTTP/1.1 206 Partial Content
Date: Mon, 15 Sep 2014 22:19:34 GMT
Content-Type: video/mp4
Content-Range: bytes 0-1023/2048
Content-Length: 1024
(Content...)
沒有終點位置的請求
浏覽器發送:
GET /dota2/techies.mp4 HTTP/1.1
Host: localhost:8000
Range: bytes=1024-
服務器返回:
HTTP/1.1 206 Partial Content
Date: Mon, 15 Sep 2014 22:19:34 GMT
Content-Type: video/mp4
Content-Range: bytes 1024-2047/2048
Content-Length: 1024
(Content...)
注意:服務器並不需要在單個響應中返回所有剩下的字節,特別是當正文太長或者有其他性能的考慮。所以下面的兩個例子在這種情況下也是可接受的:
Content-Range: bytes 1024-1535/2048
Content-Length: 512
服務器僅返回剩余正文的一半。下一次請求的范圍將從第1536個字節開始。
Content-Range: bytes 1024-1279/2048
Content-Length: 256
服務器僅返回剩余正文的256個字節。下一次請求的范圍將從第1280個字節開始。
請求最後512個字節
浏覽器發送:
GET /dota2/techies.mp4 HTTP/1.1
Host: localhost:8000
Range: bytes=-512
服務器返回:
HTTP/1.1 206 Partial Content
Date: Mon, 15 Sep 2014 22:19:34 GMT
Content-Type: video/mp4
Content-Range: bytes 1536-2047/2048
Content-Length: 512
(Content...)
請求不可用的范圍:
浏覽器發送:
GET /dota2/techies.mp4 HTTP/1.1
Host: localhost:8000
Range: bytes=1024-4096
服務器返回:
HTTP/1.1 416 Requested Range Not Satisfiable
Date: Mon, 15 Sep 2014 22:19:34 GMT
Content-Range: bytes */2048
理解了工作流和頭部信息後,現在我們可以用Node.js去實現這個機制。
Ubunru 12.04 下Node.js開發環境的安裝配置 http://www.linuxidc.com/Linux/2014-05/101418.htm
Node.Js入門[PDF+相關代碼] http://www.linuxidc.com/Linux/2013-06/85462.htm
Node.js入門開發指南中文版 http://www.linuxidc.com/Linux/2012-11/73363.htm
Node.js安裝與配置 http://www.linuxidc.com/Linux/2013-05/84836.htm
Ubuntu 編譯安裝Node.js http://www.linuxidc.com/Linux/2013-10/91321.htm
第一步:創建一個簡單的HTTP服務器
我們將像下面的例子那樣,從一個基本的HTTP服務器開始。這已經可以基本足夠處理大多數的浏覽器請求了。首先,我們初始化我們需要用到的對象,並且用initFolder來代表文件的位置。為了生成Content-Type頭部,我們列出文件擴展名和它們相對應的MIME名稱來構成一個字典。在回調函數httpListener()中,我們將僅允許GET可用。如果出現其他方法,服務器將返回405 Method Not Allowed,在文件不存在於initFolder,服務器將返回404 Not Found。
// 初始化需要的對象
var http = require("http");
var fs = require("fs");
var path = require("path");
var url = require("url");
// 初始的目錄,隨時可以改成你希望的目錄
var initFolder = "C:\\Users\\User\\Videos";
// 將我們需要的文件擴展名和MIME名稱列出一個字典
var mimeNames = {
".css": "text/css",
".html": "text/html",
".js": "application/javascript",
".mp3": "audio/mpeg",
".mp4": "video/mp4",
".ogg": "application/ogg",
".ogv": "video/ogg",
".oga": "audio/ogg",
".txt": "text/plain",
".wav": "audio/x-wav",
".webm": "video/webm";
};
http.createServer(httpListener).listen(8000);
function httpListener (request, response) {
// 我們將只接受GET請求,否則返回405 'Method Not Allowed'
if (request.method != "GET") {
sendResponse(response, 405, {"Allow" : "GET"}, null);
return null;
}
var filename =
initFolder + url.parse(request.url, true, true).pathname.split('/').join(path.sep);
var responseHeaders = {};
var stat = fs.statSync(filename);
// 檢查文件是否存在,不存在就返回404 Not Found
if (!fs.existsSync(filename)) {
sendResponse(response, 404, null, null);
return null;
}
responseHeaders["Content-Type"] = getMimeNameFromExt(path.extname(filename));
responseHeaders["Content-Length"] = stat.size; // 文件大小
sendResponse(response, 200, responseHeaders, fs.createReadStream(filename));
}
function sendResponse(response, responseStatus, responseHeaders, readable) {
response.writeHead(responseStatus, responseHeaders);
if (readable == null)
response.end();
else
readable.on("open", function () {
readable.pipe(response);
});
return null;
}
function getMimeNameFromExt(ext) {
var result = mimeNames[ext.toLowerCase()];
// 最好給一個默認值
if (result == null)
result = "application/octet-stream";
return result;
}
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-09/106496p2.htm