Node.js Express中Axios通用工具适配PDF响应的问题咨询
解决方案
关于默认响应类型下转PDF的问题
不行,默认响应类型(json或text)返回的字符串无法还原成有效的PDF文件。因为axios会把二进制响应(比如PDF)按文本编码(默认UTF-8)解析成字符串,这个过程中二进制数据会被不可逆地损坏——多字节的二进制值会被错误转码,丢失原始字节信息,所以再转回去也无法得到正确的PDF文件。必须用二进制类型的responseType(arraybuffer或blob)来获取原始二进制数据。
动态适配响应类型的可行方案
axios无法在收到响应后再设置responseType,因为这个参数是请求前就确定的,决定了axios如何解析响应数据。不过可以通过以下两种方式实现动态适配:
方案1:让调用者指定响应类型(推荐)
给工具函数添加可选的responseType参数,默认值设为json,需要获取文件时传入arraybuffer或blob。同时在错误处理中,针对二进制响应类型做兼容——如果错误响应的Content-Type是JSON格式,就把二进制buffer转成字符串再解析成JSON对象。
修改后的代码示例:
function axiosCall(method, endpoint, body, responseType = 'json') { let requestConfig = { url: encodeURI(`${endpoint.host}:${endpoint.port}${endpoint.path}`), method: method, proxy: false, data: body, responseType: responseType, // 新增响应类型参数 headers: { "x-access-token": token, "X-Correlation-ID": correlationId, "Content-Type": "application/json" }, }; return axios.request(requestConfig).then(response => { return response.data; }).catch((errorRes) => { let errorDetails = { error: errorRes.message, status: errorRes?.response?.status || 500, responseContent: "Server Error" }; // 处理二进制响应类型下的JSON错误 if (errorRes?.response?.data && responseType === 'arraybuffer') { const contentType = errorRes.response.headers['content-type']; if (contentType?.includes('application/json')) { // 把buffer转成UTF-8字符串再解析成JSON errorDetails.responseContent = JSON.parse(Buffer.from(errorRes.response.data).toString('utf8')); } else { // 非JSON的二进制错误,直接返回buffer errorDetails.responseContent = errorRes.response.data; } } else { errorDetails.responseContent = errorRes?.response?.data || "Server Error"; } throw errorDetails; }); }
调用示例:
- 获取JSON:
axiosCall('GET', endpoint, null) - 获取PDF:
axiosCall('GET', pdfEndpoint, null, 'arraybuffer')
方案2:先通过HEAD请求获取Content-Type再发起请求
先发送一个HEAD请求到目标接口,拿到响应头的Content-Type,判断是否是二进制类型(比如application/pdf、image/png等),再决定设置哪种responseType发起实际请求。但这个方案有两个缺点:
- 多一次HTTP请求,增加开销和延迟
- 部分接口的HEAD响应和实际请求(比如POST)的Content-Type可能不一致,存在适配风险
示例代码(仅作参考):
async function axiosCall(method, endpoint, body) { // 先发送HEAD请求获取Content-Type const headResponse = await axios.head(encodeURI(`${endpoint.host}:${endpoint.port}${endpoint.path}`), { headers: { "x-access-token": token, "X-Correlation-ID": correlationId } }); const contentType = headResponse.headers['content-type']; let responseType = 'json'; // 判断是否为二进制类型 const binaryTypes = ['application/pdf', 'image/png', 'image/jpeg', 'application/octet-stream']; if (binaryTypes.some(type => contentType?.includes(type))) { responseType = 'arraybuffer'; } // 发起实际请求 let requestConfig = { url: encodeURI(`${endpoint.host}:${endpoint.port}${endpoint.path}`), method: method, proxy: false, data: body, responseType: responseType, headers: { "x-access-token": token, "X-Correlation-ID": correlationId, "Content-Type": "application/json" }, }; return axios.request(requestConfig).then(response => { return response.data; }).catch((errorRes) => { // 错误处理逻辑同方案1 let errorDetails = { error: errorRes.message, status: errorRes?.response?.status || 500, responseContent: "Server Error" }; if (errorRes?.response?.data && responseType === 'arraybuffer') { const errContentType = errorRes.response.headers['content-type']; if (errContentType?.includes('application/json')) { errorDetails.responseContent = JSON.parse(Buffer.from(errorRes.response.data).toString('utf8')); } else { errorDetails.responseContent = errorRes.response.data; } } else { errorDetails.responseContent = errorRes?.response?.data || "Server Error"; } throw errorDetails; }); }
总结
优先选择方案1,让调用者按需指定responseType,既灵活又避免额外请求开销。二进制响应的错误处理只需针对JSON格式做转码即可,其他二进制错误直接返回原始buffer即可。
内容的提问来源于stack exchange,提问作者Shubham Shaw
相关产品推荐
相关产品推荐

