我从 api 接收文件 URL 作为响应。当用户点击下载按钮时,文件应该在新的选项卡中不打开文件预览就可以下载。如何在反应中实现这一点?
这与反应无关。但是,可以使用锚 <a>元素上的 download属性告诉浏览器下载该文件。
<a>
download
<a href='/somefile.txt' download>Click to download</a>
并非所有浏览器都支持这一点: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
从前端触发浏览器下载是不可靠的。
您应该做的是,在服务器上创建一个端点,该端点在被调用时,用正确的响应头进行响应,从而触发浏览器下载。
前端代码只能做这么多。例如,“ download”属性可能会根据浏览器和文件类型在新的选项卡中打开文件。
您需要查看的响应头是 Content-Type和 Content-Disposition。您应该检查这个 回答以获得关于这些头的更详细的解释。
Content-Type
Content-Disposition
浏览器足够聪明,能够在不使用 download 属性的情况下单击锚标记时检测到链接并直接下载它。
在从 api 获得文件链接之后,只需通过创建锚标记使用普通的 javascript,并在动态地立即点击它之后删除它。
const link = document.createElement('a'); link.href = `your_link.pdf`; document.body.appendChild(link); link.click(); document.body.removeChild(link);
如果你正在使用 React 路由器,请使用以下命令:
<Link to="/files/myfile.pdf" target="_blank" download>Download</Link>
其中 /files/myfile.pdf在您的 public文件夹中。
/files/myfile.pdf
public
您可以定义一个组件并在任何地方使用它。
import React from 'react'; import PropTypes from 'prop-types'; export const DownloadLink = ({ to, children, ...rest }) => { return ( <a {...rest} href={to} download > {children} </a> ); }; DownloadLink.propTypes = { to: PropTypes.string, children: PropTypes.any, }; export default DownloadLink;
React 在使用 a标签和 target="_blank"时会出现安全问题。
a
target="_blank"
我设法让它像这样工作:
<a href={uploadedFileLink} target="_blank" rel="noopener noreferrer" download> <Button> <i className="fas fa-download"/> Download File </Button> </a>
我在《反应》中是这样做的:
import MyPDF from '../path/to/file.pdf'; <a href={myPDF} download="My_File.pdf"> Download Here </a>
使用 download="name_of_file_you_want.pdf"覆盖默认文件名很重要,否则在下载时文件将获得附加到它的散列号。
download="name_of_file_you_want.pdf"
我也有同样的问题,下面是我现在使用的解决方案: (注意,这对我来说似乎很理想,因为它将文件紧密地绑定到从 Amazon S3加载的 SinglePageApplicationReact 应用程序。因此,它就像是存储在 S3上,在应用程序中,相对而言,它知道自己在 S3中的位置。
3个步骤:
npm install file-saver
resource
asset
index.html
import FileSaver from 'file-saver'; FileSaver.saveAs( process.env.PUBLIC_URL + "/resource/file.anyType", "fileNameYouWishCustomerToDownLoadAs.anyType");
react-router
Link
style={color: inherit}
button button-primary
你可以使用 FileSaver.js来实现这个目标:
const saveFile = () => { fileSaver.saveAs( process.env.REACT_APP_CLIENT_URL + "/resources/cv.pdf", "MyCV.pdf" );
};
<button className="cv" onClick={saveFile}> Download File </button>
Tldr; 从 URL 获取文件,将其存储为本地 Blob,将 link 元素注入 DOM,然后单击它下载 Blob
我有一个 PDF 文件,它存储在 S3中的 Cloudfront URL 后面。我希望用户能够点击一个按钮和 马上启动下载,而不会弹出一个新的标签页与 PDF 预览。通常,如果一个文件驻留在一个 URL 上,该 URL 的域与用户当前所在的站点不同,出于用户安全原因,许多浏览器会阻止立即下载。如果使用此解决方案,则 不要启动文件下载,除非用户单击按钮故意下载。
为了解决这个问题,我需要绕过 CORS 策略从 URL 中获取文件,以保存本地 Blob,然后将其作为下载文件的源。在下面的代码中,确保交换自己的 fileURL、 Content-Type和 FileName。
fileURL
FileName
fetch('https://cors-anywhere.herokuapp.com/' + fileURL, { method: 'GET', headers: { 'Content-Type': 'application/pdf', }, }) .then((response) => response.blob()) .then((blob) => { // Create blob link to download const url = window.URL.createObjectURL( new Blob([blob]), ); const link = document.createElement('a'); link.href = url; link.setAttribute( 'download', `FileName.pdf`, ); // Append to html link element page document.body.appendChild(link); // Start download link.click(); // Clean up and remove the link link.parentNode.removeChild(link); });
这个解决方案参考了 从一个 URL 获取一个斑点和 使用 CORS 代理的解决方案。
更新 从 2021年1月31日开始,Heroku 服务器上托管的 cors-where 演示将只允许有限的测试用途,不能用于生产应用程序。您必须遵循 任何地方或 Cors-server托管您自己的 cors-where 服务器。
解决方案 (工作完美的反应 JS,下一个 JS)
你可以使用 Js-file-download,这是我的例子:
import axios from 'axios' import fileDownload from 'js-file-download' ... handleDownload = (url, filename) => { axios.get(url, { responseType: 'blob', }) .then((res) => { fileDownload(res.data, filename) }) } ... <button onClick={() => {this.handleDownload('https://your-website.com/your-image.jpg', 'test-download.jpg') }}>Download Image</button>
这个插件可以下载 Excel 和其他文件类型。
我们可以使用用户反应-下载-链接组件将内容作为文件下载。
<DownloadLink label="Download" filename="fileName.txt" exportFile={() => "Client side cache data here…"}/>
Https://frugalisminds.com/how-to-download-file-in-react-js-react-download-link/
对于下载,你可以使用多种方法,如上所述,此外,我也将提供我的策略,这个场景。
npm install --save react-download-link
import DownloadLink from "react-download-link";
<DownloadLink label="Download" filename="fileName.txt" exportFile={() => "Client side cache data here…"} />
<DownloadLink label="Download with Promise" filename="fileName.txt" exportFile={() => Promise.resolve("cached data here …")} />
getDataFromURL = (url) => new Promise((resolve, reject) => { setTimeout(() => { fetch(url) .then(response => response.text()) .then(data => { resolve(data) }); }); }, 2000);
<DownloadLink label=”Download” filename=”filename.txt” exportFile={() => Promise.resolve(this. getDataFromURL (url))} />
fetchFile(){ axios({ url: `/someurl/thefiles/${this.props.file.id}`, method: "GET", headers: headers, responseType: "blob" // important }).then(response => { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement("a"); link.href = url; link.setAttribute( "download", `${this.props.file.name}.${this.props.file.mime}` ); document.body.appendChild(link); link.click(); // Clean up and remove the link link.parentNode.removeChild(link); }); } render(){ return( <button onClick={this.fetchFile}> Download file </button>) }
解决我下载链接问题的软件包是:
Npm install —— save response-download-link
像这样使用它:
fileDownload(axiosResponse.data, 'filename.csv');
您可以在后端创建如下 C # Web API 端点:
[HttpGet("GenerateSitemap")] public async Task<IActionResult> GenerateSitemap() { var sitemapString = "[place-xml-sitemap-string-here]"; var serializedObj = JsonConvert.SerializeObject(obj); var bytesObj = Encoding.UTF8.GetBytes(serializedObj); return File(sitemapString.SerializeToByteArray(), "application/octet-stream"); }
import resume from '../assets/data/resume.pdf';
<a href={resume} download="YourName resume.pdf"> Download CV </a>
最好的快速解决方案:
window.open('https://myapi.com/download/file-name')
我已经试过这个 DownloadLink,它从 API 中获取数据,我可以使用 dev 工具看到这一点,但它不会触发文件下载。知道我错过了什么吗?
这就是我用过的方法:
getDataFromURL = (url) => new Promise((resolve, reject) => { setTimeout(() => { fetch(url) .then(response => response.text()) .then(data => { resolve(data) }); }); });
很多好的答案,我认为布莱恩李的答案是好的。要挑剔的是,获取中的 Content-Type 用于当您将 发送中数据传送到服务器而没有接收到时。
对于那些还没有重新加载的持久应用程序来说,确保在使用链接之后执行 URL.revokeObjectURL (url)也很重要。如果您不再使用该链接,也应该删除该链接:))