全栈框架自定义路由规则?

访客 全栈框架 2

本文目录导读:

  1. Next.js (React)
  2. Nuxt.js (Vue)
  3. SvelteKit
  4. Remix (React)
  5. 自定义 Node.js 全栈(如 Express + Vite)
  6. 不同场景的最佳实践

这是一个很专业的问题,全栈框架(如 Next.js、Nuxt.js、SvelteKit、Remix 等)通常基于文件系统约定路由(即文件名即路径),但在复杂业务中,常需要自定义路由规则以应对动态路径、参数校验、重定向或非标准 URL 映射。

不同框架的实现方式不同,以下是主流全栈框架的自定义路由规则策略:

Next.js (React)

核心方式: 通过 middleware.ts + 文件系统路由,或使用 rewrites / redirects 配置。

  • 方法A:next.config.js 中的 rewrites / redirects(静态映射) 适合:将 /blog-2024 映射到 /blog/[year],或实现 URL 重写(不改变浏览器地址栏)与重定向。

    // next.config.js
    module.exports = {
      async rewrites() {
        return [
          { source: '/api/:path*', destination: 'https://external-api.com/:path*' }, // 代理
          { source: '/old-path', destination: '/new-path' }, // URL 重写
          { source: '/user/:id', has: [{ type: 'query', key: 'lang' }], destination: '/user/:id?lang=:lang' }
        ];
      },
      async redirects() {
        return [
          { source: '/legacy', destination: '/new-page', permanent: true },
        ];
      }
    };
  • 方法B:middleware.ts(动态逻辑) 适合:需要根据 Cookie、Header、用户状态等动态重写路由(如 A/B 测试、国际化前缀)。

    // middleware.ts
    import { NextResponse } from 'next/server'
    import type { NextRequest } from 'next/server'
    export function middleware(request: NextRequest) {
      const { pathname } = request.nextUrl
      // 自定义规则:如果访问 /product/123,但用户是管理员,重定向到 /admin/product/123
      if (pathname.startsWith('/product/') && request.cookies.get('role') === 'admin') {
        return NextResponse.redirect(new URL(`/admin${pathname}`, request.url))
      }
      return NextResponse.next()
    }

Nuxt.js (Vue)

核心方式: pages/ 目录 + middleware/ + router.options.tsapp/router.options.ts

  • 方法A:middleware(全局或局部)

    // middleware/custom-route.global.ts
    export default defineNuxtRouteMiddleware((to, from) => {
      if (to.path === '/legacy' && !to.query.token) {
        return navigateTo('/login')
      }
    })
  • 方法B:自定义 router.options.ts(高阶自定义) 适合:完全自定义路由表,或添加通配符路由。

    // app/router.options.ts
    import type { RouterConfig } from '@nuxt/schema'
    export default <RouterConfig> {
      routes: (_routes) => [
        // 插入自定义规则
        {
          path: '/custom/:slug',
          component: () => import('~/pages/[...slug].vue'),
          name: 'custom'
        },
        // 然后追加 Nuxt 自动生成的路由
        ..._routes
      ]
    }

SvelteKit

核心方式: src/params/ + src/routes/[param] 约定 + hooks.server.ts

  • 方法:自定义参数匹配器(高级) 适合:限制参数格式(如数字、UUID)、转换参数。

    // src/params/integer.ts
    export function match(value) {
      return /^\d+$/.test(value)
    }
    // 路由文件:src/routes/[id=integer]/+page.server.ts
    export async function load({ params }) {
      // params.id 保证是数字字符串
    }
  • 方法:src/hooks.server.ts 中的 handle 适合:全局路由拦截、重定向。

    // src/hooks.server.ts
    export async function handle({ event, resolve }) {
      const url = new URL(event.request.url)
      if (url.pathname.startsWith('/app') && !event.cookies.get('session')) {
        return new Response(null, { status: 307, headers: { location: '/login' } })
      }
      return await resolve(event)
    }

Remix (React)

核心方式: app/routes/ 文件系统 + resource routes + loader/action 中的条件判断。 由于 Remix 的 loader 运行在服务端,你可以直接在函数内实现复杂路由逻辑。

  • 方法:在 loader 中动态跳转

    // app/routes/$.tsx(Splat 路由,捕获所有未匹配路径)
    import { redirect } from '@remix-run/node'
    export async function loader({ request }) {
      const url = new URL(request.url)
      if (url.pathname.startsWith('/api')) {
        // 可在此动态分发到不同处理函数
        return proxyRequest(url)
      }
      throw new Response('Not Found', { status: 404 })
    }

自定义 Node.js 全栈(如 Express + Vite)

如果你是自己搭建全栈框架(非 Next/Nuxt),则可以完全控制路由。

// 自定义路由规则中间件
const customRouter = (req, res, next) => {
  if (req.path === '/user/:id' && req.query.mode === 'admin') {
    req.params.id = `admin-${req.params.id}` // 改写参数
    req.url = `/user/${req.params.id}` // 重写 URL
  }
  next()
}
app.use(customRouter)
app.get('/user/:id', (req, res) => { /* ... */ })

不同场景的最佳实践

场景 推荐方法
静态 URL 重写(如 /old/new Next.js:rewrites 配置;Nuxt:redirect 配置;SvelteKit:hooks.server.ts
参数验证与转换(如只允许数字 ID) SvelteKit:src/params/;Next.js:middleware 中验证
国际化前缀(如 /en/page/zh/page Next.js:middleware 判断 Accept-Languagerewrite;Nuxt:i18n 模块
A/B 测试(根据 Cookie 展示不同页面) Next.js:middlewarerewrite 到不同路径
完全自定义路由表(不依赖文件系统) Nuxt:router.options.ts;Next.js:自定义 server.js 使用 app.getPathRoutes 不适合,建议用 middlewarerewrites

关键思路: 尽量利用框架提供的 中间件/钩子/配置 来完成路由自定义,而不是试图绕过文件系统路由引擎(除非迫不得已),大多数框架的设计哲学是“约定优于配置”,但同时也提供了足够的“逃生舱”来自定义规则。

如果需要针对某个具体框架的极端自定义(如动态注册路由、拦截所有请求),请告知你使用的框架,我可以提供更深入的代码示例。

标签: 前端路由 自定义路由

抱歉,评论功能暂时关闭!