Bootstrap

【Nest】文件下载——普通下载和流式下载

普通下载

直接对服务端中的某个路径进行响应下载。

import {
  Controller,
  Get,
  Post,
  Res,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { UploadService } from './upload.service';
import { FileInterceptor } from '@nestjs/platform-express';
import type { Response } from 'express';
import { join } from 'node:path';
import { zip } from 'compressing';

@Controller('upload')
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @Post('album')
  @UseInterceptors(FileInterceptor('file')) // file 为前端表单字段名
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log(file);
    return {
      localPath: file.path,
      onlinePath: 'http://localhost:3000/images/' + file.filename,
    };
  }

  @Get('export')
  downloadFile(@Res() res: Response) {
    const url = join(__dirname, '../images/file-1741220280567-926338688.jpg');
    res.download(url);
  }
}

前端

<template>
  <div>
    <el-button @click="downloadFile">下载</el-button>
  </div>
</template>
<script setup lang="ts">
const downloadFile = () => {
  //   普通下载
  window.open('/api/upload/export')
}
</script>

流式下载

import {
  Controller,
  Get,
  Post,
  Res,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { UploadService } from './upload.service';
import { FileInterceptor } from '@nestjs/platform-express';
import type { Response } from 'express';
import { join } from 'node:path';
import { zip } from 'compressing';

@Controller('upload')
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @Post('album')
  @UseInterceptors(FileInterceptor('file')) // file 为前端表单字段名
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log(file);
    return {
      localPath: file.path,
      onlinePath: 'http://localhost:3000/images/' + file.filename,
    };
  }

  @Get('export')
  downloadFile(@Res() res: Response) {
    const url = join(__dirname, '../images/file-1741220280567-926338688.jpg');
    res.download(url);
  }

  @Get('stream')
  async downloadFileStream(@Res() res: Response) {
    const url = join(__dirname, '../images/file-1741220280567-926338688.jpg');
    const tarStream = new zip.Stream();
    await tarStream.addEntry(url);

    res.setHeader('Content-Type', 'application/octet-stream');
    res.setHeader('Content-Disposition', `attachment; filename=heo`);
    tarStream.pipe(res);
  }
}

前端

<template>
  <div>
    <el-button @click="downloadFile">下载</el-button>
  </div>
</template>
<script setup lang="ts">
/**
 * 使用 Fetch API 异步获取指定 URL 的二进制数据,并触发下载
 *
 * @param {string} url - 要获取数据的 URL 地址
 */
const useFetch = async (url: string) => {
  // 异步获取 URL 对应的二进制数据
  const res = await fetch(url).then(res => res.arrayBuffer())

  // 创建一个新的 <a> 元素
  const a = document.createElement('a')

  // 将获取到的二进制数据转换为 Blob 对象,并生成 URL
  a.href = URL.createObjectURL(new Blob([res]))

  // 设置下载的文件名
  a.download = 'heo.zip'

  // 触发 <a> 元素的点击事件,开始下载
  a.click()
}

const downloadFile = () => {
  //   流式下载
  useFetch('/api/upload/stream')
  //   普通下载
  // window.open('/api/upload/export')
}
</script>

在这里插入图片描述

;