【React】- 跨域PDF预览、下载(改文件名)、打印

我们经常会碰到跨域来方位PDF,同时需要下载、打印的需求,通常由于浏览器的安全策略,可以预览,但是下载和打印可能会受限,这时候怎么办呢?

1.创建一个隐藏的标签

要下载 iframe 中的 PDF 文件,你可以通过以下步骤实现:

  1. 获取 PDF 文件的 URL:确保你已经有一个指向 PDF 文件的 URL,即 url
  2. 创建一个下载链接:使用 JavaScript 创建一个隐藏的下载链接,并触发点击事件来下载文件。

以下是一个示例代码:

// 假设 url是你已经定义的 PDF 文件 URL
const downloadPdf = () => {const link = document.createElement('a');link.href = url;link.download = 'document.pdf'; // 你可以根据需要更改文件名document.body.appendChild(link);link.click();document.body.removeChild(link);
};// 在你的组件中添加一个按钮来触发下载
<button onClick={downloadPdf}>下载 PDF</button>

将上述代码集成到你的 index.jsx 文件中,确保 slnPdfUrl 是有效的 PDF 文件 URL。用户点击按钮时,PDF 文件将被下载。

示例集成

假设你的 index.jsx 文件如下:

import React from 'react';const YourComponent = ({ slnPdfUrl }) => {const downloadPdf = () => {const link = document.createElement('a');link.href = slnPdfUrl;link.download = 'document.pdf';document.body.appendChild(link);link.click();document.body.removeChild(link);};return (<div><iframe className='sln-detail-pdf'src={slnPdfUrl}width="100%" height="100%"/><button onClick={downloadPdf}>下载 PDF</button></div>);
};export default YourComponent;

但是呢,有些浏览器会直接打开一个新窗口显示pdf,并没有下载PDF

2. Fetch方式

上面的问题通常是由于以下几个原因造成的:

  1. 浏览器行为

    • 某些浏览器可能不会自动下载文件,而是会在新标签页中打开文件。这取决于浏览器的设置和文件类型。
  2. 文件 URL 的问题

    • 确保 url 是一个有效的 URL,并且指向一个可以直接下载的文件资源。
  3. CORS 问题

    • 如果 url 是一个跨域的 URL,浏览器可能会阻止下载操作,除非服务器正确设置了 CORS 头。
  4. 文件 MIME 类型

    • 确保服务器返回的文件具有正确的 MIME 类型(例如,PDF 文件应为 application/pdf),以确保浏览器能够正确处理下载。

解决方法

1. 检查文件 URL

确保 url 是一个有效的 URL,并且指向一个可以直接下载的文件资源。你可以在浏览器中直接访问该 URL,看看是否能正常下载文件。

2. 检查 CORS 设置

如果 url 是一个跨域的 URL,确保服务器设置了正确的 CORS 头。例如,服务器应该返回以下头信息:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
3. 检查文件 MIME 类型

确保服务器返回的文件具有正确的 MIME 类型。例如,对于 PDF 文件,服务器应该返回 Content-Type: application/pdf

4. 使用 fetchaxios 下载文件

如果上述方法都不奏效,可以尝试使用 fetchaxios 来下载文件。以下是一个使用 fetch 的示例:

const slnDownload = async () => {if (!url) {message.error('PDF URL 无效');return;}try {const response = await fetch(url);if (!response.ok) {throw new Error('网络响应不正确');}const blob = await response.blob();const url = window.URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'document.pdf';document.body.appendChild(a);a.click();a.remove();window.URL.revokeObjectURL(url);} catch (error) {message.error('下载文件时出错: ' + error.message);}
};

示例代码解释

  1. 检查 URL

    • 确保 url 存在且有效。
  2. 使用 fetch 获取文件

    • 使用 fetch 发送请求以获取文件的二进制数据(blob)。
  3. 创建下载链接

    • 创建一个临时的 URL 对象(URL.createObjectURL)。
    • 创建一个隐藏的 <a> 标签,并设置其 hrefdownload 属性。
    • 触发点击事件以开始下载。
    • 移除临时的 <a> 标签并释放 URL 对象。

3.组件化

笔者直接提供一个react的PDF组件,可以直接复制到自己工程里使用。

工程结构

在这里插入图片描述

index.jsx代码

