L'ho fatto su un sito dove le persone pagano per scaricare determinati file e i file sono archiviati in RAILS_ROOT/private
. La prima cosa da sapere è che vuoi che il server web gestisca l'invio del file, altrimenti la tua app verrà trattenuta trasmettendo file di grandi dimensioni e questo porterà rapidamente il tuo sito a fermarsi se hai qualsiasi tipo di volume di download. Pertanto, se è necessario verificare l'autorizzazione in un controller, è necessario anche un modo per trasferire il controllo del download al server Web. Il modo migliore per farlo (che io sappia) è l'intestazione X-Sendfile, che è supportata da Nginx, Apache (con modulo) e altri. Con X-Sendfile configurato, quando il tuo server web riceve un'intestazione dalla tua app, riprende l'invio del file al client.
Una volta che avete X-Sendfile lavorare per il proprio server web, un metodo di controllo privato come questo è utile:
##
# Send a protected file using the web server (via the x-sendfile header).
# Takes the absolute file system path to the file and, optionally, a MIME type.
#
def send_file(filepath, options = {})
options[:content_type] ||= "application/force-download"
response.headers['Content-Type'] = options[:content_type]
response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filepath)}\""
response.headers['X-Sendfile'] = filepath
response.headers['Content-length'] = File.size(filepath)
render :nothing => true
end
Allora la vostra azione di controllo potrebbe essere simile a questa:
##
# Private file download: check permission first.
#
def download
product = Product.find_by_filename!(params[:filename])
if current_user.has_bought?(product) or current_user.is_superuser?
if File.exist?(path = product.filepath)
send_file path, :content_type => "application/pdf"
else
not_found
end
else
not_authorized
end
end
Ovviamente il tuo metodo di autorizzazione varierà e dovrai modificare le intestazioni se offri file diversi dai PDF o desideri che il file venga visualizzato nel browser (elimina il tipo di contenuto application/force-download
).
fonte
2010-01-26 23:12:09
Perché non si utilizza il metodo send_file incorporato? –
Perché non lo sapevo! Chiunque usi questa tecnica dovrebbe rimuovere la mia definizione di metodo 'send_file' criptata e invece chiamare il percorso send_file di Rails-incluso,: type =>" application/pdf ",: x_sendfile => true'. Grazie per il biglietto, Ryan. –
Ho commentato ulteriormente su 'X-Sendfile' a: http://stackoverflow.com/a/26884350/895245 –