图片 URL 直接下载

实现点击图片链接触发下载而非预览

问题

访问一个图片 URL 时,浏览器默认会直接预览图片。如何实现点击后直接下载?

解答

方案一:使用 download 属性(同源限制)

<!-- 仅对同源图片有效 -->
<a href="/images/photo.jpg" download="photo.jpg">下载图片</a>

方案二:Fetch + Blob 下载(推荐)

function downloadImage(url, filename) {
  fetch(url)
    .then(response => response.blob())
    .then(blob => {
      // 创建 Blob URL
      const blobUrl = URL.createObjectURL(blob);
      
      // 创建隐藏的 a 标签
      const link = document.createElement('a');
      link.href = blobUrl;
      link.download = filename || 'image.jpg';
      
      // 触发点击下载
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      
      // 释放 Blob URL
      URL.revokeObjectURL(blobUrl);
    })
    .catch(err => console.error('下载失败:', err));
}

// 使用
downloadImage('https://example.com/photo.jpg', 'my-photo.jpg');

方案三:后端设置响应头

// Node.js Express 示例
app.get('/download', (req, res) => {
  const imageUrl = req.query.url;
  
  res.setHeader('Content-Type', 'application/octet-stream');
  res.setHeader('Content-Disposition', 'attachment; filename="image.jpg"');
  
  // 代理图片流
  request(imageUrl).pipe(res);
});

方案四:Canvas 转换下载

function downloadViaCanvas(imgUrl, filename) {
  const img = new Image();
  img.crossOrigin = 'anonymous'; // 处理跨域
  
  img.onload = () => {
    const canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;
    
    const ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0);
    
    // 转为 Blob 并下载
    canvas.toBlob(blob => {
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = filename;
      link.click();
      URL.revokeObjectURL(url);
    });
  };
  
  img.src = imgUrl;
}

关键点

  • download 属性受同源策略限制,跨域图片无效
  • Fetch + Blob 方案需要服务器支持 CORS
  • Content-Disposition: attachment 响应头可强制下载
  • Canvas 方案需要图片服务器设置 Access-Control-Allow-Origin
  • 下载后记得调用 URL.revokeObjectURL() 释放内存