hyperf/docs/zh-cn/router.md
2023-01-03 07:13:43 +08:00

9.4 KiB
Raw Blame History

路由

默认情况下路由由 nikic/fast-route 提供支持,并由 hyperf/http-server 组件负责接入到 Hyperf 中,RPC 路由由对应的 hyperf/rpc-server 组件负责。

HTTP 路由

通过配置文件定义路由

hyperf-skeleton 骨架下,默认在 config/routes.php 文件内完成所有的路由定义,当然如果您路由众多,您也可以对该文件进行扩展,以适应您的需求,但 Hyperf 还支持 注解路由,我们更推荐使用 注解路由,特别是在路由众多的情况下。

通过闭包定义路由

构建一个最基本的路由只需一个 URI 和一个 闭包(Closure),我们直接通过代码来演示一下:

<?php
use Hyperf\HttpServer\Router\Router;

Router::get('/hello-hyperf', function () {
    return 'Hello Hyperf.';
});

您可以通过 浏览器 或 cURL 命令行来请求 http://host:port/hello-hyperf 来访问该路由。

定义标准路由

所谓标准路由指的是由 控制器(Controller)操作(Action) 来处理的路由,如果您使用 请求处理器(Request Handler) 模式也是类似的,我们通过代码来演示一下:

<?php
use Hyperf\HttpServer\Router\Router;

// 下面三种方式的任意一种都可以达到同样的效果
Router::get('/hello-hyperf', 'App\Controller\IndexController::hello');
Router::get('/hello-hyperf', 'App\Controller\IndexController@hello');
Router::get('/hello-hyperf', [App\Controller\IndexController::class, 'hello']);

该路由定义为将 /hello-hyperf 路径绑定到 App\Controller\IndexController 下的 hello 方法。

可用的路由方法

路由器提供了多种方法帮助您注册任何的 HTTP 请求的路由:

use Hyperf\HttpServer\Router\Router;

// 注册与方法名一致的 HTTP METHOD 的路由
Router::get($uri, $callback);
Router::post($uri, $callback);
Router::put($uri, $callback);
Router::patch($uri, $callback);
Router::delete($uri, $callback);
Router::head($uri, $callback);

// 注册任意 HTTP METHOD 的路由
Router::addRoute($httpMethod, $uri, $callback);

有时候您可能需要注册一个可以同时响应多种 HTTP METHOD 请求的路由,可以通过 addRoute 方法实现定义:

use Hyperf\HttpServer\Router\Router;

Router::addRoute(['GET', 'POST','PUT','DELETE'], $uri, $callback);

路由组的定义方式

实际路由为 group/route, 即 /user/index, /user/store, /user/update, /user/delete

Router::addGroup('/user/',function (){
    Router::get('index','App\Controller\UserController@index');
    Router::post('store','App\Controller\UserController@store');
    Router::get('update','App\Controller\UserController@update');
    Router::post('delete','App\Controller\UserController@delete');
});

通过注解定义路由

Hyperf 提供了非常便利的 注解 路由功能,您可以直接在任意类上通过定义 #[Controller]#[AutoController] 注解来完成一个路由的定义。

#[AutoController] 注解

#[AutoController] 为绝大多数简单的访问场景提供路由绑定支持,使用 #[AutoController] 时则 Hyperf 会自动解析所在类的所有 public 方法并提供 GETPOST 两种请求方式。

使用 #[AutoController] 注解时需 use Hyperf\HttpServer\Annotation\AutoController; 命名空间;

驼峰命名的控制器,会自动转化为蛇形路由,以下为控制器与实际路由的对应关系示例:

控制器 注解 访问路由
MyDataController @AutoController() /my_data/index
MydataController @AutoController() /mydata/index
MyDataController @AutoController(prefix="/data") /data/index
<?php
declare(strict_types=1);

namespace App\Controller;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\AutoController;

#[AutoController]
class UserController
{
    // Hyperf 会自动为此方法生成一个 /user/index 的路由,允许通过 GET 或 POST 方式请求
    public function index(RequestInterface $request)
    {
        // 从请求中获得 id 参数
        $id = $request->input('id', 1);
        return (string)$id;
    }
}

#[Controller] 注解

