Receive xlsx file from Flask server on JS client

On my client, the user clicks on a button which then calls the function below. I followed some code of other questions asked on StackOverflow about creating a url for the file and then downloading it:

export const exportData = async (checked) => {
  let checked_arr = await exportDataHelper(checked)
  try {
    const res = await axios.post(local + "/get-files", checked_arr);
    const url = URL.createObjectURL(res.data)
    const link = document.createElement('a')
    link.download = true;
    link.href = url;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link)
    return res.data;
  } catch (err) {
    return err;
  }
}

My Flask server receives some data from my JS client and creates an excel file out of that data. As a response back to the client, I send that excel file via Flask's send_file:

@app.route("/get-files", methods=['POST'])
def get_files():
    if request.method == "POST":
        ..Creating excel file here..
            try:
                return send_file("newOutput.xlsx", as_attachment=True)
            except FileNotFoundError as e:
                return json.jsonify(message="Failed"), 404
        else:
            return json.jsonify(message="Failed"), 500
    return json.jsonify(message="Failed"), 500

When i do console.log(res.data) I see some gibbersih like this PK����������?�a]I:O�����������[Content_Types].xml���n�0�E�����*1tQU��E������\. It's longer but I won't paste the whole thing.

But the JS code does nothing else after. In fact, I tried logging something to the console after I create the const url, and nothing is being logged, it's like it is stuck there. Any help? I am trying to have the file downloaded on the client side.

1 answer

  • answered 2021-07-28 14:39 Kinnturo

    This is for future people who stumble upon this problem. I did not test this answer with other file types such as .png .jpeg. txt. or any other type other than .xlsx, but I think it will still work as long as you change the mimetype.

    I ended up splitting my requests, one POST request that sends the data to my Flask server from my JS client. And another FETCH request that asks for the created .xlsx file.

    JS/React code:

    export const exportData = async (checked) => {
      let checked_arr = await exportDataHelper(checked)
      try {
        const res = await axios.post(local + "/get-files", checked_arr);
        return res;
      } catch (err) {
        return err;
      }
    }
    
    export const fetchOutput = async () => {
      await fetch(local + '/fetch-output').then(res => res.blob()).then(blob=> {
        var file = new Blob([blob], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"})
        var url = URL.createObjectURL(file)
        var link = document.createElement('a')
        link.download = "newOutput.xlsx";
        link.href = url;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link)
      })
    }
    

    Python/Flask code:

    @app.route("/get-files", methods=['POST'])
    def get_files():
        if request.method == "POST":
            ...some irrelevant code...
            res = create_output_excel(result)
            if res:
                try:
                    return json.jsonify(message="Success"), 200
                except FileNotFoundError as e:
                    return json.jsonify(message="Failed"), 404
            else:
                return json.jsonify(message="Failed"), 500
        return json.jsonify(message="Failed"), 500
    
    @app.route("/fetch-output")
    def fetch_output():
        return send_file("newOutput.xlsx", mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    

    In my case, the output file will always have the same name, so of course if yours is variable then you must do the appropriate changes for that.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum