跳到內容

HTTP 請求

簡介

Laravel 的 Illuminate\Http\Request 類別提供物件導向的方式來與應用程式正在處理的當前 HTTP 請求互動,並檢索請求中提交的輸入、Cookie 和檔案。

與請求互動

存取請求

若要透過依賴注入取得當前 HTTP 請求的實例,您應該在路由閉包或控制器方法上類型提示 Illuminate\Http\Request 類別。傳入的請求實例將由 Laravel 服務容器 自動注入

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7 
8class UserController extends Controller
9{
10 /**
11 * Store a new user.
12 */
13 public function store(Request $request): RedirectResponse
14 {
15 $name = $request->input('name');
16 
17 // Store the user...
18 
19 return redirect('/users');
20 }
21}

如前所述,您也可以在路由閉包上類型提示 Illuminate\Http\Request 類別。當執行閉包時,服務容器將自動將傳入的請求注入到閉包中

1use Illuminate\Http\Request;
2 
3Route::get('/', function (Request $request) {
4 // ...
5});

依賴注入和路由參數

如果您的控制器方法也期望從路由參數取得輸入,您應該在其他依賴項之後列出路由參數。例如,如果您的路由定義如下

1use App\Http\Controllers\UserController;
2 
3Route::put('/user/{id}', [UserController::class, 'update']);

您仍然可以類型提示 Illuminate\Http\Request 並透過定義如下的控制器方法來存取您的 id 路由參數

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7 
8class UserController extends Controller
9{
10 /**
11 * Update the specified user.
12 */
13 public function update(Request $request, string $id): RedirectResponse
14 {
15 // Update the user...
16 
17 return redirect('/users');
18 }
19}

請求路徑、主機和方法

Illuminate\Http\Request 實例提供了多種方法來檢查傳入的 HTTP 請求,並擴展了 Symfony\Component\HttpFoundation\Request 類別。我們將在下面討論一些最重要的方​​法。

檢索請求路徑

path 方法會傳回請求的路徑資訊。因此,如果傳入的請求目標為 http://example.com/foo/bar,則 path 方法將傳回 foo/bar

1$uri = $request->path();

檢查請求路徑 / 路由

is 方法可讓您驗證傳入的請求路徑是否符合給定的模式。使用此方法時,您可以將 * 字元用作萬用字元

1if ($request->is('admin/*')) {
2 // ...
3}

使用 routeIs 方法,您可以判斷傳入的請求是否符合具名路由

1if ($request->routeIs('admin.*')) {
2 // ...
3}

檢索請求 URL

若要檢索傳入請求的完整 URL,您可以使用 urlfullUrl 方法。 url 方法將傳回不帶查詢字串的 URL,而 fullUrl 方法則包含查詢字串

1$url = $request->url();
2 
3$urlWithQueryString = $request->fullUrl();

如果您想要將查詢字串資料附加到當前 URL,您可以呼叫 fullUrlWithQuery 方法。此方法會將給定的查詢字串變數陣列與當前查詢字串合併

1$request->fullUrlWithQuery(['type' => 'phone']);

如果您想要取得不帶給定查詢字串參數的當前 URL,您可以使用 fullUrlWithoutQuery 方法

1$request->fullUrlWithoutQuery(['type']);

檢索請求主機

您可以透過 hosthttpHostschemeAndHttpHost 方法檢索傳入請求的「主機」

1$request->host();
2$request->httpHost();
3$request->schemeAndHttpHost();

檢索請求方法

method 方法將傳回請求的 HTTP 動詞。您可以使用 isMethod 方法來驗證 HTTP 動詞是否符合給定的字串

1$method = $request->method();
2 
3if ($request->isMethod('post')) {
4 // ...
5}

請求標頭

您可以使用 header 方法從 Illuminate\Http\Request 實例中檢索請求標頭。如果請求中不存在標頭,則會傳回 null。但是,header 方法接受一個可選的第二個參數,如果請求中不存在標頭,則會傳回該參數

