HTTP层 —— 路由

本文介绍了Laravel框架中的路由配置方法,包括基本路由设置、路由参数、命名路由、路由群组、路由模型绑定等内容,并提供了表单方法伪造及访问当前路由的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

1、基本路由

最基本的 Laravel 路由只接收一个 URI 和一个闭包,并以此提供一个非常简单且优雅的定义路由方法:

Route::get('foo', function () {
    return 'Hello World';
});

默认路由文件

所有Laravel路由都定义位于routes目录下的路由文件中,这些文件通过框架自动加载。routes/web.php文件定义了web界面的路由,这些路由被分配给web中间件组,从而可以提供session和csrf防护等功能。routes/api.php中的路由是无状态的,被分配到api中间件组。

对大多数应用而言,都是从 routes/web.php 文件开始定义路由。

有效的路由方法

我们可以注册路由来响应任何 HTTP 请求:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

有时候还需要注册路由响应多个 HTTP 请求——这可以通过 match 方法来实现。或者,可以使用 any 方法注册一个路由来响应所有 HTTP 请求:

Route::match(['get', 'post'], '/', function () {
    //
});
Route::any('foo', function () {
    //
});

CSRF防护

web路由文件中所有请求方式为PUTPOSTDELETE的HTML表单都会包含一个CSRF令牌字段,否则,请求会被拒绝。关于CSRF的更多细节,可以参考其文档

<form method="POST" action="/profile">
    {{ csrf_field() }}
    ...
</form>
2、路由参数
必选参数

有时我们需要在路由中捕获 URI 片段。比如,要从 URL 中捕获用户 ID,需要通过如下方式定义路由参数:

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

可以按需要在路由中定义多个路由参数:

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

路由参数总是通过花括号进行包裹,这些参数在路由被执行时会被传递到路由的闭包。

注意:路由参数不能包含 - 字符,需要的话可以使用 _ 替代。

可选参数

有时候可能需要指定可选的路由参数,这可以通过在参数名后加一个 ? 标记来实现,这种情况下需要给相应的变量指定默认值:

Route::get('user/{name?}', function ($name = null) {
    return $name;
});
Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});
3、命名路由

命名路由为生成 URL 或重定向提供了便利。实现也很简单,在路由定义之后使用 name 方法链的方式来实现:

Route::get('user/profile', function () {
    //
})->name('profile');

还可以为控制器动作指定路由名称:

Route::get('user/profile', 'UserController@showProfile')->name('profile');

为命名路由生成URL

为给定路由分配名称之后,就可以通过辅助函数 route 为该命名路由生成 URL:

$url = route('profile');
$redirect = redirect()->route('profile');

如果命名路由定义了参数,可以将该参数作为第二个参数传递给 route 函数。给定的路由参数将会自动插入到 URL 中:

Route::get('user/{id}/profile', ['as' => 'profile', function ($id) {
    //
}]);
$url = route('profile', ['id' => 1]);
4、路由群组

路由群组允许我们在多个路由中共享路由属性,比如中间件和命名空间等,这样的话我们就不必为每一个路由单独定义属性。共享属性以数组的形式作为第一个参数被传递给 Route::group 方法。

中间件

要给路由群组中定义的所有路由分配中间件,可以在群组属性数组中使用 middleware。中间件将会按照数组中定义的顺序依次执行:

Route::group(['middleware' => 'auth'], function () {
    Route::get('/', function () {
        // 使用 Auth 中间件
    });

    Route::get('user/profile', function () {
        // 使用 Auth 中间件
    });
});
命名空间

另一个通用的例子是路由群组分配同一个 PHP 命名空间给其下的多个控制器,可以在分组属性数组中使用 namespace来指定群组中所有控制器的公共命名空间:

Route::group(['namespace' => 'Admin'], function(){
    // 控制器在 "App\Http\Controllers\Admin" 命名空间下

    Route::group(['namespace' => 'User'], function(){
        // 控制器在 "App\Http\Controllers\Admin\User" 命名空间下
    });
});

默认情况下,RouteServiceProvider 引入你的路由文件并指定其下所有控制器类所在的默认命名空间App\Http\Controllers,因此,我们在定义的时候只需要指定命名空间 App\Http\Controllers 之后的部分即可。

子域名路由

路由群组还可以被用于子域名路由通配符,子域名可以像 URI 一样被分配给路由参数,从而允许捕获子域名的部分用于路由或者控制器,子域名可以通过群组属性数组中的 domain 来指定:

