Koa2(四)

637 阅读1分钟

Koa2

koa-send进行文件的下载

// app.js
const download = require('./routes/download')
app.use(download.routes(), download.allowedMethods())

单文件下载

  • 新建download路由 image.png
const router = require('koa-router')()
const send = require('koa-send')
router.prefix('/download')

router.get('/:name', async (ctx) => {
  const name = ctx.params.name
  const path = `public/images/${name}`
  ctx.attachment(path)
  await send(ctx, path)
})

module.exports = router
  • 前端使用情况
<button @click="download">下载</button>
download() {
      window.open('http://localhost:3000/download/16190580105525993.jpg', '_self')
}
<iframe name="myIframe" style="display:none"></iframe>
download() {
      window.open('http://localhost:3000/download/16190580105525993.jpg', 'myIframe')
}

image.png

批量下载

  • 多个文件打包成一个压缩包
  • archiver 是一个在 Node.js 中能跨平台实现打包功能的模块,支持 zip 和 tar 格式
  • 参考文档
  • 安装 npm install archiver -S
  • 此处用于压缩的文件,我这边直接在后端写死,没有用到前端传值,需要的话自行操作,并没有难度上的升级,这边只是介绍archiver
  • 使用

image.png

image.png

image.png

const router = require('koa-router')()
const send = require('koa-send')

const archiver = require('archiver')
const fs = require('fs')

router.prefix('/download')

router.get('/zip', async ctx => {
  // 1. 创建文件用于将需要被压缩的数据写入
  const output = fs.createWriteStream('public/all.zip')
  const archive = archiver('zip', {
    zlib: { level: 9 } // 设置压缩级别
  })

  // 2. 各种监听,错误监听等
  // listen for all archive data to be written
  // 'close' event is fired only when a file descriptor is involved
  output.on('close', function() {
    console.log(archive.pointer() + ' total bytes');
    console.log('archiver has been finalized and the output file descriptor has closed.');
  });

  // This event is fired when the data source is drained no matter what was the data source.
  // It is not part of this library but rather from the NodeJS Stream API.
  // @see: https://nodejs.org/api/stream.html#stream_event_end
  output.on('end', function() {
    console.log('Data has been drained');
  });

  // good practice to catch warnings (ie stat failures and other non-blocking errors)
  archive.on('warning', function(err) {
    if (err.code === 'ENOENT') {
      // log warning
    } else {
      // throw error
      throw err;
    }
  });

  // good practice to catch this error explicitly
  archive.on('error', function(err) {
    throw err;
  });

  // 3. 开启archiver管道,将数据写入,其中public/images/16190607585174899.jpg为现存文件的地址,fs.createReadStream用于读取文件
  // 当获取文件流之后,archive.append()添加到创建的压缩文件中
  archive.pipe(output)
  archive.append(fs.createReadStream('public/images/16190607585174899.jpg'), {
    name: '16190607585174899.jpg'
  })
  archive.append(fs.createReadStream('public/images/16190580105525993.jpg'), {
    name: '16190580105525993.jpg'
  })
  archive.append('hello world', {
    name: 'test.txt'
  })

  // 完成,得异步处理
  await archive.finalize()
  ctx.attachment('public/all.zip')
  await send(ctx, 'public/all.zip')
})

router.get('/:name', async (ctx) => {
  const name = ctx.params.name
  const path = `public/images/${name}`
  ctx.attachment(path)
  await send(ctx, path)
})

module.exports = router
  • 前端使用情况
<iframe name="myIframe" style="display:none"></iframe>
<button @click="download">下载</button>
download() {
  window.open('http://localhost:3000/download/zip', 'myIframe')
}

image.png

image.png

image.png