HTTP Request
簡介
Laravel 的 Illuminate\Http\Request
類別提供了一種物件導向的方法來讓你存取目前程式在處理的 HTTP Request,包含 Request 的輸入、Cookie、上傳的檔案⋯⋯等。
使用 Request
Accessing the Request
若要通過相依性插入 (Dependency Injection) 來取得目前的 HTTP Request,可在 Route 閉包或 Controller 方法上型別提示 Illuminate\Http\Request
類別。連入的 Request 實體會自動被插入到 Laravel 的 Service Container:
1<?php23namespace App\Http\Controllers;45use Illuminate\Http\RedirectResponse;6use Illuminate\Http\Request;78class UserController extends Controller9{10 /**11 * Store a new user.12 */13 public function store(Request $request): RedirectResponse14 {15 $name = $request->input('name');1617 // Store the user...1819 return redirect('/users');20 }21}
1<?php23namespace App\Http\Controllers;45use Illuminate\Http\RedirectResponse;6use Illuminate\Http\Request;78class UserController extends Controller9{10 /**11 * Store a new user.12 */13 public function store(Request $request): RedirectResponse14 {15 $name = $request->input('name');1617 // Store the user...1819 return redirect('/users');20 }21}
剛才也提到過,我們也可以在 Route 閉包上型別提示 Illuminate\Http\Request
類別。Service Container 會自動在閉包執行時將連入的 Request 插入進去:
1use Illuminate\Http\Request;23Route::get('/', function (Request $request) {4 // ...5});
1use Illuminate\Http\Request;23Route::get('/', function (Request $request) {4 // ...5});
Dependency Injection and Route Parameters
若 Controller 方法中還會從 Route 引數中收到輸入,請將 Route 引數列在其他相依性之後。舉例來說,若 Route 定義長這樣:
1use App\Http\Controllers\UserController;23Route::put('/user/{id}', [UserController::class, 'update']);
1use App\Http\Controllers\UserController;23Route::put('/user/{id}', [UserController::class, 'update']);
則我們還是可以像這樣定義 Controller 方法來型別提示 Illuminate\Http\Request
並取得 id
Route 參數:
1<?php23namespace App\Http\Controllers;45use Illuminate\Http\RedirectResponse;6use Illuminate\Http\Request;78class UserController extends Controller9{10 /**11 * Update the specified user.12 */13 public function update(Request $request, string $id): RedirectResponse14 {15 // Update the user...1617 return redirect('/users');18 }19}
1<?php23namespace App\Http\Controllers;45use Illuminate\Http\RedirectResponse;6use Illuminate\Http\Request;78class UserController extends Controller9{10 /**11 * Update the specified user.12 */13 public function update(Request $request, string $id): RedirectResponse14 {15 // Update the user...1617 return redirect('/users');18 }19}
Request Path, Host, and Method
Illuminate\Http\Request
提供了多種可檢查連入 HTTP Request 的方法。這個方法也繼承了 Symfony\Component\HttpFoundation\Request
類別。我們稍後會討論其中幾個最重要的方法。
Retrieving the Request Path
path
方法會回傳 Request 的路徑資訊。因此,若連入 Request 是在瀏覽 http://example.com/foo/bar
,則 path
方法會回傳 foo/bar
:
1$uri = $request->path();
1$uri = $request->path();
Inspecting the Request Path / Route
可以使用 is
方法來驗證連入 Request 的路徑是否符合給定的格式。使用這個方法的時候,可以使用 *
字元作為萬用字元:
1if ($request->is('admin/*')) {2 // ...3}
1if ($request->is('admin/*')) {2 // ...3}
使用 routeIs
方法可以判斷連入的 Request 是否為某個命名 Route:
1if ($request->routeIs('admin.*')) {2 // ...3}
1if ($request->routeIs('admin.*')) {2 // ...3}
Retrieving the Request URL
若要取得連入 Request 的完整 URL,可以使用 url
或 fullUrl
方法。url
方法會回傳不含查詢字串 (Query String) 的 URL,而 fullUrl
則包含查詢字串:
1$url = $request->url();23$urlWithQueryString = $request->fullUrl();
1$url = $request->url();23$urlWithQueryString = $request->fullUrl();
若想將查詢字串資料附加到目前的 URL,可以使用 fullUrlWithQuery
方法。傳入一個包含查詢字串變數的陣列,然後這個方法會將給定的陣列與目前的查詢字串合併:
1$request->fullUrlWithQuery(['type' => 'phone']);
1$request->fullUrlWithQuery(['type' => 'phone']);
若想取得不含給定 Query String 參數的目前 URL,可使用 fullUrlWithoutQuery
方法:
1$request->fullUrlWithoutQuery(['type']);
1$request->fullUrlWithoutQuery(['type']);
Retrieving the Request Host
可以使用 host
、httpHost
、與 schemeAndHttpHost
來取得連入 Request 的「主機」:
1$request->host();2$request->httpHost();3$request->schemeAndHttpHost();
1$request->host();2$request->httpHost();3$request->schemeAndHttpHost();
Retrieving the Request Method
method
方法會回傳該 Request 的 HTTP 動詞 (Verb)。可以使用 isMethod
方法來判斷目前的 HTTP 動詞是否符合給定字串:
1$method = $request->method();23if ($request->isMethod('post')) {4 // ...5}
1$method = $request->method();23if ($request->isMethod('post')) {4 // ...5}
Request 標頭
可以使用 header
方法來從 Illuminate\Http\Request
內取得 Request 的標頭 (Header)。若該 Request 未包含指定的標頭,則會回傳 null
。不過,header
方法也接受第三個可選的引數,會在標頭不存在時回傳該值:
1$value = $request->header('X-Header-Name');23$value = $request->header('X-Header-Name', 'default');
1$value = $request->header('X-Header-Name');23$value = $request->header('X-Header-Name', 'default');
hasHeader
方法可用來判斷 Request 是否包含給定的標頭:
1if ($request->hasHeader('X-Header-Name')) {2 // ...3}
1if ($request->hasHeader('X-Header-Name')) {2 // ...3}
為了方便起見,可以使用 bearerToken
方法來從 Authorization
標頭中取得 Bearer Token。若該標頭不存在,會回傳空字串:
1$token = $request->bearerToken();
1$token = $request->bearerToken();
Request 的 IP 位址
可以使用 ip
方法來取得用戶端發起 Request 使用的 IP 位址:
1$ipAddress = $request->ip();
1$ipAddress = $request->ip();
If you would like to retrieve an array of IP addresses, including all of the client IP addesses that were forwarded by proxies, you may use the ips
method. The "original" client IP address will be at the end of the array:
1$ipAddresses = $request->ips();
1$ipAddresses = $request->ips();
In general, IP addresses should be considered untrusted, user-controlled input and be used for informational purposes only.
判斷適當的內容
Laravel 提供了數種方法來通過 Accept
標頭判斷連入 Request 所要求的 Content Type (內容類型)。首先,getAcceptableContentTypes
會回傳一個陣列,其中包含該 Request 所接受的所有 Content Type:
1$contentTypes = $request->getAcceptableContentTypes();
1$contentTypes = $request->getAcceptableContentTypes();
accepts
方法接受一個包含 Content Type 的陣列,當陣列中有任何一個 Content Type 是 Request 接受的,就會回傳 true
。否則,會回傳 false
:
1if ($request->accepts(['text/html', 'application/json'])) {2 // ...3}
1if ($request->accepts(['text/html', 'application/json'])) {2 // ...3}
可以使用 prefers
方法來判斷給定陣列中的哪個 Content Type 是該 Request 最優先選擇的。若所提供的 Content Type 都不為 Request 接受,則會回傳 null
:
1$preferred = $request->prefers(['text/html', 'application/json']);
1$preferred = $request->prefers(['text/html', 'application/json']);
因為大部分專案都只提供 HTML 或 JSON,所以我們可以通過 expectsJson
方法來快速判斷連入的 Request 是否預期 Response 應為 JSON:
1if ($request->expectsJson()) {2 // ...3}
1if ($request->expectsJson()) {2 // ...3}
PSR-7 Request
PSR-7 標準 指定了用於 HTTP 訊息通訊的介面,其中包含 Request 與 Response。若你想取得 PSR-7 Request 的實體而不是 Laravel Request,首先你會需要安裝幾個函式庫。Laravel 使用 Symfony 的 HTTP Message Bridge 元件來將一般的 Laravel Request 與 Response 轉換為相容於 PSR-7 的實作:
1composer require symfony/psr-http-message-bridge2composer require nyholm/psr7
1composer require symfony/psr-http-message-bridge2composer require nyholm/psr7
安裝好這些函式庫後,就可以在 Route 閉包或 Controller 方法上型別提示 PSR-7 Request 介面來取得 PSR-7 Request 的實體:
1use Psr\Http\Message\ServerRequestInterface;23Route::get('/', function (ServerRequestInterface $request) {4 // ...5});
1use Psr\Http\Message\ServerRequestInterface;23Route::get('/', function (ServerRequestInterface $request) {4 // ...5});
若從 Route 或 Controller 中回傳 PSR-7 Response,這個 Response 會先被轉回到 Laravel 的 Response 實體,然後才會由 Laravel 顯示出來。
輸入
取得輸入
取得所有輸入的資料
可以使用 all
方法來將所有連入 Request 的輸入資料取得為 array
。無論連入的 Request 是來自 HTML 表單還是 XHR Request,都可以使用這個方法:
1$input = $request->all();
1$input = $request->all();
使用 collect
方法就可以將連入 Request 的輸入資料作為 Collection 取得:
1$input = $request->collect();
1$input = $request->collect();
使用 collect
方法也可以用來將連入 Request 輸入中的一部分取得為 Collection:
1$request->collect('users')->each(function (string $user) {2 // ...3});
1$request->collect('users')->each(function (string $user) {2 // ...3});
Retrieving an Input Value
使用幾個簡單的方法,不需要擔心 Request 使用了哪個 HTTP 動詞,都可以存取 Illuminate\Http\Request
實體中所有的使用者輸入。無論 HTTP 動詞是什麼,都可以用 input
方法來取得使用者輸入:
1$name = $request->input('name');
1$name = $request->input('name');
也可以傳入第二個引數給 input
方法來取得預設值。若 Request 中沒有要求的輸入值時,就會回傳這個預設值:
1$name = $request->input('name', 'Sally');
1$name = $request->input('name', 'Sally');
在處理包含陣列輸入的表單時,可以使用「點 (.)」標記法來存取陣列:
1$name = $request->input('products.0.name');23$names = $request->input('products.*.name');
1$name = $request->input('products.0.name');23$names = $request->input('products.*.name');
呼叫 input
方法時若不傳入任何引數,則可以用關聯式陣列的方式取得所有輸入資料:
1$input = $request->input();
1$input = $request->input();
Retrieving Input From the Query String
雖然 input
方法可以從所有的 Request 承載 (Payload) 上取得資料 (其中也包含查詢字串),若使用 query
方法,則可以只從查詢字串中取得資料:
1$name = $request->query('name');
1$name = $request->query('name');
若要求的查詢字串值不存在,則會回傳第二個傳入該方法的值:
1$name = $request->query('name', 'Helen');
1$name = $request->query('name', 'Helen');
呼叫 query
方法時若不傳入任何引數,則可以用關聯式陣列的方式取得所有查詢字串的資料:
1$query = $request->query();
1$query = $request->query();
取得 JSON 輸入值
傳送 JSON 的 Request 時,只要 Request 的 Content-Type
由正確設定為 application/json
,就可以使用 input
方法來存取 JSON 資料。也可以使用「點 (.)」標記法來存取 JSON 陣列/物件中的巢狀資料:
1$name = $request->input('user.name');
1$name = $request->input('user.name');
取得 Stringable 的輸入值
除了將輸入值以原生型別的 string
取得,還可以使用 string
方法來將 Request 資料以 Illuminate\Support\Stringable
實體的形式取得:
1$name = $request->string('name')->trim();
1$name = $request->string('name')->trim();
取得布林輸入值
在處理如勾選框 (Checkbox) 等 HTML 元素時,我們的程式可能會收到以字串形式呈現的「真假」值。舉例來說,這個值可能是「true」或「on」。為了方便起見,我們可以使用 boolean
方法來將這些值以布林方式取得。值為 1、"1"、true、"true"、"on"、"yes" 時,boolean
方法回傳 true
。其他任何的值則會回傳 false
:
1$archived = $request->boolean('archived');
1$archived = $request->boolean('archived');
取得日期的輸入值
為了方便起見,我們可以使用 date
方法來將包含日期 / 時間的輸入值以 Carbon 實體來存取。若 Request 中為包含給定名稱的輸入值,則會回傳 null
:
1$birthday = $request->date('birthday');
1$birthday = $request->date('birthday');
可以使用 date
的第二與第三個引數來分別指定日期的格式與時區:
1$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
1$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
若輸入中有值,但格式不正確時,會擲回 InvalidArgumentException
。因此,建議你在叫用 date
方法前先驗證輸入。
取得 Enum 輸入值
也可以從 Request 中取得對應到 PHP Enum 的輸入值。若 Request 中沒有輸入值,或是給定的名稱或 Enum 中沒有符合該輸入值的後端值 (Backing Value),則會回傳 null
。enum
方法的第一個引數為輸入值的名稱、第二個引數為 Enum 類別:
1use App\Enums\Status;23$status = $request->enum('status', Status::class);
1use App\Enums\Status;23$status = $request->enum('status', Status::class);
Retrieving Input via Dynamic Properties
可以在 Illuminate\Http\Request
實體上通過動態屬性來存取使用者輸入。舉例來說,若其中一個程式的表單包含了 name
欄位,則可以像這樣存取該欄位的值:
1$name = $request->name;
1$name = $request->name;
使用動態方法時,Laravel 會先在 Request 的 Payload (承載) 上尋找參數值。若 Payload 上沒有該值,Laravel 會接著在 Route 參數中尋找符合名稱的欄位:
Retrieving a Portion of the Input Data
若只想取得一部分的輸入資料,可以使用 only
或 except
方法。這兩個方法都接受一個 array
值、或是一組引數的動態列表:
1$input = $request->only(['username', 'password']);23$input = $request->only('username', 'password');45$input = $request->except(['credit_card']);67$input = $request->except('credit_card');
1$input = $request->only(['username', 'password']);23$input = $request->only('username', 'password');45$input = $request->except(['credit_card']);67$input = $request->except('credit_card');
only
方法會回傳所要求的所有索引鍵 / 值配對組。不過,若要求的索引鍵 / 值配對未出現在 Request 中,將不會回傳。
Input Presence
可以使用 has
方法來判斷某個值是否存在 Request 中。若給定的輸入值存在於 Request 中,has
方法會回傳 true
:
1if ($request->has('name')) {2 // ...3}
1if ($request->has('name')) {2 // ...3}
傳入陣列時,has
方法判斷其中所有的值是否都存在:
1if ($request->has(['name', 'email'])) {2 // ...3}
1if ($request->has(['name', 'email'])) {2 // ...3}
hasAny
方法會給定的值有其中一個存在時回傳 true
:
1if ($request->hasAny(['name', 'email'])) {2 // ...3}
1if ($request->hasAny(['name', 'email'])) {2 // ...3}
whenHas
方法會執行給定的閉包來判斷某個值是否存在於 Request 中:
1$request->whenHas('name', function (string $input) {2 // ...3});
1$request->whenHas('name', function (string $input) {2 // ...3});
可以傳入第二個閉包給 whenHas
方法,當指定的值未存在於 Request 中,則會執行這個閉包:
1$request->whenHas('name', function (string $input) {2 // The "name" value is present...3}, function () {4 // The "name" value is not present...5});
1$request->whenHas('name', function (string $input) {2 // The "name" value is present...3}, function () {4 // The "name" value is not present...5});
若想判斷某個值是否有出現在 Request 中,且該值不是空字串時,可使用 filled
方法:
1if ($request->filled('name')) {2 // ...3}
1if ($request->filled('name')) {2 // ...3}
anyFilled
方法會在給定的值中有其中一個值不為空字串時回傳 true
:
1if ($request->anyFilled(['name', 'email'])) {2 // ...3}
1if ($request->anyFilled(['name', 'email'])) {2 // ...3}
whenFilled
方法會執行給定的閉包來判斷 Request 中某個值是否為空字串:
1$request->whenFilled('name', function (string $input) {2 // ...3});
1$request->whenFilled('name', function (string $input) {2 // ...3});
可以傳入第二個閉包給 whenFilled
方法,當 Request 中指定的值為空時會執行這個閉包:
1$request->whenFilled('name', function (string $input) {2 // The "name" value is filled...3}, function () {4 // The "name" value is not filled...5});
1$request->whenFilled('name', function (string $input) {2 // The "name" value is filled...3}, function () {4 // The "name" value is not filled...5});
若要判斷 Request 中是否不存在給定的索引鍵,可使用 missing
方法與 whenMissing
方法:
1if ($request->missing('name')) {2 // ...3}45$request->whenMissing('name', function (array $input) {6 // The "name" value is missing...7}, function () {8 // The "name" value is present...9});
1if ($request->missing('name')) {2 // ...3}45$request->whenMissing('name', function (array $input) {6 // The "name" value is missing...7}, function () {8 // The "name" value is present...9});
合併額外的輸入
有時候,我們需要手動合併額外的輸入到 Request 中現有的輸入資料。這種情況下,可使用 merge
方法。若 Request 中已存在給定的輸入索引鍵,則會使用提供給 merge
方法的資料來複寫:
1$request->merge(['votes' => 0]);
1$request->merge(['votes' => 0]);
使用 mergeIfMissing
方法就可以只在 Request 的輸入資料中缺少特定索引鍵時才合併進 Request:
1$request->mergeIfMissing(['votes' => 0]);
1$request->mergeIfMissing(['votes' => 0]);
舊輸入
Laravel 提供了將輸入資料從一個 Request 帶到下一個 Request 的功能。這個功能特別適合用在表單驗證失敗後要重新填充表單時。不過,若你使用 Laravel 提供的表單驗證功能,那麼你應該不需要直接手動進行這些 Session 的 Input 快閃方法,因為 Laravel 的內建表單驗證功能已經自動處理好了。
Flashing Input to the Session
使用 Illuminate\Http\Request
類別的 flash
方法,就可以將目前的輸入快閃 (Flash) 進 Session。這樣一來,使用者的下個 Request 中就有這些輸入值可用:
1$request->flash();
1$request->flash();
也可以使用 flashOnly
與 flashExcept
方法來只將一部分的 Request 資料刷入 Session。這些方法特別適用於想讓一些機密資料(如密碼)不要被刷入 Session 時:
1$request->flashOnly(['username', 'email']);23$request->flashExcept('password');
1$request->flashOnly(['username', 'email']);23$request->flashExcept('password');
快閃存入輸入後再重新導向
由於我們很常會需要再將輸入資料快閃存入 Session 後再重新導向回上一頁,因此我們只要把 withInput
方法串到重新導向後,就可以輕鬆地快閃存入輸入值:
1return redirect('form')->withInput();23return redirect()->route('user.create')->withInput();45return redirect('form')->withInput(6 $request->except('password')7);
1return redirect('form')->withInput();23return redirect()->route('user.create')->withInput();45return redirect('form')->withInput(6 $request->except('password')7);
取得舊輸入
若要取得前一個 Request 中的快閃輸入,可叫用 Illuminate\Http\Request
上的 old
方法。old
方法從 Session 中拉取前次快閃存入輸入資料:
1$username = $request->old('username');
1$username = $request->old('username');
Laravel 也提供了一個全域 old
輔助函式。若想在 Blade 樣板中顯示舊輸入,那麼使用 old
輔助函式來將其填回表單回比較方便。若給定欄位沒有舊輸入的話,會回傳 null
:
1<input type="text" name="username" value="{{ old('username') }}">
1<input type="text" name="username" value="{{ old('username') }}">
Cookie
從 Request 中取得 Cookie
所有由 Laravel 框架所建立的 Cookie 都是經過加密且使用驗證碼簽名過的,這代表若用戶端有修改這些值,就會讓 Cookie 變成無效。若要從 Request 中取得 Cookie,請使用 Illuminate\Http\Request
實體上的 cookie
方法:
1$value = $request->cookie('name');
1$value = $request->cookie('name');
Input Trimming and Normalization
預設情況下,Laravel 中包含了 App\Http\Middleware\TrimStrings
與 Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull
這兩個 Middleware,且放在程式的全域 Middleware Stack 中。這些 Middleware 被列在 App\Http\Kernel
類別的全域 Middleware Stack 中。這些 Middleware 會自動修剪 Request 中的所有連入子船,並將空白的字串欄位轉為 null
。這樣,我們就不需要在 Route 或 Controller 中去費心正常化這些資料。
禁用輸入正規化
若想在所有 Request 上禁用這些行為,可在 App\Http\Kernel
類別的 $middleware
屬性中將其移除:
若只想在專案中一部分的 Request 上禁用字串修剪與空字串轉換,可使用這兩個 Middleware 提供的 skipWhen
方法。請傳入一個回傳 true
或 false
的閉包給該方法,用來判斷是否應跳過字串的正規化。一般來說,應在專案的 AppServiceProvider
中 boot
方法內叫用這個 skipWhen
方法。
1use App\Http\Middleware\TrimStrings;2use Illuminate\Http\Request;3use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;45/**6 * Bootstrap any application services.7 */8public function boot(): void9{10 TrimStrings::skipWhen(function (Request $request) {11 return $request->is('admin/*');12 });1314 ConvertEmptyStringsToNull::skipWhen(function (Request $request) {15 // ...16 });17}
1use App\Http\Middleware\TrimStrings;2use Illuminate\Http\Request;3use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;45/**6 * Bootstrap any application services.7 */8public function boot(): void9{10 TrimStrings::skipWhen(function (Request $request) {11 return $request->is('admin/*');12 });1314 ConvertEmptyStringsToNull::skipWhen(function (Request $request) {15 // ...16 });17}
檔案
取得上傳的檔案
可以使用 file
方法或動態屬性來從 Illuminate\Http\Request
實體上取得上傳的檔案。file
方法會回傳 Illuminate\Http\UploadedFile
類別的實體,該實體繼承了 PHP 的 SplFileInfo
類別,並提供各種能處理使用該檔案的方法:
1$file = $request->file('photo');23$file = $request->photo;
1$file = $request->file('photo');23$file = $request->photo;
可以使用 hasFile
方法來判斷某個檔案是否存在於 Request 中:
1if ($request->hasFile('photo')) {2 // ...3}
1if ($request->hasFile('photo')) {2 // ...3}
驗證成功上傳
除了檢查檔案是否存在外,還可以使用 isValid
方法來確認上傳檔案的過程中是否無問題:
1if ($request->file('photo')->isValid()) {2 // ...3}
1if ($request->file('photo')->isValid()) {2 // ...3}
File Paths and Extensions
UploadedFile
類別也包含了能存取檔案完整路徑與副檔名的方法。extension
方法可以使用檔案的內容來推測檔案的副檔名。這個副檔名克呢功能會與用戶端提供的副檔名有所不同:
1$path = $request->photo->path();23$extension = $request->photo->extension();
1$path = $request->photo->path();23$extension = $request->photo->extension();
其他檔案方法
UploadedFile
實體還提供了其他各種方法。請參考該類別的 API 說明文件來瞭解有關這些方法的更多資訊。
儲存上傳的檔案
若要儲存已上傳的檔案,通常我們需要先設定好檔案系統。UploadedFile
類別中有個 store
方法,該方法可以將已上傳的檔案移到其中一個磁碟裡。這個磁碟可以是本機檔案系統,也可以是像 Amazon S3 之類的雲端儲存空間。
store
方法接受一個路徑,該路徑就是相對於檔案系統設定中根目錄的位置。路徑不包含檔案名稱,Laravel 會自動產生獨立的 ID 來當作檔案名稱。
store
方法也接受可選的第二個引數,該引數是要用來儲存檔案的磁碟名稱。 store
方法會回傳相對於磁碟根目錄的檔案路徑:
1$path = $request->photo->store('images');23$path = $request->photo->store('images', 's3');
1$path = $request->photo->store('images');23$path = $request->photo->store('images', 's3');
若不想要自動產生的檔案名稱,可以使用 storeAs
方法,該方法的引數是路徑、檔案名稱、磁碟名稱:
1$path = $request->photo->storeAs('images', 'filename.jpg');23$path = $request->photo->storeAs('images', 'filename.jpg', 's3');
1$path = $request->photo->storeAs('images', 'filename.jpg');23$path = $request->photo->storeAs('images', 'filename.jpg', 's3');
更多有關 Laravel 中檔案儲存的資訊,請參考完整的檔案儲存說明文件。
設定信任的代理 (Trusted Proxy)
在負責處理 TLS / SSL 證書的 Load Balancer (負載平衡器) 後方執行應用程式時,有時候由 url
輔助函式產生的連結可能不會使用 HTTPS。者通常是因為,Load Balancer 把流量傳過來時使用的是 80 Port,因為 Laravel 不知道是否要產生 HTTPS 的連結。
為此,我們可以使用 Laravel 專案中有包含的 App\Http\Middleware\TrustProxies
Middleware。該 Middleware 能讓我們快速自訂程式要信任的 Load Balancer 或代理伺服器 (Proxy)。應在該 Middleware 內的 $proxies
屬性內列出信任的代理伺服器。除了設定信任的代理外,也可以設定信任代理的 $headers
:
1<?php23namespace App\Http\Middleware;45use Illuminate\Http\Middleware\TrustProxies as Middleware;6use Illuminate\Http\Request;78class TrustProxies extends Middleware9{10 /**11 * The trusted proxies for this application.12 *13 * @var string|array14 */15 protected $proxies = [16 '192.168.1.1',17 '192.168.1.2',18 ];1920 /**21 * The headers that should be used to detect proxies.22 *23 * @var int24 */25 protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;26}
1<?php23namespace App\Http\Middleware;45use Illuminate\Http\Middleware\TrustProxies as Middleware;6use Illuminate\Http\Request;78class TrustProxies extends Middleware9{10 /**11 * The trusted proxies for this application.12 *13 * @var string|array14 */15 protected $proxies = [16 '192.168.1.1',17 '192.168.1.2',18 ];1920 /**21 * The headers that should be used to detect proxies.22 *23 * @var int24 */25 protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;26}
若要使用 AWS Elastic Load Balancing,則 $headers
的值應為 Request::HEADER_X_FORWARDED_AWS_ELB
。更多有關能用在 $headers
屬性的常數資訊,請參考 Symfony 說明文件中的 Trusting Proxies。
信任所有代理
若使用 Amazon AWS 或其他的「雲端」Load Balancer 提供者,則我們可能不知道 Load Balancer 實際的 IP 位置。這時,可以使用 *
來信任所有代理:
1/**2 * The trusted proxies for this application.3 *4 * @var string|array5 */6protected $proxies = '*';
1/**2 * The trusted proxies for this application.3 *4 * @var string|array5 */6protected $proxies = '*';
設定信任的主機 (Trusted Hosts)
預設情況下,無論收到的 HTTP Request 中 Host
標頭內容為何,Laravel 都會回應所有收到的 Request。此外,Laravel 還會使用 Host
標頭的值來在 Request 中為你的程式產生絕對路徑的網址。
一般來說,應在 Web Server 上 (如 Nginx 或 Apache) 設定只有特定的主機名稱時才將 Request 送往你的程式中。不過,若沒機會能自訂 Web Server,則需要讓 Laravel 只對特定主機名稱作回應。為此,可以啟用專案中的 App\Http\Middleware\TrustHosts
Middleware。
TrustHosts
Middleware 以預先包含在專案中的 $middlware
Stack 裡的。不過,需要先取消註解這個 Middleware,才能啟用它。在這個 Middleware 中有個 hosts
方法,我們可以在其中指定我們的程式要回應的主機名稱。有其他 Host
標頭值的連入 Request 將會被拒絕:
1/**2 * Get the host patterns that should be trusted.3 *4 * @return array<int, string>5 */6public function hosts(): array7{8 return [9 'laravel.test',10 $this->allSubdomainsOfApplicationUrl(),11 ];12}
1/**2 * Get the host patterns that should be trusted.3 *4 * @return array<int, string>5 */6public function hosts(): array7{8 return [9 'laravel.test',10 $this->allSubdomainsOfApplicationUrl(),11 ];12}
allSubdomainsOfApplicationUrl
輔助函式會回傳一個可配對應用程式中 app.url
設定值子網域的正規表示式。使用這個輔助函式,就可以方便地在使用萬用子網域的程式中允許所有的子網域。