Vue3+Vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案

目录

Vue3+vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案

一、情景介绍

1、问题出现的场景

2、无法加载的图片写法

二、反向代理原理简介

三、造成该现象的原因

四、解决方案

1、放弃动态渲染

2、在页面挂载的时候引入图片资源

3、修改base路径(最推荐)

五、总结


作者:watermelo37

CSDN万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者,全平台博客昵称watermelo37。

一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。


温柔地对待温柔的人,包容的三观就是最大的温柔。


Vue3+vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案

本篇博客旨在填补去年遇到的一个技术坑。去年遇到了这个问题只碰巧找到了一种解决方案,并没有确定错误发生的原因,今年更新项目重部署的时候又遇到了该问题,这次成功找到了根本原因,并且找到了多种解决方案,特此分享给大家,没看过去年博文的也没关系,这篇会详细介绍。

去年的博文重实践(不求甚解,只有一种解决方案),今年的博文重思维(求根问底,不同思路的解决方案)。欢迎读者按需阅读~

直接获取解决方案请点击:四、解决方案

去年博文传送门:

开发和内网部署正常,反向代理后出现404和图片加载失败的解决方案;部署到公网后报错404;部署到公网后图片加载出错;动态渲染获取图片失败_访问代理服务器图片加载不出来

一、情景介绍

1、问题出现的场景

最近开发一个前端项目,在开发环境和部署到内网的生产环境都没问题。将其反向代理到一个公网域名上,发现其他的内容没有问题,唯独部分图片资源无法加载,打开控制台,这部分图片资源请求状态码是404。

说实话这种情况非常令人迷惑,要是所有图片都无法加载那还好理解,可是我图片统一放在public文件夹,打包后也检查了确实都存在,然后部分图片无法获取,这是为什么呢?

2、无法加载的图片写法

经过检查,我发现直接写相对路径或者绝对路径都不会丢失图片资源,例如,以下写法都能正常加载图片:

html 复制代码
<!-- 图片直接放在组件文件旁边的情况(放在assets文件夹同理) -->
 
<div class="fig-container">
        <img class="fig" src="./chaptersImgs/chapter2Fig1.png" alt="" />
        <p class="figTitle" align="center">图2 指标体系构建思路图</p>
</div>
 
 
 
<!-- 图片放在public文件夹中的情况 -->
<img
    src="/dataCenterLogo.png"
    style="
        height: 5.5vh;
        width: auto;
        margin-right: 0.7vw;
          "
/>

然而,只有v-for或者其他变量生成的动态路径,在反向代理后无法加载。要知道在开发环境和内网生产环境都没有问题,却在反向代理之后出错了,这是为什么呢?

举个会出错的例子:

html 复制代码
      <!-- 使用v-for动态渲染模块,并填充图片,动态生成图片路径的方式 -->
      <el-row class="row" :gutter="0">
        <el-col
          v-for="(item, i) in urlReport"
          :span="6"
          class="chapter-col"
          justify="center"
          :key="i"
        >
          <div class="singleDownload" @click="downloadByUrl(item.url)">
            <div class="card-image-container">
              <img :src="'/download/report' + ( i + 1 ) + '.png'" class="card-image" />
            </div>
            <div class="description">
              {{ item.reportName }}
            </div>
          </div>
        </el-col>
      </el-row>

二、反向代理原理简介

反向代理的基本原理是,客户端的请求先发送到代理服务器,代理服务器再将请求转发给真实的后端服务。比如我将一个项目只部署到一个内网服务器上,同时反向代理到一个可公开访问的代理服务器上,这样用户只需要访问这个代理服务器,代理服务器就会将请求发送到内网的真实服务器上并获取相应资源。这样可以避免用户直接接触真实服务器。同时也可以通过一个域名挂载多个前端项目。

在前端项目中,反向代理通常用于跨域请求、资源代理等场景。当反向代理配置不当时,可能导致一些资源的路径错误,进而导致资源加载失败。

三、造成该现象的原因

问题的根源在于 Vite 的动态路径解析方式。在开发环境中,Vite 会根据根路径(base)自动解析资源路径,但当通过反向代理部署时,代理服务器可能会为项目添加一个子路由路径(根据nginx的配置来决定)。这个路径的变化影响了 Vite 对资源路径的解析,导致动态生成的路径与实际资源路径不一致,因此找不到对应的图片资源。

具体来说,当我们使用动态路径时,Vite 默认将其视为相对于项目根路径来解析,但当反向代理添加了子路由路径后,动态路径没有考虑到这个变化,最终导致图片无法加载。

以这个nginx配置为例,部署之后拼接的资源动态路径就是"域名+high+动态路由",可如果你的项目base目录是默认值或者"./",那资源的实际路径其实是"域名+动态路由",自然就会报404错误。

html 复制代码
server {
    listen 8001;
    server_name xxx.xx.xxx.xx;

    location /high/{
        alias E:/deploy/developmentV2.0-update2024report/; 
        try_files $uri $uri/ /project1/index.html;
    }
}

四、解决方案

为了解决这个问题,本文提供了三种不同思路的解决方案。欢迎大家根据自己的需求选择合适的方案,也欢迎在评论区分享其他解决思路。

1、放弃动态渲染

这个方案的思路比较简单:如果动态渲染无法正常加载图片,那么就放弃动态渲染,改为静态引用。属于是"解决不了问题,就解决产生问题的对象"。但它不适用于需要大量渲染、图片较多的场景,因此不具备长效解决问题的作用。

2、在页面挂载的时候引入图片资源

动态路径是在运行时才解析并加载图片资源。我们可以通过import提前加载图片并将其存储到数组中。这样,动态渲染时只需要从已加载的图片数组中获取资源,避免了路径解析的问题。具体实现如下:

html 复制代码
      <el-row class="row" :gutter="0">
        <el-col
          v-for="(item, i) in urlReport"
          :span="6"
          class="chapter-col"
          justify="center"
          :key="i"
        >
          <div class="singleDownload" @click="downloadByUrl(item.url)">
            <div class="card-image-container">
              <img :src="reportPic[i]" class="card-image" />
            </div>
            <div class="description">
              {{ item.reportName }}
            </div>
          </div>
        </el-col>
      </el-row>
javascript 复制代码
 
// 图片存放路径
const webPic = ref([]);
const reportPic = ref([]);
 
 
// 异步加载图片
Promise.all([import("/download/web1.png"), import("/download/web2.png")]).then(
  (images) => {
    webPic.value = images.map((image) => image.default);
  }
);
Promise.all([
  import("/download/report1.png"),
  import("/download/report2.png"),
  import("/download/report3.png"),
  import("/download/report4.png"),
  import("/download/report5.png"),
  import("/download/report6.png"),
  import("/download/report7.png"),
  // import("/download/report8.png"),
  import("/download/report9.png"),
  import("/download/report10.png"),
  import("/download/report11.png"),
  import("/download/report12.png"),
  import("/download/report13.png"),
]).then((images) => {
  reportPic.value = images.map((image) => image.default);
});

在构建时,Vite 会处理这些图片资源,并将其打包到最终的构建目录中。import 会返回一个模块对象,其中 default 属性包含了图片的实际路径,所以不受base路径变化的影响。

简单点说,不管你的开发环境base路径是什么,生产环境base路径是什么,你都可以用这种方法批量获得路径。

3、修改base路径(最推荐)

既然我们已经知道了问题的原因,最直接的解决办法是修改 Vite 的 base 路径,使其与反向代理的实际路径匹配。你可以还是按照原来的写法:

html 复制代码
      <!-- 使用v-for动态渲染模块,并填充图片,动态生成图片路径的方式 -->
      <el-row class="row" :gutter="0">
        <el-col
          v-for="(item, i) in urlReport"
          :span="6"
          class="chapter-col"
          justify="center"
          :key="i"
        >
          <div class="singleDownload" @click="downloadByUrl(item.url)">
            <div class="card-image-container">
              <img :src="'/download/report' + ( i + 1 ) + '.png'" class="card-image" />
            </div>
            <div class="description">
              {{ item.reportName }}
            </div>
          </div>
        </el-col>
      </el-row>

然后在 vite.config.js 中配置 base 选项:

javascript 复制代码
export default defineConfig({
    base: '/你的子路径/'
});

这里的子路径是由反向代理的路由决定的。比如你的域名是www.jd.com你将项目反向代理到www.jd.com/newProject上,那么base的值就是"/newProject/"。这里其实就是老生常谈的**"开发环境应与生产环境一致"** 的体现**。**

五、总结

回头来看,这其实是一个很简单的问题,只需要遵守开发环境应与生产环境一致的原则就好了,可是在我真正做一次部署之前是没法深刻理解这句话的含义的,不吃一堑就是不长一智,那能怎么办呢?去年我甚至都没意识到根本问题出在哪,只是找到了一种解决方案(上述第二种)。希望我这篇博客能帮助大家理解这句话,或者在犯了错的时候找到解决方案。

本篇博文详细分析了 Vue3 + Vite 前端项目在反向代理部署后,部分图片(动态路径图片)无法加载的问题。通过分析问题的原因,并结合三种解决方案(放弃动态渲染、提前引入图片资源、修改 base 路径),我们可以有效地解决这一问题。希望本篇文章能为大家解决类似问题提供帮助。

只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

其他热门文章,请关注:

极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

通过array.filter()实现数组的数据筛选、数据清洗和链式调用

通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能

通过MongoDB Atlas 实现语义搜索与 RAG------迈向AI的搜索机制

TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急

深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

MutationObserver详解+案例------深入理解 JavaScript 中的 MutationObserver

Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具

在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境

干货含源码!如何用Java后端操作Docker(命令行篇)

相关推荐
朝阳58135 分钟前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路43 分钟前
GeoTools 读取影像元数据
前端
ssshooter1 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
Jerry2 小时前
Jetpack Compose 中的状态
前端
dae bal3 小时前
关于RSA和AES加密
前端·vue.js
柳杉3 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化
lynn8570_blog3 小时前
低端设备加载webp ANR
前端·算法
LKAI.3 小时前
传统方式部署(RuoYi-Cloud)微服务
java·linux·前端·后端·微服务·node.js·ruoyi
数据超市3 小时前
香港数据合集:建筑物、手机基站、POI、职住数据、用地类型
大数据·人工智能·智能手机·数据挖掘·数据分析
刺客-Andy4 小时前
React 第七十节 Router中matchRoutes的使用详解及注意事项
前端·javascript·react.js