Nodejs实现web静态服务器对多媒体文件的支持

前几天,一个同事说他写的web静态服务器不支持音视频的播放,现简单实现一下。

原理:实现http1.1协议的range部分。

其实这一点都不神秘,我们常用的下载工具,如迅雷,下载很快,还支持断点续传,就是利用http协议的range和多线程实现的。假如下载一个1MB的文件,如果开一个线程下载,那么只能从头到尾依次下载这个文件,这样不可能提升速度。通常,下载工具会开很多个线程,这里暂且假设是4个,然后这4个线程同时分别下载这1MB的0~255KB、256-511KB、512~767KB和768~1024KB,很显然,理论上速度提升了4倍。

那么怎么将服务器上的1MB文件分成4份呢?这就是range的强大功能了!

当请求下载文件时,带有

  Range: bytes=0-255[,256-511]  //这里表示0~255个字节,如果请求多个分段,用逗号隔开

服务器响应请求时发现头部带有Range,那么做出响应:

  Content-Range: bytes 0-255/789  //789就是整个文件的大小了

  Content-Length: 256

同时status变为206,而不是200,并发送这一段数据给客户端,这样客户端接收到的数据就是整个文件的一部分了!

range的请求头还可以是:

  • Range: bytes=0-  //整个文件
  • Range: bytes=-200  //最后200个字节
  • Range: bytes=200-  //200字节后的所有字节
  • Range: bytes=0-0,-1  //第一、最后一个字节

看代码如何实现

//判断是请求头中是否有range部分
if(request.headers.range){
    var size = stat.size;//获取文件大小
    //暂且写在这里
    function getRange(){
        var range = request.headers.range;
        
        if(range.indexOf(",") != -1){//这里只处理了一个分段的情况
            return false;
        }
        //range大约长这样子:bytes=0-255[,256-511]
        var parts = range.replace(/bytes=/, '').split("-");
        var partiaStart = parts[0];
        var partialEnd = parts[1];

        var start = parseInt(partiaStart);//起始位置
        //如果是bytes=0-,就是整个文件大小了
        var end = partialEnd ? parseInt(partialEnd) : size - 1;

        if(isNaN(start) || isNaN(end)) return false;
        //分段的大小
        var chunkSize = end - start + 1;

        return {'start': start, 'end': end, 'chunkSize': chunkSize};
    }

    var rangeData = getRange();
    if(rangeData){
        //createReadStream这东西原生支持range,是不是很爽?
        var raw = fs.createReadStream(realPath, {'start': rangeData.start, 'end': rangeData.end});
        //状态码当然是206了
        response.writeHead(206, 'Partial Content', {
            'Content-Type' : contentType,
            'Content-Range' : 'bytes ' + rangeData.start + '-' + rangeData.end + '/' + size,
            'Content-Length' : rangeData.chunkSize
        });
        raw.pipe(response);
    }else{
        response.writeHead(416, "not ok!");
        response.end();
    }
}else{
    //状态码200
}

大概就是这样子,其他部分略去。

用html5的audio标签试验下mp3的播放:

<audio src="audio/test.mp3" controls="controls" preload="auto" autoplay="autoplay"></audio>

得到的请求和响应头如下:

下图是MP3文件加载到6MB时的截图,这时音乐已经播放超过一半了,所以可不是加载完成才播放的。

这样web服务器就实现range功能,可以处理多媒体文件了,当然只是非常简单的实现,想了解更多可以查阅W3的网站(前面说的下载、断点续传什么的就不验证了,客户端也搞不明白)

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

 

 

 

posted @ 2013-08-04 21:37  chollaflower  阅读(1736)  评论(0编辑  收藏  举报