iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0

request 與 route 流程

https://ithelp.ithome.com.tw/upload/images/20230922/20162893pdeDWlHJjU.png
請求通常會經過路由定義、路由服務提供者、中介件、控制器、中介件和 HTTP 響應等階段,以完成請求處理過程。(當然還是要依照需求進行設計)

  1. 路由定義 (Route Definitions)

    請求首先會被路由定義處理。根據您的請求 URL 和 HTTP 方法,Laravel 會查找匹配的路由定義。這可以包括 routes/web.phproutes/api.php 中的路由定義。

  2. 路由服務提供者 (Route Service Provider)

    找到匹配的路由後,Laravel 會呼叫相關的控制器方法。在這個過程中,RouteServiceProvider 可以用來定義路由模型繫結,將 URL 參數綁定到相應的 Eloquent 模型。

  3. 中介件 (Middleware)

    在執行控制器方法之前,請求通常會經過中介件。這些中介件可以在處理請求之前或之後執行一些操作,如驗證、記錄、權限檢查等。中介件可以在控制器方法中指定,也可以在路由群組中全局應用。

  4. 控制器 (Controller)

    路由的控制器部分負責處理請求的邏輯。控制器方法接收請求,可能包含一些業務邏輯,然後返回一個響應。

  5. 中介件 (Middleware - 再次)

    在控制器方法處理完請求後,請求還可以經過一個或多個中介件。這些中介件可以在請求處理完畢後執行額外的操作,如設定 HTTP 響應標頭等。

  6. HTTP 響應 (Response)

    最終,控制器方法將返回一個 HTTP 響應,該響應將根據您的應用程序邏輯生成,並最終返回給客戶端,以完成整個請求-響應流程。

web.php 和 api.php 的差異是什麼

前面有說明過前後端分離的差異,剛開啟 Laravel 專案,routes 資料夾裡面預設會有 web.php 及 api.php 兩個檔案:

  • web.php 主要用於處理與網站的前端頁面有關的請求,如果是將 Laravel 用於全端網站,需要處理包含 View 的部分,通常會將 routes 寫在 web.php。
  • api.php 如果只負責撰寫後端程式,提供 JSON 或其他資料格式的 API 請求和響應,會將這部分的 routes 寫在api.php。

https://ithelp.ithome.com.tw/upload/images/20230922/20162893lPAqbKlTA5.png

除此差異外, Laravel 內部對於這兩個檔案也有不同的處理,包括:

  1. 中介層(Middleware)
    • web.php 預設包含了一些與瀏覽器相關的中介層,例如 web 中介層組。這些中介層處理會話、身份驗證、CSRF 保護等功能,通常用於網頁應用程式。
    • api.php 預設包含了一些與 API 相關的中介層,例如 api 中介層組。這些中介層通常用於處理 API 請求,並可能包括身份驗證、速率限制等功能。
  2. 預設路由前綴
    • web.php 中的路由通常不需要指定前綴,因為它們預設位於根路由(例如 /home)。
    • api.php 中的路由通常會使用 /api 作為路由前綴(例如 /api/users)。

Routes

  • 功能:定義傳入的 URI 規則
    我自己會把它想成鋪設網站的柏油路,使用者只能在柏油路上走指定好的路,不能自行探索其他森林小徑
  • 如果傳入 Request 不符合 Route 的格式限制, Laravel 會直接回傳內建的 404 頁面,建議自訂此錯誤邏輯以免使用者會突然看到與網站完全不同風格的 404 頁面,使用者體驗會很差。

RouteServiceProvider.php

可以用 pattern() 方法在這邊定義整個專案通用的 route 規則


// App\Providers\**RouteServiceProvider** 中定義好後
/**
 * Define your route model bindings, pattern filters, etc.
 */
public function boot(): void
{
    Route::pattern('id', '[0-9]+');
}

// web.php 或 api.php
Route::get('/user/{id}', function ($id) {
    // 只會在 {id} 為數字時執行...
});

簡單的 routes 範例

// 定義一個 uri ,當網站接收到此 uri 時,會給予 $callback 回傳
Route::get($uri, $callback);

// 這裡回傳的 $callback 可以改成閉包 
use Illuminate\Support\Facades\Route;

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

// 或是傳入 controller 中指定的方法
Route::get('/greeting', [GreetingController::class, 'hello']);
		// 搭配的 controller : GreetingController.php
		public function hello()
		{
				return 'Hello World';
		}

https://ithelp.ithome.com.tw/upload/images/20230922/20162893DCPtwWBxpP.png

上面使用了閉包寫法,如果完全看不懂建議回去參考 closure 喔!

更詳細的 routes 寫法請參考官方文件

(再次附上這張圖讓大家參考)

https://ithelp.ithome.com.tw/upload/images/20230922/20162893fkvEYtrvsx.png

Laravel 針對 web.php 便利寫法

