hyperf路由

Hyperf框架作为基于Swoole的高性能PHP协程框架,其路由系统是整个Web应用的入口,负责将客户端请求分发到对应的处理逻辑,Hyperf的路由组件基于PSR-7标准设计,支持灵活的路由定义、参数约束、中间件机制等功能,能够满足复杂业务场景的需求,本文将详细介绍Hyperf路由的核心功能及使用方法,帮助开发者快速掌握路由配置技巧。

hyperf路由

路由的基本定义

Hyperf的路由定义通过HyperfHttpServerRouterRouter类提供的方法实现,支持常见的HTTP请求方法,如GETPOSTPUTDELETE等,基本语法为在路由配置文件(通常为config/routes.phpconfig/routes/*.php)中调用Router的对应方法,并指定路由路径和处理器。

闭包处理器

闭包是最简单的处理器形式,适合快速实现接口或简单逻辑:

use HyperfHttpServerRouterRouter;
Router::get('/', function () {
    return 'Hello, Hyperf!';
});
Router::post('/api/login', function (PsrHttpMessageServerRequestInterface $request) {
    $data = $request->getParsedBody();
    return ['token' => 'sample-token'];
});

闭包中可以直接注入PsrHttpMessageServerRequestInterface请求对象,用于获取请求参数、头部等信息。

控制器处理器

实际开发中更常用的是控制器处理器,将业务逻辑封装到类方法中:

use HyperfHttpServerRouterRouter;
Router::get('/user/{id}', [AppControllerUserController::class, 'show']);

控制器需继承HyperfHttpServerAnnotationController注解,并定义对应方法,例如UserController中的show方法:

#[Controller]
class UserController
{
    #[GetMapping(path: '/user/{id}')]
    public function show(int $id)
    {
        return ['id' => $id, 'name' => 'John'];
    }
}

通过注解#[GetMapping]可以明确路由方法和路径,支持IDE类型提示和路由扫描。

路由参数与约束

路由参数允许从URL中提取动态数据,Hyperf支持必选参数、可选参数及参数约束。

必选参数

用包裹参数名,如/user/{id},参数会自动注入到处理器方法中:

Router::get('/user/{id}', function ($id) {
    return "User ID: {$id}";
});

可选参数

参数后添加标记为可选,需提供默认值:

Router::get('/user/{name?}', function ($name = 'Guest') {
    return "Hello, {$name}";
});

参数约束

通过正则表达式约束参数格式,避免无效参数进入业务逻辑:

Router::get('/user/{name:[a-zA-Z]+}', function ($name) {
    return "User: {$name}";
});

参数约束规则需紧跟参数名,用分隔,例如d+匹配数字,[a-z]+匹配小写字母等,以下是常见参数约束示例:

参数约束 说明 示例路径
{id:d+} 匹配1个或多个数字 /user/123
{name:w+} 匹配字母、数字、下划线 /user/john_doe
{year:d{4}} 匹配4位数字 /blog/2023
{slug:[a-z-]+} 匹配小写字母和连字符 /post/hello-world

路由分组与中间件

路由分组可以将具有共同特征的路由(如相同前缀、中间件)归为一组,减少重复代码,提升可维护性。

路由前缀分组

通过Router::group()prefix参数统一设置路径前缀:

Router::group(function () {
    Router::get('/profile', function () { return 'Profile Page'; });
    Router::get('/settings', function () { return 'Settings Page'; });
}, ['prefix' => '/user']);

上述代码会生成/user/profile/user/settings两条路由。

hyperf路由

中间件分组

中间件用于请求前后的处理逻辑(如身份验证、日志记录),分组可统一应用中间件:

Router::group(function () {
    Router::get('/dashboard', function () { return 'Dashboard'; });
    Router::post('/data', function () { return 'Data Saved'; });
}, ['middleware' => [AppMiddlewareAuthMiddleware::class]]);

中间件类需实现HyferrMiddlewareInterface接口,或使用注解#[Middleware]定义,中间件执行顺序与定义顺序一致,全局中间件可在config/autoload/middlewares.php中配置。

域分组

通过domain参数实现多域名路由分组,适用于多租户或子域名场景:

Router::group(function () {
    Router::get('/info', function () { return 'Admin Info'; });
}, ['domain' => 'admin.example.com', 'prefix' => '/api']);

需确保服务器配置支持泛域名解析(如*.example.com)。

路由命名与URL生成

为路由命名后,可通过route()函数动态生成URL,避免硬编码路径。

路由命名

使用name()方法为路由指定唯一名称:

Router::get('/user/profile', [UserController::class, 'profile'])->name('profile');
Router::post('/user/avatar', [UserController::class, 'avatar'])->name('avatar.upload');

URL生成

在控制器或闭包中调用route()函数生成URL:

use HyperfDiAnnotationInject;
use HyperfHttpServerContractUrlGeneratorInterface;
#[Controller]
class UserController
{
    #[Inject]
    private UrlGeneratorInterface $urlGenerator;
    public function redirect()
    {
        $url = $this->urlGenerator->route('profile');
        return $this->response->withStatus(302)->withHeader('Location', $url);
    }
}

route()函数支持参数传递,自动替换URL中的占位符:

$url = $this->urlGenerator->route('user.show', ['id' => 123]); // /user/123

路由模型绑定

路由模型绑定可将路由参数直接与Eloquent模型关联,减少手动查询逻辑。

隐式绑定

默认情况下,Hyperf会根据参数名(如id)查找对应模型(如User模型):

Router::get('/user/{user}', [UserController::class, 'show']);
#[Controller]
class UserController
{
    public function show(User $user) // 自动注入User模型实例
    {
        return $user->toArray();
    }
}

需确保模型的主键字段与参数名一致(默认为id)。

显式绑定

通过Router::model()方法自定义参数与模型的映射关系:

Router::model('post', AppModelPost::class);
Router::get('/post/{post}', [PostController::class, 'show']);

这样{post}参数会自动绑定到Post模型实例,若模型不存在会抛出ModelNotFoundException异常。

RESTful资源路由

Hyperf提供resource()方法快速生成符合RESTful规范的路由,适用于资源型接口(如用户、文章等)。

hyperf路由

定义资源路由

Router::resource('posts', PostController::class);

上述代码会自动生成7条标准路由,如下表所示:

方法 路径 控制器方法 作用
GET /posts index 列表资源
POST /posts store 创建资源
GET /posts/{id} show 显示单个资源
PUT /posts/{id} update 更新资源
PATCH /posts/{id} update 部分更新资源
DELETE /posts/{id} destroy 删除资源

自定义资源路由

若需调整生成的路由(如添加自定义方法),可通过exceptonly参数:

Router::resource('posts', PostController::class)->only(['index', 'show', 'store']);
Router::resource('comments', CommentController::class)->except(['create', 'edit']);

路由缓存

生产环境中,路由缓存可显著提升路由匹配效率,通过以下命令生成缓存:

php bin/hyperf.php route:cache

缓存文件位于runtime/route.php,清除缓存使用:

php bin/hyperf.php route:clear

注意:修改路由后需重新生成缓存,否则路由变更不会生效。

路由异常处理

404未找到路由

默认情况下,未匹配的路由会返回404错误,可通过fallback路由自定义处理:

Router::fallback(function () {
    return ['code' => 404, 'message' => 'Page Not Found'];
});

405方法不允许

若请求方法与路由定义不匹配(如GET请求POST路由),返回405错误,可通过HttpMethodNotAllowedHandler自定义处理逻辑,或在config/autoload/exceptions.php中配置异常处理器。

相关问答FAQs

问题1:Hyperf中如何为路由参数添加自定义正则约束,并在参数不符合约束时返回自定义错误信息?
答:通过路由参数的正则约束功能可实现参数格式校验,限制id必须为4位数字:

Router::get('/test/{id:d{4}}', function ($id) {
    return "ID: {$id}";
});

若参数不符合正则规则(如/test/123),Hyperf会自动返回404错误,若需自定义错误信息,可结合全局异常处理,在config/autoload/exceptions.php中定义NotFoundHttpException的处理器:

'exceptions' => [
    HyperfHttpMessageExceptionNotFoundHttpException::class => [
        AppExceptionHandlerRouterExceptionHandler::class,
    ],
],

然后在RouterExceptionHandler中捕获异常并返回自定义响应:

public function handle(Throwable $throwable, RequestInterface $request)
{
    if ($throwable instanceof NotFoundHttpException) {
        return ['code' => 400, 'message' => 'Parameter format error'];
    }
    return parent::handle($throwable, $request);
}

问题2:如何在Hyperf中实现路由组的条件中间件(例如仅对特定用户角色应用中间件)?
答:可通过闭包中间件结合路由分组参数实现条件中间件,仅对admin角色用户应用权限中间件:

Router::group(function ($router) {
    $router->get('/admin/dashboard', function () { return 'Admin Dashboard'; });
    $router->get('/admin/users', function () { return 'User List'; });
}, [
    'prefix' => '/admin',
    'middleware' => function (PsrHttpMessageServerRequestInterface $request, $next) {
        $user = $request->getAttribute('user'); // 假设已通过中间件注入用户信息
        if ($user && $user->role === 'admin') {
            return $next($request);
        }
        return ['code' => 403, 'message' => 'Forbidden'];
    },
]);

上述代码中,闭包中间件会检查用户角色,仅允许admin用户访问分组内路由,也可将角色判断逻辑抽离为独立中间件类,通过依赖注入实现更灵活的控制。

来源互联网整合,作者:小编,如若转载,请注明出处:https://www.aiboce.com/ask/267833.html

Like (0)
小编小编
Previous 2025年11月1日 08:04
Next 2025年11月1日 08:18

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注