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

React JS中如何正确下载PDF与DOCX文件?解决文件损坏问题

React下载Flask返回的DOCX/PDF文件损坏问题

我在React中尝试根据Flask后端的响应下载DOCX或PDF文件,但下载后的文件总是损坏。

前端React代码

const {
  isDownloadPdfDocumentSuccess, downloadPdfDocument,
  isDownloadDocDocumentSuccess,  downloadDocDocument,
} = useSelector(state => state.document)

useEffect(() => {
  if(isDownloadPdfDocumentSuccess || isDownloadDocDocumentSuccess) {
      downloadDocument(downloadPdfDocument || downloadDocDocument, 
      "application/pdf" || "application/vnd.openxmlformats- 
      officedocument.wordprocessingml.document");
   }
}, [isDownloadPdfDocumentSuccess, isDownloadDocDocumentSuccess]);

function downloadDocument(downloadLink, downloadType) {
 const documentBlob = new Blob([downloadLink], { type: downloadType });
 const url = window.URL.createObjectURL(documentBlob);
 const anchor = document.createElement('a');
 anchor.href = url;
 anchor.download = document_title;
 document.body.appendChild(anchor);
 anchor.click();
 document.body.removeChild(anchor);
 window.URL.revokeObjectURL(url) ;
}

后端Flask代码

@app.route('/download_document_docx/<request_document_id>', methods=['GET'])
@token_required
def download_document_docx(current_user, request_document_id):
    '''
    Docx document preparation code
    '''
    return send_file(docx_file_path, as_attachment=True, mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document")

问题分析及修复方案

1. 核心问题

  • 请求未指定响应类型,后端返回的二进制文件被默认转成UTF-8字符串,导致Blob创建时数据损坏。
  • MIME类型判断逻辑错误,"application/pdf" || "其他类型"永远返回第一个值,DOCX文件会被错误标记为PDF类型。

2. 修复步骤

(1)请求阶段指定响应类型

在Redux Action发起请求时,必须设置responseType: 'blob',确保直接获取二进制Blob数据:

// PDF请求示例Action
export const fetchPdf = (docId) => async (dispatch) => {
  try {
    const res = await axios.get(`/download_document_pdf/${docId}`, {
      responseType: 'blob' // 关键配置
    });
    dispatch({
      type: 'DOWNLOAD_PDF_SUCCESS',
      payload: res.data // 直接存储Blob对象
    });
  } catch (err) {
    console.error('PDF下载失败', err);
  }
};

// DOCX请求示例Action
export const fetchDocx = (docId) => async (dispatch) => {
  try {
    const res = await axios.get(`/download_document_docx/${docId}`, {
      responseType: 'blob'
    });
    dispatch({
      type: 'DOWNLOAD_DOCX_SUCCESS',
      payload: res.data
    });
  } catch (err) {
    console.error('DOCX下载失败', err);
  }
};
(2)修正组件下载逻辑

拆分PDF和DOCX的下载判断,确保MIME类型与文件名匹配:

const {
  isDownloadPdfDocumentSuccess, downloadPdfDocument,
  isDownloadDocDocumentSuccess, downloadDocDocument,
} = useSelector(state => state.document);

useEffect(() => {
  if (isDownloadPdfDocumentSuccess) {
    downloadDocument(downloadPdfDocument, 'application/pdf', `${document_title}.pdf`);
  }
  if (isDownloadDocDocumentSuccess) {
    downloadDocument(downloadDocDocument, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', `${document_title}.docx`);
  }
}, [isDownloadPdfDocumentSuccess, isDownloadDocDocumentSuccess, document_title]);

function downloadDocument(blobData, mimeType, fileName) {
  const url = window.URL.createObjectURL(blobData); // 直接使用已有Blob
  const anchor = document.createElement('a');
  anchor.href = url;
  anchor.download = fileName;
  document.body.appendChild(anchor);
  anchor.click();
  document.body.removeChild(anchor);
  window.URL.revokeObjectURL(url);
}
(3)后端优化(可选)

在Flask的send_file中明确指定下载文件名,避免前端文件名混乱:

@app.route('/download_document_docx/<request_document_id>', methods=['GET'])
@token_required
def download_document_docx(current_user, request_document_id):
    # Docx文件准备逻辑
    return send_file(
        docx_file_path,
        as_attachment=True,
        mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        attachment_filename=f"document_{request_document_id}.docx"
    )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:52:25