Rails&Lighttpdの環境で動画とか大容量ファイルを高速にダウンロードさせるとき、Rails の send_file を使わずに Lighttpd の X-sendfile という仕組みを使うと良いようです。
lighttpd-1.4.15 で試しました。
通常のsend_file
send_file '/tmp/movie.wmv'
Lighttpdを使ったx-sendfile
# X_SENDFILE する
path = '/tmp/movie.wmv'
response.headers['Content-Type'] = "application/force-download"
response.headers['Content-Disposition'] = "attachment; filename=\"123.mmv\"" # 好きな名前でダウンロードさせる
response.headers["X-LIGHTTPD-SEND-FILE"] = path
response.headers['Content-length'] = File.size(path)
render :nothing => true
これだけではダメで、lighttpdの設定も変更する必要がある。
lighttpdにパスが通ってる環境では lighttpd が優先的に起動されるが、初回起動時に config/lighttpd.conf が生成されるはずで、以下のようなくだりがあるはず。
fastcgi.server = ( ".fcgi" => ( "localhost" => ( "min-procs" => 1, "max-procs" => 1, "socket" => CWD + "/tmp/sockets/fcgi.socket", "bin-path" => CWD + "/public/dispatch.fcgi", "bin-environment" => ( "RAILS_ENV" => "development" ) ) ) )
ここに、 "allow-x-send-file" => "enable"
を追加すると先ほどの X-LIGHTTPD-SEND-FILE が使えるようになります。追加しないと、エラーは起きないけど、1byteの空ファイルしかダウンロードされません。
設定すると、以下のようになります。
fastcgi.server = ( ".fcgi" => ( "localhost" => ( "allow-x-send-file" => "enable", "min-procs" => 1, "max-procs" => 1, "socket" => CWD + "/tmp/sockets/fcgi.socket", "bin-path" => CWD + "/public/dispatch.fcgi", "bin-environment" => ( "RAILS_ENV" => "development" ) ) ) )
x-send-file の注意点ではないですが、IEでは ヘッダに Cache-Control: no-cache
がついていた場合、SSLでファイルのダウンロードが出来ないという仕様があります。こういうときは、SSLを経由しないようにするか、no-cache をやめる必要があります。どういう仕様なんだろう…。
どういう条件かわからないが、ファイルが変更されても304 Not Modified が返されてしまうことがあることが発覚。強制的に、200を返してあげれば最新のファイルがダウンロードされます。逆に変更されていない場合は304を返したいので、そういう割り当てをすれば良いのだが。
render :status => 200
とかで、強制的に200を返せるようだ。
おもすれ~
大容量ってどのくらいから効果あるの?
うーん。どれくらいといわれると分からないな(笑)
send_file を使うよりは安定するっぽいから、
容量にこだわらず使ってしまえばいいんじゃない(´∀`)