이 장에서는 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
을 생성하려면 Buffer
나 Stream
을 StreamableFile
생성자에 전달할 수 있습니다.
Hint!
StreamableFile
클래스는@nestjs/common
에서 가져올 수 있습니다.
Fastify는 기본적으로 stream.pipe(res)
를 호출하지 않아도 파일을 보내는 것을 지원하므로 StreamableFile
클래스를 전혀 사용할 필요가 없습니다. 그러나 Nest는 Express와 Fastify 양쪽에서 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 } 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);
}
// Or even:
@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);
}
}
스트림(Stream)은 데이터를 조각조각으로 나누어 전송하는 방식을 말하는 것이다. 데이터가 한 번에 모두 로드되지 않고 작은 덩어리로 나누어져 전송되면, 메모리 효율성과 성능을 향상시킬 수 있다.
스트림의 종류 :
file.pipe(res);
대신에 return new StreamableFile(file);
을 사용하는 이유는 NestJS의 기능과 권장사항을 활용하여 파일 다운로드를 더 효율적으로 처리하기 위함
process.cwd()
=> 현재 디렉토리
인터셉터는 NestJS에서 요청 및 응답 처리를 중간에 가로채어 로직을 적용하거나 수정할 수 있는 기능이다. 하지만 pipe를 사용하면 인터셉터 사용이 어려운 이유는 다음과 같다.
Stream에 대한 자료 : 링크