1$value = $request->header('X-Header-Name');
2 
3$value = $request->header('X-Header-Name', 'default');

hasHeader 方法可用於判斷請求是否包含給定的標頭

1if ($request->hasHeader('X-Header-Name')) {
2 // ...
3}

為了方便起見,可以使用 bearerToken 方法從 Authorization 標頭檢索 bearer 令牌。如果不存在此類標頭,則會傳回空字串

1$token = $request->bearerToken();

請求 IP 位址

ip 方法可用於檢索向您的應用程式發出請求的客戶端的 IP 位址

1$ipAddress = $request->ip();

如果您想要檢索 IP 位址陣列,包括代理伺服器轉發的所有客戶端 IP 位址,您可以使用 ips 方法。「原始」客戶端 IP 位址將位於陣列的末尾

1$ipAddresses = $request->ips();

一般來說,IP 位址應被視為不受信任、使用者控制的輸入,且僅用於資訊目的。

內容協商

Laravel 提供了幾種方法來透過 Accept 標頭檢查傳入請求所請求的內容類型。首先,getAcceptableContentTypes 方法將傳回一個陣列,其中包含請求接受的所有內容類型

1$contentTypes = $request->getAcceptableContentTypes();

accepts 方法接受內容類型陣列,如果請求接受任何內容類型,則傳回 true。否則,將傳回 false

1if ($request->accepts(['text/html', 'application/json'])) {
2 // ...
3}

您可以使用 prefers 方法來判斷請求最偏好的給定內容類型陣列中的哪種內容類型。如果請求不接受提供的任何內容類型,則會傳回 null

1$preferred = $request->prefers(['text/html', 'application/json']);

由於許多應用程式僅提供 HTML 或 JSON,因此您可以使用 expectsJson 方法快速判斷傳入的請求是否期望 JSON 回應

1if ($request->expectsJson()) {
2 // ...
3}

PSR-7 請求

PSR-7 標準 指定了 HTTP 訊息的介面,包括請求和回應。如果您想要取得 PSR-7 請求的實例而不是 Laravel 請求,您首先需要安裝一些程式庫。 Laravel 使用Symfony HTTP Message Bridge 組件將典型的 Laravel 請求和回應轉換為 PSR-7 相容的實作

1composer require symfony/psr-http-message-bridge
2composer require nyholm/psr7

安裝這些程式庫後,您可以透過在路由閉包或控制器方法上類型提示請求介面來取得 PSR-7 請求

1use Psr\Http\Message\ServerRequestInterface;
2 
3Route::get('/', function (ServerRequestInterface $request) {
4 // ...
5});

如果您從路由或控制器傳回 PSR-7 回應實例,它將自動轉換回 Laravel 回應實例並由框架顯示。

輸入

檢索輸入

檢索所有輸入資料

您可以使用 all 方法將所有傳入請求的輸入資料檢索為 array。無論傳入的請求是來自 HTML 表單還是 XHR 請求,都可以使用此方法

1$input = $request->all();

使用 collect 方法,您可以將所有傳入請求的輸入資料檢索為集合

1$input = $request->collect();

collect 方法還允許您將傳入請求輸入的子集檢索為集合

1$request->collect('users')->each(function (string $user) {
2 // ...
3});

檢索輸入值

透過幾個簡單的方法,您可以從 Illuminate\Http\Request 實例存取所有使用者輸入,而無需擔心請求使用了哪個 HTTP 動詞。無論 HTTP 動詞為何,input 方法都可用於檢索使用者輸入

1$name = $request->input('name');

您可以將預設值作為第二個參數傳遞給 input 方法。如果請求中不存在請求的輸入值,則將傳回此值

1$name = $request->input('name', 'Sally');

當使用包含陣列輸入的表單時,請使用「點」表示法來存取陣列

1$name = $request->input('products.0.name');
2 
3$names = $request->input('products.*.name');

