【记载一次前端图片下载标题】办理跨域+直接下载

[复制链接]
发表于 2026-2-26 06:42:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
克日有个需求必要下载协议照片,使用的是阿里云的oss,由于无法调和后端那里设置跨域相应头,找了许多方案都不抱负,终于在探索下可以实现美满下载
常见方案有两个标题
1.图片格式(png,jpg等)不会触发下载,直接打开预览
2.跨域标题
先捋一下常见方案
方法一、a标签下载

a标签html5版本新增了download属性,用来告诉欣赏器下载该url,而不是导航到它,可以带属性值,用来作为生存文件时的文件名,只管说有同源限定,但是我实际测试时非同源的也是可以下载的。
对于没有设置Content-Disposition相应头大概设置为inline的图片来说,由于图片对于欣赏器来说是属于能打开的文件,以是并不会触发下载,而是直接打开,欣赏器不能预览的文件无论有没有Content-Disposition头都会触发生存:
  1. <!-- 直接打开 -->
  2. <a href="/test.jpg" download="test.jpg" target="_blank">jpg静态资源</a>
  3. <!-- 触发保存 -->
  4. <a href="/test.zip" download="test.pdf" target="_blank">zip静态资源</a>
  5. <!-- 触发保存 -->
  6. <a href="https://www.7-zip.org/a/7z1900-x64.exe" download="test.zip" target="_blank">三方exe静态资源</a>
  7. <!-- 直接打开 -->
  8. <!-- 直接打开 -->
  9. <a href="/getFileStream?name=test.jpg" download target="_blank">jpg流</a>
  10. <!-- 触发保存 -->
  11. <a href="/getFileStream?name=test.zip" download target="_blank">zip流</a>
  12. <!-- 触发保存 -->
  13. <a href="/getAttachmentFileStream?name=test.jpg" download target="_blank">附件jpg流</a>
  14. <!-- 触发保存 -->
  15. <a href="/getAttachmentFileStream?name=test.zip" download target="_blank">附件zip流</a>
复制代码
以是说如果想用a标签下载图片,那么要让后端加上Content-Disposition相应头,别的也必须以流的情势返回,跨域图片符合这个要求也可以下载,纵然相应没有答应跨域的头,但是静态图片纵然添加了这个头也是直接打开:
  1. // 经测试,浏览器仍然直接打开图片
  2. app.use(express.static('./public', {
  3.     setHeaders(res) {
  4.         res.attachment()
  5.     }
  6. }))
复制代码
和a标签方式雷同的还可以使用location.href:
  1. location.href = '/test.jpg'
  2. location.href = '/test.zip'
复制代码
活动和a标签完全划一。
这两种方式的缺点也很显着,一是不支持post等其他方式的哀求,二是必要后端支持。
方法二、base64格式下载

a标签支持data:协议的URL,使用这个可以让后端返回base64格式的字符串,然后使用download属性举行下载:
  1. <template>
  2.     <a :href="base64Img" download target="_blank">base64字符串</a>
  3. </template>
  4. <script>
  5. import axios from 'axios'
  6. export default {
  7.   data () {
  8.     return {
  9.       base64Img: ''
  10.     }
  11.   },
  12.   async created () {
  13.     let { data } = await axios.get('/createBase64QrCode?text=http://lxqnsys.com/')
  14.     this.base64Img = data
  15.   }
  16. }
  17. </script>
复制代码
这个方式就任意get照旧post哀求了,缺点是base64字符串大概会非常大,传输慢以及浪费流量,别的固然也得后端支持,必要同域或答应跨域。
方法三、blob格式下载

照旧a标签,它还支持blob:协议的URL,使用这个可以把相应范例设置为blob,然后和base64一样扔给a标签:
  1. <template>
  2.     <a :href="blobData" download target="_blank">blob</a>
  3. </template>
  4. <script>
  5. import axios from 'axios'
  6. export default {
  7.   data () {
  8.     return {
  9.       blobData: null,
  10.       blobDataName: ''
  11.     }
  12.   },
  13.   async created () {
  14.     let { data } = await axios.get('/test.jpg', {
  15.       responseType: 'blob'
  16.     })
  17.     const blobData = URL.createObjectURL(data)
  18.     this.blobData = blobData
  19.   }
  20. }
  21. </script>
复制代码
这个方式必要和上述几个必要通过ajax哀求的一样,都必要后端可控,即图片同域或支持跨域。
方法四、使用canvas下载

