web前端

node如何实现下载功能?

2022-05-17  本文已影响0人  姜治宇

如何实现一个下载功能呢?其实最简单的方式就是用get请求,指向后台的一个资源即可,不过有的情况下,我们需要传输的参数过多,无法使用get,那使用post又该如何实现呢?今天我们就来系统理一下。

get方式

get方式比较简单,直接上代码:

import { Controller, Get, Req, Res } from "@nestjs/common";
const fs = require('fs');
const path = require('path');
@Controller("file")
export class FileController {
    constructor() { }

    @Get('/download')
    async download(@Req() req, @Res() res) {
        let filepath = `D:/test.zip`;
        res.setHeader('ContentType', 'application/octet-stream');
        let filename = `test.zip`;
        res.setHeader('Content-Disposition', `attachment;filename=` + encodeURIComponent(filename));
        fs.createReadStream(filepath).pipe(res);
    }

}

get请求上可以带上userid和filename等信息,后端根据这些参数定位到文件所在的路径,然后将文件流通过stream管道输出即可。

window.open('http://localhost:3000/file/download?userid=xxx&filename=test')

post方式

如果我们改成post请求:

import { Controller, Get,Post, Req, Res } from "@nestjs/common";
const fs = require('fs');
const path = require('path');
@Controller("file")
export class FileController {
    constructor() { }

    @Post('/download')
    async download(@Req() req, @Res() res) {
        let filepath = `D:/test.zip`;
        
        res.setHeader('ContentType', 'application/octet-stream');
        let filename = `test.zip`;
        res.setHeader('Content-Disposition', `attachment;filename=` + encodeURIComponent(filename));
        fs.createReadStream(filepath).pipe(res);
    }

}

然后前端可以这样访问吗:

axios.post('/api/file/download',{}).then(result=>{ //代理
  let res = result.data;//后端直接返回流
  window.open(res);
});

这样做很明显是不行的,我们可以改变一下策略,把请求拆分为两步。
1、发起post请求,当文件处理完毕后,返回给前端文件相关信息,如果是处理大文件时间较长的话,就设置永不超时。
2、发起get请求,根据post返回的信息,定位到资源的存放路径,用window.open指向一下即可。
后端:

import { Controller, Get,Post, Req, Res } from "@nestjs/common";
const fs = require('fs');
const path = require('path');
@Controller("file")
export class FileController {
    constructor() { }

    @Post('/zip')
    handleZip(@Req() req, @Res() res) {
        console.log('开始处理>>>');
        res.connection.setTimeout(0);//永不超时
        
        console.log('处理中...');
        fs.copyFileSync('D:/test.zip','D:/zip/123456/test.zip');//拷贝文件,src dest
        setTimeout(() => {

            res.json({ //返回文件信息
                code: 200,
                data:{
                    filename:'test.zip',
                    userid:'123456'
                }
            });
            console.log('处理完毕');
        }, 3000);

    }
    @Get('/download')
    async download(@Req() req, @Res() res) {
        let filename = decodeURIComponent(req.query.filename);
        let userid = req.query.userid;
        
        let zipPath = path.resolve('D:/', 'zip',userid, filename);
        if(filename && fs.existsSync(zipPath)) {
            res.setHeader('ContentType', 'application/octet-stream');
               
            res.setHeader('Content-Disposition', `attachment;filename=` + encodeURIComponent(filename));
            fs.createReadStream(zipPath).pipe(res);
        }
    }

}

前端:

axios.post('/api/file/zip',{}).then(result=>{ //代理
  
  let res = result.data;//返回的json
  if(res && res['code'] === 200) {

      window.open(`http://localhost:3000/file/download?userid=${res.data.userid}&filename=${encodeURIComponent(res.data.filename)}`);
  }
});
上一篇下一篇

猜你喜欢

热点阅读