目錄
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、無法加載的圖片寫法
? ? ? ? 經過檢查,我發現直接寫相對路徑或者絕對路徑都不會丟失圖片資源,例如,以下寫法都能正常加載圖片:
<!-- 圖片直接放在組件文件旁邊的情況(放在assets文件夾同理) --><div class="fig-container"><img class="fig" src="./chaptersImgs/chapter2Fig1.png" alt="" /><p class="figTitle" align="center">圖2 指標體系構建思路圖</p>
</div><!-- 圖片放在public文件夾中的情況 -->
<imgsrc="/dataCenterLogo.png"style="height: 5.5vh;width: auto;margin-right: 0.7vw;"
/>
? ? ? ? 然而,只有v-for或者其他變量生成的動態路徑,在反向代理后無法加載。要知道在開發環境和內網生產環境都沒有問題,卻在反向代理之后出錯了,這是為什么呢?
????????舉個會出錯的例子:
<!-- 使用v-for動態渲染模塊,并填充圖片,動態生成圖片路徑的方式 --><el-row class="row" :gutter="0"><el-colv-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-colv-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-colv-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全面指南:從基礎到進階,掌握容器化構建的核心工具
????????在線編程實現!如何在Java后端通過DockerClient操作Docker生成python環境
??? ? ??干貨含源碼!如何用Java后端操作Docker(命令行篇)