Vue 项目部署在子目录下时hash vs history 的真实区别解析
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、先说结论</a></li><li><a href="#_label1">二、hash 和 history 的 URL 本质区别</a></li><li><a href="#_label2">三、子目录 + hash:为什么几乎不会出问题?</a></li><li><a href="#_label3">四、子目录 + history:为什么容易翻车?</a></li><li><a href="#_label4">五、history 模式在子目录下必须做哪些配置?</a></li><li><a href="#_label5">六、hash vs history:子目录下的真实对比</a></li><li><a href="#_label6">七、什么时候才应该用 history?</a></li><li><a href="#_label7">八、推荐配置(子目录)</a></li><li><a href="#_label8">九、总结</a></li></ul></div><p>在 Vue 项目部署中, <strong>子目录部署</strong>是一个非常常见、但也非常容易踩坑的场景,例如:</p><div class="jb51code"><pre class="brush:js;">http://ip:port/wvp/
</pre></div>
<p>而不是默认的:</p>
<div class="jb51code"><pre class="brush:js;">http://ip:port/
</pre></div>
<p>这时,Vue Router 的 <strong>hash 模式</strong> 和 <strong>history 模式</strong> 在行为上会出现<strong>本质区别</strong>。</p>
<p class="maodian"><a name="_label0"></a></p><h2>一、先说结论</h2>
<p>在子目录(如 <code>/wvp/</code>)下部署 Vue 项目:</p>
<ul><li>✅ hash 模式:稳定、省心,几乎不需要后端配合</li><li>⚠️ history 模式:必须配合后端 / Nginx,否则刷新必 404</li></ul>
<p>如果是<strong>内部系统 / 后台管理系统</strong>,<strong>强烈推荐 hash 模式</strong>。</p>
<p class="maodian"><a name="_label1"></a></p><h2>二、hash 和 history 的 URL 本质区别</h2>
<p>1️⃣ hash 模式</p>
<div class="jb51code"><pre class="brush:js;">/wvp/#/dashboard
</pre></div>
<p>特点:</p>
<ul><li><code>#</code> 后面的内容 <strong>不会发送给服务器</strong></li><li>属于浏览器行为</li><li>前端路由完全由 Vue 接管</li></ul>
<p><strong>2️⃣ history 模式</strong></p>
<div class="jb51code"><pre class="brush:js;">/wvp/dashboard
</pre></div>
<p>特点:</p>
<ul><li><strong>完整路径会发送给服务器</strong></li><li>服务器必须知道如何处理这个路径</li></ul>
<p class="maodian"><a name="_label2"></a></p><h2>三、子目录 + hash:为什么几乎不会出问题?</h2>
<p><strong>访问流程解析</strong></p>
<p>当访问:</p>
<div class="jb51code"><pre class="brush:js;">http://ip:port/wvp/#/dashboard
</pre></div>
<p>浏览器与服务器的交互是:</p>
<div class="jb51code"><pre class="brush:js;">浏览器请求 → /wvp/
服务器返回 → index.html
Vue Router 解析 → #/dashboard
</pre></div>
<p>👉 服务器永远只看到 <code>/wvp/</code></p>
<p><strong>hash 模式的优势</strong></p>
<ul><li>刷新页面不会 404</li><li>浏览器直接访问任意路由都正常</li><li>后端 / Nginx <strong>无需任何额外配置</strong></li></ul>
<p>📌 <strong>子目录部署下,hash 模式天生安全</strong></p>
<p class="maodian"><a name="_label3"></a></p><h2>四、子目录 + history:为什么容易翻车?</h2>
<p><strong>访问流程解析</strong></p>
<p>访问:</p>
<div class="jb51code"><pre class="brush:js;">http://ip:port/wvp/dashboard
</pre></div>
<p>服务器接收到的是:</p>
<div class="jb51code"><pre class="brush:js;">/wvp/dashboard
</pre></div>
<p>如果服务器没有配置该路径:</p>
<div class="jb51code"><pre class="brush:js;">→ 找不到资源
→ 返回 404
</pre></div>
<p>❌ 页面刷新 404<br />❌ 浏览器直接访问 404<br />❌ 前进 / 后退偶发 404</p>
<p class="maodian"><a name="_label4"></a></p><h2>五、history 模式在子目录下必须做哪些配置?</h2>
<p><strong>1️⃣ 前端配置(缺一不可)</strong></p>
<div class="jb51code"><pre class="brush:js;">// vue.config.js
module.exports = {
publicPath: '/wvp/'
}</pre></div>
<div class="jb51code"><pre class="brush:js;">// router/index.js
const router = new VueRouter({
mode: 'history',
base: '/wvp/',
routes
})</pre></div>
<p>2️⃣ Nginx / 后端配置(核心)</p>
<p>Nginx 示例</p>
<div class="jb51code"><pre class="brush:js;">location /wvp/ {
try_files $uri $uri/ /wvp/index.html;
}
</pre></div>
<p>含义:</p>
<ul><li>如果是静态资源 → 正常返回</li><li>如果不是 → 统一返回 <code>index.html</code></li><li>由 Vue Router 接管路由</li></ul>
<p><strong>如果没有这一步会怎样?</strong></p>
<div class="jb51code"><pre class="brush:js;">/wvp/dashboard → Nginx找文件 → 找不到 → 404
</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>六、hash vs history:子目录下的真实对比</h2>
<table><thead><tr><th>对比项</th><th>hash 模式</th><th>history 模式</th></tr></thead><tbody><tr><td>子目录部署</td><td>✅ 非常稳</td><td>⚠️ 易翻车</td></tr><tr><td>是否依赖后端</td><td>❌ 不需要</td><td>✅ 必须</td></tr><tr><td>页面刷新</td><td>✅ 永不 404</td><td>❌ 不配就 404</td></tr><tr><td>URL 美观</td><td>❌ 有 #</td><td>✅ 干净</td></tr><tr><td>SEO</td><td>❌ 差</td><td>✅ 好</td></tr><tr><td>运维成本</td><td>⭐ 低</td><td>⭐⭐⭐ 高</td></tr></tbody></table>
<p class="maodian"><a name="_label6"></a></p><h2>七、什么时候才应该用 history?</h2>
<ul><li>对外网站</li><li>需要 SEO</li><li>需要分享干净 URL</li><li>后端 / Nginx 完全可控</li></ul>
<p>否则:</p>
<blockquote><p><strong>子目录部署 + 内部系统 → hash 是最优解</strong></p></blockquote>
<p class="maodian"><a name="_label7"></a></p><h2>八、推荐配置(子目录)</h2>
<div class="jb51code"><pre class="brush:js;">// vue.config.js
module.exports = {
publicPath: '/wvp/'
}
</pre></div>
<div class="jb51code"><pre class="brush:js;">// router/index.js
export default new VueRouter({
mode: 'hash',
base: '/wvp/',
routes
})
</pre></div>
<p>✅ 不依赖后端<br />✅ 刷新不炸<br />✅ 部署简单</p>
<p class="maodian"><a name="_label8"></a></p><h2>九、总结</h2>
<blockquote><p>hash 是“工程优先”<br />history 是“美观优先”</p></blockquote>
<p>在子目录部署场景下,<strong>稳定永远比好看重要</strong>。</p>
頁:
[1]