TL/DR: Inside a flask endpoint, I'm making a request to a different endpoint and I want to return the response of that request. The response is a file attachment, how do I correctly return that response? response.content
won't cut it (displays file binaries in browser rather than downloading file)
Details below:
I've been looking around for solutions to this online, but I can't seem to find anyone with the same problem, which could suggest I might be going about this wrong. Here's the breakdown:
I've got a backend running a few flask microservices, one of which is the main gateway that interacts with the frontend. Part of my app involves the user accessing a specific link that returns a file download. With a bit of research, I found that doing this in flask is quite straightforward with the use of send_file()
or send_from_directory()
. The problem I'm facing is that I've put all filestorage-related activity into its own microservice, and I can't figure out how to "forward" the response I get from that microservice back to the client from the gateway.
So in essence, I've got:
filestorage_service: app.py:
# flask stuff: imports, app config, etc
@app.route('/get', methods=['GET'])
def get_file():
filename = request.form.get('filename')
try:
return send_from_directory("<some_base_dir>", filename=filename, as_attachment=True)
except FileNotFoundError:
return "Error: File not found", 400
gateway: app.py:
# flask stuff: imports, app config, etc
@app.route('/get-file/<filename>', methods=['GET'])
@cross_origin()
def get_file(filename):
data = {
'filename': filename
}
res = requests.get("<filestorage_service_url>" + "/get", data=data)
# now what??
How do I go about returning res
? Simply putting return res
gives an error, and returning res.content
actually displays the image binaries in the browser. Should I be going full proxy mode and rebuild the entire response from scratch, or is there an easier way that I'm missing?
I managed to get a stripped down version of your app to do what you want.
import os
import requests
from flask import Flask, send_from_directory, Response
app = Flask(__name__)
# Storage service
@app.route('/get', methods=['GET'])
def get_file():
filename = 'somefile.txt'
try:
return send_from_directory(os.getcwd(), filename=filename, as_attachment=True)
except FileNotFoundError:
return "Error: File not found", 400
# Front end
@app.route('/getfile', methods=['GET'])
def get_file_1():
res = requests.get("http://127.0.0.1:5000" + "/get",) # call storage
return Response(
res.content, # content fromthe storage service has the file data
headers=dict(res.headers) # headers need to copied to start download
)
app.run(debug=True)
All you need to do is make sure that the content & headers are copied from the response you want to forward. The important headers are the Content-Disposition
, Content-Type
& Content-Length
headers. The file contents themselves are in response.content