路由系统

最后更新: 2026-01-27 11:02:47

路由系统

Unicode Framework 提供了强大且灵活的路由系统,支持 RESTful 路由、路由组、中间件、命名路由等功能。

基础路由

基本语法

路由定义在 route.php 文件中(框架级别)或 app/{app-name}/route.php 文件中(应用级别)。

use Unicode\Framework\Route\Route;

// GET 路由 Route::get('/users', [UserController::class, 'index']);

// POST 路由 Route::post('/users', [UserController::class, 'store']);

// PUT 路由 Route::put('/users/{id}', [UserController::class, 'update']);

// PATCH 路由 Route::patch('/users/{id}', [UserController::class, 'updatePartial']);

// DELETE 路由 Route::delete('/users/{id}', [UserController::class, 'destroy']);

路由处理器

路由处理器可以是:

  • 闭包函数
  • Route::get('/hello', function() {
        return ['message' => 'Hello, World!'];
    });
    
  • 控制器方法
  • Route::get('/users', [UserController::class, 'index']);
    
  • 带参数的闭包
  • Route::get('/users/{id}', function(Request $request, int $id) {
        return ['user_id' => $id];
    });
    

    HTTP 方法

    框架支持所有标准 HTTP 方法:

    Route::get('/resource', $handler);
    Route::post('/resource', $handler);
    Route::put('/resource/{id}', $handler);
    Route::patch('/resource/{id}', $handler);
    Route::delete('/resource/{id}', $handler);
    Route::options('/resource', $handler);
    Route::head('/resource', $handler);
    

    路由参数

    必需参数

    使用 {param} 语法定义路由参数:

    Route::get('/users/{id}', [UserController::class, 'show']);
    

    // 访问 /users/123,$id = 123

    可选参数

    使用 {param?} 语法定义可选参数:

    Route::get('/posts/{id?}', [PostController::class, 'show']);
    

    // 访问 /posts,$id = null // 访问 /posts/123,$id = 123

    参数约束

    路由参数会自动进行类型转换。在控制器方法中,可以指定参数类型:

    // 路由定义
    Route::get('/users/{id}', [UserController::class, 'show']);
    

    // 控制器方法 public function show(Request $request, int $id): array { // $id 自动转换为整数 return ['user_id' => $id]; }

    多个参数

    Route::get('/users/{userId}/posts/{postId}', function(Request $request, int $userId, int $postId) {
        return [
            'user_id' => $userId,
            'post_id' => $postId,
        ];
    });
    

    路由组

    路由组允许您为一组路由共享公共属性(前缀、中间件等)。

    前缀组

    Route::group('/api/v1', function() {
        Route::get('/users', [UserController::class, 'index']);
        Route::post('/users', [UserController::class, 'store']);
        Route::get('/users/{id}', [UserController::class, 'show']);
    });
    

    // 实际路由: // GET /api/v1/users // POST /api/v1/users // GET /api/v1/users/{id}

    嵌套路由组

    Route::group('/api', function() {
        Route::group('/v1', function() {
            Route::get('/users', [UserController::class, 'index']);
        });
    });
    

    // 实际路由:GET /api/v1/users

    中间件

    单个路由中间件

    use Unicode\Framework\Auth\Middleware\JwtMiddleware;
    

    Route::get('/profile', [UserController::class, 'profile'], 'profile', [ JwtMiddleware::class ]);

    中间件组

    Route::middleware([JwtMiddleware::class], function() {
        Route::get('/profile', [UserController::class, 'profile']);
        Route::put('/profile', [UserController::class, 'updateProfile']);
    });
    

    嵌套中间件组

    Route::middleware([AuthMiddleware::class], function() {
        Route::middleware([AdminMiddleware::class], function() {
            Route::get('/admin/users', [AdminController::class, 'users']);
        });
    });
    

    组合使用(前缀 + 中间件)

    Route::group('/api/v1', function() {
        Route::middleware([JwtMiddleware::class], function() {
            Route::get('/users', [UserController::class, 'index']);
            Route::post('/users', [UserController::class, 'store']);
        });
    });
    

    命名路由

    命名路由允许您通过名称生成 URL,而不需要硬编码路径。

    定义命名路由

    Route::get('/users/{id}', [UserController::class, 'show'], 'users.show');
    

    生成 URL

    use function router;
    

    // 生成 URL $url = router()->url('users.show', ['id' => 123]); // 结果:/users/123

    // 生成完整 URL(包含域名) $fullUrl = router()->url('users.show', ['id' => 123], true);

    在控制器中使用

    class UserController
    {
        public function index(Request $request): array
        {
            $url = router()->url('users.show', ['id' => 1]);
            return ['show_url' => $url];
        }
    }
    

    检查路由是否存在

    if (router()->hasRoute('users.show')) {
        $url = router()->url('users.show', ['id' => 1]);
    }
    

    路由缓存

    在生产环境中,框架会自动缓存路由以提高性能。

    启用路由缓存

    路由缓存在生产环境(APP_ENV=production)下自动启用。

    缓存位置

    路由缓存文件位于:bootstrap/cache/routes.php

    清除路由缓存

    删除 bootstrap/cache/routes.php 文件即可清除缓存。框架会在下次请求时重新生成缓存。

    开发环境

    在开发环境(APP_ENV=development)下,路由不会使用缓存,每次修改路由文件后立即生效。

    最佳实践

    1. RESTful 路由组织

    // 推荐:使用路由组组织 RESTful API
    Route::group('/api/v1', function() {
        // 用户资源
        Route::get('/users', [UserController::class, 'index'], 'api.users.index');
        Route::post('/users', [UserController::class, 'store'], 'api.users.store');
        Route::get('/users/{id}', [UserController::class, 'show'], 'api.users.show');
        Route::put('/users/{id}', [UserController::class, 'update'], 'api.users.update');
        Route::delete('/users/{id}', [UserController::class, 'destroy'], 'api.users.destroy');
    

    // 文章资源 Route::get('/posts', [PostController::class, 'index'], 'api.posts.index'); Route::post('/posts', [PostController::class, 'store'], 'api.posts.store'); // ... });

    2. 中间件分层

    // 公共中间件(所有 API 路由)
    Route::group('/api', function() {
        Route::middleware([CorsMiddleware::class], function() {
            // 需要认证的路由
            Route::middleware([JwtMiddleware::class], function() {
                Route::get('/profile', [UserController::class, 'profile']);
            });
    

    // 公开路由 Route::get('/posts', [PostController::class, 'index']); }); });

    3. 路由命名规范

    使用点号分隔的命名空间风格:

    Route::get('/api/v1/users', [UserController::class, 'index'], 'api.v1.users.index');
    Route::get('/api/v1/users/{id}', [UserController::class, 'show'], 'api.v1.users.show');
    Route::get('/admin/users', [AdminController::class, 'index'], 'admin.users.index');
    

    4. 控制器组织

    // 推荐:按功能模块组织路由
    Route::group('/api/v1', function() {
        // 用户相关
        Route::group('/users', function() {
            Route::get('/', [UserController::class, 'index']);
            Route::post('/', [UserController::class, 'store']);
            Route::get('/{id}', [UserController::class, 'show']);
        });
    

    // 文章相关 Route::group('/posts', function() { Route::get('/', [PostController::class, 'index']); Route::post('/', [PostController::class, 'store']); }); });

    5. 路由文件组织

    对于大型项目,可以将路由拆分到多个文件:

    // app/index/route.php
    require __DIR__ . '/routes/api.php';
    require __DIR__ . '/routes/web.php';
    require __DIR__ . '/routes/admin.php';
    

    常见问题

    Q: 路由冲突怎么办?

    A: 框架支持路由覆盖。如果定义了两个相同方法和路径的路由,后定义的路由会覆盖先定义的路由。

    Q: 如何获取当前路由信息?

    A: 在控制器中通过 Request 对象获取:

    public function index(Request $request): array
    {
        $routeName = $request->getAttribute('routeName');
        $routePath = $request->getAttribute('routePath');
        $params = $request->getAttribute('routeParams');
    

    return [ 'name' => $routeName, 'path' => $routePath, 'params' => $params, ]; }

    Q: 如何限制路由参数格式?

    A: 在控制器方法中使用类型提示,框架会自动进行类型转换和验证:

    Route::get('/users/{id}', [UserController::class, 'show']);
    

    public function show(Request $request, int $id): array { // $id 必须是整数,否则会返回 404 }

    Q: 路由顺序重要吗?

    A: 是的。路由按照定义的顺序进行匹配,第一个匹配的路由会被使用。建议将更具体的路由放在前面。

    // 正确:具体路由在前
    Route::get('/users/new', [UserController::class, 'create']);
    Route::get('/users/{id}', [UserController::class, 'show']);
    

    // 错误:如果顺序相反,/users/new 会被匹配为 /users/{id},id = 'new'

    相关文档

  • 多应用架构 - 多应用模式下的路由
  • 中间件系统 - 中间件开发指南
  • 控制器开发 - 控制器最佳实践