Route::group(['domain' => '{account}.myapp.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});
路由前缀

群组属性 prefix 可以用来为群组中每个路由添加一个给定 URI 前缀,例如,你可以为所有路由 URI 添加 admin 前缀 :

Route::group(['prefix' => 'admin'], function () {
    Route::get('users', function () {
        // 匹配 "/admin/users" URL
    });
});
5、路由模型绑定

注入模型ID到路由或控制器动作时,通常需要查询数据库才能获取相应的模型数据。Laravel 路由模型绑定让注入模型实例到路由变得简单,例如,你可以将匹配给定 ID 的整个 User 类实例注入到路由中,而不是直接注入用户 ID。

隐式绑定

Laravel 会自动解析定义在路由或控制器动作(变量名匹配路由片段)中的 Eloquent 模型类型声明,例如:

Route::get('api/users/{user}', function (App\User $user) {
    return $user->email;
});

在这个例子中,由于类型声明了 Eloquent 模型 App\User,对应的变量名 $user 会匹配路由片段中的{user},这样,Laravel 会自动注入与请求 URI 中传入的 ID 对应的用户模型实例。

如果数据库中找不到对应的模型实例,会自动生成 HTTP 404 响应。

自定义键名

如果你想要隐式模型绑定使用数据表的其它字段,可以重写 Eloquent 模型类的 getRouteKeyName 方法:

/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}
显式绑定

要注册显式绑定,需要使用路由的 model 方法来为给定参数指定绑定类。应该在 RouteServiceProvider::boot 方法中定义模型绑定:

绑定参数到模型

public function boot()
{
    parent::boot();
    $router->model('user', 'App\User');
}

接下来,定义一个包含 {user} 参数的路由:

$router->get('profile/{user}', function(App\User $user) {
     //
});

由于我们已经绑定 {user} 参数到 App\User 模型,User 实例会被注入到该路由。因此,如果请求 URL 是profile/1,就会注入一个用户 ID 为 1 的 User 实例。

如果匹配的模型实例在数据库不存在,会自动生成并返回 HTTP 404 响应。

自定义解析逻辑

如果你想要使用自定义的解析逻辑,需要使用 Route::bind 方法,传递到 bind 方法的闭包会获取到 URI 请求参数中的值,并且返回你想要在该路由中注入的类实例:

$router->bind('user', function($value) {
    return App\User::where('name', $value)->first();
});
6、表单方法伪造

HTML 表单不支持 PUTPATCH 或者 DELETE 请求方法,因此,当定义 PUTPATCHDELETE 路由时,需要添加一个隐藏的 _method 字段到表单中,其值被用作该表单的 HTTP 请求方法:

<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

还可以使用辅助函数 method_field 来实现这一目的:

{{ method_field('PUT') }}
7、访问当前路由

你可以使用 Route 门面上的 currentcurrentRouteNamecurrentRouteAction 方法来访问处理当前输入请求的路由信息:

$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();

参考API文档了解路由门面底层类以及Route实例的更多可用方法。

 

转载于:https://www.cnblogs.com/zhengyanbin2016/p/6005035.html

<think>好的,我现在需要为用户解析Spring Cloud Gateway中的RouteDefinitionRepository存储器。首先,我需要回忆一下Spring Cloud Gateway的基本架构,特别是路由存储的部分。 用户提到了RouteDefinitionRepository,这是负责存储路由定义的接口。我需要先理解这个接口的作用和它在整个路由机制中的位置。根据之前的了解,RouteDefinitionRepository用于加载和保存路由配置,可能涉及不同的实现类,比如内存存储或从配置中心读取。 接下来,我需要确定RouteDefinitionRepository的继承关系和主要方法。记得它可能有几个实现,比如InMemoryRouteDefinitionRepository,这个类将路由信息存储在内存中。另外,可能还有基于配置文件的实现,或者集成外部配置中心如Nacos、Consul的实现。 然后,我需要详细说明每个方法的功能。例如,save方法用于保存路由定义,delete方法用于删除,getRouteDefinitions返回所有路由的Flux流。这里需要解释反应式编程中的Flux,以及如何与Spring WebFlux结合使用。 还要考虑RouteDefinitionRepository如何与其他组件交互,比如RouteLocator,它可能使用Repository中的路由定义来创建可用的路由。需要说明整个流程,从加载路由配置到转换为Route对象的过程。 另外,用户可能对如何自定义RouteDefinitionRepository感兴趣,比如如何实现自己的存储逻辑,连接到数据库或远程配置服务。这部分需要给出一个简单的例子,说明如何通过实现接口来扩展功能。 需要注意源码中的关键点,比如事件发布机制。当路由变更时,是否会有RefreshRoutesEvent事件被触发,导致路由重新加载。这一点对于动态更新路由很重要,应该提及。 最后,总结RouteDefinitionRepository的作用,强调它在路由管理中的核心地位,以及不同实现方式的适用场景。确保解释清晰,结构合理,符合用户的需求。</think>Spring Cloud Gateway 中的 **`RouteDefinitionRepository`** 是路由定义(`RouteDefinition`)的核心存储器,负责路由配置的加载、存储与动态管理。以下从源码角度解析其设计逻辑与关键实现: --- ### 1. 接口定义 `RouteDefinitionRepository` 继承自 `ReactiveCrudRepository`,是一个反应式存储接口: ```java public interface RouteDefinitionRepository extends ReactiveCrudRepository<RouteDefinition, String> { Flux<RouteDefinition> getRouteDefinitions(); } ``` - **核心方法**: - `save()` / `delete()`:保存或删除路由定义(支持动态更新) - `getRouteDefinitions()`:返回所有路由的 `Flux` 流(反应式特性) --- ### 2. 默认实现:内存存储 **`InMemoryRouteDefinitionRepository`** 是默认实现,使用 `ConcurrentHashMap` 存储路由: ```java public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository { private final Map<String, RouteDefinition> routes = synchronizedMap(new ConcurrentHashMap<>()); @Override public Flux<RouteDefinition> getRouteDefinitions() { return Flux.fromIterable(routes.values()); } @Override public Mono<Void> save(Mono<RouteDefinition> route) { return route.doOnNext(r -> routes.put(r.getId(), r)).then(); } @Override public Mono<Void> delete(Mono<String> routeId) { return routeId.doOnNext(id -> routes.remove(id)).then(); } } ``` - **特点**: - 路由存储在 JVM 内存中,重启后失效 - 适用于静态配置或开发环境 --- ### 3. 动态路由扩展 通过自定义 `RouteDefinitionRepository` 可实现动态路由: #### 示例:从数据库加载路由 ```java @Bean public RouteDefinitionRepository jdbcRouteRepository(DataSource dataSource) { return new RouteDefinitionRepository() { @Override public Flux<RouteDefinition> getRouteDefinitions() { // 从数据库查询并转换为 RouteDefinition return Flux.fromIterable(queryRoutesFromDB()); } @Override public Mono<Void> save(Mono<RouteDefinition> route) { // 保存到数据库 return route.doOnNext(r -> saveToDB(r)).then(); } @Override public Mono<Void> delete(Mono<String> routeId) { // 从数据库删除 return routeId.doOnNext(id -> deleteFromDB(id)).then(); } }; } ``` --- ### 4. 与路由定位器的协作 `RouteDefinitionRouteLocator` 负责将 `RouteDefinition` 转换为可执行的 `Route`: ```java public class RouteDefinitionRouteLocator implements RouteLocator { private final RouteDefinitionRepository routeDefinitionRepository; public Flux<Route> getRoutes() { return routeDefinitionRepository.getRouteDefinitions() .map(this::convertToRoute); } private Route convertToRoute(RouteDefinition routeDefinition) { // 转换为 Route 对象(包含 Predicate 和 Filter) } } ``` - **流程**:`RouteDefinitionRepository` → `RouteDefinition` → `Route` --- ### 5. 动态刷新机制 当路由变更时,通过发布 `RefreshRoutesEvent` 事件触发更新: ```java // 示例:手动触发刷新 applicationContext.publishEvent(new RefreshRoutesEvent(this)); ``` --- ### 总结 - **核心角色**:`RouteDefinitionRepository` 是路由配置的抽象存储 - **扩展性**:可通过自定义实现对接 Nacos/Consul/DB 等外部配置源 - **动态能力**:结合事件机制,实现路由热更新 - **性能考量**:反应式设计避免阻塞,适合高并发场景 实际应用中,建议结合 `Spring Cloud Config` 或 `Nacos` 实现持久化动态路由管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值