Open file from Firebase Storage in new table and not download - javascript

I have various buckets in Firebase Storage that all contain an html file. What I want to do is through Javascript, get the URL of a particular HTML file in a bucket, and then open it in a new tab. When I use the 'getDownloadURL' method, and pass the url to window.open what I'm finding is that a new tab opens temporarily, the file gets downloaded, and then the tab closes. Ideally, I would like to completely avoid downloading the file, and just view it. I believe this is happening because of the format of the URL itself:
https://firebasestorage.googleapis.com/v0/b/[project].appspot.com/o/[bucket]%2Fcreate.html?alt=media&token=[token]
Can anybody please help me use window.load to only open the html file in a new tab? I would prefer to not download the file at all, and I need the tab to remain open. Thanks in advance for any help!
var storage = firebase.storage();
var storageRef = storage.ref();
var reportFileRef = storageRef.child(currentUid + '/create.html');
reportFileRef.getDownloadURL().then(function(url) {
window.open(url, '_blank')
});

Setting the metadata correctly solved the Content-Disposition issue. Here is the function I've defined, where contenttype is either "text/html" or "image/png"
def uploadToFirebaseStorage(filename, filepath, user, report, contenttype):
my_file = open(os.path.join(filepath, filename), "rb")
my_bytes = my_file.read()
my_url = "https://firebasestorage.googleapis.com/v0/b/[project].appspot.com/o/" + filename
my_headers = { "Content-Type": contenttype }
my_request = urllib.request.Request(my_url, data=my_bytes, headers=my_headers)
try:
loader = urllib.request.urlopen(my_request)
except urllib.error.URLError as e:
message = json.loads(e.read())
return message["error"]["message"]
else:
return loader.read()

Related

javascript - make browser send PDF file to download folder

How do I send a PDF file I am downloading from a server to the browser's download area instead of opening it in a browser window?
I am working with C# in Blazor. This is my current code, which I need to modify, but don't know how to (ofc I googled before asking here):
async void DownloadDocument(string apiURL, Guid ID)
{
JSRuntime.InvokeAsync<string>("open", $"{apiURL}/GetPDF/{ID}", "_blank");
}
The server returns a FileStreamResult here and the browser shows the file in a new tab. I want it to send it to its downloads folder instead.
You are invoking a JS Function called "open" with two params. (https://developer.mozilla.org/en-US/docs/Web/API/Window/open)
Try creating your own JS download function inside of a script file / tag and invoking it.
The crucial part to save a file in the downloads folder is to set the download attribute of the a tag.
It could look something like this.
inside wwwroot/index.html:
<script>
window.downloadFile = (fileName, pdfData) => {
const linkSource = `data:application/pdf;base64,${pdfData}`;
const downloadLink = document.createElement("a");
downloadLink.href = linkSource;
downloadLink.download = fileName;
downloadLink.click();
downloadLink.remove();
}
</script>
and in your blazor component:
async void DownloadDocument(string apiURL, Guid ID)
{
// call your api to download the file you want to download
var response = await Http.GetAsync($"{apiURL}/GetPDF/{ID}"));
// convert to base64
var pdfExportBytes = await response.Content.ReadAsByteArrayAsync();
var pdfExportB64 = Convert.ToBase64String(pdfExportBytes);
// invoke js download
await JSRuntime.InvokeVoidAsync("downloadFile", "FileName", pdfExportB64);
}
The file will still be opened if configured so in the users browser, but it will also be stored in the download folder.

In node/js, how can I display a text file that I fetched in the browser window?

