Skip to main content

文件流式传输

note

本章介绍如何从您的 HTTP 应用程序中流式传输文件。下面的示例不适用于 GraphQL 或微服务应用程序。

在某些情况下,您可能希望从您的 REST API 将文件发送回客户端。为了在 Nest 中实现这一点,通常会执行以下操作:

@Controller('file')
export class FileController {
@Get()
getFile(@Res() res: Response) {
const file = createReadStream(join(process.cwd(), 'package.json'));
file.pipe(res);
}
}

但是通过这样做,您最终会失去对控制器后拦截器逻辑的访问。 为了处理这个问题,您可以返回一个 StreamableFile 实例,在底层,框架将负责管道化响应。

StreamableFile 类

StreamableFile 是一个保存即将返回的流的类。要创建一个新的 StreamableFile,您可以将 Buffer 或 Stream 传递给 StreamableFile 构造函数。

tip

可以从 @nestjs/common 导入 StreamableFile 类。

跨平台支持

Fastify 默认情况下可以支持在不需要调用 stream.pipe(res) 的情况下发送文件,因此根本不需要使用 StreamableFile 类。 然而,Nest 在两种平台类型中都支持 StreamableFile 的使用,因此如果在 Express 和 Fastify 之间切换, 无需担心两个引擎之间的兼容性问题。

示例

下面是一个简单的示例,将 package.json 作为文件返回而不是 JSON, 但这个想法自然扩展到图像、文档和任何其他文件类型。

import { Controller, Get, StreamableFile } from '@nestjs/common';
import { createReadStream } from 'fs';
import { join } from 'path';

@Controller('file')
export class FileController {
@Get()
getFile(): StreamableFile {
const file = createReadStream(join(process.cwd(), 'package.json'));
return new StreamableFile(file);
}
}

默认的内容类型是 application/octet-stream,如果您需要自定义响应, 可以使用 res.set 方法或 @Header() 装饰器,如下所示:

import { Controller, Get, StreamableFile, Res, Header } from '@nestjs/common';
import { createReadStream } from 'fs';
import { join } from 'path';
import type { Response } from 'express';

@Controller('file')
export class FileController {
@Get()
getFile(@Res({ passthrough: true }) res: Response): StreamableFile {
const file = createReadStream(join(process.cwd(), 'package.json'));
res.set({
'Content-Type': 'application/json',
'Content-Disposition': 'attachment; filename="package.json"',
});
return new StreamableFile(file);
}

// 或者甚至:
@Get()
@Header('Content-Type', 'application/json')
@Header('Content-Disposition', 'attachment; filename="package.json"')
getStaticFile(): StreamableFile {
const file = createReadStream(join(process.cwd(), 'package.json'));
return new StreamableFile(file);
}
}