The concept here is super simple:
- Have the server-side download page set a Cookie.
- Check for that cookie on the client-side.
Since the cookie headers will only arrive on the client when the download response has arrived, it means that the mere existence of the cookie will indicate that the user has completed the download request. Brilliant in its simplicity!
To test this, I set up a page with a download link. Then, using jQuery, I intercept the navigation event (on the link) and append the cookie value that the server will echo. Working with cookies on the client is, in my experience, extremely frustrating; as such, my demo does only the bare minimum needed to perform the test in this context.
Index.cfm - Our Client-Side Code
Download.cfm - Our Server-Side Code
<!--- This is the download-tracker value that we will need to set in the response so that the client-side knows when the download has been executed. ---> <cfparam name="url.downloadID" type="string" default="" /> <!--- Pause here to simulate download preperation. ---> <cfset sleep( 5 * 1000 ) /> <!--- Set the tracking cookie. ---> <cfcookie name="downloadID" value="#url.downloadID#" /> <!--- Define the download content. ---> <cfheader name="content-disposition" value="attachment; filename=download.txt" /> <cfcontent type="application/octetstream; charset=utf-8" variable="#charsetDecode( 'Download file content.', 'utf-8' )#" />
That's all there is to it! If I make a request to the download page, which has a sleep() command for several seconds, I get the following console output:
File still downloading... 1379695746067
File still downloading... 1379695746565
File still downloading... 1379695747066
File still downloading... 1379695747565
File still downloading... 1379695748066
File still downloading... 1379695748568
File still downloading... 1379695749066
File still downloading... 1379695749585
File still downloading... 1379695750065
File still downloading... 1379695750567
How sweet is that! This is so simple, I can't believe I've never seen this before! I'll definitely be incorporating this approach in my ColdFusion applications.
Want to use code from this post? Check out the license.