Router

路由架构

Breeze 已经架构好利用 inertia.js 取得 Login 等画面的路由,不过为了解路由的运作,先用基础的路由做说明。

专案已经预设好用於定义路由的档案,分别是

routes/web.php
routes/api.php

web.php 目标用於网页的请求处理,框架预先帮这里的路由加上许多中介层(Middleware)帮助处理请求,像是处理 cookie 或是防止 CSRF。

对於 web 的 Middleware 设定位於

app\Http\Kernel.php

当中的 $middlewareGroups 参数。

开启 web.php 我们可以看到已经有一组预设的路由

Route::get('/', function () {
    return view('welcome');
});

这就是前面我们执行 php artisan serve 之後让我们可以在浏览器上看到预设画面的路由。

在底下我们可以加上

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

然後存档,再到浏览器输入网址 http://127.0.0.1:8000/greeting
就可以看到老朋友 Hello World 的字样了。

api.php

至於 api.php 顾名思义就是用来定义 api 路由的,打开可以看到这边也有预设的路由

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

我们可以试着用浏览器请求这个路由,网址输入

http://127.0.0.1:8000/api/user

应该会看到这个画面

首先可以注意的是路由明明只写了 /user, 为什麽会需要带上 /api 的路由呢?

这是因为预设在 app\Providers\RouteServiceProvider.php 档案中,已经设定好前缀了。

<!-- app\Providers\RouteServiceProvider.php -->
//...

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::prefix('api') //这里定义了前缀
            ->middleware('api')   
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));

        Route::middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
    });
}

所以 api.php 当中的所有路由记得都要戴上 /api 在前面,才能正确地请求。

请求方法

对应不同的 HTTP 请求方法的路由:

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

如果路由需要对应复数种类的请求:

Route::match(['get', 'post'], '/', $callback);

如果路由要对应所有种类的请求:

Route::any('/', $callback);

依赖注入请求实例

利用 Laravel 的服务容器(Service Container)功能,用 型别提示(Type hinting)可以直接将 Http 请求的实例注入到路由的函式中

use Illuminate\Http\Request;

Route::get('/ip', function (Request $request) {
    return $request->ip();
});

浏览器输入 http://127.0.0.1:8000/api/ip 会出现 127.0.0.1

Request 物件是在请求周期最一开始的时候就将请求解析分装好的产物,具体来说发生在 index.php 第52行的位置

// public/index.php 
$response = tap($kernel->handle(
    $request = Request::capture()
))->send();

可以从 Request 物件中很方便地取出请求的资讯,像是 Header ,Body 等,如果有建立好 Laravel 的用户认证机制的话也可以直接取得登入使用者的资讯。

路由参数

实作上常常会在路由带上资料库的 id 参数,像这样

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

可以同时使用多个参数,会依照顺序对应到函式的参数上。
参数的字串要用字母,除此之外底线也是可以的。

Route::get('/posts/{post}/comments/{_comment}', function ($postId, $commentId) {
    return "post = $postId , _comment = $commentId";
});

用上述的路由然後在浏览器输入网址 http://127.0.0.1:8000/api/posts/1/comments/2
就会出现

post = 1 , _comment = 2

如果跟依赖注入一起用的话,函式参数要先用注入实例,後面再依序排入参数

use Illuminate\Http\Request;
 
Route::get('/posts/{post}/comments/{_comment}',
    function (Request $request, $postId, $commentId) {
        $ip = $request->ip();
        return "From ip: $ip ,post = $postId , _comment = $commentId";
    }
);

可以设定路由参数为非必要,当参数是非必要的时候要注意设定预设值

Route::get('/user/{name?}', function ($name = 'John') {
    return $name;
});

绑定 Model

在路由中带入参数通常是为了根据参数搜寻出单笔数据进行处理,如果该参数是资料主键的话,Laravel 提供了捷径直接搜寻出该笔资料以供处理

use App\Models\User;

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

这边宣告了路由函式的参数型别是 User Model,而在路径中有着名为 user 的参数,这种情况下 Laravel 会自动将 user 参数当作 User 主键值进行查询,查询成功就可以从 $user 取得该笔资料,查询失败则直接回传 404 查询失败回应。

命名路由

可以给路由加上名称标签

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

这样当要重新导向的时候可以很方便的参照,也可以带参数

return redirect()->route('profile', ['id' => 1]); 

路由分组

当有数个路由需要用到相同的 Middleware 进行处里的时候,就会建立分组

Route::middleware(['auth:api', 'cache.headers'])->group(function () {
    Route::get('/user', function () {
        // handle function
    });

    Route::get('/user/profile', function () {
        // handle function
    });
});

像这样 '/user' 跟 '/user/profile' 两个路由收到请求时,都会先经由 'auth:api', 'cache.headers' 对请求进行处理。

对於分组也可以定义共通的路由前缀,像是把上面的 user 提取出来变成前缀

Route::group(
    [
        'prefix' => 'user',
        'middleware' => ['auth:api', 'cache.headers'],
    ], function () {
        Route::get('/', function () {
            // handle function
        });

        Route::get('/profile', function () {
            // handle function
        });
    }
);

查看路由清单

可以用指令查看目前定义的路由们,会包含各路由应用的 middleware 列表

 sail artisan route:list

References

Laravel Routing
https://stackoverflow.com/questions/54486616/how-passing-request-instance-in-methods-work-in-laravel

<<:  [Day5]DML语句中的命令:SELECT语句

>>:  第十五天:用 detekt 做静态分析

人的管理 - 危机感 vs. 安全感

我在 MIT 的两年改变了我很多。其中一个重要的体验是有很多世界级的创业家、执行长会来学校演讲,甚至...

伪元素(pseudo element)、伪类别(pseudo element)

伪元素 : Before 、After Before 对指定元素添加最後一个子元素 After 对指...

Day01 - 铁人赛我又来罗

避免像去年一样焦头烂额,这次提前至 7 月开始准备铁人赛, 即便提早准备,也不知要写什麽... 只准...

JS放在哪里呢?

JS 可以放在HTML里面,也可以另开一个.js 档案,把你的code放进去,然後变成连结放在htm...

Day 16 建立资料库

我们现在有了基本的日志,但是每次输入完重整页面都会刷新,因为这些资料都只存在於浏览器,没有真正储存到...