import React, { useRef, useEffect, useState } from 'react';
import { Button,  message} from "antd";
import './index.less';
export default function RPdf(props, ref) {const [url, setUrl] = useState('');const iframeRef = useRef(null);useEffect(() => {init();}, [props.src,props.download])const init = async() => {if (!props.src) {return;}try {const pdfResponse = await fetch(props.src);if (!pdfResponse.ok) {throw new Error('网络响应不正确');}const blob = await pdfResponse.blob();const url = window.URL.createObjectURL(blob);setUrl(url);} catch (error) {message.error('加载 PDF 时出错: ' + error.message);}}const downloadPdf = async() => {if (!url) {message.error('PDF URL 无效');return;}try {const a = document.createElement('a');a.href = url;a.download = props.download;document.body.appendChild(a);a.click();a.remove();window.URL.revokeObjectURL(url);} catch (error) {message.error('下载文件时出错: ' + error.message);}}const printPdf = () => {if (!url) {message.error('PDF URL 无效');return;}const iframe = iframeRef.current;if (!iframe) {message.error('无法找到 iframe');return;}iframe.contentWindow.focus();iframe.contentWindow.print();}return (<div className='r-pdf-container'><div className='r-pdf-header'><Button onClick={downloadPdf}>下载</Button><Button onClick={printPdf}>打印</Button></div><div className="r-pdf-content"><iframe className='r-pdf'ref={iframeRef}src={url}width="100%" height="100%"/></div></div>)
}

index.less代码

