web学习笔记编程技术学习与分享
首页 / 前端开发 / 正文

前端路由的两种实现:hash 与 history

2026 年 07 月 10 日约 3 分钟阅读 前端开发

单页应用切换视图时不重新请求 HTML,但浏览器的地址栏、前进后退、刷新都要正常工作。hash 和 history 是两条不同的实现路径。

hash 模式

地址形如 example.com/#/user/1。# 后面是片段标识符,改变它不会触发页面请求,浏览器只抛出 hashchange 事件。

window.addEventListener('hashchange', () => {
  const path = location.hash.slice(1) || '/';
  render(path);
});

优点:服务端零配置,刷新永远回到 index.html。缺点:URL 里有个 #,对 SEO 不友好,部分统计工具也会把它截断。

history 模式

用 pushState 修改地址,不触发请求:

history.pushState({ page: 1 }, '', '/user/1');
window.addEventListener('popstate', () => render(location.pathname));

优点:URL 干净,像传统多页站点。缺点:刷新会真的向服务器请求 /user/1,如果服务器没有对应文件,就是 404。

解决方式是在服务端把未匹配的路径统一回退到入口文件:

# Apache
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

Nginx 对应的是 try_files $uri $uri/ /index.html;。

容易忽略的细节

  • pushState 不会触发 popstate,前进后退才会。所以路由跳转要手动调用渲染。
  • 需要拦截站内 <a> 点击,否则整页刷新;
  • 滚动位置恢复要自己记录,浏览器不会自动处理;
  • 部署到子目录时,路由前缀和静态资源路径都要相应调整。

怎么选

内部系统、后台管理优先 hash,省掉服务端配置。面向公众、需要被搜索引擎收录的站点用 history,并配好回退规则。本站是静态站点,每篇文章都是真实文件,不涉及这个问题——但理解它对于排查线上 404 仍然必要。

前端路由SPA