Safari未在Rails应用中加载HTML5video

我有一个Rails应用程序我正在尝试使用以下标记播放HTML5video:

不起作用:

 

在Safari上,video显示“正在加载…”但从未播放,尽管它​​在Chrome和Firefox中的效果与预期一致。 我认为它最初可能是路径,但我已经尝试了绝对路径,相对路径和Rails image_path助手,但没有结果。

为了调试,我复制了这个示例HTML5video标签,它按预期在Safari中播放(这里唯一的区别是源video):

Works :外部托管的示例video

  

但是,当我采用这个完全相同的标记并在本地托管这些相同的文件时,video在Safari中停止工作:

不起作用 :本地托管的示例video

  

笔记:

  • 我没有在Safari控制台或Rails日志中收到错误; 没有404s文件或任何东西。
  • 本地托管的video可在Chrome和FF中使用,因此我知道路径是正确的。
  • 外部托管的video在Safari中运行良好。
  • 本地托管的video在Rails应用程序之外的Safari中工作 – 我创建了一个静态页面并使用上面的所有示例产生了良好的效果。

基于所有这些,似乎Safari和Rails的某些组合阻止了video的加载。

我遇到了同样的问题,并且发现它是在video中前后移动所需的字节范围。

这里有一些中间件增加了对字节范围HTTP头的支持 :

 # (c) Thomas Fritzsche # This is prove-of-concept coding only # iOS devices insist on support for byte-rage http header, that is not native # supported by rack apps like dragonfly # this rack middleware will evaluate the http header and provide byte range support. # For a dragonfly Rails (3.2.3) app I have tested this will call like this. # I reload Rack::Cache that case trouble when initialized by Rails. # This small trick makes it working :-) #----------------------- #require 'dragonfly/rails/images' #require "range" # # #Rails.application.middleware.delete(Rack::Cache) #Rails.application.middleware.insert 0, Rack::Cache, { # :verbose => true, # :metastore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"), # :entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body") #} # #Rails.application.middleware.insert_before Rack::Cache, RangeFilter # # [...] #------------------- class RangeFilter def initialize(app) @app = app end def call(env) dup._call(env) end def _call(env) @status, @headers, @response = @app.call(env) range = env["HTTP_RANGE"] if @status == 200 and range and /\Abytes=(\d*)-(\d*)\z/ =~ range @first_byte, @last_byte = $1, $2 @data = "".encode("BINARY") @response.each do |s| @data << s end @length = @data.bytesize if @length.nil? if @last_byte.empty? @last_byte = @length - 1 else @last_byte = @last_byte.to_i end if @first_byte.empty? @first_byte = @length - @last_byte @last_byte = @length - 1 else @first_byte = @first_byte.to_i end @range_length = @last_byte - @first_byte + 1 @headers["Content-Range"] = "bytes #{@first_byte}-#{@last_byte}/#{@length}" @headers["Content-Length"] = @range_length.to_s [@status, @headers, self] else [@status, @headers, @response] end end def each(&block) block.call(@data[@first_byte..@last_byte]) @response.close if @response.respond_to?(:close) end end 

有关进一步的参考,请通过send_data或send_file方法或此Ruby论坛post查看rails media file stream accept byte range request 。