目录
Vue3+vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案
作者:watermelo37
CSDN万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者,全平台博客昵称watermelo37。
一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。
---------------------------------------------------------------------
温柔地对待温柔的人,包容的三观就是最大的温柔。
---------------------------------------------------------------------
Vue3+vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案
本篇博客旨在填补去年遇到的一个技术坑。去年遇到了这个问题只碰巧找到了一种解决方案,并没有确定错误发生的原因,今年更新项目重部署的时候又遇到了该问题,这次成功找到了根本原因,并且找到了多种解决方案,特此分享给大家,没看过去年博文的也没关系,这篇会详细介绍。
去年的博文重实践(不求甚解,只有一种解决方案),今年的博文重思维(求根问底,不同思路的解决方案)。欢迎读者按需阅读~
直接获取解决方案请点击:四、解决方案
去年博文传送门:
开发和内网部署正常,反向代理后出现404和图片加载失败的解决方案;部署到公网后报错404;部署到公网后图片加载出错;动态渲染获取图片失败_访问代理服务器图片加载不出来
一、情景介绍
1、问题出现的场景
最近开发一个前端项目,在开发环境和部署到内网的生产环境都没问题。将其反向代理到一个公网域名上,发现其他的内容没有问题,唯独部分图片资源无法加载,打开控制台,这部分图片资源请求状态码是404。
说实话这种情况非常令人迷惑,要是所有图片都无法加载那还好理解,可是我图片统一放在public文件夹,打包后也检查了确实都存在,然后部分图片无法获取,这是为什么呢?
2、无法加载的图片写法
经过检查,我发现直接写相对路径或者绝对路径都不会丢失图片资源,例如,以下写法都能正常加载图片:
<!-- 图片直接放在组件文件旁边的情况(放在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或者其他变量生成的动态路径,在反向代理后无法加载。要知道在开发环境和内网生产环境都没有问题,却在反向代理之后出错了,这是为什么呢?
举个会出错的例子:
<!-- 使用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错误。
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提前加载图片并将其存储到数组中。这样,动态渲染时只需要从已加载的图片数组中获取资源,避免了路径解析的问题。具体实现如下:
<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>
// 图片存放路径
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 路径,使其与反向代理的实际路径匹配。你可以还是按照原来的写法:
<!-- 使用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 选项:
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全面指南:从基础到进阶,掌握容器化构建的核心工具