步骤 3 - 检查数据范围是否合理回到函数 httpListener(), 在HTTP方法通过之后,现在我们来检查请求的数据范围是否可用. 如果浏览器没有发送 Range 消息头过来, 请求就会直接被当做一般的请求对待. 服务器会返回整个文件,HTTP状态将会是 200 OK. 另外我们还会看看开始和结束位置是否比文件长度更大或者相等. 只要有一个是这种情况,请求的数据范围就是不能被满足的. 返回的状态就将会是 416 Requested Range Not Satisfiable 而 Content-Range 也会被发送.
步骤 4 - 满足请求 最后使人迷惑的一块来了。对于状态 216 Partial Content, 我们有另外一种格式的 Content-Range 消息头,包括开始,结束位置以及当前文件的总字节数. 我们也还有 Content-Length 消息头,其值就等于开始和结束位置之间的差。在最后一句代码中,我们调用了 createReadStream() 并将开始和结束位置的值给了第二个参数选项的对象, 这意味着返回的流将只包含从开始到结束位置的只读数据.
下面是完整的 httpListener() 回调函数.
测试实现 我们怎么来测试我们的代码呢?就像在介绍中提到的,部分正文最常用的场景是流和播放视频。所以我们创建了一个ID为mainPlayer并包含一个<source/>标签的<video/>。函数onLoad()将在mainPlayer预读取当前视频的元数据时被触发,这用于检查在URL中是否有数字参数,如果有,mainPlayer将跳到指定的时间点。
现在我们把页面保存为"player.html"并和"dota2/techies.mp4"一起放在initFolder目录下。然后在浏览器中打开URL:http://localhost:8000/player.html 在Chrome中看起来像这样:
因为在URL中没有任何参数,文件将从最开始出播放。 接下来就是有趣的部分了。让我们试着打开这个然后看看发生了什么:http://localhost:8000/player.html?60 如果你按F12来打开Chrome的开发者工具,切换到网络标签页,然后点击查看最近一次日志的详细信息。你会发现范围的头信息(Range)被你的浏览器发送了:
很有趣,对吧?当函数onLoad()改变currentTime属性的时候,浏览器计算这部视频60秒处的字节位置。因为mainPlayer已经预加载了元数据,包括格式、比特率和其他基本信息,这个起始位置立刻就被得到了。之后,浏览器就可以下载并播放视频而不需要请求开头的60秒了。成功了! 结论 我们已经用Node.js来实现支持部分正文的HTTP服务器端了。我们也用HTML5页面测试了。但这只是一个开始。如果你对头部信息和工作流这些都已经理解透彻了,你可以试着用其他像ASP.NET MVC或者WCF服务这类框架来实现它。但是不要忘记启动任务管理器来查看CPU和内存的使用。像我们在之前讨论到的,服务器没有在单个响应中返回所用剩余的字节。要找到性能的平衡点将是一项重要的任务。 |