background
When we upload images, videos, music, PDFS, or other files to the back end, the back end may do some processing to make sure that the file name is not the same. For example, use date + time stamp + random number to name names, or use UUID or other methods to generate file names. This leads to a problem. After downloading a file, users cannot intuitively determine the file content by the file name. Here’s an example:
- Mp3 => 6fe3C93A-D3CD-47C6-AC54-11a6978a08cf.mp3
- PDF => a4e50bFC-63b0-4a19-b0c9-363c7467b2b4.pdf
- JPG => ad58b4d1-022C-4095-aa21-829cda8f9F33.jpg
These examples can also be distinguished by name extensions, but if all the files you download are of the same type, then…
Download the file and rename it
For the browser, when you click on a link that jumps to an image, video, or music, the browser will directly open a new TAB and preview it. If you want to download the file, you need to right-click save as, or find the download button. Compressed packages, or other files that cannot be previewed, will be downloaded directly. Is there a way to skip the right click save as, or the download button, and just download it? You’ve all tried adding the Download attribute to the A tag.
<a href="path/ad58b4d1-022c-4095-aa21-829cda8f9f33.jpg" download="Family Photo">download</a>
Copy the code
Unfortunately, most of the time it doesn’t work. So how do you do that? It’s actually quite simple, it involves XMLHttpRequest, url.createObjecturl ().
implementation
On paper come zhongjue shallow, must know this to practice.
Without further ado, go straight to the code:
<button id="btn" type="button"> download < / button >const btn = document.getElementById('btn');
btn.addEventListener('click'.function () {
downloadFile('path/ad58b4d1-022c-4095-aa21-829cda8f9f33.jpg'.'Family Photo');
});
/** * Download file *@param {string} url
* @param {string} fileName
*/
function downloadFile(url, fileName) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
// Set the response type to BLOB
xhr.responseType = 'blob';
// The request succeeded
xhr.addEventListener('load'.function () {
if (xhr.status === 200) {
const a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response);
a.download = fileName;
// The a tag is added to the body for better compatibility. Google Chrome does not need to add it
document.body.appendChild(a);
a.click();
/ / remove
a.remove();
/ / release the url
window.URL.revokeObjectURL(a.href); }});// Monitor the download progress
xhr.addEventListener('progress'.function (e) {
let percent = Math.trunc(e.loaded / e.total * 100);
});
// Error handling
xhr.addEventListener('error'.function (e) {
// todo
});
// Send the request
xhr.send();
}
Copy the code
rendering
In addition, if you want to save a string of characters as a TXT file, you can do the same with Blob by setting the type attribute of the second Blob constructor to text/plain. Save signatures, public keys, private keys, etc.
/** * Save the file *@param {string} str
* @param {string} fileName
*/
function saveAsFile(str, fileName) {
const blob = new Blob([str], { type: 'text/plain' });
const a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = fileName;
// The a tag is added to the body for better compatibility. Google Chrome does not need to add it
document.body.appendChild(a);
a.click();
/ / remove
a.remove();
/ / release the url
window.URL.revokeObjectURL(a.href);
}
Copy the code
Online Demo: jsdemo. Codeman. Top/HTML/downlo…
Existing problems
Of course, this method is not perfect, there are the following problems.
- Cross-domain problems exist if resources are not from the same source (Demo has been set to allow cross-domain resources)
- The file will be preloaded. If the file is large, the network speed is slow, and the server bandwidth is low, the waiting time will be long (so Demo has a progress bar).