I have a protected API that fetches the contents of a file. By protected I mean, I need to send in Authorization headers before the API will allow me to fetch the file contents.
How do I display this in a browser window?
Currently, my nodejs backend is returning the contents with Content-Type:text/html
On the frontend, my current code looks like this
$http.get(downloadUrl)
.then(function(resp) {
var data = resp.data;
var blob = new Blob([data], { type: "text/html" });
let objectUrl = (window.URL || window.webkitURL).createObjectURL( blob );
let anchor = document.createElement("a");
anchor.href = objectUrl;
anchor.download = 'source.html';
anchor.click();
window.URL.revokeObjectURL(objectUrl);
This just download the file though. I just want to display it, preferably in a new window.
Edit I believe this is a duplicate of this question and there is no front-end-only solution to it. It requires the backend to play a part, such as implementing a "Holder-Of-Key Authentication Scheme"

How can I use download a .zip file from a URL to the user in Angular 4?

I have about 10 .csv and 10 .xlsx files of sale items that are each zipped and and deployed daily at a URL specified by an API get request I make depending on which file the user wants to download.
So basically, when I call the API, I get back a string of the destination URL, and it's hot, so if you navigate to that url, the file downloads for the user, however this is how I'm doing it, and I'm wondering if there is a better way, or an Angular way?
Here is the response I get the URL from the API get request when the user changes a radio button for the file they want:
{
"fileUrl": "https://example.com.csv.zip"
}
Then I'm using #ngrx store to set that destination URL in state. I won't go into that here...
Here is the method that is called when the user clicks the download button:
downloadCSV() {
const url = this.state.destinationUrl;
this.http.get(url).subscribe(res => {
// Don't like modifying the DOM just to download a file :(
const link = document.createElement('a');
link.download = this.state.destinationUrl;
link.href = this.state.destinationUrl;
document.body.appendChild(link);
// Don't like forcing an event :(
link.click();
}, (error) => {
console.log('error fetching file download');
});
}
The problem is, this seems hacky, and I am looking for a better solution. Is there a better way of doing this, keeping in ind that I want to avoid popup blockers? I have seen file-saver used in Angular but I don't think I can create a Blob out of the .zip file location and us FileSaver.saveAs(blob, 'example.zip'). Any suggestions would be greatly appreciated.
download() {
const url = 'mydomain.com';
if (url) {
const link = document.createElement('a');
link.href = url;
document.body.appendChild(link);
link.click();
}
}

Prompt file download

I have a link on my page on click of which I am trying to generate a PDF document and then show the "Open - Save" prompt on the browser.
My HTML (reactjs component) has the below code where onclick calls the _getMyDocument function which then calls a Webapi method.
<div className="row">
<a href="#" onClick={this._getMyDocument.bind(this)}>Test Link</a>
</div>
_getMyDocument(e) {
GetMyDocument(this.props.mydata).then(()=> {
}).catch(error=> {
});
My Controller has the below code
[HttpPost]
[Route("Generate/Report")]
public IHttpActionResult GetMyReport(MyData myData)
{
byte[] myDoc = MyBusinessObject.GenerateMyReport(myData);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(myDoc)
};
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = "MyDocument.pdf"
};
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
var response = ResponseMessage(result);
return response;
}
Currently all the code executes but I don't get the file PDF download prompt. What am I doing wrong here?
Response object on success from the ajax call lokks like below
Your response from the server looks good.
The missing part is that you are not handling this response from the client side in the correct way.
Lets assume that your resource url object looks like below in js. (i.e. you already know the resource url, if you don't know it yet, then you will need a separate call to the server to know the download url)
response.downloadUrl = app/media/fileId/document.pdf
All you need to do is set,
window.location = item.downloadUrl;
This will cause the browser to request a resource from the server, the response from the server must include Content-Disposition:attachment;. It will cause the browser to show the download dialog.
P.S. I have recently worked on a similar functionality. If you have questions please ask.
When you want to force the browser to show the download prompt for some files (or resources), you must include Content-Disposition:attachment; in the response header (which you already did).
In our app(angular) we had to create an object url for that with a code like:
WebApi:
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(data);
result.Content.Headers.Add("Content-Type", "application/pdf");
result.Content.Headers.ContentDisposition =
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "FileNameHere"
};
return result;
javascript:
// HttpCall in here
// On SuccessResponse
var file = new Blob([data], {
type: 'application/pdf'
});
var fileURL = URL.createObjectURL(file);
// create an anchor and click on it.
var ancorTag = document.createElement('a');
ancorTag.href = fileURL;ancorTag.target = '_blank';
ancorTag.download = 'CouponOrder.pdf';
document.body.appendChild(ancorTag);
ancorTag.click();
document.body.removeChild(ancorTag);
A simple way to do this is on your server to use GET method, and receive your data by query parameters.
Then in your client app you just have to create a classic link:
Test Link
Or use that simple js script if your want to manage it from your script logic:
window.open("http://your-server.com/your-resource?param1=123&param2=456");
Create Content Disposition and add it to your response header
var cd = new System.Net.Mime.ContentDisposition
{
// for example foo.bak
FileName = System.IO.Path.GetFileName(fileName),
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
Your issue is that the GetMyDocument function will receive the PDF file as a server response, and currently you are doing nothing with that response. You need to handle the response in the then callback. Saving files from javascript is not entirely simple, so I would recommend using an external library such as filesaver.js to help you.
It will end up looking something like...
_getMyDocument(e) {
GetMyDocument(this.props.mydata)
.then((response)=> {
const returnedFile = new Blob([response], { type: 'application/pdf'});
saveAs(returnedFile);
}).catch(error=> {
});

Start downloading file using JQuery

I want to start file downloading when I clicked the button.
I just have the path of the file.
How can I start downloading?
This is what I tried so far:
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
var do = 'file';
$(body).append(do);
});
What I am doing wrong.
I never want to redirect the page.
Is downloading start in browser or in software for downloading files if installed on client machine
Alternatively you can also set the top.location
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
top.location.href = filepath;
});
You cannot force a file to be downloaded in JavaScript.
What you can do is location.href = "somefile.ext";, however it will only be downloaded if the server includes Content-Disposition: attachment as one of its response headers to that file request.
If you want to download a file to the client, then do this:
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
location.href = filepath;
});
location.href will look for a page, but it will not find anything, so it will download the file instead.
You can create a form using jQuery and use the submit function. This will not change the URL in the address bar.
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
var form = $('<form>').attr('action', filepath);
form.submit();
});

Categories

Resources