Tom*_*ler 7 javascript node.js nestjs
我尝试使用 NestJs 从控制器端点返回 PDF 文件。当不设置Content-type标题时,返回的数据getDocumentFile会很好地返回给用户。然而,当我添加标题时,我得到的返回似乎是某种奇怪的 GUID 形式,响应总是如下所示:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxwherex是一个小写的十六进制字符。它似乎也与处理程序函数的实际返回值完全无关,因为我什至在根本不返回任何内容时得到了这个奇怪的 GUID。
不设置时Content-type: application/pdf,该函数返回缓冲区的数据就好了,但是我需要设置标题以使浏览器将响应识别为 PDF 文件,这对我的用例很重要。
控制器看起来像这样:
@Controller('documents')
export class DocumentsController {
constructor(private documentsService: DocumentsService) {}
@Get(':id/file')
@Header('Content-type', 'application/pdf')
async getDocumentFile(@Param('id') id: string): Promise<Buffer> {
const document = await this.documentsService.byId(id)
const pdf = await this.documentsService.getFile(document)
// using ReadableStreamBuffer as suggested by contributor
const stream = new ReadableStreamBuffer({
frequency: 10,
chunkSize: 2048,
})
stream.put(pdf)
return stream
}
}
Run Code Online (Sandbox Code Playgroud)
和我的 DocumentsService 是这样的:
@Injectable()
export class DocumentsService {
async getAll(): Promise<Array<DocumentDocument>> {
return DocumentModel.find({})
}
async byId(id: string): Promise<DocumentDocument> {
return DocumentModel.findOne({ _id: id })
}
async getFile(document: DocumentDocument): Promise<Buffer> {
const filename = document.filename
const filepath = path.join(__dirname, '..', '..', '..', '..', '..', 'pdf-generator', 'dist', filename)
const pdf = await new Promise<Buffer>((resolve, reject) => {
fs.readFile(filepath, {}, (err, data) => {
if (err) reject(err)
else resolve(data)
})
})
return pdf
}
}
Run Code Online (Sandbox Code Playgroud)
我最初只是返回缓冲区 ( return pdf),但这带来了与上述尝试相同的结果。在 NestJs 的存储库上,有用户建议使用上述方法,这显然对我也不起作用。请参阅此处的 GitHub 线程。
小智 18
2021 年更新:
从现在开始,在 Nest 版本 8 中,您可以使用该类StreamableFile:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
官方 Nest 文档中的更多信息:https ://docs.nestjs.com/techniques/streaming-files
我知道这个旧线程。但它可能会帮助某人。类似于@Victor
@Get('pdf')
@HttpCode(201)
@Header('Content-Type', 'image/pdf')
@Header('Content-Disposition', 'attachment; filename=test.pdf')
public pdf() {
return fs.createReadStream('./test.pdf');
}Run Code Online (Sandbox Code Playgroud)
这个对我有用。
@Get('pdf')
@HttpCode(HttpStatus.OK)
@Header('Content-Type', 'application/pdf')
@Header('Content-Disposition', 'attachment; filename=test.pdf')
pdf() {
return createReadStream('./nodejs.pdf');
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我认为应该更好地使用Stream替代readFile。因为它将文件的所有内容加载到 RAM 中。
小智 5
您可以使用现成的装饰器 @Res 这是我的工作解决方案:
控制器(NestJs):
async getNewsPdfById(@Param() getNewsParams: GetNewsPdfParams, @Req() request: Request, @Res() response: Response): Promise<void> {
const stream = await this.newsService.getNewsPdfById(getNewsParams.newsId, request.user.ownerId);
response.set({
'Content-Type': 'image/pdf',
});
stream.pipe(response);
}
Run Code Online (Sandbox Code Playgroud)
在我的情况下,流变量只是由 html-pdf 库创建的就绪流,因为我通过 html https://www.npmjs.com/package/html-pdf创建 pdf,但您如何创建流并不重要。问题是您应该使用 @Res 装饰器并将其管道化,因为它是原生的 NestJs 解决方案。
这里也是如何在客户端声明文件的代码:https : //gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743
无论如何,让我们在您的情况下尝试这个:
@Controller('documents')
export class DocumentsController {
constructor(private documentsService: DocumentsService) {}
@Get(':id/file')
async getDocumentFile(@Param('id') id: string, @Res res: Response): Promise<Buffer> {
const document = await this.documentsService.byId(id)
const pdf = await this.documentsService.getFile(document)
const stream = new ReadableStreamBuffer({
frequency: 10,
chunkSize: 2048,
})
res.set({
'Content-Type': 'image/pdf',
});
stream.pipe(res);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
也在 2021 年更新:
我更喜欢这种方式,因为我不需要后控制器拦截器逻辑。我们可以控制文件的名称并使其内联或下载文件。
@Get()
download(@Res() res) {
const filename = '123.pdf';
// make it to be inline other than downloading
// res.setHeader('Content-disposition', 'inline; filename=' + filename);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
const filestream = createReadStream('files/' + filename);
filestream.pipe(res);
}
Run Code Online (Sandbox Code Playgroud)
官方 Nest 文档中的更多信息:https ://docs.nestjs.com/techniques/streaming-files
| 归档时间: |
|
| 查看次数: |
18817 次 |
| 最近记录: |