0

I'm writing a full stack app. I have a python backend using flask that sends a file and a Vue client that receives. Its been working fine up until the point when I try to send the filename over using a Content-Disposition header.

On the backend I've tried:

return send_file(base_path + filename, as_attachment=True, download_name=filename)

And to set the headers manually,

response = make_response(send_file(base_path + filename))
response.headers['Content-Disposition'] = f"attachment; filename=\"{filename}\""

return response

I've also tried to put in headers that would not be blocked by CORS just to see if the request would receive the header but to no avail,

response = make_response(send_file(base_path + filename))
response.headers['Content-Type'] = "sample/info"

return response

I'm printing the header to the console by doing


fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
method: 'GET'
}).then(res =\> {
if (res.status == '500') { }

                console.log(res.headers)
                //const header = res.headers.get('Content-Disposition');
                //console.log(header)
    
                res.blob().then((blob) => {
                    /* ... */
                })
            })

Any help would be appreciated! Thanks :)

Insomnes
  • 1
  • 4

1 Answers1

0

Research

In the interest of logging the solution I found and helping out anyone in the future who may be interested in knowing the answer here's what I discovered:
  1. There is a restriction to access response headers when you are using Fetch API over CORS.

    https://stackoverflow.com/a/44816592/20342081

    So, no matter what using the JS fetch-api you will be unable to access all headers (outside of Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma) unless you expose them by specifying them in a request header. That would look something like this:

    fetch('https://myrequest/requestend/', {
        headers: {
            'Access-Control-Expose-Headers': 'Content-Disposition'
        }
    })
    
  2. When a cross-origin source accesses your API you will have to expose the header from the back end as well. https://stackoverflow.com/a/66291644/20342081

I was also confused about how the differences between Access-Control-Expose-Headers and Access-Control-Allow-Headers. In my case the solution was use "expose headers" on both the frontend and the backend (and allow wouldn't work). However, Allow has its own applications which I have yet to understand fully. For those endeavoring check out: https://stackoverflow.com/a/28108431/20342081

Solution

I implemented these things in my code by doing:
class RequestResult(Resource):
    def get(self, index):
        base_path = f"Requests/{index}/"
        filename = os.listdir(base_path)[0]

        response = make_response(send_file(base_path + filename, as_attachment=True, download_name=filename))
        response.headers['Access-Control-Expose-Headers'] = "Content-Disposition"

        return response

And on the front end exposing the header as well on the fetch request:

fetch('http://localhost:4999/rdownload/' + this.$route.params.id, {
    method: 'GET',
    mode: 'cors',
    headers: {
        'Access-Control-Expose-Headers': 'Content-Disposition'
    }
})

I hope this is helpful for the next 5 people who open this in the next 10 years!

Insomnes
  • 1
  • 4