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

Django项目中XPS文件在浏览器直接下载而非显示的解决方法咨询

在浏览器中显示XPS文件的解决方案(基于Django项目)

问题描述

我在Django项目中需要实现在浏览器内查看PDF与XPS格式文档,用iframe方式实现时PDF可正常显示,但XPS文件会直接触发下载,求解决方法。

我的JS代码:

function displayFile(element) {
  var objectId = element.id.substring('categories_'.length);
  var project_id = '{{ project.id }}';
  var url = `/pilot_doc/get_file/${objectId}/${project_id}/`;
  var options = {
      method: 'GET', 
      headers: {
          'Accept': 'application/octet-stream' 
      }
  };

  fetch(url, options)
      .then(response => {
          if (!response.ok) {
              throw new Error('Network response was not ok');
          }
          return response.json(); 
      })
      .then(data => {
          if (data.status === 'success') {
            var byteCharacters = atob(data.file);
            var byteNumbers = new Array(byteCharacters.length);
            for (var i = 0; i < byteCharacters.length; i++) {
              byteNumbers[i] = byteCharacters.charCodeAt(i);
            }
            var byteArray = new Uint8Array(byteNumbers);
            fileName = data.file_name;
            fileExtension = getFileExtension(fileName);
            console.log(fileExtension);
            var contentType;
            if (fileExtension === 'pdf') {
              contentType = 'application/pdf';
            } else if (fileExtension === 'xps') {
              contentType = 'application/vnd.ms-xpsdocument';
            } else {
              throw new Error('Unsupported file format');
            }
            var blob = new Blob([byteArray], {type: contentType}); 
            var url = URL.createObjectURL(blob);
            var iframe = document.createElement('iframe');
            var docBox = document.querySelector('.box.doc');
            var heightInPixels = docBox.offsetHeight;
            iframe.style.width = "100%";
            iframe.style.height = `${heightInPixels-30}px`; 
            iframe.src = url; 
            docBox.innerHTML = ''; 
            docBox.appendChild(iframe); 
          }
      })
      .catch(error => {
          console.error('There was a problem with your fetch operation:', error);
          alert('Ошибка при загрузке файла: ' + error.message);
      });
}

核心原因

现代主流浏览器(Chrome、Firefox、Safari等)不原生支持XPS格式渲染,所以直接用iframe加载XPS Blob时,浏览器会默认触发下载,而非显示内容。下面是两种可行的解决思路:

方法一:后端将XPS转换为PDF(推荐)

因为浏览器对PDF的支持非常完善,所以在Django后端处理XPS文件,将其转换为PDF后再返回给前端,前端就可以用现有iframe逻辑直接显示。

具体步骤:

  1. 安装转换工具:

    • Linux/macOS:安装libreoffice(大部分发行版自带,或通过包管理器安装),它支持批量转换XPS到PDF。
    • Windows:可使用libreoffice或调用系统XPS查看器的转换接口,也可借助pywin32调用Office组件完成转换。
  2. 修改Django视图get_file:
    在返回文件前,判断文件格式如果是XPS,先执行转换命令生成临时PDF文件,再返回PDF的base64内容和修改后缀后的文件名。示例伪代码:

    import subprocess
    import os
    import base64
    from django.http import JsonResponse
    
    def get_file(request, object_id, project_id):
        # 假设已获取到XPS文件的本地路径 file_path
        file_name = os.path.basename(file_path)
        if file_name.lower().endswith('.xps'):
            # 转换XPS到PDF
            pdf_path = file_path.replace('.xps', '.pdf')
            # 调用libreoffice命令执行转换
            subprocess.run([
                'libreoffice', '--headless', '--convert-to', 'pdf',
                file_path, '--outdir', os.path.dirname(file_path)
            ], check=True)
            # 读取转换后的PDF内容
            with open(pdf_path, 'rb') as f:
                file_content = f.read()
            # 清理临时PDF文件(可选)
            os.remove(pdf_path)
            # 返回PDF数据给前端
            return JsonResponse({
                'status': 'success',
                'file': base64.b64encode(file_content).decode('utf-8'),
                'file_name': file_name.replace('.xps', '.pdf')
            })
        # 原有的PDF文件处理逻辑
        # ...
    
  3. 前端无需修改:
    后端返回的PDF会被现有代码自动识别,用application/pdf类型的Blob加载到iframe中,实现正常显示。

方法二:前端使用JS库渲染XPS

如果不想在后端处理,可以借助前端JS库解析XPS文件并渲染到页面,比如xpsjs(需注意浏览器兼容性)。

具体步骤:

  1. 引入XPS渲染库:
    下载xpsjs的核心文件(如xps.js、xps.worker.js),放到项目静态资源目录,在页面中引入:

    <script src="{% static 'js/xps.js' %}"></script>
    
  2. 修改前端JS代码:
    检测到XPS文件时,不再创建iframe,而是调用库的渲染方法将内容展示到指定容器:

    function displayFile(element) {
      var objectId = element.id.substring('categories_'.length);
      var project_id = '{{ project.id }}';
      var url = `/pilot_doc/get_file/${objectId}/${project_id}/`;
      var options = {
          method: 'GET', 
          headers: {
              'Accept': 'application/octet-stream' 
          }
      };
    
      fetch(url, options)
          .then(response => {
              if (!response.ok) {
                  throw new Error('Network response was not ok');
              }
              return response.json(); 
          })
          .then(data => {
              if (data.status === 'success') {
                var byteCharacters = atob(data.file);
                var byteNumbers = new Array(byteCharacters.length);
                for (var i = 0; i < byteCharacters.length; i++) {
                  byteNumbers[i] = byteCharacters.charCodeAt(i);
                }
                var byteArray = new Uint8Array(byteNumbers);
                fileName = data.file_name;
                fileExtension = getFileExtension(fileName);
                console.log(fileExtension);
                var docBox = document.querySelector('.box.doc');
                docBox.innerHTML = ''; // 清空容器
                if (fileExtension === 'pdf') {
                  // 保留原有的PDF处理逻辑
                  var contentType = 'application/pdf';
                  var blob = new Blob([byteArray], {type: contentType}); 
                  var url = URL.createObjectURL(blob);
                  var iframe = document.createElement('iframe');
                  var heightInPixels = docBox.offsetHeight;
                  iframe.style.width = "100%";
                  iframe.style.height = `${heightInPixels-30}px`; 
                  iframe.src = url; 
                  docBox.appendChild(iframe); 
                } else if (fileExtension === 'xps') {
                  // 使用XPS库渲染文件内容
                  var blob = new Blob([byteArray], {type: 'application/vnd.ms-xpsdocument'});
                  var reader = new FileReader();
                  reader.onload = function(e) {
                    var xpsData = new Uint8Array(e.target.result);
                    // 初始化渲染器并加载XPS文件
                    var xpsViewer = new XPSViewer(docBox);
                    xpsViewer.loadDocument(xpsData);
                  };
                  reader.readAsArrayBuffer(blob);
                } else {
                  throw new Error('Unsupported file format');
                }
              }
          })
          .catch(error => {
              console.error('There was a problem with your fetch operation:', error);
              alert('Ошибка при загрузке файла: ' + error.message);
          });
    }
    

注意事项

  • 后端转换方法需要服务器安装对应工具,同时要处理文件权限、临时文件清理等问题。
  • 前端JS库渲染可能存在兼容性问题,部分复杂XPS文件的渲染效果可能不如PDF转换方式。

内容的提问来源于stack exchange,提问作者Лев Герасимов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:14:55