簡介 (Introduction)
Laravel 的 Illuminate\Http\Request 類別提供了物件導向的方式來與應用程式目前正在處理的 HTTP 請求互動,以及檢索與請求一起提交的輸入、Cookie 和檔案。
與 Request 互動 (Interacting With The Request)
存取 Request (Accessing The Request)
要透過依賴注入取得當前 HTTP 請求的實例,你應該在路由閉包或 Controller 方法上型別提示 Illuminate\Http\Request 類別。傳入的請求實例將由 Laravel Service Container 自動注入:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Store a new user.
*/
public function store(Request $request): RedirectResponse
{
$name = $request->input('name');
// Store the user...
return redirect('/users');
}
}
如前所述,你也可以在路由閉包上型別提示 Illuminate\Http\Request 類別。Service Container 會在執行時自動將傳入的請求注入閉包中:
use Illuminate\Http\Request;
Route::get('/', function (Request $request) {
// ...
});
依賴注入與路由參數 (Dependency Injection Route Parameters)
如果你的 Controller 方法還期望從路由參數接收輸入,你應該在其他依賴項後列出路由參數。例如,如果你的路由定義如下:
use App\Http\Controllers\UserController;
Route::put('/user/{'{id}'}', [UserController::class, 'update']);
你仍然可以型別提示 Illuminate\Http\Request 並透過如下定義 Controller 方法來存取你的 id 路由參數:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Update the specified user.
*/
public function update(Request $request, string $id): RedirectResponse
{
// Update the user...
return redirect('/users');
}
}
Request 路徑、主機與方法 (Request Path And Method)
Illuminate\Http\Request 實例提供了各種方法來檢查傳入的 HTTP 請求,並擴充了 Symfony\Component\HttpFoundation\Request 類別。我們將在下面討論幾個最重要的方法。
取得 Request 路徑 (Retrieving The Request Path)
path 方法回傳請求的路徑資訊。因此,如果傳入的請求目標是 http://example.com/foo/bar,path 方法將回傳 foo/bar:
$uri = $request->path();
檢查 Request 路徑 / 路由 (Inspecting The Request Path)
is 方法允許你驗證傳入的請求路徑是否符合給定的模式。在使用此方法時,你可以使用 * 字元作為萬用字元:
if ($request->is('admin/*')) {
// ...
}
使用 routeIs 方法,你可以判斷傳入的請求是否符合命名路由:
if ($request->routeIs('admin.*')) {
// ...
}
取得 Request URL (Retrieving The Request Url)
要取得傳入請求的完整 URL,你可以使用 url 或 fullUrl 方法。url 方法將回傳不含查詢字串的 URL,而 fullUrl 方法則包含查詢字串:
$url = $request->url();
$urlWithQueryString = $request->fullUrl();
如果你想將查詢字串資料附加到當前 URL,你可以呼叫 fullUrlWithQuery 方法。此方法將給定的查詢字串變數陣列與當前查詢字串合併:
$request->fullUrlWithQuery(['type' => 'phone']);
如果你想取得不含給定查詢字串參數的當前 URL,你可以使用 fullUrlWithoutQuery 方法:
$request->fullUrlWithoutQuery(['type']);
取得 Request 主機 (Retrieving The Request Host)
你可以透過 host、httpHost 和 schemeAndHttpHost 方法取得傳入請求的「主機」:
$request->host();
$request->httpHost();
$request->schemeAndHttpHost();
取得 Request 方法 (Retrieving The Request Method)
method 方法會回傳請求的 HTTP 動詞。你可以使用 isMethod 方法來驗證 HTTP 動詞是否符合給定的字串:
$method = $request->method();
if ($request->isMethod('post')) {
// ...
}
Request 標頭 (Request Headers)
你可以使用 header 方法從 Illuminate\Http\Request 實例取得請求標頭。如果請求中不存在該標頭,將回傳 null。然而,header 方法接受一個可選的第二個參數,如果請求中不存在該標頭,將回傳該參數:
$value = $request->header('X-Header-Name');
$value = $request->header('X-Header-Name', 'default');
hasHeader 方法可用於判斷請求是否包含給定的標頭:
if ($request->hasHeader('X-Header-Name')) {
// ...
}
為了方便起見,bearerToken 方法可用於從 Authorization 標頭取得 bearer token。如果不存在這樣的標頭,將回傳空字串:
$token = $request->bearerToken();
Request IP 位址 (Request Ip Address)
ip 方法可用於取得向你的應用程式發出請求的客戶端的 IP 位址:
$ipAddress = $request->ip();
如果你想取得 IP 位址陣列,包括所有由代理轉發的客戶端 IP 位址,你可以使用 ips 方法。「原始」客戶端 IP 位址將位於陣列的末尾:
$ipAddresses = $request->ips();
一般來說,IP 位址應該被視為不可信任的、使用者控制的輸入,僅用於資訊目的。
內容協商 (Content Negotiation)
Laravel 提供了幾種方法來透過 Accept 標頭檢查傳入請求所請求的內容類型。首先,getAcceptableContentTypes 方法將回傳一個包含請求接受的所有內容類型的陣列:
$contentTypes = $request->getAcceptableContentTypes();
accepts 方法接受一個內容類型陣列,如果請求接受任何內容類型,則回傳 true。否則,將回傳 false:
if ($request->accepts(['text/html', 'application/json'])) {
// ...
}
你可以使用 prefers 方法來判斷給定內容類型陣列中哪個內容類型最受請求青睞。如果請求不接受任何提供的內容類型,將回傳 null:
$preferred = $request->prefers(['text/html', 'application/json']);
由於許多應用程式只提供 HTML 或 JSON,你可以使用 expectsJson 方法來快速判斷傳入的請求是否期望 JSON 回應:
if ($request->expectsJson()) {
// ...
}
PSR-7 Request
PSR-7 標準 為 HTTP 訊息指定了介面,包括請求和回應。如果你想取得 PSR-7 請求的實例而不是 Laravel 請求,你首先需要安裝幾個函式庫。Laravel 使用 Symfony HTTP Message Bridge 元件將典型的 Laravel 請求和回應轉換為 PSR-7 相容的實作:
composer require symfony/psr-http-message-bridge
composer require nyholm/psr7
安裝這些函式庫後,你可以透過在路由閉包或 Controller 方法上型別提示請求介面來取得 PSR-7 請求:
use Psr\Http\Message\ServerRequestInterface;
Route::get('/', function (ServerRequestInterface $request) {
// ...
});
[!NOTE] 如果你從路由或 Controller 回傳 PSR-7 回應實例,它將自動轉換回 Laravel 回應實例並由框架顯示。
輸入 (Input)
取得輸入 (Retrieving Input)
取得所有輸入資料 (Retrieving All Input Data)
你可以使用 all 方法以 array 形式取得所有傳入請求的輸入資料。無論傳入的請求是來自 HTML 表單還是 XHR 請求,都可以使用此方法:
$input = $request->all();
使用 collect 方法,你可以將所有傳入請求的輸入資料以集合的形式取得:
$input = $request->collect();
collect 方法還允許你將傳入請求輸入的子集作為集合取得:
$request->collect('users')->each(function (string $user) {
// ...
});
取得輸入值 (Retrieving An Input Value)
使用幾個簡單的方法,你可以從你的 Illuminate\Http\Request 實例存取所有使用者輸入,而不必擔心請求使用了哪個 HTTP 動詞。無論 HTTP 動詞如何,input 方法都可用於取得使用者輸入:
$name = $request->input('name');
你可以將預設值作為第二個參數傳遞給 input 方法。如果請求中不存在請求的輸入值,將回傳此值:
$name = $request->input('name', 'Sally');
處理包含陣列輸入的表單時,使用「點」符號來存取陣列:
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
你可以在不帶任何參數的情況下呼叫 input 方法,以將所有輸入值作為關聯陣列取得:
$input = $request->input();
從查詢字串取得輸入 (Retrieving Input From The Query String)
雖然 input 方法從整個請求負載(包括查詢字串)取得值,但 query 方法只會從查詢字串取得值:
$name = $request->query('name');
如果請求的查詢字串值資料不存在,將回傳此方法的第二個參數:
$name = $request->query('name', 'Helen');
你可以在不帶任何參數的情況下呼叫 query 方法,以將所有查詢字串值作為關聯陣列取得:
$query = $request->query();
取得 JSON 輸入值 (Retrieving Json Input Values)
當向你的應用程式發送 JSON 請求時,只要請求的 Content-Type 標頭正確設定為 application/json,你就可以透過 input 方法存取 JSON 資料。你甚至可以使用「點」語法來取得巢狀在 JSON 陣列 / 物件中的值:
$name = $request->input('user.name');
取得可字串化的輸入值 (Retrieving Stringable Input Values)
你可以使用 string 方法將請求資料作為 Illuminate\Support\Stringable 的實例取得,而不是將請求的輸入資料作為基本 string 取得:
$name = $request->string('name')->trim();
取得整數輸入值 (Retrieving Integer Input Values)
要將輸入值作為整數取得,你可以使用 integer 方法。此方法將嘗試將輸入值轉換為整數。如果輸入不存在或轉換失敗,它將回傳你指定的預設值。這對於分頁或其他數值輸入特別有用:
$perPage = $request->integer('per_page');
取得布林值輸入值 (Retrieving Boolean Input Values)
處理像核取方塊這樣的 HTML 元素時,你的應用程式可能會收到實際上是字串的「真值」。例如,「true」或「on」。為了方便起見,你可以使用 boolean 方法將這些值作為布林值取得。boolean 方法對於 1、「1」、true、「true」、「on」和「yes」回傳 true。所有其他值將回傳 false:
$archived = $request->boolean('archived');
取得陣列輸入值 (Retrieving Array Input Values)
可以使用 array 方法取得包含陣列的輸入值。此方法將始終將輸入值轉換為陣列。如果請求不包含具有給定名稱的輸入值,將回傳空陣列:
$versions = $request->array('versions');
取得日期輸入值 (Retrieving Date Input Values)
為了方便起見,包含日期 / 時間的輸入值可以使用 date 方法作為 Carbon 實例取得。如果請求不包含具有給定名稱的輸入值,將回傳 null:
$birthday = $request->date('birthday');
date 方法接受的第二個和第三個參數可分別用於指定日期的格式和時區:
$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
如果輸入值存在但格式無效,將拋出 InvalidArgumentException;因此,建議你在呼叫 date 方法之前驗證輸入。
取得列舉輸入值 (Retrieving Enum Input Values)
對應於 PHP 列舉的輸入值也可以從請求中取得。如果請求不包含具有給定名稱的輸入值,或列舉沒有與輸入值匹配的支援值,將回傳 null。enum 方法接受輸入值的名稱和列舉類別作為其第一個和第二個參數:
use App\Enums\Status;
$status = $request->enum('status', Status::class);
你也可以提供一個預設值,如果值遺失或無效,將回傳該預設值:
$status = $request->enum('status', Status::class, Status::Pending);
如果輸入值是對應於 PHP 列舉的值陣列,你可以使用 enums 方法將值陣列作為列舉實例取得:
use App\Enums\Product;
$products = $request->enums('products', Product::class);
透過動態屬性取得輸入 (Retrieving Input Via Dynamic Properties)
你也可以使用 Illuminate\Http\Request 實例上的動態屬性來存取使用者輸入。例如,如果你的應用程式的表單之一包含 name 欄位,你可以像這樣存取欄位的值:
$name = $request->name;
使用動態屬性時,Laravel 將首先在請求負載中尋找參數的值。如果不存在,Laravel 將在匹配路由的參數中搜尋該欄位。
取得輸入資料的一部分 (Retrieving A Portion Of The Input Data)
如果你需要取得輸入資料的子集,你可以使用 only 和 except 方法。這兩個方法都接受單個 array 或動態參數列表:
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
[!WARNING] >
only方法回傳你請求的所有鍵 / 值對;但是,它不會回傳請求中不存在的鍵 / 值對。
輸入存在性 (Input Presence)
你可以使用 has 方法來判斷請求中是否存在值。如果請求中存在該值,has 方法會回傳 true:
if ($request->has('name')) {
// ...
}
當給定一個陣列時,has 方法將判斷是否存在所有指定的值:
if ($request->has(['name', 'email'])) {
// ...
}
如果存在任何指定的值,hasAny 方法回傳 true:
if ($request->hasAny(['name', 'email'])) {
// ...
}
如果請求中存在值,whenHas 方法將執行給定的閉包:
$request->whenHas('name', function (string $input) {
// ...
});
可以將第二個閉包傳遞給 whenHas 方法,如果請求中不存在指定的值,則將執行該閉包:
$request->whenHas('name', function (string $input) {
// The "name" value is present...
}, function () {
// The "name" value is not present...
});
如果你想判斷請求中是否存在值且不是空字串,你可以使用 filled 方法:
if ($request->filled('name')) {
// ...
}
如果你想判斷請求中遺失值或是空字串,你可以使用 isNotFilled 方法:
if ($request->isNotFilled('name')) {
// ...
}
當給定一個陣列時,isNotFilled 方法將判斷所有指定的值是否都遺失或為空:
if ($request->isNotFilled(['name', 'email'])) {
// ...
}
如果任何指定的值不是空字串,anyFilled 方法回傳 true:
if ($request->anyFilled(['name', 'email'])) {
// ...
}
如果請求中存在值且不是空字串,whenFilled 方法將執行給定的閉包:
$request->whenFilled('name', function (string $input) {
// ...
});
可以將第二個閉包傳遞給 whenFilled 方法,如果指定的值未「填充」,則將執行該閉包:
$request->whenFilled('name', function (string $input) {
// The "name" value is filled...
}, function () {
// The "name" value is not filled...
});
要判斷請求中是否缺少給定的鍵,你可以使用 missing 和 whenMissing 方法:
if ($request->missing('name')) {
// ...
}
$request->whenMissing('name', function () {
// The "name" value is missing...
}, function () {
// The "name" value is present...
});
合併額外輸入 (Merging Additional Input)
有時你可能需要手動將額外的輸入合併到請求的現有輸入資料中。為了實現這一點,你可以使用 merge 方法。如果請求中已經存在給定的輸入鍵,它將被提供給 merge 方法的資料覆蓋:
$request->merge(['votes' => 0]);
mergeIfMissing 方法可用於將輸入合併到請求中,如果相應的鍵在請求的輸入資料中尚不存在:
$request->mergeIfMissing(['votes' => 0]);
舊輸入 (Old Input)
Laravel 允許你在下一次請求期間保留來自一次請求的輸入。此功能對於在檢測到驗證錯誤後重新填充表單特別有用。但是,如果你使用 Laravel 包含的驗證功能,你可能不需要手動直接使用這些 Session 輸入快閃方法,因為 Laravel 的一些內建驗證功能會自動呼叫它們。
將輸入快閃到 Session (Flashing Input To The Session)
Illuminate\Http\Request 類別上的 flash 方法會將當前輸入快閃到 Session,以便在使用者的下一次請求期間可用:
$request->flash();
你也可以使用 flashOnly 和 flashExcept 方法將請求資料的子集快閃到 Session。這些方法對於將敏感資訊(如密碼)保留在 Session 之外非常有用:
$request->flashOnly(['username', 'email']);
$request->flashExcept('password');
快閃輸入然後重新導向 (Flashing Input Then Redirecting)
由於你通常希望將輸入快閃到 Session,然後重新導向到上一頁,你可以使用 withInput 方法輕鬆地將輸入快閃鏈結到重新導向上:
return redirect('/form')->withInput();
return redirect()->route('user.create')->withInput();
return redirect('/form')->withInput(
$request->except('password')
);
取得舊輸入 (Retrieving Old Input)
要從上一次請求中取得快閃的輸入,請在 Illuminate\Http\Request 的實例上呼叫 old 方法。old 方法將從 Session 中拉取先前快閃的輸入資料:
$username = $request->old('username');
Laravel 還提供了一個全域 old 輔助函式。如果你在 Blade 模板中顯示舊輸入,使用 old 輔助函式重新填充表單會更方便。如果給定欄位不存在舊輸入,將回傳 null:
<input type="text" name="username" value="{{ old('username') }}">
Cookie
從 Request 取得 Cookie (Retrieving Cookies From Requests)
Laravel 框架建立的所有 Cookie 都經過加密並使用驗證碼簽名,這意味著如果客戶端更改了它們,它們將被視為無效。要從請求中取得 Cookie 值,請在 Illuminate\Http\Request 實例上使用 cookie 方法:
$value = $request->cookie('name');
輸入修整與正規化 (Input Trimming And Normalization)
預設情況下,Laravel 在應用程式的全域 Middleware 堆疊中包含 Illuminate\Foundation\Http\Middleware\TrimStrings 和 Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull Middleware。這些 Middleware 會自動修整請求中的所有傳入字串欄位,並將任何空字串欄位轉換為 null。這使你不必在路由和 Controller 中擔心這些正規化問題。
停用輸入正規化
如果你想為所有請求停用此行為,你可以透過在應用程式的 bootstrap/app.php 檔案中呼叫 $middleware->remove 方法從應用程式的 Middleware 堆疊中移除這兩個 Middleware:
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Illuminate\Foundation\Http\Middleware\TrimStrings;
->withMiddleware(function (Middleware $middleware): void {
$middleware->remove([
ConvertEmptyStringsToNull::class,
TrimStrings::class,
]);
})
如果你想為應用程式的請求子集停用字串修整和空字串轉換,你可以在應用程式的 bootstrap/app.php 檔案中使用 trimStrings 和 convertEmptyStringsToNull Middleware 方法。這兩個方法都接受一個閉包陣列,應該回傳 true 或 false 來指示是否應跳過輸入正規化:
->withMiddleware(function (Middleware $middleware): void {
$middleware->convertEmptyStringsToNull(except: [
fn (Request $request) => $request->is('admin/*'),
]);
$middleware->trimStrings(except: [
fn (Request $request) => $request->is('admin/*'),
]);
})
檔案 (Files)
取得上傳的檔案 (Retrieving Uploaded Files)
你可以使用 file 方法或使用動態屬性從 Illuminate\Http\Request 實例取得上傳的檔案。file 方法回傳 Illuminate\Http\UploadedFile 類別的實例,它擴充了 PHP SplFileInfo 類別,並提供了各種與檔案互動的方法:
$file = $request->file('photo');
$file = $request->photo;
你可以使用 hasFile 方法判斷請求中是否存在檔案:
if ($request->hasFile('photo')) {
// ...
}
驗證成功上傳 (Validating Successful Uploads)
除了檢查檔案是否存在之外,你還可以透過 isValid 方法驗證上傳檔案時沒有問題:
if ($request->file('photo')->isValid()) {
// ...
}
檔案路徑和副檔名 (File Paths Extensions)
UploadedFile 類別還包含存取檔案完全限定路徑及其副檔名的方法。extension 方法將嘗試根據其內容猜測檔案的副檔名。此副檔名可能與客戶端提供的副檔名不同:
$path = $request->photo->path();
$extension = $request->photo->extension();
其他檔案方法 (Other File Methods)
UploadedFile 實例上還有各種其他可用的方法。查看類別的 API 文件以獲取有關這些方法的更多資訊。
儲存上傳的檔案 (Storing Uploaded Files)
要儲存上傳的檔案,你通常會使用你配置的檔案系統之一。UploadedFile 類別有一個 store 方法,它會將上傳的檔案移動到你的磁碟之一,這可能是你本地檔案系統上的位置或像 Amazon S3 這樣的雲端儲存位置。
store 方法接受檔案應儲存的路徑,該路徑相對於檔案系統的配置根目錄。此路徑不應包含檔案名稱,因為將自動產生唯一 ID 作為檔案名稱。
store 方法還接受一個可選的第二個參數,用於應該用於儲存檔案的磁碟名稱。該方法將回傳相對於磁碟根目錄的檔案路徑:
$path = $request->photo->store('images');
$path = $request->photo->store('images', 's3');
如果你不希望自動產生檔案名稱,你可以使用 storeAs 方法,該方法接受路徑、檔案名稱和磁碟名稱作為其參數:
$path = $request->photo->storeAs('images', 'filename.jpg');
$path = $request->photo->storeAs('images', 'filename.jpg', 's3');
[!NOTE] 有關 Laravel 中檔案儲存的更多資訊,請查看完整的檔案儲存文件。
設定受信任的代理 (Configuring Trusted Proxies)
在終止 TLS / SSL 憑證的負載平衡器後面執行應用程式時,你可能會注意到你的應用程式在使用 url 輔助函式時有時不會產生 HTTPS 連結。通常這是因為你的應用程式正在從你的負載平衡器在連接埠 80 上轉發流量,並且不知道它應該產生安全連結。
要解決這個問題,你可以啟用 Laravel 應用程式中包含的 Illuminate\Http\Middleware\TrustProxies Middleware,它允許你快速自訂應用程式應該信任的負載平衡器或代理。你的受信任代理應使用應用程式的 bootstrap/app.php 檔案中的 trustProxies Middleware 方法指定:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(at: [
'192.168.1.1',
'10.0.0.0/8',
]);
})
除了設定受信任的代理之外,你還可以設定應該信任的代理標頭:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(headers: Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB
);
})
[!NOTE] 如果你使用 AWS Elastic Load Balancing,
headers值應該是Request::HEADER_X_FORWARDED_AWS_ELB。如果你的負載平衡器使用來自 RFC 7239 的標準Forwarded標頭,headers值應該是Request::HEADER_FORWARDED。有關可在headers值中使用的常數的更多資訊,請查看 Symfony 關於信任代理的文件。
信任所有代理 (Trusting All Proxies)
如果你使用 Amazon AWS 或其他「雲端」負載平衡器提供者,你可能不知道實際平衡器的 IP 位址。在這種情況下,你可以使用 * 來信任所有代理:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(at: '*');
})
設定受信任的主機 (Configuring Trusted Hosts)
預設情況下,Laravel 會回應它收到的所有請求,而不管 HTTP 請求的 Host 標頭的內容如何。此外,在 Web 請求期間產生應用程式的絕對 URL 時,將使用 Host 標頭的值。
通常,你應該設定你的 Web 伺服器(如 Nginx 或 Apache)僅向應用程式發送與給定主機名稱匹配的請求。但是,如果你沒有直接自訂 Web 伺服器的能力,並且需要指示 Laravel 僅回應某些主機名稱,你可以透過為應用程式啟用 Illuminate\Http\Middleware\TrustHosts Middleware 來實現。
要啟用 TrustHosts Middleware,你應該在應用程式的 bootstrap/app.php 檔案中呼叫 trustHosts Middleware 方法。使用此方法的 at 參數,你可以指定應用程式應該回應的主機名稱。具有其他 Host 標頭的傳入請求將被拒絕:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustHosts(at: ['laravel.test']);
})
預設情況下,來自應用程式 URL 的子網域的請求也會自動受到信任。如果你想停用此行為,你可以使用 subdomains 參數:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustHosts(at: ['laravel.test'], subdomains: false);
})
如果你需要存取應用程式的設定檔或資料庫來判斷受信任的主機,你可以為 at 參數提供一個閉包:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustHosts(at: fn () => config('app.trusted_hosts'));
})