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逻辑直接显示。
具体步骤:
安装转换工具:
- Linux/macOS:安装
libreoffice(大部分发行版自带,或通过包管理器安装),它支持批量转换XPS到PDF。 - Windows:可使用
libreoffice或调用系统XPS查看器的转换接口,也可借助pywin32调用Office组件完成转换。
- Linux/macOS:安装
修改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文件处理逻辑 # ...前端无需修改:
后端返回的PDF会被现有代码自动识别,用application/pdf类型的Blob加载到iframe中,实现正常显示。
方法二:前端使用JS库渲染XPS
如果不想在后端处理,可以借助前端JS库解析XPS文件并渲染到页面,比如xpsjs(需注意浏览器兼容性)。
具体步骤:
引入XPS渲染库:
下载xpsjs的核心文件(如xps.js、xps.worker.js),放到项目静态资源目录,在页面中引入:<script src="{% static 'js/xps.js' %}"></script>修改前端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,提问作者Лев Герасимов
相关产品推荐
相关产品推荐