您可以呼叫不帶任何參數的 input 方法,以將所有輸入值檢索為關聯陣列

1$input = $request->input();

從查詢字串檢索輸入

雖然 input 方法從整個請求有效負載(包括查詢字串)檢索值,但 query 方法僅從查詢字串檢索值

1$name = $request->query('name');

如果請求的查詢字串值資料不存在,則會傳回此方法的第二個參數

1$name = $request->query('name', 'Helen');

您可以呼叫不帶任何參數的 query 方法,以將所有查詢字串值檢索為關聯陣列

1$query = $request->query();

檢索 JSON 輸入值

當將 JSON 請求傳送到您的應用程式時,只要請求的 Content-Type 標頭已正確設定為 application/json,您就可以透過 input 方法存取 JSON 資料。您甚至可以使用「點」語法來檢索巢狀在 JSON 陣列/物件中的值

1$name = $request->input('user.name');

檢索 Stringable 輸入值

您可以不用將請求的輸入資料檢索為原始 string,而是使用 string 方法將請求資料檢索為 Illuminate\Support\Stringable 的實例

1$name = $request->string('name')->trim();

檢索整數輸入值

若要將輸入值檢索為整數,您可以使用 integer 方法。此方法將嘗試將輸入值轉換為整數。如果輸入不存在或轉換失敗,它將傳回您指定的預設值。這對於分頁或其他數字輸入特別有用

1$perPage = $request->integer('per_page');

檢索布林值輸入值

在處理諸如核取方塊之類的 HTML 元素時,您的應用程式可能會收到實際上是字串的「真值」。例如,「true」或「on」。為了方便起見,您可以使用 boolean 方法將這些值檢索為布林值。 boolean 方法針對 1、「1」、true、「true」、「on」和「yes」傳回 true。所有其他值將傳回 false

1$archived = $request->boolean('archived');

檢索日期輸入值

為了方便起見,可以使用 date 方法將包含日期/時間的輸入值檢索為 Carbon 實例。如果請求不包含具有給定名稱的輸入值,則會傳回 null

1$birthday = $request->date('birthday');

date 方法接受的第二個和第三個參數可用於分別指定日期的格式和時區

1$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');

如果輸入值存在但格式無效,則會擲回 InvalidArgumentException;因此,建議您在調用 date 方法之前驗證輸入。

檢索列舉輸入值

對應至 PHP 列舉 的輸入值也可以從請求中檢索。如果請求不包含具有給定名稱的輸入值,或者列舉沒有與輸入值匹配的後端值,則會返回 nullenum 方法接受輸入值的名稱和列舉類別作為其第一個和第二個參數。

1use App\Enums\Status;
2 
3$status = $request->enum('status', Status::class);

如果輸入值是對應至 PHP 列舉的值陣列,您可以使用 enums 方法來檢索作為列舉實例的值陣列。

1use App\Enums\Product;
2 
3$products = $request->enums('products', Product::class);

透過動態屬性檢索輸入

您也可以使用 Illuminate\Http\Request 實例上的動態屬性來存取使用者輸入。例如,如果您的應用程式表單之一包含 name 欄位,您可以像這樣存取該欄位的值

1$name = $request->name;

當使用動態屬性時,Laravel 將首先在請求酬載中尋找參數的值。如果不存在,Laravel 將在匹配路由的參數中搜尋該欄位。

檢索部分輸入資料

如果您需要檢索輸入資料的子集,您可以使用 onlyexcept 方法。這兩種方法都接受單個 array 或動態參數列表

1$input = $request->only(['username', 'password']);
2 
3$input = $request->only('username', 'password');
4 
5$input = $request->except(['credit_card']);
6 
7$input = $request->except('credit_card');

only 方法返回您請求的所有鍵 / 值對;但是,它不會返回請求中不存在的鍵 / 值對。

輸入存在

您可以使用 has 方法來判斷值是否存在於請求中。如果值存在於請求中,has 方法會返回 true

