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?
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 surTrue
si vous souhaitez envoyer ce fichier avec un en-têteContent-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)
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é:
# Using axios and FileSaver
let response = await axios.get(downloadUrl, downloadConfig);
let filename = response.headers["x-suggested-filename"];
FileSaver.saveAs(response.data, filename);
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