html download attribute opening new tab instead of downloading file - html

I have an Angular 4 website, which allows the users to download an image from an Amazon S3 bucket, to do this I use an anchor with the download attribute, but instead of downloading the image it gets opened in a new tab.
I tested it with Firefox, Chrome and Safari.
This is what I have in the template:
<a mat-raised-button color="accent" [href]="downloadPath" download matTooltip="Download file to pc." *ngIf="isFinalReport()">
<mat-icon>file_download</mat-icon>
DOWNLOAD
</a>
The download path is something like this: https://s3-sa-east-1.amazonaws.com/bucket-name/environment/imageName.jpg
I have also tested it with several images from around the web and doesnt work with any, but if I use a local image (C:/Users/User/Desktop/images/image.jpg) it works perfectly.
Any idea why this doesnt work and how to fix it?
If you need more information please let me know.
Thanks.

To directly download the image , you can try with
<a [href]="javascript:downloadImage(downloadLink);"></a>
downloadImage(downloadLink) {
this.mediaService.getImage(downloadLink).subscribe(
(res) => {
const a = document.createElement('a');
a.href = URL.createObjectURL(res);
a.download = title;
document.body.appendChild(a);
a.click();
});
}
}

Took some research, but I found that using the backend is the best approach to this problem. I was creating an anchor tag that upon clicking should download the s3 url, but instead it would open a new tab with the object. The problem is most likely caused by one or two things. One is that browsers do not allow for cross origin downloads directly. The second revolves around your Reponse Content Disposition. Here is my approach to getting s3 to download directly to the filesystem:
Backend (I use Django and boto3):
def get_file(self, obj):
client = boto3.client('s3', aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY)
return client.generate_presigned_url(
'get_object',
Params={
'Bucket': settings.AWS_STORAGE_BUCKET_NAME,
'Key': obj.key,
'ResponseContentDisposition': 'attachment',
},
ExpiresIn=600)
Frontend (using Angular):
<a [href]="what_i_returned_from_backend" [download]="answer.png" target="_self" rel="noopener noreferrer">Download</a>

Related

HTML <object> - download file if it cannot be loaded

