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;
  });
}
相关推荐
xiaoqi92212 分钟前
React Native鸿蒙跨平台如何实现分类页面组件通过searchQuery状态变量管理搜索输入,实现了分类的实时过滤功能
javascript·react native·react.js·ecmascript·harmonyos
打小就很皮...25 分钟前
Tesseract.js OCR 中文识别
前端·react.js·ocr
qq_1777673735 分钟前
React Native鸿蒙跨平台实现应用介绍页,实现了应用信息卡片展示、特色功能网格布局、权限/联系信息陈列、评分展示、模态框详情交互等通用场景
javascript·react native·react.js·ecmascript·交互·harmonyos
2603_9494621041 分钟前
Flutter for OpenHarmony社团管理App实战:预算管理实现
android·javascript·flutter
wuhen_n1 小时前
JavaScript内存管理与执行上下文
前端·javascript
Hi_kenyon1 小时前
理解vue中的ref
前端·javascript·vue.js
jin1233222 小时前
基于React Native鸿蒙跨平台地址管理是许多电商、外卖、物流等应用的重要功能模块,实现了地址的添加、编辑、删除和设置默认等功能
javascript·react native·react.js·ecmascript·harmonyos
2501_920931702 小时前
React Native鸿蒙跨平台医疗健康类的血压记录,包括收缩压、舒张压、心率、日期、时间、备注和状态
javascript·react native·react.js·ecmascript·harmonyos
落霞的思绪3 小时前
配置React和React-dom为CDN引入
前端·react.js·前端框架
Hacker_Z&Q3 小时前
CSS 笔记2 (属性)
前端·css·笔记