1if ($request->has('name')) {
2 // ...
3}

當給定陣列時,has 方法將判斷所有指定的值是否都存在

1if ($request->has(['name', 'email'])) {
2 // ...
3}

如果任何指定的值存在,hasAny 方法會返回 true

1if ($request->hasAny(['name', 'email'])) {
2 // ...
3}

如果值存在於請求中,whenHas 方法將執行給定的閉包

1$request->whenHas('name', function (string $input) {
2 // ...
3});

第二個閉包可以傳遞給 whenHas 方法,如果指定的值在請求中不存在,則將執行該閉包

1$request->whenHas('name', function (string $input) {
2 // The "name" value is present...
3}, function () {
4 // The "name" value is not present...
5});

如果您想判斷值是否存在於請求中且不是空字串,您可以使用 filled 方法

1if ($request->filled('name')) {
2 // ...
3}

如果您想判斷值是否從請求中遺失或為空字串,您可以使用 isNotFilled 方法

1if ($request->isNotFilled('name')) {
2 // ...
3}

當給定陣列時,isNotFilled 方法將判斷所有指定的值是否都遺失或為空

1if ($request->isNotFilled(['name', 'email'])) {
2 // ...
3}

如果任何指定的值不是空字串,anyFilled 方法會返回 true

1if ($request->anyFilled(['name', 'email'])) {
2 // ...
3}

如果值存在於請求中且不是空字串,whenFilled 方法將執行給定的閉包

1$request->whenFilled('name', function (string $input) {
2 // ...
3});

第二個閉包可以傳遞給 whenFilled 方法,如果指定的值不是「filled」,則將執行該閉包

1$request->whenFilled('name', function (string $input) {
2 // The "name" value is filled...
3}, function () {
4 // The "name" value is not filled...
5});

要判斷給定的鍵是否在請求中不存在,您可以使用 missingwhenMissing 方法

1if ($request->missing('name')) {
2 // ...
3}
4 
5$request->whenMissing('name', function () {
6 // The "name" value is missing...
7}, function () {
8 // The "name" value is present...
9});

合併其他輸入

有時您可能需要手動將額外的輸入合併到請求的現有輸入資料中。為了實現這一點,您可以使用 merge 方法。如果給定的輸入鍵已存在於請求中,它將被提供給 merge 方法的資料覆寫

1$request->merge(['votes' => 0]);

如果請求中對應的鍵尚不存在,則可以使用 mergeIfMissing 方法將輸入合併到請求中

1$request->mergeIfMissing(['votes' => 0]);

舊輸入

Laravel 允許您在下一個請求期間保留來自一個請求的輸入。此功能對於在偵測到驗證錯誤後重新填充表單特別有用。但是,如果您正在使用 Laravel 內建的 驗證功能,您可能不需要直接手動使用這些 session 輸入快閃方法,因為 Laravel 的某些內建驗證工具會自動呼叫它們。

將輸入快閃至 Session

Illuminate\Http\Request 類別上的 flash 方法會將當前輸入快閃至 session,以便在使用者下一次對應用程式的請求期間可用

1$request->flash();

您也可以使用 flashOnlyflashExcept 方法將請求資料的子集快閃至 session。這些方法對於將密碼等敏感資訊保留在 session 之外很有用

1$request->flashOnly(['username', 'email']);
2 
3$request->flashExcept('password');

快閃輸入然後重新導向

由於您通常會希望將輸入快閃至 session,然後重新導向到上一頁,因此您可以輕鬆地使用 withInput 方法將輸入快閃鏈接到重新導向。

1return redirect('/form')->withInput();
2 
3return redirect()->route('user.create')->withInput();
4 
5return redirect('/form')->withInput(
6 $request->except('password')
7);

檢索舊輸入

要從先前的請求中檢索快閃輸入,請在 Illuminate\Http\Request 的實例上調用 old 方法。old 方法將從 session 中提取先前快閃的輸入資料

