You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React前端AJAX请求下载PDF返回空白文档问题排查

问题分析与解决方案

我来帮你捋捋这个问题——你遇到的空白PDF、文件体积翻倍的情况,是代码里几个关键错误导致的,咱们一步步拆解:

一、核心错误点排查

1. HTTP请求函数的多处逻辑问题

你的httpRequest函数里有几个致命的细节错误:

  • 未初始化XMLHttpRequest实例:代码里直接用了request变量,但根本没创建new XMLHttpRequest(),这会导致请求根本发不出去(或者在某些环境下抛出异常)。
  • 未定义的变量:async、readyState、status、responseType这些都是未声明的变量,比如request.open的第三个参数应该是布尔值true(表示异步请求),而不是写个async变量;判断请求完成应该用request.readyState === 4(对应XMLHttpRequest的DONE状态),request.status === 200表示请求成功。
  • 错误的Content-Type设置:GET请求不需要设置Content-Type请求头,这个多余的头会让服务器对二进制PDF数据做错误的编码处理,直接导致返回的Blob损坏。
  • 未正确设置responseType:你没有把传入的options.responseType赋值给request.responseType,这会导致默认以文本格式解析二进制数据,拿到的Blob自然是错的。

2. 下载时重复包装Blob导致数据损坏

在下载代码里,你已经从接口拿到了正确的Blob对象,但又画蛇添足地把response.response重新包装进一个新的Blob:

const file = new Blob([response.response], { type: 'application/pdf' });

这里的response已经是httpRequest返回的Blob了,你把它转成数组再重新打包,相当于把二进制数据重复编码了一次,所以文件体积翻倍,内容全空白。

二、修正后的完整代码

1. 修复后的httpRequest函数

export const httpRequest = (options) => {
  return new Promise((resolve, reject) => {
    // 第一步:创建XMLHttpRequest实例
    const request = new XMLHttpRequest();
    // 从options中获取响应类型,默认text
    const responseType = options.responseType || 'text';

    // 初始化请求:第三个参数直接用true(异步)
    request.open(options.method, options.url, true);

    // 仅在非GET请求时设置Content-Type(GET请求不需要这个头)
    if (options.method !== 'GET' && options.contentType) {
      request.setRequestHeader('Content-Type', options.contentType);
    }

    // 关键:设置响应类型,确保服务器返回的二进制数据被正确解析为Blob
    request.responseType = responseType;

    // 请求状态变更处理
    request.onreadystatechange = () => {
      if (request.readyState === 4) { // 请求完成
        if (request.status === 200) { // 请求成功
          switch (responseType) {
            case 'json':
              try {
                resolve(JSON.parse(request.responseText));
              } catch (e) {
                reject(new Error('Can not parse JSON!'));
              }
              break;
            case 'string':
              resolve(request.responseText);
              break;
            case 'blob':
              // 直接返回解析好的Blob
              resolve(request.response);
              break;
            default:
              resolve(request);
              break;
          }
        } else {
          // 处理错误状态码
          reject(new Error(`Request failed with status ${request.status}`));
        }
      }
    };

    // 处理网络错误
    request.onerror = () => {
      reject(new Error('Network request failed'));
    };

    // GET请求send的是null,非GET请求才传数据
    request.send(options.method === 'GET' ? null : options.data);
  });
};

2. 修复后的下载代码

// 假设httpRequest返回的response就是正确的Blob对象
const link = document.createElement('a');
// 直接使用返回的Blob,不需要重复包装
const file = response;
link.href = window.URL.createObjectURL(file);
link.download = `test.pdf`;
document.body.appendChild(link);
link.click();
// 下载完成后释放URL对象,避免内存泄漏
window.URL.revokeObjectURL(link.href);
document.body.removeChild(link);

三、额外排查建议

  • 打开浏览器开发者工具的Network标签,查看这个PDF请求的响应:确认返回的Content-Type是application/pdf,响应大小和curl下载的一致。
  • 检查请求参数是否正确编码:比如param1和param2如果包含特殊字符,要先用encodeURIComponent()处理,避免参数传递错误导致服务器返回空内容。

内容的提问来源于stack exchange,提问作者kosbr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:14:16