web-dev-qa-db-fra.com

Comment changer le nom de téléchargement dans la fiole?

J'ai un petit projet qui doit répondre à certains fichiers. Je sais que l’utilisation de nginx sera meilleure, mais que les fichiers sont vraiment petits.

Une partie de mon programme:

return send_file(os.path.join(filepath, filename))

Cette ligne retourne le fichier qui a un nom de fichier comme download sans aucun format ou quelque chose comme ça. Le nom de fichier qui a été téléchargé est toujours le même et ne dépend pas du nom réel du fichier. Le vrai nom du fichier est table.csv. Comment puis-je retourner le fichier avec le nom de fichier correct?

6
faoxis

Vous devez définir un en-tête HTTP Content-Disposition: attachment; filename=.... pour que le navigateur utilise le nom de fichier correct.

Vous pouvez demander à send_file() de définir cet en-tête en définissant l’argument as_attachment=True. Le nom de fichier est ensuite extrait de l'objet fichier que vous avez transmis. Utilisez l'argument attachment_name pour définir explicitement un nom de fichier différent:

return send_file(os.path.join(filepath, filename), as_attachment=True)

Dans la documentation flask.send_file :

  • as_attachment- défini sur True si vous souhaitez envoyer ce fichier avec un en-tête Content-Disposition: attachment.
  • attachment_filename- le nom de fichier de la pièce jointe s’il diffère de celui du fichier.

Vous voudrez peut-être utiliser la fonction flask.send_from_directory() à la place. Cette fonction vérifie d’abord que le nom de fichier existe (en soulevant une NotFound sinon) et que le nom de fichier ne contient aucun élément relatif .. pouvant être utilisé pour «échapper» au répertoire. Utilisez ceci pour tous les noms de fichiers provenant de sources non fiables:

return send_from_directory(filepath, filename, as_attachment=True)
18
Martijn Pieters

Dans mon cas, la définition de as_attachment et attachment_filename ne fonctionnait pas car le Content-Disposition: attachment n'apparaissait pas dans la copie côté client de la réponse. 

Si vous avez activé Flask-CORS , vous pouvez l'initialiser avec expose_headers avec un en-tête personnalisé spécifiant le nom du fichier (par exemple, " x-suggéré-nom-fichier "). Ajoutez ensuite cet en-tête à la réponse.

# In file where the Flask app instance is initialized
app = Flask(__name__)
CORS(app, expose_headers=["x-suggested-filename"])

# In file with the download endpoint
result = send_file("/full/path/to/some/file",
                   mimetype="text/plain", # use appropriate type based on file
                   as_attachment=True,
                   conditional=False)
result.headers["x-suggested-filename"] = "use_this_filename.txt"
return result

Ensuite, dans le code de téléchargement côté client, vous pouvez inspecter les en-têtes de réponse pour obtenir le nom de fichier à partir du même en-tête personnalisé:

 screenshot of header

# Using axios and FileSaver
let response = await axios.get(downloadUrl, downloadConfig);
let filename = response.headers["x-suggested-filename"];
FileSaver.saveAs(response.data, filename);
2
Gino Mempin

Dans certains cas, le nom du fichier n'est toujours pas visible. Pour en être sûr, vous devez définir un en-tête "x-filename" et exposer cet en-tête.

from flask import send_file
response = send_file(absolute_image_path, mimetype='image/jpeg', attachment_filename=name, as_attachment=True)
response.headers["x-filename"] = name
response.headers["Access-Control-Expose-Headers"] = 'x-filename'
return response
1
makkasi