Search code examples
node.jsexpresshttp-redirectdownloadmiddleware

How to perform an action after, or send information in res.redirect('/')?


Background Information

  • I am working on a NodeJS w/ Express project.
  • I am using some auth middleware, we can call it isAuthenticated()
  • The middleware is just protecting certain routes w/ passport, etc.
  • I am adding a file download link that is visible when a user is not authenticated yet. (i.e. the button is publicly visible).
  • If you click the button, the download route is protected, so we redirect you to a sign in page.

The Problem

  • Once the user authenticates, I am calling res.download(file);. The download works fine, but the user is still at the sign in page with their credentials typed in. (Note: the user is authenticated, but no further redirect is happening on this route). If I try res.download(file) and then make a call to res.redirect('/'), the file isn't downloaded.

Basically: I want to redirect the user to the home page at 'website.com/', but the approaches I've taken haven't worked.

Main Approach:

  • Set res.local.downloadFile2 = true in the router.get('/download/file2') route. Then redirect to home using res.redirect('/'). Now, in the home route, I would just do the following after rendering the home page again.
if (res.locals.downloadFile2 === true) { 
    res.download(file2) 
}

However: res.locals.downloadFile2 === undefined when that check is being done. I've tried to step through and somewhere it is being reset in one of the _modules I am using, so this is not working. I am currently unsure of the cause.

I could probably solve this by not displaying the links until a user is Authenticated, then there shouldn't be any cases of redirecting to login and back again, which means they would never see the login page, etc. but that is not the right solution to this problem, and is not the one I want to implement.

I would really appreciate any help, and can provide more information if needed!

Thanks in advance.


Solution

  • The issue is that after the redirect, the res object is a complete new object due to the browser issued a new request to follow the redirect. That's why res.locals.downloadFile2 is undefined.

    To solve your problem, you can replace your code res.local.downloadFile2 = true with code to set a cookie. The cookie holds information which will be stored on client side by the browser and send to the server with every request.

    See cookies npm package for example:

    var Cookies = require('cookies');
    var cookies = new Cookies(req, res, { keys: ['arbitrary string to encrypt the cookie'] })    
    
    // get value of the cookie
    var need_to_download_file = cookies.get('need_to_download_file', { signed: true })
    
    // Logic to download file (if necessary)
    if (need_to_download_file) {
        // Trigger download of the file
        // Reset cookie
        cookies.set('need_to_download_file', false, { signed: true })
    }
    
    // set the cookie 
    cookies.set('need_to_download_file', true, { signed: true })