要流式传输视频,我们必须为某些浏览器处理请求的字节范围。
解决方案 1:使用send_file_with_range
gem
简单的方法是使用send_file_with_range gemsend_file
修补方法。
在 Gemfile 中包含 gem
# Gemfile
gem 'send_file_with_range'
并提供以下range: true
选项send_file
:
def show
video = Video.find(params[:id])
send_file video.full_path, type: "video/mp4",
disposition: "inline", range: true
end
补丁很短,值得一看。但是,不幸的是,它不适用于 Rails 4.2。
send_file
解决方案 2:手动修补
受 gem 的启发,手动扩展控制器相当容易:
class VideosController < ApplicationController
def show
video = Video.find(params[:id])
send_file video.full_path, type: "video/mp4",
disposition: "inline", range: true
end
private
def send_file(path, options = {})
if options[:range]
send_file_with_range(path, options)
else
super(path, options)
end
end
def send_file_with_range(path, options = {})
if File.exist?(path)
size = File.size(path)
if !request.headers["Range"]
status_code = 200 # 200 OK
offset = 0
length = File.size(path)
else
status_code = 206 # 206 Partial Content
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
offset = bytes.begin
length = bytes.end - bytes.begin
end
response.header["Accept-Ranges"] = "bytes"
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
send_data IO.binread(path, length, offset), options
else
raise ActionController::MissingFile, "Cannot read file #{path}."
end
end
end
进一步阅读
因为,起初,我不知道 和 之间的区别stream: true
,range: true
我发现这个 railscast 很有帮助:
http://railscasts.com/episodes/266-http-streaming