Initiate file download with Koa
Asked Answered
P

4

10

I'm using Koa as a webserver to serve my Polymer application. Upon pressing a button in the frontend localhost:3000/export is called. I would like to deliver a file-download to the client after packing the some files to a zip-archive.

How to do this in Koa.js?

Here's an example on how to do it in Express (another option would be the download-helper

app.get('/export', function(req, res){

  var path = require('path');
  var mime = require('mime');

  var file = __dirname + '/upload-folder/dramaticpenguin.MOV';

  var filename = path.basename(file);
  var mimetype = mime.lookup(file);

  res.setHeader('Content-disposition', 'attachment; filename=' + filename);
  res.setHeader('Content-type', mimetype);

  var filestream = fs.createReadStream(file);
  filestream.pipe(res);
});

I'm looking for something like this:

router.post('/export', function*(){
  yield download(this, __dirname + '/test.zip')
})
Parian answered 2/11, 2015 at 16:46 Comment(0)
Z
26

You should be able to simple set this.body to the file stream

this.body = fs.createReadStream(__dirname + '/test.zip');

then set the response headers as appropriate.

this.set('Content-disposition', 'attachment; filename=' + filename);
this.set('Content-type', mimetype);
Zany answered 2/11, 2015 at 22:27 Comment(1)
It's recommended to set the headers before the body.Tallage
K
27

For anyone else who sees this in the future, it's worth mentioning that there is a built in attachment method on the response object that you can use to set the Content-Disposition to attachment with a specified filename. So you can do this:

this.attachment('hello.txt')

And it would be the same thing as the following:

this.set('Content-disposition', 'attachment; filename=hello.txt')

For Koa 2:

ctx.attachment('hello.txt')
Knowitall answered 17/1, 2017 at 2:20 Comment(0)
Z
26

You should be able to simple set this.body to the file stream

this.body = fs.createReadStream(__dirname + '/test.zip');

then set the response headers as appropriate.

this.set('Content-disposition', 'attachment; filename=' + filename);
this.set('Content-type', mimetype);
Zany answered 2/11, 2015 at 22:27 Comment(1)
It's recommended to set the headers before the body.Tallage
P
3

Browser default behaviour is to display the file, not to download it. To enforce download you need to do this:

this.header("Content-Type", "application/force-download")
this.header('Content-disposition', 'attachment; filename=' + filename);
Philosophical answered 19/7, 2017 at 19:19 Comment(0)
R
2

Bit of a different file download example with error checking, using Node with Koa 2. I am not sure if it is necessary to destroy the stream afterwards as described here https://github.com/jshttp/content-disposition#options

router.get('/downloads/:version/:file', async function(ctx) {
  const fileName = `${__dirname}/downloads/${ctx.params.version}/${ctx.params.file}`;
  try {
    if (fs.existsSync(fileName)) {
      ctx.body = fs.createReadStream(fileName);
      ctx.attachment(fileName);
    } else {
      ctx.throw(400, "Requested file not found on server");
    }
  } catch(error) {
    ctx.throw(500, error);
  }  
});

In browser sample: https://myserver.com/downloads/1.0.0/CoolAppFile.zip

Randallrandan answered 18/6, 2019 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.