NestJS如何将第三方服务返回的文件正确转发给前端下载?
文件损坏的核心原因是HttpService(基于Axios)默认会将响应体按文本/JSON格式解析,二进制PPTX文件流在编码转换过程中被破坏,需要调整请求响应的全链路配置:
1 修改FileService下载逻辑
需要调整请求配置,指定响应类型为二进制格式,同时保留完整响应对象以获取第三方返回的响应头:
import { AxiosResponse } from 'axios'; import { Observable } from 'rxjs'; @Injectable() export class FileService { constructor( private httpService: HttpService ) { } download(id: string): Observable<AxiosResponse<ArrayBuffer>> { // 替换为实际的第三方接口地址拼接逻辑 const requestUrl = `OTHER_SERVICE_URL/${id}`; return this.httpService.get(requestUrl, { headers: { 'API-KEY': 'SOME API KEY' // GET请求无请求体,无需配置Content-Type }, // 核心配置:指定响应类型为二进制数组,避免Axios自动转码损坏文件 responseType: 'arraybuffer' }); } }
2 修改Controller转发逻辑
需要将第三方返回的文件相关响应头透传给前端,再发送二进制内容:
import type { Response } from 'express'; export class MyController { constructor( private fileService: FileService, ) { } @Get('download') download(@Res() res: Response, @Query('id') id: string) { this.fileService.download(id) .subscribe({ next: (response) => { // 透传第三方返回的文件信息响应头 res.setHeader('Content-Disposition', response.headers['content-disposition']); // 也可以直接复用第三方返回的Content-Type:res.setHeader('Content-Type', response.headers['content-type']) res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'); // 发送二进制文件内容 res.send(response.data); }, error: (err) => { res.status(500).send('文件下载失败'); } }); } }
补充注意事项
- 无需自定义文件名的场景可以直接复用第三方返回的
Content-Disposition响应头,不需要手动拼接文件名 - 跨域场景下需要给当前NestJS接口配置
Access-Control-Expose-Headers: Content-Disposition,否则前端无法读取该响应头触发自动下载 - 如果需要保留NestJS全局响应拦截器的逻辑,可以将
@Res()装饰器修改为@Res({ passthrough: true })
内容的提问来源于stack exchange,提问作者Igor Zinchenko
相关产品推荐
相关产品推荐

