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.

  1. Cross-domain problems exist if resources are not from the same source (Demo has been set to allow cross-domain resources)
  2. 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).