Search code examples
node.js

How to handle file sent from server for user to download


I want to write a simple server-client code on NodeJS to get the file from server drive:

  1. Server: Port 3000
  • Route:

     app.route('/download/:name').get(file_Controller.download);
    
  • Controller:

     file_controller.download = async (request, response) => {
         const filePath = "file_path"      
         return response.download(filePath, fileName, (err) => {
           if (err) {
             console.log(err)
           }
         });
     };
    
  1. Client: Port 3001 How can I handle the response from server to let user download the file? My current code:
  • API:

     export const fileApi = {
       download(params) {
         const searchParam = queryString.stringify(params)
         const url = `/download/${searchParam}`;
         return axiosClient.get(url, {params: {...params}});
       },
     };
    
  • Page:

     const download = async () => {
       try {
         return await fileApi.download({name: "file",});
       } catch (error) {
         console.log(error);
       }
     };
    

If I type the URL directly to browser like http://localhost:3000/download/file, broswer will let me download the file. However, I don't want to reveal this url to user, so I try to use above code to handle, but have no luck. How should I process?


Solution

  • To download a file, you will need to get response as blob, then

    1. Create a ObjectUrl using URL.createObjectURL
    2. Create a <a> element with href linked to the ObjectUrl and click the link.
    3. Finally clean up the resources
    export const fileApi = {
        download(params) {
            const searchParam = queryString.stringify(params);
            const url = `/download/${searchParam}`;
            return axiosClient
                .get(url, {
                    params: { ...params },
                    responseType: 'blob' // important
                })
                .then(res => {
                    const href = URL.createObjectURL(res.data); // creates a object url in memory
    
                    const link = document.createElement('a');
                    link.href = href;
                    link.setAttribute('download', params.name); // name must include a valid file extension
                    document.body.appendChild(link);
                    link.click();
    
                    document.body.removeChild(link); // removing the link element
                    URL.revokeObjectURL(href); // Releasing the URL from memory, this is important for optimal performance and memory usage
                });
        }
    };
       
    

    To download

    const download = async () => {
        try {
            return await fileApi.download({ name: 'file.pdf' });
        } catch (error) {
            console.log(error);
        }
    };
    

    Each time you call createObjectURL(), a new object URL is created, even if you've already created one for the same object. Each of these must be released by calling URL.revokeObjectURL() when you no longer need them.