1$username = $request->old('username');

Laravel 還提供了一個全域 old 輔助函數。如果您在 Blade 模板 中顯示舊輸入,則使用 old 輔助函數來重新填充表單更方便。如果給定欄位不存在舊輸入,則會返回 null

1<input type="text" name="username" value="{{ old('username') }}">

Cookie

從請求中檢索 Cookies

由 Laravel 框架建立的所有 cookies 都使用身份驗證碼進行加密和簽名,這意味著如果它們被客戶端更改,它們將被視為無效。要從請求中檢索 cookie 值,請在 Illuminate\Http\Request 實例上使用 cookie 方法

1$value = $request->cookie('name');

輸入修剪和正規化

預設情況下,Laravel 在應用程式的全域 middleware 堆疊中包含 Illuminate\Foundation\Http\Middleware\TrimStringsIlluminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull middleware。這些 middleware 將自動修剪請求上所有傳入的字串欄位,以及將任何空字串欄位轉換為 null。這使您不必擔心在路由和控制器中處理這些正規化問題。

停用輸入正規化

如果您想為所有請求停用此行為,您可以透過在應用程式的 bootstrap/app.php 檔案中調用 $middleware->remove 方法,從應用程式的 middleware 堆疊中移除這兩個 middleware

1use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
2use Illuminate\Foundation\Http\Middleware\TrimStrings;
3 
4->withMiddleware(function (Middleware $middleware) {
5 $middleware->remove([
6 ConvertEmptyStringsToNull::class,
7 TrimStrings::class,
8 ]);
9})

如果您想為應用程式的部分請求停用字串修剪和空字串轉換,您可以在應用程式的 bootstrap/app.php 檔案中使用 trimStringsconvertEmptyStringsToNull middleware 方法。這兩種方法都接受閉包陣列,這些閉包應返回 truefalse 以指示是否應跳過輸入正規化

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->convertEmptyStringsToNull(except: [
3 fn (Request $request) => $request->is('admin/*'),
4 ]);
5 
6 $middleware->trimStrings(except: [
7 fn (Request $request) => $request->is('admin/*'),
8 ]);
9})

檔案

檢索上傳的檔案

您可以使用 file 方法或使用動態屬性從 Illuminate\Http\Request 實例檢索上傳的檔案。file 方法返回 Illuminate\Http\UploadedFile 類別的實例,該實例擴展了 PHP SplFileInfo 類別,並提供了多種與檔案互動的方法

1$file = $request->file('photo');
2 
3$file = $request->photo;

您可以使用 hasFile 方法判斷檔案是否存在於請求中

1if ($request->hasFile('photo')) {
2 // ...
3}

驗證成功上傳

除了檢查檔案是否存在之外,您還可以透過 isValid 方法驗證上傳檔案時沒有問題

1if ($request->file('photo')->isValid()) {
2 // ...
3}

檔案路徑和副檔名

UploadedFile 類別還包含用於存取檔案完整路徑及其副檔名的方法。extension 方法將嘗試根據檔案內容猜測檔案的副檔名。此副檔名可能與客戶端提供的副檔名不同

1$path = $request->photo->path();
2 
3$extension = $request->photo->extension();

其他檔案方法

UploadedFile 實例上還有許多其他方法可用。請查看 該類別的 API 文件,以獲取有關這些方法的更多資訊。

儲存上傳的檔案

要儲存上傳的檔案,您通常會使用您配置的 檔案系統 之一。UploadedFile 類別有一個 store 方法,它會將上傳的檔案移動到您的磁碟之一,這可能是您本地檔案系統上的位置,也可能是像 Amazon S3 這樣的雲端儲存位置。

store 方法接受檔案應儲存在相對於檔案系統配置的根目錄的路徑。此路徑不應包含檔案名,因為將自動產生唯一 ID 作為檔案名。

store 方法還接受一個可選的第二個參數,用於應使用哪個磁碟來儲存檔案。該方法將返回檔案相對於磁碟根目錄的路徑

