web-dev-qa-db-fra.com

Quelle est la différence entre send_data et send_file dans Ruby on Rails?

Lequel est le meilleur pour le streaming et les téléchargements de fichiers?

Veuillez fournir des exemples.

75
Mr. Black
send_data(_data_, options = {})
send_file(_path_, options = {}) 

La principale différence ici est que vous passez DATA (code binaire ou autre) avec send_data ou fichier PATH avec send_file.

Vous pouvez donc générer des données et les envoyer sous forme de texte en ligne ou sous forme de pièce jointe sans générer de fichier sur votre serveur via send_data. Ou vous pouvez envoyer un fichier prêt avec send_file

data = "Hello World!"
send_data( data, :filename => "my_file.txt" )

Ou

data = "Hello World!"
file = "my_file.txt"
File.open(file, "w"){ |f| f << data }
send_file( file )

Pour les performances, il est préférable de générer le fichier une fois, puis de l'envoyer autant de fois que vous le souhaitez. Alors send_file conviendra mieux.

Pour le streaming, si je comprends bien, ces deux méthodes utilisent le même tas d'options et de paramètres, vous pouvez donc utiliser X-Send ou autre chose.

UPD

send_data et enregistrez le fichier:

data = "Hello World!"
file = "my_file.txt"
File.open(file, "w"){ |f| f << data }
send_data( data )
101
fl00r

send_file peut être plus rapide que send_data

Comme fl00r mentionné , send_file Prend un chemin et send_data Les données.

Par conséquent, send_file Est un sous-ensemble de send_data, Car vous avez besoin d'un fichier sur le système de fichiers: vous pouvez bien sûr simplement lire le fichier et utiliser send_data Dessus. Mais send_file Peut être plus rapide, c'est donc un compromis performance/généralité.

send_file Peut être plus rapide car il peut envoyer l'en-tête X-Sendfile sur Apache ( X-Accel-Redirect sur Nginx ) au lieu du contenu du fichier, car il connaît le chemin d'accès.

Cet en-tête est consommé par le proxy inverse (Apache ou Nginx) qui s'exécute normalement devant Rails dans une configuration de production.

Si X-Sendfile Est présent dans la réponse, le proxy inverse ignore la plupart de la réponse actuelle et en crée une nouvelle qui renvoie le fichier au chemin donné.

Client <---> Internet <---> Reverse proxy <---> Rails

Ceci est beaucoup plus efficace car le proxy inverse est hautement spécialisé dans le service de fichiers statiques et peut le faire beaucoup plus rapidement que Rails (qui n'envoie pas les données du fichier si X-Sendfile Sera envoyé) .

Le cas d'utilisation typique de send_file Est lorsque vous souhaitez contrôler l'autorisation d'accès des fichiers statiques: vous ne pouvez pas les placer sous /public Ou bien ils seraient servis avant que Rails n'ait une chance de décider. Ceci est discuté à: Protéger le contenu du public/dans une Rails app

Pour utiliser les en-têtes X-Sendfile, Vous devez ajouter:

config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx

à config/initializers/production.rb (ou config/environment/production.rb dans Rails 5.x), pas application.rb, Car en cours de développement, vous n'avez pas de serveur proxy et vous voulez que send_file Envoie réellement les données.

X-Sendfile Est abordé dans le Asset Pipeline Guide .