I have a web application that serves files for viewing. If it's a PDF, I simply attach it to an <object> element. However, the app supports serving word, excel, and powerpoint files. I have tried looking for ways to preview them online, but apparently we do not have the proper technology for that (at least not natively in a browser). So instead, I want the user to download the file to view locally.
The front-end is built with React and the back-end with Spring Boot. Currently, all static resources that are documents (PDF's, docs, spreadsheets, etc.) are served under the "/document-files/**" ant-matcher. Additionally, these resources can only be viewed privately, meaning that you have to be logged in to the application to view them. Here's how part of my SecurityConfig file looks like:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String documentRootPath = "file:" + this.documentRootPath;
registry.addResourceHandler("/resources/**").addResourceLocations("resources/");
registry.addResourceHandler("/document-files/**").addResourceLocations(documentRootPath);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // ant matchers below are api routes and the baseUri for serving documents
.antMatchers("/clients/**", "/projects/**", "/documents/**", "/document-files/**").authenticated()
.anyRequest().permitAll() //... additional method chaining omitted for brevity
}
The problem is apparently just on the front end. I don't think it has anything to do with the configuration, but I posted it for reference. With this configuration I can download and preview PDF files just fine, using <object> but for all other files, the file does not load, so in <object> I add a link to open the file like so:
render() {
// some code omitted for brevity
return (
<Module>
{!this.state.currDoc ? (
<ul className={this.state.displayType}>{list}</ul>
) : (
<object
data={"/document-files" + this.state.filePath}
type={this.mimeTypes[document.fileType]}
title={"Current Document: " + document.description + "." + document.fileType.toLowerCase()}>
{document.fileType === "PDF" ? "File could not be loaded!" : <div id="download-prompt">This file cannot be previewed online, click below to download and open locally.<a href={"http://localhost:3000/document-files" + this.state.filePath} download>Open</a></div>}
</object>
)}
</Module>
);
}
Upon clicking, the "save as" dialog box appears with the file name populated and the correct mime type but once I hit save, Chrome displays "Failed - No File". I have tried writing the href with and without the hostname. I've also tried removing the download attribute, but it redirects the page back to itself. I've even tried onLoad attribute on <object> but apparently that only works for images. I checked the network tab on dev tools and there is no record of the file being downloaded, unlike PDFs where the request is noted down.
How can I make non-PDF files download correctly using this setup?
Thanks to javilobo8's GitHubGist, I found a way to download files using Axios, which library I was already using in my app to begin with. For quick reference, here is his code:
axios({
url: 'http://localhost:5000/static/example.xlsx',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
Also, there's multiple ways to work with Blobs, depending on if you're in IE, a browser that supports HTML5's Blob object, or another browser. This question helps split the code in 3 ways to form the dataUri for downloading raw data.
After setting up my <a> tag, I just trigger the click event and the non-PDF file downloads!

How to convert HTML to image in Node.js

I need to convert an HTML template into an image, on a Node server.
The server will receive the HTML as a string. I tried PhantomJS (using a library called Webshot), but it doesn't work well with flex box and modern CSS. I tried to use Chrome headless-browser but it doesn't seem to have an API for parsing html, only URL.
What is the currently best way to convert a piece of HTML into image?
Is there a way to use headless Chrome in a template mode instead of URL mode? I mean, instead of doing something like
chrome.goTo('http://test.com')
I need something like:
chrome.evaluate('<div>hello world</div>');
Another option, suggested here in the comments to this post, is to
save the template in a file on the server and then serve it locally and do something like:
chrome.goTo('http://localhost/saved_template');
But this option sounds a bit awkward. Is there any other, more straightforward solution?
You can use a library called Puppeteer.
Sample code snippet :
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({
width: 960,
height: 760,
deviceScaleFactor: 1,
});
await page.setContent(imgHTML);
await page.screenshot({path: example.png});
await browser.close();
This will save a screenshot of the HTML in the root directory.
You can easily do it on frontend using html2canvas. On backend you can write the html on a file and access using a file URI (i.e: file:///home/user/path/to/your/file.html), it should work fine with chrome headless-browser and Nightmare (screenshot feature). Another option is to setup a simple HTTP server and access the url.

What does "blob" mean in the `href` property in "<link>"? [duplicate]

My page generates a URL like this: "blob:http%3A//localhost%3A8383/568233a1-8b13-48b3-84d5-cca045ae384f" How can I convert it to a normal address?
I'm using it as an <img>'s src attribute.
A URL that was created from a JavaScript Blob can not be converted to a "normal" URL.
A blob: URL does not refer to data the exists on the server, it refers to data that your browser currently has in memory, for the current page. It will not be available on other pages, it will not be available in other browsers, and it will not be available from other computers.
Therefore it does not make sense, in general, to convert a Blob URL to a "normal" URL. If you wanted an ordinary URL, you would have to send the data from the browser to a server and have the server make it available like an ordinary file.
It is possible convert a blob: URL into a data: URL, at least in Chrome. You can use an AJAX request to "fetch" the data from the blob: URL (even though it's really just pulling it out of your browser's memory, not making an HTTP request).
Here's an example:
var blob = new Blob(["Hello, world!"], { type: 'text/plain' });
var blobUrl = URL.createObjectURL(blob);
var xhr = new XMLHttpRequest;
xhr.responseType = 'blob';
xhr.onload = function() {
var recoveredBlob = xhr.response;
var reader = new FileReader;
reader.onload = function() {
var blobAsDataUrl = reader.result;
window.location = blobAsDataUrl;
};
reader.readAsDataURL(recoveredBlob);
};
xhr.open('GET', blobUrl);
xhr.send();
data: URLs are probably not what you mean by "normal" and can be problematically large. However they do work like normal URLs in that they can be shared; they're not specific to the current browser or session.
another way to create a data url from blob url may be using canvas.
var canvas = document.createElement("canvas")
var context = canvas.getContext("2d")
context.drawImage(img, 0, 0) // i assume that img.src is your blob url
var dataurl = canvas.toDataURL("your prefer type", your prefer quality)
as what i saw in mdn, canvas.toDataURL is supported well by browsers. (except ie<9, always ie<9)
For those who came here looking for a way to download a blob url video / audio, this answer worked for me. In short, you would need to find an *.m3u8 file on the desired web page through Chrome -> Network tab and paste it into a VLC player.
Another guide shows you how to save a stream with the VLC Player.
UPDATE:
An alternative way of downloading the videos from a blob url is by using the mass downloader and joining the files together.
Download Videos Part
Open network tab in chrome dev tools
Reload the webpage
Filter .m3u8 files
Look through all filtered files and find the playlist of the '.ts' files. It should look something like this:
You need to extract those links somehow. Either download and edit the file manually OR use any other method you like. As you can see, those links are very similar, the only thing that differs is the serial number of the video: 's-0-v1-a1.ts', 's-1-v1-a1.ts' etc.
https://some-website.net/del/8cf.m3u8/s-0-v1-a1.ts
https://some-website.net/del/8cf.m3u8/s-1-v1-a1.ts
https://some-website.net/del/8cf.m3u8/s-2-v1-a1.ts
and so on up to the last link in the .m3u8 playlist file. These .ts files are actually your video. You need to download all of them.
For bulk downloading I prefer using the Simple Mass Downloader extension for Chrome (https://chrome.google.com/webstore/detail/simple-mass-downloader/abdkkegmcbiomijcbdaodaflgehfffed)
If you opt in for the Simple Mass Downloader, you need to:
a. Select a Pattern URL
b. Enter your link in the address field with only one modification: that part of the link that is changing for each next video needs to be replaced with the pattern in square brackets [0:400] where 0 is the first file name and 400 is the last one. So your link should look something like this https://some-website.net/del/8cf.m3u8/s-[0:400]-v1-a1.ts.
Afterwards hit the Import button to add these links into the Download List of Mass Downloader.
c. The next action may ask you for the destination folder for EACH video you download. So it is highly recommended to specify the default download folder in Chrome Settings and disable the Select Destination option in Chrome Settings as well. This will save you a lot of time! Additionally you may want you specify the folder where these files will go to:
c1. Click on Select All checkbox to select all files from the Download List.
c2. Click on the Download button in the bottom right corner of the SMD extension window. It will take you to next tab to start downloading
c3. Hit Start selected. This will download all vids automatically into the download folder.
That is it! Simply wait till all files are downloaded and you can watch them via the VLC Player or any other player that supports the .ts format. However, if you want to have one video instead of those you have downloaded, you need to join all these mini-videos together
Joining Videos Part
Since I am working on Mac, I am not aware of how you would do this on Windows. If you are the Windows user and you want to merge the videos, feel free to google for the windows solution. The next steps are applicable for Mac only.
Open Terminal in the folder you want the new video to be saved in
Type: cat and hit space
Open the folder where you downloaded your .ts video. Select all .ts videos that you want to join (use your mouse or cmd+A)
Drag and drop them into the terminal
Hit space
Hit >
Hit Space
Type the name of the new video, e.g. my_new_video.ts. Please note that the format has to be the same as in the original videos, otherwise it will take long time to convert and even may fail!
Hit Enter. Wait for the terminal to finish the joining process and enjoy watching your video!
Found this answer here and wanted to reference it as it appear much cleaner than the accepted answer:
function blobToDataURL(blob, callback) {
var fileReader = new FileReader();
fileReader.onload = function(e) {callback(e.target.result);}
fileReader.readAsDataURL(blob);
}
I'm very late to the party.
If you want to download the content you can simply use fetch now
fetch(blobURL)
.then(res => res.blob())
.then(blob => /*do what you want with the blob here*/)
Here the solution:
let blob = new Blob(chunks, { 'type' : 'video/mp4;' });
let videoURL = window.URL.createObjectURL(blob);
const blobF = await fetch(videoURL).then(res => res.blob())
As the previous answer have said, there is no way to decode it back to url, even when you try to see it from the chrome devtools panel, the url may be still encoded as blob.
However, it's possible to get the data, another way to obtain the data is to put it into an anchor and directly download it.
<a href="blob:http://example.com/xxxx-xxxx-xxxx-xxxx" download>download</a>
Insert this to the page containing blob url and click the button, you get the content.
Another way is to intercept the ajax call via a proxy server, then you could view the true image url.

Chrome Download Attribute not working to replace the original name

I've experienced some unexpected behavior of Chrome since the newest version:
While in Firefox this Code is working Perfectly fine:
<a
id="playlist"
class="button"
download="Name.xspf"
href="data:application/octet-stream;base64,PD94ANDSOON"
style="display: inline;">
Download Me
</a>
It isn't working in Chrome (Simply downloading a file named "Download"), but has worked pretty fine before. What do I have to change that it is working again?
After some research I have finally found your problem.
<a>'s download attribute:
If the HTTP header Content-Disposition: is present and gives a different filename than this attribute, the HTTP header has priority over this attribute.
If this attribute is present and Content-Disposition: is set to inline, Firefox gives priority to Content-Disposition, like for the filename case, while Chrome gives priority to the download attribute.
Source
HTTP-Header Content-Disposition
Reading the comments, I had the same issue as #buffer-overflow and found this in the issue:
I'm guessing that the web page and the download are on different origins. We no longer honor the download attribute suggested filename for cross origin requests. Clicking on the link still initiates a download. But the the filename is only derived from factors solely dependent on the server (e.g. Content-Disposition header in the response and the URL).
So no chance I could make it work ... :(
I had this problem with wordpress, the problem is that wordpress generates the full path of the file, and in the a tag you have to remove the full domain name and add a relative path
Example, instead of:
<a href="http://mywordpresssite.com/wp-content/uploads/file.mp4" download="file.mp4" >
You have to do this:
<a href="/wp-content/uploads/file.mp4" download="file.mp4">
This will make it work
This is the current behaviour in Chrome as of 16 Aug, 2021
If you are calling an api like this:
http://localhost:9000/api/v1/service/email/attachment/dummy.pdf
Chrome will try to parse the last value of the path param and ignore any value passed to attachment attribute of a link if Content-Disposition is not set or is set to inline from the server, in which case the pdf file will have the name dummy.pdf
If Content-Disposition is set to attachment, then chrome will save the file with the filename value from Content-Disposition header.
That is if the server were to respond like this:
res.setHeader(
"Content-disposition",
"attachment; filename=" + "server-dummy.pdf"
);
res.setHeader("Content-Type", "application/pdf");
The file would be saved as server-dummy.pdf regardless of the presence of download attribute.
I have a simple solution regarding this issue. You just need to put your html file into a server like Apache using xampp control and so on. Because the download attribute is properly working through a server.
<a download href="data:application/octet-stream;base64,PD94ANDSOON">Download Me</a>
Are you looking at the files via a web server or your local filesystem - Does the browser's URL bar start with http:// or file:///?
I just ran some tests in Chrome, and while it will download the file, it doesn't respect the value of the download attribute when you're using the local file.
If you start hosting it on a web server, this will start working. If you're just doing this for yourself on your computer, check out WAMP for Windows or MAMP for macOS to get started with Apache.
I recommend using the file-saver NPM Package to implement or force download.
// 1.
npm i file-saver // install via npm or
yarn add file-saver // install via yarn
// 2.
import { saveAs } from 'file-saver'
// 3.
saveAs('https://httpbin.org/image', 'image.jpg')
References
https://www.npmjs.com/package/file-saver
https://www.npmjs.com/package/file-saver#saving-urls // direct url to Saving URLs
https://www.javascripting.com/view/filesaver-js
It won't work without a server. download attribute will do the work only when using a server (local/remote) like tomcat/xampp/wampserver...
<a href="videos/sample.mp4" download>Download Video</a>
<a href="images/sample.jpg" download>Download Image</a>
Not just only for videos or images.
In case anyone is having problems with this when the address of the file is different from this one, you could try to:
Locally create a Blob from downloading locally the original file.
Creating a URL object based on the local Blob.
It would look like this:
const outsideRes = await fetch(outsideUrl);
const blob = await outsideRes.blob();
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "marketing-payout-report.csv";
link.click();
This can be resolved by adding target="_blank" attribute to the href.
Like this:
Save sprites.svg as
<a target="_blank" download="somefilename.svg"
href="https://cdn.sstatic.net/Img/unified/sprites.svg"
>somefilename.svg</a>
The file has to be in some zipped format!
Go To Chrome Click on “Settings” and you'll see a new page pop up in your Chrome browser window. Scroll down to Advanced Settings, find the Downloads group, and clear your Auto Open options. Next time you download an item, it will be saved instead of opened automatically.

How can I create download link in HTML?

I have a basic idea of HTML. I want to create the download link in my sample website, but I don't have idea of how to create it. How do I make a link to download a file rather than visit it?
In modern browsers that support HTML5, the following is possible:
<a href="link/to/your/download/file" download>Download link</a>
You also can use this:
Download link
This will allow you to change the name of the file actually being downloaded.
This answer is outdated. We now have the download attribute. (see also this link to MDN)
If by "the download link" you mean a link to a file to download, use
Download
the target=_blank will make a new browser window appear before the download starts. That window will usually be closed when the browser discovers that the resource is a file download.
Note that file types known to the browser (e.g. JPG or GIF images) will usually be opened within the browser.
You can try sending the right headers to force a download like outlined e.g. here. (server side scripting or access to the server settings is required for that.)
In addition (or in replacement) to the HTML5's <a download attribute already mentioned,
the browser's download to disk behavior can also be triggered by the following http response header:
Content-Disposition: attachment; filename=ProposedFileName.txt;
This was the way to do before HTML5 (and still works with browsers supporting HTML5).
A download link would be a link to the resource you want to download. It is constructed in the same way that any other link would be:
Link
Link to installer
To link to the file, do the same as any other page link:
link text
To force things to download even if they have an embedded plugin (Windows + QuickTime = ugh), you can use this in your htaccess / apache2.conf:
AddType application/octet-stream EXTENSION
This thread is probably ancient by now, but this works in html5 for my local file.
For pdfs:
<p>test pdf</p>
This should open the pdf in a new windows and allow you to download it (in firefox at least). For any other file, just make it the filename. For images and music, you'd want to store them in the same directory as your site though. So it'd be like
<p><a href="images/logo2.png" download>test pdf</a></p>
There's one more subtlety that can help here.
I want to have links that both allow in-browser playing and display as well as one for purely downloading. The new download attribute is fine, but doesn't work all the time because the browser's compulsion to play the or display the file is still very strong.
BUT.. this is based on examining the extension on the URL's filename!You don't want to fiddle with the server's extension mapping because you want to deliver the same file two different ways. So for the download, you can fool it by softlinking the file to a name that is opaque to this extension mapping, pointing to it, and then using download's rename feature to fix the name.
<a target="_blank" download="realname.mp3" href="realname.UNKNOWN">Download it</a>
<a target="_blank" href="realname.mp3">Play it</a>
I was hoping just throwing a dummy query on the end or otherwise obfuscating the extension would work, but sadly, it doesn't.
You can use in two ways
<a href="yourfilename" download>Download</a>
it will download file with original name In Old Browsers this option was not available
2nd
Download
Here You have option to rename your file and download with a different name
The download attribute is new for the <a> tag in HTML5
<a href="http://www.odin.com/form.pdf" download>Download Form</a>
or
Download Form
I prefer the first one it is preferable in respect to any extension.
If you host your file in AWS, this may work for you. The code is very easy to understand. Because the browser doesn't support same-origin download links, 1 way to solve it is to convert the image URL to a base64 URL. Then, you can download it normally.
var canvas = document.createElement("canvas")
var ctx = canvas.getContext('2d')
var img = new Image()
img.src = your_file_url + '?' + new Date().getTime();
img.setAttribute('crossOrigin', '')
var array = your_file_url.src.split("/")
var fileName = array[array.length - 1]
img.onload = function() {
canvas.width = img.naturalWidth
canvas.height = img.naturalHeight
ctx.drawImage(img,
0, 0, img.naturalWidth, img.naturalHeight,
0, 0, canvas.width, canvas.height)
var dataUrl = canvas.toDataURL("image/png", 1)
var a = document.createElement('a')
a.href = dataUrl
a.download = fileName
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
Like this
Link name
So a file name.jpg on a site example.com would look like this
Image
i know i am late but this is what i got after 1 hour of search
<?php
$file = 'file.pdf';
if (! file) {
die('file not found'); //Or do something
} else {
if(isset($_GET['file'])){
// Set headers
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$file");
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
// Read the file from disk
readfile($file); }
}
?>
and for downloadable link i did this
Download PDF