简体   繁体   中英

How to properly send a binary file over http and download it using javascript?

This issue I'm having could be literally anything in my workflow, but I will start with this scope for now...

I have a rest api that you send a JSON structure and it sends back an excel file, but I can't get it to work probably in the browser/Javascript.

My Javascript code in the browser is basically the following:

    fetch('myapiurl')
    .then(response => response.blob)
    .then(blob => downloadBlob(blob))

    function downloadBlob(blob){
        const a = document.createElement("a");
        a.href = URL.createObjectURL(blob);
        a.download = 'export.xlsx;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }

But this generates a corrupted file, there's either something missing or I'm not sending the file in the right encoding.

Here's the python code from the API in the part where it sends the file (it's an AWS lambda):

output = BytesIO()
#Code that puts an excel file in output
return {
        'statusCode' : 200,
        'headers' : {
            'Content-Disposition': 'attachment; filename="export.xlsx"',
            'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'Access-Control-Allow-Origin': '*'
        },
        #I can't return raw bytes so I transform it into a string
        'body' : output.getvalue().hex(),
    }

Am I sending the file the wrong way?

I tried sending it as base64 but it still was corrupted

It works if I make a test locally using python and just bytes.fromhex() the api response and write it in a file in byte mode.

I wonder if AWS Api Gateway is automatically encoding my body as base64

Make this change and it might work
- .then(response => response.blob)
+ .then(response => response.blob())


Regarding the response body

    #I can't return raw bytes so I transform it into a string
    'body' : output.getvalue().hex(),

you can't send back a hex string, you need to send the raw data. otherwise you would have to convert the hex back to binary as well on the client side before making a blob and later a objectURL


As you may already know the browser will not save an attachment if you fetch it with ajax, what you have to do is "navigate" to the file to trigger the download. And since you are posting json data and converting it to excel you have to do a form submit to send the data over to the server instead of using ajax, since it's not a regular GET request?

<form hidden method="post" enctype="text/plain" action="url">
  <textarea name="json">{"a":12}</textarea>
  <input type="submit">
</form>

This would be better as you don't have to hold all data in the browsers memory before the file can be saved, besides, you can start saving the file much earlier

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM