Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger a download in Koa request handler

I'm trying to trigger a download from a POST request handler in Koa with koa-router. Essentially, I'm trying to do something like this:

app.js

const Koa = require('koa')
const router = require('./router')

const app = new Koa()

app.use(router.routes())
app.use(router.allowedMethods())

app.listen(3000)

router.js

const fs = require('fs')
const Router = require('koa-router')

const router = new Router()

router.post('/generate', function * () {
  const path = `${__dirname}/test.txt`
  this.body = fs.createReadStream(path)
  this.set('Content-disposition', 'attachment; filename= test.txt')
})

module.exports = router

client.js

const { fetch } = window;

const request = {
  method: 'POST',
  body: JSON.stringify({ fake: 'data' })
}

// Make the POST request
fetch('/generate', request)

However, when the POST request is sent, nothing happens. I don't get any error in the server console or the browser console either. Any help would be appreciated!

like image 634
Saad Avatar asked Sep 25 '16 12:09

Saad


2 Answers

You should set file stream in the body and send Content-disposition to attachment with that file name. Use below code

const Router = require('koa-router');
const router = new Router();

router.post('/generate', function * () {
  const path = `${__dirname}/file.txt`;
  this.body = fs.createReadStream(path);
  this.set('Content-disposition', 'attachment; filename= file.txt');
});

module.exports = router;

UPDATE: Complete working code:

var app = require('koa')();
var router = require('koa-router')();
const fs = require('fs');
router.post('/generate', function () {
  const path = `${__dirname}/file.txt`;
  this.body = fs.createReadStream(path);
  this.set('Content-disposition', 'attachment; filename= file.txt');
});

app
  .use(router.routes())
  .use(router.allowedMethods());

  app.listen(3000);

Client:

<button id="btnDownload">Download</button>

<script type="text/javascript">
    const request = {
        method: 'POST',
        body: JSON.stringify({
            fake: 'data'
        })
    }

    document.getElementById('download').onclick = () => {
        fetch('/generate', request)
            .then(res => {
                return res.text()
            })
            .then(content => {});
    }
</script>
like image 144
Sachin Avatar answered Oct 11 '22 17:10

Sachin


You could try using https://github.com/koajs/send

router.post('/generate', function * (next) {
    yield send(this, 'file.txt');
});

And in client side, you'll need to create and trigger download upon receiving file content via post request. Put this code in request callback

fetch('/generate', request)
  .then(res => { return res.text() })
  .then(content => {

    uriContent = "data:application/octet-stream," + encodeURIComponent(content);

    newWindow = window.open(uriContent, 'somefile');

  });
like image 26
Vedran Jukic Avatar answered Oct 11 '22 17:10

Vedran Jukic