http接口响应头类型不对,导致svg图片无法预览,前端解决方案

场景描述:

项目开发初期,对于一些资源上传功能和产品经理沟通过,图片类是png、jpg两个格式,所以上传组件开发也是只限制了这两个格式文件,那么到了生产环境客户给的格式是svg,其实到这里给前端也没多大影响加个type就行,那么问题就来了,在预览图片的时候图片无法加载显示???

问题分析:图片 -> 接口 -> redis服务 -> 文件链接url -> 浏览器预览

png/jpg文件这一套流程都没问题,那么问题就是出在svg上

对比了解得知:

PNG - 纯二进制格式
  • 纯粹的图像数据
  • 浏览器只能将其作为图片处理
  • 没有其他用途,所以默认就是预览

SVG - 文本格式的 XML

arduino 复制代码
<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" fill="red" />
</svg>
  • 既是图片,也是可读的文本文件
  • 可能包含脚本和样式,有安全考虑
  • 服务器可能出于安全原因强制下载

浏览器在预览的处理策略

PNG 的处理:

xml 复制代码
<!-- 浏览器看到 PNG 只会尝试渲染为图片 -->
<img src="image.png" alt="示例">

SVG 的处理:

浏览器需要决定:

  • 是作为图片渲染?
  • 是作为 XML 文档显示源代码?
  • 还是因为有安全风险而强制下载?

并且对比接口响应头

后端服务返回的是 content-type: application/json

能够正确预览的情况下应该是 Content-Type: image/svg+xml

所以浏览器识别到不对的响应头会去触发强制下载,img标签预览地址限制所以无法加载预览

前端解决思路

既然svg预览不了,那我就把svg转成png

js 复制代码
// UI上就正常可以预览了

<el-table-column label="图片" prop="resUrl" align="center" :show-overflow-tooltip="true" width="300">
    <template slot-scope="scope">
      <el-image 
        style="width: 100px; height: 100px"
        :src="scope.row._previewUrl || scope.row.resUrl"
      >
      </el-image>
    </template>
</el-table-column>
js 复制代码
async svgUrlToPng(svgUrl, width = 100, height = 100) {
  const res = await fetch(svgUrl);
  const svgText = await res.text();
  const svgBase64 = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgText);
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = "anonymous";
    img.onload = () => {
      const canvas = document.createElement("canvas");
      canvas.width = width;
      canvas.height = height;
      const ctx = canvas.getContext("2d");
      ctx.drawImage(img, 0, 0, width, height);
      resolve(canvas.toDataURL("image/png"));
    };
    img.onerror = reject;
    img.src = svgBase64;
  });
}

getListData() {
  this.loading = true;
  getList(this.queryParams).then(async response => {
    const rows = response.rows;
    // 处理每一行
    for (let row of rows) {
      if (row.resUrl && row.resUrl.endsWith(".svg")) {
        try {
          row._previewUrl = await this.svgUrlToPng(row.resUrl, 100, 100);
        } catch (e) {
          console.error("SVG 转换失败:", e);
          row._previewUrl = row.resUrl; 
        }
      }
    }
    this.roleList = rows;
    this.total = response.total;
    this.loading = false;
  });
}
相关推荐
小恰学逆向2 分钟前
【爬虫JS逆向之旅】某球网参数“md5__1038”逆向
javascript·爬虫
竹林8182 分钟前
从“连接失败”到丝滑登录:我用 ethers.js v6 搞定 MetaMask 钱包连接的全过程
前端·javascript
oi..6 分钟前
《Web 安全入门|XSS 漏洞原理、CSP 策略与 HttpOnly 防护实践》
前端·网络·测试工具·安全·web安全·xss
UXbot16 分钟前
2026年AI全链路产品开发工具对比:5款从创意到上线一站式平台深度解析
前端·ui·kotlin·软件构建·swift·原型模式
一拳不是超人25 分钟前
前端工程师也要懂的服务器部署知识:从 Nginx 到 CI/CD
服务器·前端
AlkaidSTART30 分钟前
TanStack Query 技术指南:异步状态管理核心实践
前端·react.js
前端那点事31 分钟前
前端必看!JS高频实用案例(单行代码+实战场景+十大排序)
javascript
种花家的强总35 分钟前
前端项目开发/维护中降低成本的方式之一:降低耦合度
前端
Palpitate_LL43 分钟前
从XSS到“RCE“的PC端利用链构建
前端·xss
qq_334466861 小时前
Edge 浏览器不要提示还原页面
前端·edge