Vue3+Vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案
Vue3+vite前端项目部署后部分图片资源无法获取、动态路径图片资源报404错误的原因及解决方案
代码语言:txt复制 本篇博客旨在填补去年遇到的一个技术坑。去年遇到了这个问题只碰巧找到了一种解决方案,并没有确定错误发生的原因,今年更新项目重部署的时候又遇到了该问题,这次成功找到了根本原因,并且找到了多种解决方案,特此分享给大家,没看过去年博文的也没关系,这篇会详细介绍。
代码语言:txt复制 去年的博文重实践(不求甚解,只有一种解决方案),今年的博文重思维(求根问底,不同思路的解决方案)。欢迎读者按需阅读~
代码语言:txt复制 直接获取解决方案请点击:四、解决方案
代码语言:txt复制 去年博文传送门:
开发和内网部署正常,反向代理后出现404和图片加载失败的解决方案;部署到公网后报错404;部署到公网后图片加载出错;动态渲染获取图片失败_访问代理服务器图片加载不出来
一、情景介绍
1、问题出现的场景
代码语言:txt复制 最近开发一个前端项目,在开发环境和部署到内网的生产环境都没问题。将其反向代理到一个公网域名上,发现其他的内容没有问题,唯独**部分图片资源**无法加载,打开控制台,这部分图片资源请求状态码是404。
代码语言:txt复制 说实话这种情况非常令人迷惑,要是所有图片都无法加载那还好理解,可是我图片统一放在public文件夹,打包后也检查了确实都存在,然后部分图片无法获取,这是为什么呢?
2、无法加载的图片写法
代码语言:txt复制 经过检查,我发现直接写相对路径或者绝对路径都不会丢失图片资源,例如,以下写法都能正常加载图片:
代码语言:javascript代码运行次数:0运行复制<!-- 图片直接放在组件文件旁边的情况(放在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;
"
/>
代码语言:txt复制 然而,只有v-for或者其他变量生成的**动态路径**,在反向代理后无法加载。要知道在开发环境和内网生产环境都没有问题,却在反向代理之后出错了,这是为什么呢?
代码语言:txt复制 举个会出错的例子:
代码语言:javascript代码运行次数:0运行复制 <!-- 使用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>
二、反向代理原理简介
代码语言:txt复制 反向代理的基本原理是,客户端的请求先发送到代理服务器,代理服务器再将请求转发给真实的后端服务。比如我将一个项目只部署到一个内网服务器上,同时反向代理到一个可公开访问的代理服务器上,这样用户只需要访问这个代理服务器,代理服务器就会将请求发送到内网的真实服务器上并获取相应资源。这样可以避免用户直接接触真实服务器。同时也可以通过一个域名挂载多个前端项目。
代码语言:txt复制 在前端项目中,反向代理通常用于跨域请求、资源代理等场景。当反向代理配置不当时,可能导致一些资源的路径错误,进而导致资源加载失败。
三、造成该现象的原因
代码语言:txt复制 问题的根源在于 Vite 的动态路径解析方式。在开发环境中,Vite 会根据根路径(base)自动解析资源路径,但当通过反向代理部署时,代理服务器可能会为项目添加一个子路由路径(根据nginx的配置来决定)。这个路径的变化影响了 Vite 对资源路径的解析,导致动态生成的路径与实际资源路径不一致,因此找不到对应的图片资源。
代码语言:txt复制 具体来说,当我们使用动态路径时,Vite 默认将其视为相对于项目根路径来解析,但当反向代理添加了子路由路径后,动态路径没有考虑到这个变化,最终导致图片无法加载。
代码语言:txt复制 以这个nginx配置为例,部署之后拼接的资源动态路径就是“域名+high+动态路由”,可如果你的项目base目录是默认值或者“./”,那资源的实际路径其实是“域名+动态路由”,自然就会报404错误。
代码语言:javascript代码运行次数:0运行复制server {
listen 8001;
server_name xxx.xx.xxx.xx;
location /high/{
alias E:/deploy/developmentV2.0-update2024report/;
try_files $uri $uri/ /project1/index.html;
}
}
四、解决方案
代码语言:txt复制 为了解决这个问题,本文提供了三种不同思路的解决方案。欢迎大家根据自己的需求选择合适的方案,也欢迎在评论区分享其他解决思路。
1、放弃动态渲染
代码语言:txt复制 这个方案的思路比较简单:如果动态渲染无法正常加载图片,那么就放弃动态渲染,改为静态引用。属于是“解决不了问题,就解决产生问题的对象”。但它不适用于需要大量渲染、图片较多的场景,因此不具备长效解决问题的作用。
2、在页面挂载的时候引入图片资源
代码语言:txt复制 动态路径是在运行时才解析并加载图片资源。我们可以通过import提前加载图片并将其存储到数组中。这样,动态渲染时只需要从已加载的图片数组中获取资源,避免了路径解析的问题。具体实现如下:
代码语言:javascript代码运行次数:0运行复制 <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代码运行次数:0运行复制// 图片存放路径
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路径变化的影响。
代码语言:txt复制 简单点说,不管你的开发环境base路径是什么,生产环境base路径是什么,你都可以用这种方法批量获得路径。
3、修改base路径(最推荐)
代码语言:txt复制 既然我们已经知道了问题的原因,最直接的解决办法是修改 Vite 的 base 路径,使其与反向代理的实际路径匹配。你可以还是按照原来的写法:
代码语言:javascript代码运行次数:0运行复制 <!-- 使用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>
代码语言:txt复制 然后在 vite.config.js 中配置 base 选项:
代码语言:javascript代码运行次数:0运行复制export default defineConfig({
base: '/你的子路径/'
});
代码语言:txt复制 这里的子路径是由反向代理的路由决定的。比如你的域名是www.jd,你将项目反向代理到www.jd/newProject上,那么base的值就是"/newProject/"。这里其实就是老生常谈的**“开发环境应与生产环境一致”**的体现**。**
五、总结
代码语言:txt复制 回头来看,这其实是一个很简单的问题,只需要遵守开发环境应与生产环境一致的原则就好了,可是在我真正做一次部署之前是没法深刻理解这句话的含义的,不吃一堑就是不长一智,那能怎么办呢?去年我甚至都没意识到根本问题出在哪,只是找到了一种解决方案(上述第二种)。希望我这篇博客能帮助大家理解这句话,或者在犯了错的时候找到解决方案。
代码语言:txt复制 本篇博文详细分析了 Vue3 + Vite 前端项目在反向代理部署后,部分图片(动态路径图片)无法加载的问题。通过分析问题的原因,并结合三种解决方案(放弃动态渲染、提前引入图片资源、修改 base 路径),我们可以有效地解决这一问题。希望本篇文章能为大家解决类似问题提供帮助。
代码语言:txt复制 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-04-14,如有侵权请联系 cloudcommunity@tencent 删除解决方案前端图片资源vite部署