NestJS使用StreamableFile返回图片流无法正常显示问题
NestJS使用StreamableFile返回图片无法显示的问题
我按照NestJS官网示例用StreamableFile返回图片文件流,但图片无法正常显示,已确认文件存在且路径正确。
原始代码
@Get('/avatar/:userId') async showAvatar( @Param('userId') userId: number, @Res({ passthrough: true }) res: Response ): Promise<StreamableFile> { const { filename, mimetype } = await this.fileService.queryAvatar(userId); const filePath = join(process.cwd(), `${AVATAR_PATH}/${filename}`); const file = createReadStream(filePath); const fileStats = await promises.stat(filePath); console.log(fileStats.size) // 50365 res.set({ 'Content-Type': mimetype, // 'image/jpeg' 'Content-Length': fileStats.size, // 实际响应头中显示396 'Content-Disposition': 'inline;', }); return new StreamableFile(file); }
异常现象
- 控制台打印的文件实际大小是50365,但响应头里的
Content-Length却只有396,导致图片数据截断无法显示 - 改用
file.pipe(res)时图片显示正常,此时响应头的Content-Type是image/jpeg;但用StreamableFile时变成了image/jpeg; charset=utf-8
解决方案
删除手动设置的Content-Length
StreamableFile会自动处理文件流的长度计算,手动设置的数值会和实际流长度冲突,直接移除res.set中的'Content-Length'配置。通过StreamableFile的options设置响应头
不要用res.set手动设置Content-Type和Content-Disposition,而是在创建StreamableFile时传入options参数,这样可以避免自动添加多余的charset=utf-8:
return new StreamableFile(file, { type: mimetype, disposition: 'inline' });
- 优化后的完整代码
import { createReadStream } from 'fs'; import { join } from 'path'; import { Get, Param, Res, StreamableFile } from '@nestjs/common'; import { Response } from 'express'; @Get('/avatar/:userId') async showAvatar( @Param('userId') userId: number, @Res({ passthrough: true }) res: Response ): Promise<StreamableFile> { const { filename, mimetype } = await this.fileService.queryAvatar(userId); const filePath = join(process.cwd(), `${AVATAR_PATH}/${filename}`); const file = createReadStream(filePath); return new StreamableFile(file, { type: mimetype, disposition: 'inline' }); }
原因解析
- StreamableFile内部会自动处理文件流的传输逻辑,手动设置Content-Length会覆盖正确的长度值,导致浏览器接收到不完整的二进制数据
- 用
res.set设置Content-Type时,NestJS的默认响应处理会自动追加charset=utf-8,而图片属于二进制文件,不需要字符编码,这会干扰浏览器的解析逻辑
内容的提问来源于stack exchange,提问作者Zern4518
相关产品推荐
相关产品推荐

