强制<a download />下载图片而不是打开指向图片的链接

18

<a download='file' href="https://tinyjpg.com/images/social/website.jpg">
  Download
</a>

有没有一种方法可以强制下载文件,而不是在新窗口中打开文件?目前,如果文件是一个URL,比如下面的例子,它将不会被下载,而是会在新窗口中打开。

不,正如您运行它所看到的那样,它会打开一个新页面并显示图像,而不是下载它。 - gnifrus
你的代码应该可以工作。但是,你已经将下载重命名为“file”,如果它是jpg或图像,则可能需要在其上添加该文件扩展名。 - Dylan Wright
1
除了HTML5中已经提到的<a download>属性之外,浏览器的下载到磁盘行为也可以通过以下HTTP响应头来触发:Content-Disposition: attachment; filename=ProposedFileName.txt; 这是在HTML5之前的做法(并且仍然适用于支持HTML5的浏览器)。参考:https://dev59.com/jHE85IYBdhLWcg3wZyqt - Ivan-San
我尝试过了,它可以正常工作(使用另一个文件)... 你能使用一小段代码吗? - D. Pardal
3
这个问题的回答是否满意?如何在HTML中创建下载链接? - Yevhenii Bahmutskyi
显示剩余3条评论
5个回答

39

你可能会感到困扰,因为Firefox和Chrome 65+只支持同源下载链接,这可能是作为一种安全措施。

来源:https://caniuse.com/#feat=download(请参阅“已知问题”选项卡)

Web超文本应用技术工作组(WHATWG)建议,在跨源场景中(如您的示例),托管图像/文件的Web服务器需要发送Content-Disposition HTTP头以使download=得到尊重。

来源:https://html.spec.whatwg.org/multipage/links.html#downloading-resources


简而言之:

如果满足以下条件,你只能使用<a download='...'></a>来强制下载图片/文件:

  1. HTML图片/文件都托管在同一个域名下,
    或者
  2. HTML图片/文件位于不同的域名下,并且外部图片/文件服务器也通过Content-Disposition HTTP头字段表示应该下载。

3
感谢您的提问!我们的后端将文件托管在S3上,那么是否有一个Content-Disposition的设置可以允许下载呢?或者这个设置可以在我们的API中定义吗? - gnifrus
@gnifrus 应该从 AWS 设置。 - Humoyun Ahmad

2

也许你已经解决了,但是由于你将文件托管在 S3 上(请参见 Peter B 的回答中的评论),你需要使用 AWS SDK 给文件 URL 添加签名,并将 ResponseContentType 设置为 binary/octet-stream。我正在使用 Node,所以代码如下:

const promises = array.map((item) => {
        const promise = s3.getSignedUrlPromise('getObject', {
            Bucket: process.env.S3_BUCKET,
            Key: key, //filename
            Expires: 604800, //time to expire in seconds (optional)
            ResponseContentType: 'binary/octet-stream' 
        });

        return promise;
    });

    const links = await Promise.all(promises);

我希望这能有所帮助。

1
你可以使用这个函数来使用fetch下载图片。
async function downloadImage(imageSrc) {
  const image = await fetch(imageSrc)
  const imageBlog = await image.blob()
  const imageURL = URL.createObjectURL(imageBlog)

  const link = document.createElement('a')
  link.href = imageURL
  link.download = 'image file name here'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}

0

setTimeout(function() {
  
   url = 'https://media.sproutsocial.com/uploads/2017/02/10x-featured-social-media-image-size.png';
   // downloadFile(url); // UNCOMMENT THIS LINE TO MAKE IT WORK
  
}, 2000);

// Source: http://pixelscommander.com/en/javascript/javascript-file-download-ignore-content-type/
window.downloadFile = function (sUrl) {

    //iOS devices do not support downloading. We have to inform user about this.
    if (/(iP)/g.test(navigator.userAgent)) {
       //alert('Your device does not support files downloading. Please try again in desktop browser.');
       window.open(sUrl, '_blank');
       return false;
    }

    //If in Chrome or Safari - download via virtual link click
    if (window.downloadFile.isChrome || window.downloadFile.isSafari) {
        //Creating new link node.
        var link = document.createElement('a');
        link.href = sUrl;
        link.setAttribute('target','_blank');

        if (link.download !== undefined) {
            //Set HTML5 download attribute. This will prevent file from opening if supported.
            var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length);
            link.download = fileName;
        }

        //Dispatching click event.
        if (document.createEvent) {
            var e = document.createEvent('MouseEvents');
            e.initEvent('click', true, true);
            link.dispatchEvent(e);
            return true;
        }
    }

    // Force file download (whether supported by server).
    if (sUrl.indexOf('?') === -1) {
        sUrl += '?download';
    }

    window.open(sUrl, '_blank');
    return true;
}

window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;


4
请说明为什么这段代码是对问题的一个好解决方案,仅仅给出代码答案在 Stack Overflow 上是不被看好的。 - Marcello B.

-8

你的链接应该有一个ID来强制下载:

<a download='website.jpg' id='blablabla' href="https://tinyjpg.com/images/social/website.jpg">
  Download
</a>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接