Code前端首页关于Code前端联系我们

一、vue-router的hash和history模式,到底差在哪?

terry 2小时前 阅读数 7 #Vue
文章标签 router;路由模式

p>做Vue项目时,用vue-router搞路由跳转开发时挺顺,一部署到nginx服务器,刷新页面就404,路由跳转后样式还丢了…这事儿是不是特闹心?其实这和vue-router的路由模式、nginx的请求处理逻辑有关,今天就把这些坑一个个掰扯清楚。

先看hash模式:url里会带个,比如http://xxx.com/#/about,后面的内容是前端路由自己玩的,浏览器发请求给服务器时,只会把前面的部分(也就是http://xxx.com/)传给服务器,所以服务器只需要返回根路径的index.html,前端再解析后的路径渲染页面就行,这种模式下,部署到nginx基本不用改配置,刷新页面也不会404——因为服务器收到的始终是根路径请求。

再看history模式:url是“干净”的,比如http://xxx.com/about,它用的是HTML5的history API(像pushStatereplaceState这些),好处是url好看、对SEO友好点(虽然SPA主要靠前端渲染,SEO作用有限,但路径看着正规),但问题也在这:当用户刷新页面,或者直接输入http://xxx.com/about访问时,浏览器会把整个/about路径发给服务器,nginx默认会去对应目录找/about这个文件或文件夹,找不到就返回404——这就是“刷新404”的根源!

nginx为啥“搞不定”history模式的页面刷新?

得先明白单页应用(SPA)的逻辑:整个项目就一个index.html,所有路由切换都是前端用JS动态渲染的,比如用户点导航到/about,是前端把url改成/about,然后加载对应的组件,这时候没发新的HTTP请求,但刷新页面时,浏览器以为要请求/about这个“真实”资源,可nginx服务器里根本没有这个文件,自然就404了。

举个现实例子:你做了个博客,用history模式,路由是/article/123,开发时用vue-cli的devServer,它内置了请求处理逻辑,所以刷新没事,但部署到nginx后,nginx不知道“/article/123”该对应哪个文件,只能返回404。

给nginx加配置,让history模式“听话”

核心思路:让nginx把所有找不到的请求,都转发到index.html,让前端路由自己处理,具体改nginx的配置文件(一般在/etc/nginx/conf.d/下的xxx.conf,不同系统路径可能不同,比如Ubuntu是/etc/nginx/sites-available/default),在server块里加这段配置:

server {
    listen 80;
    server_name 你的域名或IP;
    root /usr/share/nginx/html; # 假设你把dist包放到这个目录
    index index.html;
    location / {
        try_files $uri $uri/ /index.html; 
        # 逻辑:先找请求的文件($uri),再找目录($uri/),都没有就返回index.html
    }
}

解释try_files的逻辑:

比如用户访问/about,nginx会先去/usr/share/nginx/html/about找文件,没有;再找/usr/share/nginx/html/about/这个目录,也没有;最后返回/usr/share/nginx/html/index.html,前端路由拿到/about这个路径,就会渲染对应的页面,刷新404的问题就解决了。

细节提醒:静态资源别被“误伤”

如果项目里有静态资源(比如/static/js/static/css),得确保nginx能正确返回这些资源,别被try_files拦截,所以可以单独给静态资源配location

location /static/ {
    root /usr/share/nginx/html;
    try_files $uri $uri/ =404; # 直接找静态资源,找不到返回404
}

这样请求/static/js/app.js时,nginx会直接去/usr/share/nginx/html/static/js/app.js找文件,不会走到/index.html的逻辑,避免静态资源加载出错。

部署后样式、图片全丢了?检查这两个配置

很多人改完nginx配置,路由不404了,但样式没了、图片裂了,大概率是静态资源路径配错了。

Vue项目里的publicPath配置(Vue CLI项目)

打开vue.config.js,里面有个publicPath(旧版叫baseUrl),如果你的项目部署在域名根路径(比如http://xxx.com/),publicPath设为就行,但如果部署在子路径下,比如http://xxx.com/myapp/,那publicPath得设为'/myapp/'——这样打包后,静态资源的路径会是/myapp/static/js/xxx.js,nginx里root对应的目录也要和子路径匹配。

举个配置示例:

// vue.config.js
module.exports = {
  publicPath: process.env.NODE_ENV === 'production' ? '/myapp/' : '/',
  // 其他配置...
}

nginx里的rootlocation匹配

假设你把dist包放到/usr/share/nginx/html/myapp目录下,nginx配置得改成这样:

server {
    listen 80;
    server_name 你的域名或IP;
    root /usr/share/nginx/html; # 注意:这里是myapp的父目录
    index index.html;
    location /myapp/ {
        try_files $uri $uri/ /myapp/index.html; 
        # 因为root是/usr/share/nginx/html,所以请求/myapp/about时,实际找的是/usr/share/nginx/html/myapp/about
    }
    location /myapp/static/ {
        root /usr/share/nginx/html;
        try_files $uri $uri/ =404;
    }
}

这样静态资源的路径才会对应到/myapp/static/下面,样式和图片就能正常加载了。

hash模式部署时,nginx需要特殊处理吗?

如果用hash模式,url长这样:http://xxx.com/#/about,这时候浏览器发请求给服务器的只有http://xxx.com/,所以nginx不需要配try_files那套——因为服务器永远只收到根路径请求,返回index.html后前端自己解析后的路由。

但如果你的项目部署在子路径(比如/myapp),还是得注意publicPath和nginx的root配置(原理和上面一样)——确保静态资源路径能被正确找到。

部署要踩的坑和解决步骤

  1. 选路由模式

    • 想要url干净选history,但得配nginx;
    • 图省事选hash,部署时不用改nginx(但url带)。
  2. history模式必配nginx的try_files:把所有请求“兜底”到index.html,让前端路由接管。

  3. 静态资源路径别踩坑:Vue的publicPath和nginx的rootlocation要对应,尤其是子路径部署时。

  4. 测试环节:部署后多刷新不同路由页面,检查样式、图片、接口是否正常;修改nginx配置后,记得重启nginx(比如sudo systemctl restart nginx)让配置生效。

其实理解了SPA的“单页”本质——所有路由由前端控制,而nginx是服务器端的请求转发,就明白为啥要让nginx把“不认识”的请求都丢给index.html,把这些逻辑理顺,部署时就不会抓瞎啦~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门