我不确定这是编程问题还是网络服务器配置问题。
视频文件不在public/
中,因此请求必须通过控制器。
在我的控制器中:
def play_video
video=Video.find params[:id]
response.headers['Content-Length'] = File.size(video.path).to_s
send_data File.read(video.path,mode: 'rb'), type: video.mime_type, disposition: 'inline'
端
在客户端,我现在正在使用JPlayer
。在Linux上运行的Firefox中,无论是开发还是生产,它都能正常运行,我可以毫无问题地前进或后退。在Linux和Windows上几乎所有其他浏览器中,它都可以正常播放,但就是它,在开发和生产中没有向前或向后跳过。我会将其添加到JPlayer
错误中,但只使用<video> with control attribute
以及mediaelement.js
,我会得到完全相同的行为。
在开发中,我正在使用Thin
,正在制作Passenger
和Nginx
。
nginx.conf:
worker_processes 4;
events {
worker_connections 1024;
}
sendfile on;
#tcp_nopush on;
http {
passenger_root /usr/local/lib64/ruby/gems/2.2.0/gems/passenger-5.0.11;
passenger_ruby /usr/local/bin/ruby;
keepalive_timeout 120;
gzip on;
server {
server_tokens off;
listen 80 default_server;
listen 443 ssl;
server_name www.example.com;
root /path/to/public;
passenger_enabled on;
client_max_body_size 100M;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
include mime.types;
default_type application/octet-stream;
#removed SSL config stuff
...
我不确定问题出在哪里。尝试跳过时,我没有收到任何错误消息。
请不要链接到Rails HTTP Streaming教程,因为它们都是蹩脚的,并且没有任何帮助向客户端发送“hello world”10次示例,除非您有一个实际上解决视频流的问题。我找到的任何东西都是旧版本的rails和其他网络服务器。
答案 0 :(得分:2)
这是一个反模式,你正在尝试做什么,send_file是完全阻塞同步机制,基本上它需要N个Rails进程,因为你的应用程序将一次提供多少请求。这是通过控制访问文件或执行任何类型的前/后处理的理由来完成的:权限检查,审计等。
如果这是反模式图案的样子: 1)X-Accel-Redirect 2)通过auth_request模块进行异步权限检查
在第一种情况下,您的Rails应用程序仅返回X-Accel-Redirect标头中的文件URL,其中包含空主体,然后关闭此请求,以便Rails可以立即继续提供新请求,而不是等到客户端获取文件(如果客户端的连接速度慢,Rails在完成之前无法自由处理)。基本上要同时服务10个大型视频文件,10个工作人员要求你拥有。 X-Accel-Redirect仅与一名工人完成同样的工作:
<强>滑轨强>
def download
video=Video.find params[:id]
headers['X-Accel-Redirect'] = "#{video.file_name}"
render nothing: true
end
<强> Nginx的强>
location /video {
internal;
root /mnt/video;
}
备选方案是auth_request,效率相似,但您需要事先知道文件目标URL不是由服务器生成的。 Auth_request位置是内部的,它通过Rails路由处理身份验证,然后拒绝或将用户传递到目标视频文件URL:
<强> Nginx的强>
location /video/ {
root /mnt/video;
auth_request /auth;
...
}
location = /auth {
internal;
proxy_pass http://localhost;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}