vue3中404页面显示问题Catch all routes (“*“) must now be defined using a param with a custom regexp.
vue3中404页面显示问题Catch all routes (“*“) must now be defined using a param with a custom regexp
一、背景与问题
在Vue3项目中,开发者常会遇到一个令人困惑的错误提示:
Catch all routes ("*") must now be defined using a param with a custom regexp这个错误通常出现在使用Vue Router 4.x版本时,尝试使用*通配符定义404页面。这一行为在Vue Router 2.x版本中是被允许的,但在Vue Router 4.x中被移除并重新设计。此变更背后是Vue Router对路由匹配机制的重构,其核心目标是提升路由系统的灵活性和安全性。
二、基本原理
Vue Router 4.x的路由匹配机制发生了重大变化,其核心改进包括:
- 参数化通配符:将原本的通配符
*改为必须定义参数并使用正则表达式 - 更精确的路由匹配:通过正则表达式控制路径匹配的边界条件
- 安全性增强:防止路径遍历漏洞(如
../)的潜在风险
在Vue Router 2.x中,通配符路由的实现原理是:
{
path: '*',
component: NotFound
}当所有其他路由都未匹配时,会自动匹配到这个通配符路由。但在Vue Router 4.x中,这种用法已被废弃,取而代之的是:
{
path: '/:pathMatch(.*)*',
component: NotFound
}三、环境准备
确保你的开发环境满足以下条件:
- Vue 3.x
- Vue Router 4.x
- Node.js 14+
- 项目结构示例:
src/
├── App.vue
├── main.js
└── router/
└── index.js四、核心实现
1. 基础通配符配置
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import NotFound from '../views/NotFound.vue'
const routes = [
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound
}
]
export default createRouter({
history: createWebHistory(),
routes
})关键代码解释:
:pathMatch:定义一个参数名为pathMatch的捕获参数(.*)*:正则表达式,.*匹配任意字符(除换行符),*表示重复0次或多次- 这种写法确保只有当所有其他路由都未匹配时,才会触发404页面
2. 带参数的通配符路由
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound,
props: (route) => ({
pathMatch: route.params.pathMatch
})
}关键代码解释:
props配置允许将捕获的参数传递给组件- 可通过
this.$route.params.pathMatch访问参数值
3. 自定义正则表达式路由
{
path: '/:pathMatch(^(?!/api/).*)*',
name: 'NotFound',
component: NotFound
}关键代码解释:
正则表达式
^(?!/api/).*$表示:^:匹配字符串开头(?!/api/):负向预查,确保不以/api/开头.*:匹配任意字符*:重复0次或多次
- 这种写法可以防止匹配到API接口路径
五、完整案例
创建一个完整的Vue3项目,实现动态路由匹配和404页面:
npx create-vue my-project
cd my-project
npm installsrc/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import NotFound from '../views/NotFound.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/:pathMatch(^(?!/api/).*)*',
name: 'NotFound',
component: NotFound
}
]
export default createRouter({
history: createWebHistory(),
routes
})src/views/NotFound.vue
<template>
<div class="not-found">
<h1>404 - 页面不存在</h1>
<p>当前访问的路径:{{ pathMatch }}</p>
</div>
</template>
<script>
export default {
props: ['pathMatch']
}
</script>
<style scoped>
.not-found {
padding: 30px;
text-align: center;
color: #888;
}
</style>src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')六、源码解析
Vue Router 4.x的路由匹配逻辑核心在于createRouter函数的实现。在createRouter中,会创建一个history对象,并注册onBeforeRouteUpdate和onBeforeRouteLeave钩子。
关键代码片段(简化版):
function createRouter(options) {
const history = createWebHistory()
const routes = options.routes
function matchRoute(path) {
for (const route of routes) {
const { path: routePath, regex } = route
if (regex.test(path)) {
return route
}
}
return null
}
return {
history,
matchRoute
}
}在matchRoute函数中,通过正则表达式进行路径匹配。当匹配到通配符路由时,会返回对应的组件。
七、进阶使用
1. 动态路由参数捕获
{
path: '/:id/:name*',
name: 'User',
component: User
}这个路由可以匹配/123、/123/John等路径,*表示可选捕获参数。
2. 通配符路由的优先级控制
{
path: '/:pathMatch(^(?!/api/).*)*',
name: 'NotFound',
component: NotFound
}通过正则表达式控制匹配优先级,避免误匹配到API路径。
3. 多级通配符路由
{
path: '/:pathMatch(^(?!/api/).*)*',
name: 'NotFound',
component: NotFound
}这种写法可以匹配多级路径,如/user/123/profile。
八、性能与工程实践
1. 性能优化
- 避免使用过于宽泛的正则表达式
- 对关键路由使用
exact匹配 - 使用
v-pre指令避免Vue的编译干扰
2. 安全风险
使用正则表达式防止路径遍历攻击:
{ path: '/:pathMatch(^[^/]+/[^/]+)*', name: 'NotFound', component: NotFound }限制路径深度:
{ path: '/:pathMatch(^[^/]{1,20}/[^/]{1,20})*', name: 'NotFound', component: NotFound }
3. 异常处理
{
path: '/:pathMatch(^[^/]+/[^/]+)*',
name: 'NotFound',
component: NotFound,
beforeEnter: (to, from, next) => {
console.log('Invalid route:', to.fullPath)
next()
}
}九、常见问题与踩坑
1. 通配符匹配不生效
错误示例:
{
path: '*',
name: 'NotFound',
component: NotFound
}解决方法:
使用参数化通配符:
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }
2. 参数无法获取
错误示例:
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound
}解决方法:
- 在组件中使用
this.$route.params.pathMatch获取参数 使用
props传递参数:props: (route) => ({ pathMatch: route.params.pathMatch })
3. 正则表达式错误
错误示例:
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound
}解决方法:
使用更精确的正则表达式:
{ path: '/:pathMatch(^(?!/api/).*)*', name: 'NotFound', component: NotFound }
十、最佳实践
- 优先使用参数化通配符:始终使用
/:pathMatch(正则表达式)*格式 - 限制路径深度:使用正则表达式限制路径长度
- 安全过滤:使用正则表达式防止路径遍历攻击
- 明确优先级:在路由配置文件中明确通配符路由的位置
- 使用props传递参数:通过
props将参数传递给组件 - 异常处理:在路由配置中添加
beforeEnter钩子处理异常情况
十一、总结
Vue3中404页面显示问题的核心在于对通配符路由的重新设计。通过参数化通配符和正则表达式,我们可以获得更精确的路由控制能力。在实际开发中,需要根据具体场景选择合适的正则表达式,既要保证路由匹配的准确性,又要防范潜在的安全风险。通过合理配置通配符路由,可以有效提升应用的健壮性和可维护性。
评论已关闭