.r-pdf-container {width: 100%;height: 100%;display: flex;flex-direction: column;gap: 6px;margin: 12px;.r-pdf-header {height: 40px;display: flex;justify-content: flex-end;gap: 8px;}.r-pdf-content {width: 100%;height: 100%;// overflow: auto;.r-pdf {border: 0px;}}
}

使用

<RPdf src={url} download={yourDownloadName+'.pdf'} />

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/498463.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSV vs 数据库:爬虫数据存储的最佳选择是什么

介绍 在爬虫技术中&#xff0c;数据存储是一个不可缺少的环节。然而&#xff0c;选择合适的存储方式对数据分析和结果应用都致关重要。CSV和数据库是常用的两种存储方式&#xff0c;但它们各有优缺。这篇文章将分析两者在爬虫数据存储方面的选择值。 微博热搜是当前网络热点话…

InstructGPT:基于人类反馈训练语言模型遵从指令的能力

大家读完觉得有意义记得关注和点赞&#xff01;&#xff01;&#xff01; 大模型进化树&#xff0c;可以看到 InstructGPT 所处的年代和位置。来自 大语言模型&#xff08;LLM&#xff09;综述与实用指南&#xff08;Amazon&#xff0c;2023&#xff09; 目录 摘要 1 引言 …

springboot511基于SpringBoot视频点播系统的设计与实现(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装视频点播系统软件来发挥其高效地信息处理的作用&#xff0c…

计算机网络——期末复习(4)协议或技术汇总、思维导图

思维导图 协议与技术 物理层通信协议&#xff1a;曼彻斯特编码链路层通信协议&#xff1a;CSMA/CD &#xff08;1&#xff09;停止-等待协议&#xff08;属于自动请求重传ARQ协议&#xff09;&#xff1a;确认、否认、重传、超时重传、 &#xff08;2&#xff09;回退N帧协…

计算机网络 (7)物理层下面的传输媒体

一、定义与位置 物理层是计算机网络体系结构的最低层&#xff0c;它位于传输媒体&#xff08;传输介质&#xff09;之上&#xff0c;主要作用是为数据链路层提供一个原始比特流的物理连接。这里的“比特流”是指数据以一个个0或1的二进制代码形式表示。物理层并不是特指某种传输…

Qt从入门到入土(七)-实现炫酷的登录注册界面(下)

前言 Qt从入门到入土&#xff08;六&#xff09;-实现炫酷的登录注册界面&#xff08;上&#xff09;主要讲了如何使用QSS样式表进行登录注册的界面设计&#xff0c;本篇文章将介绍如何对登录注册界面进行整体控件的布局&#xff0c;界面的切换以及实现登录、记住密码等功能。…

BOE(京东方)“向新2025”年终媒体智享会落地深圳

12月27日,BOE(京东方)“向新 2025”年终媒体智享会的收官之站在创新之都深圳圆满举行,为这场为期两周、横跨三地的年度科技盛会画上了完美句号。活动期间,全面回顾了 BOE(京东方)2024年在多个关键领域取得的卓越成绩,深入剖析其在六大维度构建的“向新”发展格局,精彩呈现了以“…

国产数据库TiDB从入门到放弃教程

国家层面战略&#xff0c;安全的角度&#xff0c;硬件、软件国产化是趋势&#xff0c;鸿蒙电脑操作系统、鸿蒙手机操作系统…数据库也会慢慢国产化&#xff0c;国产数据库TiDB用起来比OceanBase丝滑&#xff0c;本身没有那么重。 从入门到放弃 1. 介绍1.1 TiDB 的主要特点1.2 T…

初识 Conda:一站式包管理和环境管理工具

文章目录 1. 什么是 Conda&#xff1f;2. 为什么选择 Conda&#xff1f;3. Conda 的安装3.1 安装步骤&#xff08;以 Miniconda 为例&#xff09; 4. Conda 的核心功能4.1 包管理4.2 环境管理4.3 Conda Forge4.4 设置国内镜像 5. 常见使用场景5.1 数据科学项目5.2 离线安装5.3 …

chatwoot 开源客服系统搭建

1. 准备开源客服系统&#xff08;我是用的Chatwoot &#xff09; 可以选择以下开源客服系统作为基础&#xff1a; Chatwoot: 功能强大&#xff0c;支持多渠道客户对接&#xff0c;&#xff08;支持app&#xff0c;web&#xff09;。Zammad: 现代的开源工单系统。FreeScout: 免…

Linux-----进程处理(子进程创建)

【尚硅谷嵌入式Linux应用层开发&#xff0c;linux网络编程&#xff0c;linux进程线程&#xff0c;linux文件io】https://www.bilibili.com/video/BV1DJ4m1M77z?p35&vd_source342079de7c07f82982956aad8662b467 main函数 fork创建进程 fork()参数 /*** brief 创建一个子进…

【蓝桥杯选拔赛真题85】python摆放箱子 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析

目录 python摆放箱子 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python摆放箱子 第十五届蓝桥杯青少年组python比赛选拔赛真题详细解析 一…

【SQLi_Labs】Basic Challenges

什么是人生&#xff1f;人生就是永不休止的奋斗&#xff01; Less-1 尝试添加’注入&#xff0c;发现报错 这里我们就可以直接发现报错的地方&#xff0c;直接将后面注释&#xff0c;然后使用 1’ order by 3%23 //得到列数为3 //这里用-1是为了查询一个不存在的id,好让第一…

按照人们阅读Excel习惯来格式化BigDecimal

1、环境/问题描述 使用springboot发送邮件(附件)的方式将月度报表发送给领导查阅&#xff0c;数据是准确的&#xff0c;领导基本满意。 就是对一些数字的格式化提出了改进建议&#xff0c;比如不要让大数字自动转为科学计数法、浮点数小数点后都是0就不要带出来&#xff0c;根…

STM32 高级 WIFi案例1:测试AT指令

需求描述 测试AT指令是否能够正常控制ESP32的wifi&#xff0c;比如重启、读取设备信息等。 思路&#xff1a; stm32通过串口usart2向ESP32发布命令。ESP32通过串口1返回信息。 配置&#xff1a; 第一步&#xff1a;对ESP32芯片烧录可以读取stm32命令的固件&#xff08;fac…

Unity 读Excel,读取xlsx文件解决方案

Unity读取表格数据 效果&#xff1a; 思路&#xff1a; Unity可以解析Json&#xff0c;但是读取Excel需要插件的帮助&#xff0c;那就把这个功能分离开&#xff0c;读表插件就只管读表转Json&#xff0c;Unity就只管Json解析&#xff0c;中间需要一个存储空间&#xff0c;使用…

通过无障碍服务(AccessibilityService)实现Android设备全局水印显示

一、无障碍功能简介 首先我们先来了解下无障碍功能的官方介绍&#xff1a; 无障碍服务仅应用于帮助残障用户使用 Android 设备和应用。它们在后台运行&#xff0c;并在触发 AccessibilityEvents 时接收系统的回调。此类事件表示用户界面中的某些状态转换&#xff0c;例如焦点已…

查看vue的所有版本号和已安装的版本

1.使用npm查看Vue的所有版本&#xff1a; npm view vue versions2.查看项目中已安装的 Vue.js 版本 npm list vue

【鸿蒙NEXT】鸿蒙里面类似iOS的Keychain——关键资产(@ohos.security.asset)实现设备唯一标识

前言 在iOS开发中Keychain 是一个非常安全的存储系统&#xff0c;用于保存敏感信息&#xff0c;如密码、证书、密钥等。与 NSUserDefaults 或文件系统不同&#xff0c;Keychain 提供了更高的安全性&#xff0c;因为它对数据进行了加密&#xff0c;并且只有经过授权的应用程序才…

js ul li 事件委托

<ul><li>1111111111</li><li>2222222222</li><li>3333333333</li><li>4444444444</li> </ul>常规的 li 绑定点击事件 document.querySelectorAll(ul li).forEach((li) > {li.addEventListener(click, functio…