因為每個 controller 不外乎進行 index, store, create, show, update, destroy, edit 等動作,所以 Laravel 針對這些方法直接建立了 Route::resource() 方法,只要撰寫下面程式碼:

use App\Http\Controllers\ProductController;
 
Route::resource('product', ProductController::class);

就可以直接註冊下列 routes:

(terminal指令) php artisan route:list | grep product

  GET|HEAD        product .................................... product.index › ProductController@index
  POST            product .................................... product.store › ProductController@store
  GET|HEAD        product/create ........................... product.create › ProductController@create
  GET|HEAD        product/{product} ............................ product.show › ProductController@show
  PUT|PATCH       product/{product} ........................ product.update › ProductController@update
  DELETE          product/{product} ...................... product.destroy › ProductController@destroy
  GET|HEAD        product/{product}/edit ....................... product.edit › ProductController@edit

可以用 only() 方法限制要註冊的 routes

Route::resource('/product', ProductController::class)
    ->only('create', 'store', 'destroy');
(terminal指令) php artisan route:list | grep product

  POST            product .................................... product.store › ProductController@store
  GET|HEAD        product/create ........................... product.create › ProductController@create
  DELETE          product/{product} ...................... product.destroy › ProductController@destroy

中文官方文件英文版官方文件

Laravel 針對 api.php 便利寫法

而純後端的 api.php 不需要單純顯示頁面的 create、edit 方法,可改用 Route::apiresource() 進行排除:

use App\Http\Controllers\PhotoController;
 
Route::apiResource('photos', PhotoController::class);

中文官方文件英文版官方文件

Model Binding

Model Binding 是 Laravel routes 很大的重點,透過 Model Binding,後端小菜鳥可以輕鬆取得 Eloquent Model 的資料,Magic~~

隱式繫結 Implicit Binding

  • routes 定義的參數名稱符合 Model 的小寫名稱,例如,如果有一個 User 模型,那該 route 參數名稱應該是 {user}
  • routes 的閉包,或是 controller 裏面,引入的參數要有符合所用 model 型別提示(type-hint) ,例如:App\Models\User,型別提示(type-hint) 就是 User
// 直接用於 web.php 或 api.php
use App\Models\Product; 
Route::get('/product/{product}', function (Product $product) {
    return $product;
});

// 或是 route + Controller 方法定義...
Route::get('/product/{product}', [ Product::class, 'show' ]);

public function show(Product $product)
{
    return $product;
}

https://ithelp.ithome.com.tw/upload/images/20230922/20162893v6qekbK2Ik.png

隱式繫結 Implicit Binding vs. 顯式繫結 Explicit Binding

在 Laravel 中,有兩種不同的路由模型繫結方式,分別是 Explicit Binding(明確綁定)和 Implicit Binding(隱式綁定),它們的主要差別如下:

隱式繫結 Implicit Binding (菜鳥用這個) 顯式繫結 Explicit Binding
自動綁定 Model Binding 手動設定關聯
自動處理例外 手動處理例外
簡化配置 使用自定義邏輯
適用於常見情況 更多控制權和彈性
  1. Implicit Binding(隱式繫結):
    • 自動綁定關聯:在 Implicit Binding 中,Laravel 自動將路由參數和模型之間建立關聯,您只需在路由參數中使用模型類型進行型別提示即可。
    • 自動處理例外:如果找不到匹配的模型,Laravel 將自動處理並返回 404 錯誤,不需要您額外的處理。
    • 簡化配置:Implicit Binding 更簡單,因為它不需要您手動配置路由和模型之間的關聯,Laravel 會自動處理。
    • 適用於常見情況:Implicit Binding 適用於通常的資源路由,其中您只需要使用模型類型即可自動執行模型繫結。
  2. Explicit Binding(顯式繫結):
    • 手動設定關聯:在 Explicit Binding 中,您需要手動設定路由參數和模型之間的關聯。這通常是通過使用 Route::model 方法或在 RouteServiceProvider 中的 bind 方法中進行設定。
    • 使用自定義邏輯:Explicit Binding 允許您使用自定義的邏輯來確定要繫結的模型實例。這意味著您可以執行複雜的查詢或邏輯來找到要繫結的模型。
    • 手動處理例外:如果找不到匹配的模型,您需要手動處理,通常是通過拋出 ModelNotFoundException 來處理。
    • 更多控制權和彈性:Explicit Binding 讓您有更多控制權,因為您可以根據具體的需求自定義模型繫結的邏輯。

本文介紹了 routes 的流程與前後端差異,也比較了 隱式 和 顯式 的 Model Binding。

但若是在使用 Model Binding 時,Model 裡面根本沒有這筆資料怎麼辦?難道直接讓他回 Laravel 自訂的 404 錯誤頁面?明天就來講講如何解決這個問題~~


上一篇
前後端分離、RESTful API
下一篇
異常處理 Exception:Route Model Binding 無此資料的情況
系列文
Laravel 後端菜鳥可以知道的流程概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言