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

Rails 7在Windows环境下自定义Doc文件下载失效解决方案问询

Rails 7自定义Doc文件下载在Windows系统内容为空的问题

问题描述

在Rails 7中实现了前端自定义Doc文件下载功能,点击按钮触发downloadDoc()函数生成包含表单字段、图片的Doc文件。该功能在非Windows设备上正常,但Windows系统中下载后的文件内容为空。尝试过多个Rails gem,均只能生成纯文本内容,无法插入图片。

原代码

downloadDoc() {
  // Cif Inputs
  var labelsCont = document.getElementsByClassName("cif_form_export_filed_labels")
  var valuesCont = document.getElementsByClassName("cif_form_export_filed_values")
  var labels = []
  var values = []
  var allFields = ""

  Object.values(labelsCont).map(el => labels.push(el.value || ""))
  Object.values(valuesCont).map(el => values.push(el.value || ""))

  labels.map((l, i) => {
    allFields += `<h4>${l}  -  ${values[i]}</h4>`
  })


  // map photos
  var allPhotos = ""
  const a = document.getElementsByClassName('cif_photos')
  var photos = []
  Object.values(a).map(el => {
    photos.push(JSON.parse(el.value));
  })

  const groupedMap = photos.reduce(
    (aa, e) => aa.set(e.photo_type, [...aa.get(e.photo_type) || [], e]),
    new Map()
  );

  groupedMap.forEach((v, k) => {
    allPhotos += `<h4>${k}</h4>`
    v.map(img => {
      allPhotos += `<h5>${img.location}</h5>`
      allPhotos += `<img src=${img.url} width=200px height=200px > `
    })
  })


  // download process
  var preHtml = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'><head><meta charset='utf-8'><title>Export HTML To Doc</title></head><body>";
  var postHtml = "</body></html>";
  var html = preHtml + postHtml + "<h2>CIF Fields</h2>" + allFields + "<h2>CIF Photos</h2>" + allPhotos + "<h2>Summary</h2>";

  var blob = new Blob(['\ufeff', html], {
    type: 'application/msword'
  });

  var url = 'data:application/vnd.ms-word;charset=utf-8,' + encodeURIComponent(html);
  var filename = 'document.docx';
  var downloadLink = document.createElement("a");
  document.body.appendChild(downloadLink);

  if (navigator.msSaveOrOpenBlob) {
    navigator.msSaveOrOpenBlob(blob, filename);
  } else {
    downloadLink.href = url;
    downloadLink.download = filename;
    downloadLink.click();
  }
}

问题原因

  1. HTML结构错误:原代码将内容拼接到preHtml + postHtml之后,导致实际内容位于</body></html>标签外部。非Windows浏览器能容错解析,但Windows下的Microsoft Word对HTML结构要求严格,会忽略标签外的内容,造成文件为空。
  2. 文件类型不匹配:使用application/msword(旧版doc格式),但文件名是.docx,格式与扩展名不匹配,影响Word解析。
  3. 编码与Blob处理:Windows的navigator.msSaveOrOpenBlob接口对Blob内容的结构和编码兼容性要求更高,错误的HTML结构会导致内容无法被识别。

修正后的代码

downloadDoc() {
  // Cif Inputs
  var labelsCont = document.getElementsByClassName("cif_form_export_filed_labels")
  var valuesCont = document.getElementsByClassName("cif_form_export_filed_values")
  var labels = []
  var values = []
  var allFields = ""

  Object.values(labelsCont).map(el => labels.push(el.value || ""))
  Object.values(valuesCont).map(el => values.push(el.value || ""))

  labels.map((l, i) => {
    allFields += `<h4>${l}  -  ${values[i]}</h4>`
  })


  // map photos
  var allPhotos = ""
  const a = document.getElementsByClassName('cif_photos')
  var photos = []
  Object.values(a).map(el => {
    photos.push(JSON.parse(el.value));
  })

  const groupedMap = photos.reduce(
    (aa, e) => aa.set(e.photo_type, [...aa.get(e.photo_type) || [], e]),
    new Map()
  );

  groupedMap.forEach((v, k) => {
    allPhotos += `<h4>${k}</h4>`
    v.map(img => {
      allPhotos += `<h5>${img.location}</h5>`
      allPhotos += `<img src="${img.url}" width="200px" height="200px" /> `
    })
  })


  // download process - 修正HTML结构,将内容放在<body>内部
  var preHtml = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'><head><meta charset='utf-8'><title>Export HTML To Doc</title></head><body>";
  var contentHtml = "<h2>CIF Fields</h2>" + allFields + "<h2>CIF Photos</h2>" + allPhotos + "<h2>Summary</h2>";
  var postHtml = "</body></html>";
  var html = preHtml + contentHtml + postHtml;

  // 匹配docx格式的MIME类型
  const mimeType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
  var blob = new Blob(['\ufeff', html], { type: mimeType });

  var filename = 'document.docx';
  var downloadLink = document.createElement("a");
  document.body.appendChild(downloadLink);

  if (navigator.msSaveOrOpenBlob) {
    navigator.msSaveOrOpenBlob(blob, filename);
  } else {
    // 使用URL.createObjectURL替代data URL,避免编码问题
    downloadLink.href = URL.createObjectURL(blob);
    downloadLink.download = filename;
    downloadLink.click();
    // 释放URL对象
    setTimeout(() => URL.revokeObjectURL(downloadLink.href), 100);
  }
  document.body.removeChild(downloadLink);
}

关键修改点

  • 调整HTML拼接顺序,将内容放在<body>标签内部,确保Word能正确识别内容。
  • 更换MIME类型为application/vnd.openxmlformats-officedocument.wordprocessingml.document,与.docx扩展名匹配。
  • 使用URL.createObjectURL替代data:URL,避免encodeURIComponent带来的编码问题,同时优化内存使用(添加URL释放逻辑)。
  • 修正图片标签的属性引号,符合标准HTML语法,提升兼容性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:46:05