1$path = $request->photo->store('images');
2 
3$path = $request->photo->store('images', 's3');

如果您不希望自動產生檔案名,您可以使用 storeAs 方法,該方法接受路徑、檔案名和磁碟名稱作為其參數

1$path = $request->photo->storeAs('images', 'filename.jpg');
2 
3$path = $request->photo->storeAs('images', 'filename.jpg', 's3');

有關 Laravel 中檔案儲存的更多資訊,請查看完整的 檔案儲存文件

設定信任的代理伺服器

當在終止 TLS / SSL 憑證的負載平衡器後方執行應用程式時,您可能會注意到當使用 url 輔助函數時,您的應用程式有時不會產生 HTTPS 連結。通常,這是因為您的應用程式正在從連接埠 80 上的負載平衡器轉發流量,並且不知道它應該產生安全連結。

為了解決這個問題,您可以啟用 Laravel 應用程式中包含的 Illuminate\Http\Middleware\TrustProxies middleware,它允許您快速自訂應用程式應信任的負載平衡器或代理伺服器。您受信任的代理伺服器應使用應用程式 bootstrap/app.php 檔案中的 trustProxies middleware 方法指定

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustProxies(at: [
3 '192.168.1.1',
4 '10.0.0.0/8',
5 ]);
6})

除了配置受信任的代理伺服器之外,您還可以配置應信任的代理伺服器標頭

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustProxies(headers: Request::HEADER_X_FORWARDED_FOR |
3 Request::HEADER_X_FORWARDED_HOST |
4 Request::HEADER_X_FORWARDED_PORT |
5 Request::HEADER_X_FORWARDED_PROTO |
6 Request::HEADER_X_FORWARDED_AWS_ELB
7 );
8})

如果您正在使用 AWS Elastic Load Balancing,則 headers 值應為 Request::HEADER_X_FORWARDED_AWS_ELB。如果您的負載平衡器使用來自 RFC 7239 的標準 Forwarded 標頭,則 headers 值應為 Request::HEADER_FORWARDED。有關可用於 headers 值中的常數的更多資訊,請查看 Symfony 關於 信任代理伺服器 的文件。

信任所有代理伺服器

如果您正在使用 Amazon AWS 或其他「雲端」負載平衡器提供商,您可能不知道實際平衡器的 IP 位址。在這種情況下,您可以使用 * 來信任所有代理伺服器

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustProxies(at: '*');
3})

設定信任的主機

預設情況下,無論 HTTP 請求的 Host 標頭的內容為何,Laravel 都會回應它收到的所有請求。此外,在 Web 請求期間產生應用程式的絕對 URL 時,將使用 Host 標頭的值。

通常,您應該配置您的 Web 伺服器(例如 Nginx 或 Apache)僅將與給定主機名稱匹配的請求發送到您的應用程式。但是,如果您無法直接自訂您的 Web 伺服器,並且需要指示 Laravel 僅回應某些主機名稱,您可以透過為您的應用程式啟用 Illuminate\Http\Middleware\TrustHosts middleware 來做到這一點。

要啟用 TrustHosts middleware,您應該在應用程式的 bootstrap/app.php 檔案中調用 trustHosts middleware 方法。使用此方法的 at 參數,您可以指定您的應用程式應回應的主機名稱。來自其他 Host 標頭的傳入請求將被拒絕

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustHosts(at: ['laravel.test']);
3})

預設情況下,來自應用程式 URL 子網域的請求也會自動被信任。如果您想停用此行為,您可以使用 subdomains 參數

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustHosts(at: ['laravel.test'], subdomains: false);
3})

如果您需要存取應用程式的組態檔案或資料庫來判斷您受信任的主機,您可以為 at 參數提供一個閉包

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustHosts(at: fn () => config('app.trusted_hosts'));
3})

Laravel 是最具生產力的方式來
建構、部署和監控軟體。