这个方法着实和方法二和方法三是雷同的,只是相当于把图片哀求方式换了一下:
  1. <template>
  2.   <a :href="canvasBase64Img" download target="_blank">canvas base64字符串</a>
  3.   <a :href="canvasBlobImg" download target="_blank">canvas blob</a>
  4. </template>
  5. <script>
  6.     export default {
  7.         data () {
  8.             return {
  9.                 canvasBase64Img: '',
  10.                 canvasBlobImg: null
  11.             }
  12.         },
  13.         created () {
  14.             const img = new Image()
  15.             // 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
  16.             img.setAttribute('crossOrigin', 'anonymous')
  17.             img.onload = () => {
  18.                 let canvas = document.createElement('canvas')
  19.                 canvas.width = img.width
  20.                 canvas.height = img.height
  21.                 let ctx = canvas.getContext('2d')
  22.                 // 图片绘制到canvas里
  23.                 ctx.drawImage(img, 0, 0, img.width, img.height)
  24.                 // 1.data:协议
  25.                 let data = canvas.toDataURL()
  26.                 this.canvasBase64Img = data
  27.                 // 2.blob:协议
  28.                 canvas.toBlob((blob) => {
  29.                     const blobData = URL.createObjectURL(blob)
  30.                     this.canvasBlobImg = blobData
  31.                 })
  32.             }
  33.             img.src = '/createQrCode?text=http://lxqnsys.com/'
  34.         }
  35.     }
  36. </script>
复制代码
img标签是可以跨域的,但是跨域的图片绘制到canvas里后无法导出,欣赏器会报错,可以给img添加crossOrigin属性,但是,如果图片没有答应跨域的头加了也没用。
方法五、表单情势下载

对于post哀求方式下载图片的话,除了使用上述的方法二和方法三之外,还可以使用form表单:
  1. <template>
  2.     <el-button type="primary" @click="formType">from表单下载</el-button>
  3.   </div>
  4. </template>
  5. <script>
  6. export default {
  7.   methods: {
  8.     formType () {
  9.       // 创建一个隐藏的表单
  10.       const form = document.createElement('form')
  11.       form.style.display = 'none'
  12.       form.action = '/getAttachmentFileStream'
  13.       // 发送post请求
  14.       form.method = 'post'
  15.       form.target = '_blank'
  16.       document.body.appendChild(form)
  17.       const params = {
  18.         name: 'test.jpg'
  19.       }
  20.       // 创建input来传递参数
  21.       for (let key in params) {
  22.         let input = document.createElement('input')
  23.         input.type = 'hidden'
  24.         input.name = key
  25.         input.value = params[key]
  26.         form.appendChild(input)
  27.       }
  28.       form.submit()
  29.       form.remove()
  30.     }
  31.   }
  32. }
  33. </script>
复制代码
使用该方式,图片流的相应头必要设置Content-Disposition,否则欣赏器也是直接打开图片,有该相应头的话跨域图片也可以下载,纵然图片不答应跨域。
方法六、ifrmae下载
document.execCommand有一个SaveAs下令,可以触发欣赏器的另存为活动,使用这个可以把图片加载到iframe里,然后通过iframe的document来触发该下令:
  1. <template>
  2.   <el-button type="primary" @click="iframeType">iframe下载</el-button>
  3. </template>
  4. <script>
  5.     export default {
  6.         methods: {
  7.             iframeType () {
  8.                 const iframe = document.createElement('iframe')
  9.                 iframe.style.display = 'none'
  10.                 iframe.onload = () => {
  11.                     iframe.contentWindow.document.execCommand('SaveAs')
  12.                     document.body.removeChild(iframe)
  13.                 }
  14.                 iframe.src = '/createQrCode?text=http://lxqnsys.com/'
  15.                 document.body.appendChild(iframe)
  16.             }
  17.         }
  18.     }
  19. </script>
复制代码
图片必须要是同源的,这种方式相识一下就行,由于它只在IE里被支持。
究极办理方案

  1. // 调用方式
  2. // 参数一: src
  3. // 参数二: 图片名称,可选
  4. const downloadImage = (imgsrc, name) => {
  5.   // 这里是核心,crossOrigin+带参数的可以解决跨域问题,少一个都会有问题
  6.   imgsrc = imgsrc + "?v=" + Math.random();
  7.   var image = new Image()
  8.   image.setAttribute('crossOrigin', 'anonymous')
  9.   image.onload = function () {
  10.     var canvas = document.createElement('canvas')
  11.     canvas.width = image.width
  12.     canvas.height = image.height
  13.     var context = canvas.getContext('2d')
  14.     context.drawImage(image, 0, 0, image.width, image.height)
  15.     var url = canvas.toDataURL('image/png') // 得到图片的base64编码数据
  16.     var a = document.createElement('a') // 生成一个a元素
  17.     var event = new MouseEvent('click') // 创建一个单击事件
  18.     a.download = name || 'photo' // 设置图片名称
  19.     a.href = url // 将生成的URL设置为a.href属性
  20.     a.dispatchEvent(event) // 触发a的单击事件
  21.   }
  22.   image.src = imgsrc
  23. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表