Open Paul6552 opened 3 years ago
AxiosResponse? You should be using server techniques if possible
https://github.com/eligrey/FileSaver.js/wiki/Saving-a-remote-file#using-http-header
Content-Type: 'application/octet-stream; charset=utf-8'
Content-Disposition: attachment; filename="filename.jpg"; filename*="filename.jpg"
Content-Length: <size in bytes>
window.atob(
Do you fetch a pdf as base64 in a json payload? That is not so smart, JSON is not meant to handle binary data
Anyway i would have converted the base64 to a blob using fetch instead... https://stackoverflow.com/a/36183085/1008999 I would also have ditched Axios entirely for only using the fetch api
@jimmywarting Thank you for your quick feedback.
When I saw the Stackoverflow article, I just thought "Hello my old friend" :-D My solution is from Jeremy of this article.
I know it's not very smart to abuse json, but it was the quickest and easiest way to do that back then.
The solution would be with the fetch api -> blob -> FileSaver.saveAs (blob, 'BalanceSheet.pdf') ? Does this work reliably on apple devices as well?
Thanks
It's a reliably way of getting a blob in binary format, saving it can be an entirely different story
Fetch is supported in more newer places such as web workers, Deno, and Node (with node-fetch atm)
Axios use either node:http
or window.XMLHttpRequest, so it dose not work in Deno or in WebWorkers.
And you can't stream data using XMLHttpRequest... + i think it's too bloated and not that cross compatible
@jimmywarting Thank you for your input. Took hours for me to change everything X) But I changed my restendpoint to "Application/octed-stream" and axios to fetch.
Sadly, saving in an iMac Browser is only working with a workaround. This is my code now:
myFetch( 'report/getBalanceSheet',
{year: balanceSheetYear},
{
method: 'get',
headers: {
'Authorization': 'Bearer ' + keycloak.token
}
})
.then(async res => {
// check for error response
if (!res.ok) {
// get error message from body or default to response statusText
const error = res.status + " " + res.statusText;
return Promise.reject(error);
}
const blob = await res.blob();
setwaitForResponseWithOverlay( false );
const fileURL = URL.createObjectURL( blob );
if(safariWindow != null){
//With FileSaver it is not working, only workaround safariWindow.location.replace
//FileSaver.saveAs( file, 'BalanceSheet.pdf' );
safariWindow.location.replace(fileURL);
}else{
window.open( fileURL );
}
})
.catch( ( error ) => {
console.log("There was an error: " + error.toString());
} );
Any suggestions?
Hmm, so Authorization header is the reason why you are using ajax... the file is protected. with a simple cookie you could just navigate to the file to download it.
Any suggestions?
Was a long time since i had a look at the source of FileSaver, have forgotten how every quirk works, lots of PR seems to have happen since the last time i looked. I always try to steer ppl who tries to save something from the server and have access to it, to use the server to save file rather than using filesaver, or any other downloader lib (like streamsaver or file system access).
have you consider generating a uniq one-time / expiring download link instead?
or posting the Authorization token in some other method that don't involve sending it as a header (like ?token=
or using a <form>
)
Sorry, but that was programmatically too high for me.
Yes, the file is protected. The token refreshes itself every 3 seconds, so a cookie would not work. If I understood you, you would save the token in a cookie.
"Do you consider generating a uniq one-time / expiring download link instead? or posting the Authorization token in some other method that don't involve sending it as a header (like? token = or using a
Unfortunately that is too high for me. Do you have a Stackoverflow article so that I can read it here? thanks
Basically what james are mentioning here: https://stackoverflow.com/a/59363326/1008999 (you also have the vanila js solution from https://stackoverflow.com/a/66078703/1008999) but instead of a jwt token you post the bearer token
you would also have to change the way you authenticate on the backend to.
Parse the token from a <form>
submission instead of looking for some request header
@jimmywarting Thank you, but changing the way how I authenticate is a little bit an overkill for me. But thanks a lot for the suggestion.
@makc I will try your solution, because my solution is not relaible under Apple MAC devices.
Right now my solution is this (not tested on apple devices. I havent a mac or iphone, therefore I have everytime to ask someone else)
function getBalanceSheet(): void {
const link = document.createElement( 'a' );
myFetch( 'report/getBalanceSheet',
{year: balanceSheetYear},
{
method: 'get',
headers: {
'Authorization': 'Bearer ' + keycloak.token,
'Content-Type': 'application/json'
}
})
.then(async res => {
// check for error response
if ( !res.ok ) {
// get error message from body or default to response statusText
const error = res.status + " " + res.statusText;
return Promise.reject( error );
}
const blob = await res.blob();
if(blob.size === 0){
printout("Nothing to show");
return;
}
const fileURL = URL.createObjectURL( blob );
if(isIOS()){
if ( link.href ) {
URL.revokeObjectURL( link.href );
}
link.href = URL.createObjectURL( blob );
link.download = "Balance sheet" || 'data.json';
link.dispatchEvent( new MouseEvent( 'click' ) );
} else {
window.open( fileURL );
}
})
.catch( ( error ) => {
console.log("There was an error: " + error.toString());
} );
}
I'll tell you again how it works with Apple devices. (Hope X))
Can someone please show me a reliable alternative (pure code or a framework (please supported)) with which I can download data under React. There a a ton of frameworks, most of them not really supported anymore (e.g. js-file-download)
I'm a little desperate because in 2021 it will still be difficult to reliably download a file in all browsers.
This framework does not work e.g. in the iMac Apple and I think that the owner of this repository no longer has any desire to maintain this framework.
Right now I am doing workaround over workaround to get the file downloaded:
I thank you for any reliable solution.