项目部署到子目录,路由跳转却到主域名下?正常能访问一刷新就404?——路由模式的困扰

751 阅读3分钟

今天在做项目部署到一个服务器子目录时,遇到了两个问题,这里做下记录

一、路由模式介绍

这里以Vue Router v4版本为例

在Vue Router v4版本有三种模式,官网已经做了详细介绍

Hash 模式

hash 模式是用 createWebHashHistory() 创建的:

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    //...
  ],
})

它在内部传递的实际 URL 之前使用了一个哈希字符(#)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。不过,它在 SEO 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。

Memory 模式

Memory 模式不会假定自己处于浏览器环境,因此不会与 URL 交互也不会自动触发初始导航。这使得它非常适合 Node 环境和 SSR。它是用 createMemoryHistory() 创建的,并且需要你在调用 app.use(router) 之后手动 push 到初始导航

import { createRouter, createMemoryHistory } from 'vue-router'
const router = createRouter({
  history: createMemoryHistory(),
  routes: [
    //...
  ],
})

虽然不推荐,你仍可以在浏览器应用程序中使用此模式,但请注意它不会有历史记录,这意味着你无法后退前进

HTML5 模式(v3版本中称为History模式)

createWebHistory() 创建 HTML5 模式,推荐使用这个模式:

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    //...
  ],
})

当使用这种历史模式时,URL 会看起来很 "正常",例如 https://example.com/user/id。漂亮!

不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id,就会得到一个 404 错误。这就尴尬了。

不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!

更详细参考官网介绍

二、遇到的问题

1.项目部署到子目录,路由跳转却到主域名下解决方法

如果是history模式,需要加上当前部署的子目录,

createWebHistory()方法可以传入base参数,官网如下介绍:

base:基准路径,它被预置到每个 URL 上。这允许在一个域名子文件夹中托管 SPA,例如将 base 设置为 /sub-folder 使得其托管在 example.com/sub-folder

所以代码如下:

//获取当前路径
let path = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1)
const router = createRouter({
  history: createWebHistory(path),
  routes: [
    //...
  ],
});

!打包配置这里路径也需要注意下

这里我用的是vite

defineConfig中的base配置路径,有三种写法如下

  • 绝对 URL 路径名,例如 /foo/
  • 完整的 URL,例如 https://foo.com/(原始的部分在开发环境中不会被使用)
  • 空字符串或 ./(用于嵌入形式的开发)

举例:

如果你的应用被部署在www.xxx/admin/ 上,则base可以设为

'/admin/'
''
'./'

这三种其一即可

2.正常能访问一刷新就404解决方法

这个是因为没后端没进行配置,加载单页应用后路由改变均由浏览器处理,而刷新时将会请求当前的链接,而Nginx无法找到对应的页面

这时候需要在在Nginx配置文件nginx.conf中加入如下配置:

try_files $uri $uri/ /index.html;

这里做下举例:

location ^~/xxxx/ {
      root  /xx
      try_files $uri $uri/ /index.html;
    }

还有另一种方法可以同时解决上述两个问题,比如说就不想操作Nginx配置了,那就是更换称为hash模式

const router = createRouter({
  history: createWebHashHistory(path),
  routes: [
    //...
  ],
});

但是会有一些缺点,如上面介绍,自行选择