Rails send_file 不播放 mp4 [英] Rails send_file don't play mp4

查看:76
本文介绍了Rails send_file 不播放 mp4的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Rails 应用程序可以保护上传的视频并将它们放入一个私人文件夹中.

I have a Rails app that protects the uploaded videos putting them into a private folder.

现在我需要播放这些视频,当我在控制器中执行类似操作时:

Now I need to play these videos, and when I do something like this in the controller:

  def show
    video = Video.find(params[:id])
    send_file(video.full_path, type: "video/mp4", disposition: "inline")
  end

并在/videos/:id 处打开浏览器(Chrome 或 FF),它不会播放视频.

And open the browser(Chrome or FF) at /videos/:id it doesn't play the video.

如果我将相同的视频放在公共文件夹中,并像/video.mp4 一样访问它,它就会播放.

If I put the same video at the public folder, and access it like /video.mp4 it will play.

如果我删除 dispositon: "inline" 它将下载视频,我可以从我的电脑上播放它.webm 视频也会发生同样的情况.

If I remove the dispositon: "inline" it will download the video and I can play it from my computer. Samething happens with webm videos.

我错过了什么?这有可能吗?

What am I missing? Is this something possible to do?

推荐答案

要流式传输视频,我们必须处理请求的 某些浏览器的字节范围.

To stream videos, we have to handle the requested byte range for some browsers.

简单的方法是让 send_file 方法由 send_file_with_range gem 修补一>.

The easy way would be to have the send_file method patched by the send_file_with_range gem.

在 Gemfile 中包含 gem

Include the gem in the Gemfile

# Gemfile
gem 'send_file_with_range'

并为 send_file 提供 range: true 选项:

and provide the range: true option for 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.

The patch is quite short and worth a look. But, unfortunately, it did not work for me with Rails 4.2.

受到 gem 的启发,手动扩展控制器相当容易:

Inspired by the gem, extending the controller manually is fairly easy:

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: truerange: true 之间的区别,所以我发现这个 railscast 很有帮助:

Further reading

Because, at first, I did not know the difference between stream: true and range: true, I found this railscast helpful:

http://railscasts.com/episodes/266-http-streaming

这篇关于Rails send_file 不播放 mp4的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