#[Controller] 为满足更细致的路由定义需求而存在,使用 #[Controller] 注解用于表明当前类为一个 Controller 类,同时需配合 #[RequestMapping] 注解来对请求方法和请求路径进行更详细的定义。
我们也提供了多种快速便捷的 Mapping 注解,如 #[GetMapping]#[PostMapping]#[PutMapping]#[PatchMapping]#[DeleteMapping] 5 种便捷的注解用于表明允许不同的请求方法。

使用 #[Controller] 注解时需 use Hyperf\HttpServer\Annotation\Controller; 命名空间;
使用 #[RequestMapping] 注解时需 use Hyperf\HttpServer\Annotation\RequestMapping; 命名空间;
使用 #[GetMapping] 注解时需 use Hyperf\HttpServer\Annotation\GetMapping; 命名空间;
使用 #[PostMapping] 注解时需 use Hyperf\HttpServer\Annotation\PostMapping; 命名空间;
使用 #[PutMapping] 注解时需 use Hyperf\HttpServer\Annotation\PutMapping; 命名空间;
使用 #[PatchMapping] 注解时需 use Hyperf\HttpServer\Annotation\PatchMapping; 命名空间;
使用 #[DeleteMapping] 注解时需 use Hyperf\HttpServer\Annotation\DeleteMapping; 命名空间;

<?php
declare(strict_types=1);

namespace App\Controller;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;

#[Controller]
class UserController
{
    // Hyperf 会自动为此方法生成一个 /user/index 的路由,允许通过 GET 或 POST 方式请求
    #[RequestMapping(path: "index", methods: "get,post")]
    public function index(RequestInterface $request)
    {
        // 从请求中获得 id 参数
        $id = $request->input('id', 1);
        return (string)$id;
    }
}

注解参数

#[Controller]#[AutoController] 都提供了 prefixserver 两个参数。

prefix 表示该 Controller 下的所有方法路由的前缀,默认为类名的小写,如 UserControllerprefix 默认为 user,如类内某一方法的 pathindex,则最终路由为 /user/index
需要注意的是 prefix 并非一直有效,当类内的方法的 path/ 开头时,则表明路径从 URI 头部开始定义,也就意味着会忽略 prefix 的值,同时如果没有设置 prefix 属性,那么控制器类命名空间中 \\Controller\\ 之后的部分会以蛇形命名法(SnakeCase)被用作路由的前缀。

server 表示该路由是定义在哪个 Server 之上的,由于 Hyperf 支持同时启动多个 Server,也就意味着有可能会同时存在多个 HTTP Server,则在定义路由是可以通过 server 参数来进行区分这个路由是为了哪个 Server 定义的,默认为 http

路由参数

本框架定义的路由参数必须和控制器参数键名、类型保持一致,否则控制器无法接受到相关参数

Router::get('/user/{id}', 'App\Controller\UserController::info');
public function info(int $id)
{
    $user = User::find($id);
    return $user->toArray();
}

通过 route 方法获取

public function index(RequestInterface $request)
{
        // 存在则返回,不存在则返回默认值 null
        $id = $request->route('id');
        // 存在则返回,不存在则返回默认值 0
        $id = $request->route('id', 0);
}

必填参数

我们可以对 $uri 进行一些参数定义,通过 {} 来声明参数,如 /user/{id} 则声明了 id 值为一个必填参数。

可选参数

有时候您可能会希望这个参数是可选的,您可以通过 [] 来声明中括号内的参数为一个可选参数,如 /user/[{id}]

获取路由信息

如果安装了 devtool 组件,可使用 php bin/hyperf.php describe:routes 命令获取路由列表信息, 并且提供 path 可选项,方便获取单个路由信息,对应的命令 php bin/hyperf.php describe:routes --path=/foo/bar

HTTP 异常

在路由匹配不到路由时,如 路由找不到(404)请求方法不允许(405) 等 HTTP 异常Hyperf 会统一抛出一个 Hyperf\HttpMessage\Exception\HttpException 异常类的子类,您需要通过 ExceptionHandler 机制来管理这些异常并做对应的响应处理,默认情况下可以直接使用组件提供的 Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler 来进行异常捕获处理,注意这个异常处理器需要您自行配置到 config/autoload/exceptions.php 配置文件中去,并保障多个异常处理器之间的顺序链路是正确的。
当您需要对 路由找不到(404)请求方法不允许(405) 等 HTTP 异常情况的响应进行自定义处理时,您可直接根据 HttpExceptionHandler 的代码实现您自己的异常处理器,并配置您自己的异常处理器。关于异常处理器的逻辑和使用说明,可具体查阅 异常处理