NestJS CORS代理下载图片或文件返回编码数据问题排查请求
问题分析
你遇到的核心问题是axios默认会将响应数据自动解析为文本/JSON,而图片这类二进制文件被转换成UTF-8字符串后,再通过JSON.stringify写入响应,就会破坏原始的二进制结构,导致下载的文件是编码后的乱码内容。
解决方案
要正确代理二进制文件,你需要让axios保留原始的二进制数据,并且直接将其转发到客户端响应中,而不是做字符串化处理。具体修改如下:
1. 修改axios请求配置
添加responseType: 'stream'(或者'arraybuffer'),告诉axios不要自动解析响应数据,保留原始的二进制流:
const response: AxiosResponse = await axios.get(url, { timeout: 5000, responseType: 'stream' // 关键:保留二进制流 })
2. 直接转发响应流
不需要手动writeHead、write和end,可以直接将axios获取的响应流pipe到客户端响应中,这样能自动处理所有的二进制数据和响应头:
res.set(response.headers); response.data.pipe(res);
完整修改后的代码
@Controller('cors') export class CorsController { constructor(private readonly corsService: CorsService) { } @Get() async get(@Query('cd') uri: string, @Response() res: ExpressResponse) { try { let url = uri.charAt(0) == '/' ? uri.substring(1) : uri; const response: AxiosResponse = await axios.get(url, { timeout: 5000, responseType: 'stream' // 保留二进制流 }) // 设置响应头,排除可能导致冲突的头字段 const allowedHeaders = Object.fromEntries( Object.entries(response.headers).filter(([key]) => !['transfer-encoding', 'connection'].includes(key.toLowerCase()) ) ); res.set(allowedHeaders); // 直接将响应流转发给客户端 response.data.pipe(res); } catch (error) { res.status(error.response?.status || 500).send(error.message); } } }
额外说明
- 使用
responseType: 'stream'比'arraybuffer'更高效,尤其是处理大文件时,因为它是流式传输,不需要把整个文件加载到内存中。 - 过滤掉
transfer-encoding和connection这类头,是因为Express会自动处理这些字段,避免手动设置导致的冲突。 - 错误处理部分改为用
res.status(...).send(...),能正确向客户端返回错误状态码和信息,而不是简单返回字符串。
内容的提问来源于stack exchange,提问作者Vansham Aggarwal
相关产品推荐
相关产品推荐

