* * * * *
[TOC]
## 獲取請求
要通過依賴注入的方式來獲取當前 HTTP 請求的實例,你應該在控制器方法中引入?`Illuminate\Http\Request`?類。傳入的請求實例將通過?[服務容器](http://www.hmoore.net/tonyyu/laravel_5_6/786056)?自動注入:
~~~
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* 存儲一個新的用戶。
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->input('name');
//
}
}
~~~
#### 依賴注入 & 路由參數
如果控制器方法要從路由參數中獲取數據,則應在其他依賴項之后列出路由參數。例如,如果你的路由是這樣定義的:
~~~
Route::put('user/{id}', 'UserController@update');
~~~
如下所示使用提示類?`Illuminate\Http\Request`?,就可以在控制器方法中獲得路由參數?`id`:
~~~
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* 更新某個用戶
*
* @param Request $request
* @param string $id
* @return Response
*/
public function update(Request $request, $id)
{
//
}
}
~~~
#### 通過路由閉包獲取請求
你也同樣可以在路由閉包中使用?`Illuminate\Http\Request`?類. 程序在執行的時候,服務容器會自動的將請求注入到路由閉包中:
~~~
use Illuminate\Http\Request;
Route::get('/', function (Request $request) {
//
});
~~~
### 請求路徑 & 方法
`Illuminate\Http\Request`?實例為你的應用程序提供了一系列方法檢查路由,并且繼承了?`Symfony\Component\HttpFoundation\Request`?類。 以下是該類的一些重要用法:
#### 獲取請求路徑
`path`?方法返回請求的路徑信息。也就是說,如果傳入的請求的目標地址是?`http://domain.com/foo/bar`,那么?`path`?將會返回?`foo/bar`:
~~~
$uri = $request->path();
~~~
`is`?方法可以驗證傳入的請求路徑和指定規則是否匹配。使用這個方法的時,你也可以傳遞一個?`*`?字符作為通配符:
~~~
if ($request->is('admin/*')) {
//
}
~~~
#### 獲取請求的 URL
你可以使用?`url`?或?`fullUrl`?方法去獲取傳入請求的完整 URL。`url`?方法返回不帶有查詢字符串的 URL,而?`fullUrl`?方法的返回值包含查詢字符串:
~~~
// 沒有查詢字符串...
$url = $request->url();
// 使用查詢字符串...
$url = $request->fullUrl();
~~~
#### 獲取請求方法
對于傳入的請求?`method`?方法將返回 HTTP 的請求方式。你也可以使用?`isMethod`?方法去驗證 HTTP 的請求方式與指定規則是否相配:
~~~
$method = $request->method();
if ($request->isMethod('post')) {
//
}
~~~
### PSR-7 請求
[PSR-7 標準](http://www.php-fig.org/psr/psr-7/)?標準 規定的 HTTP 消息接口包含了請求和響應。如果你想使用一個 PSR-7 請求來代替一個 Laravel 請求實例,那么你首先要安裝幾個函數庫。Laravel 使用 Symfony 的 HTTP 消息橋接組件將典型的 Laravel 請求和響應轉換為 PSR-7 兼容實現:
~~~
composer require symfony/psr-http-message-bridge
composer require zendframework/zend-diactoros
~~~
安裝完這些庫后, 就可以在路由閉包或控制器中類型提示請求的接口來獲取 PSR-7 請求:
~~~
use Psr\Http\Message\ServerRequestInterface;
Route::get('/', function (ServerRequestInterface $request) {
//
});
~~~
> {tip} 如果從路由或者控制器返回 PSR-7 響應實例,它會自動轉換回 Laravel 響應實例,并由框架顯示。
## 輸入預處理 & 規范化
默認情況下,Laravel 在應用程序的全局中間件堆棧中包含了?`TrimStrings`?和?`ConvertEmptyStringsToNull`?兩個中間件。這些中間件由?`App\Http\Kernel`?類列在堆棧中。它們會自動處理請求上所有傳入的字符串字段,并將空的字符串字段轉變成?`null`?值。這樣你就不用再擔心路由和控制器中數據規范化的問題。
如果你想停用這些功能,可以從應用程序的中間件堆棧中刪除這兩個中間件,只需在?`App\Http\Kernel`?類的?`$middleware`?屬性中移除它們。
## 獲取輸入
#### 獲取所有輸入數據
你可以使用?`all`?方法以?`array`?形式獲取到所有輸入數據:
~~~
$input = $request->all();
~~~
#### 獲取指定輸入值
使用幾種簡單的方法(不需要特別指定哪個 HTTP 動作),就可以訪問?`Illuminate\Http\Request`?實例中所有的用戶輸入。也就是說無論是什么樣的 HTTP 動作,`input`?方法都可以被用來獲取用戶輸入數據:
~~~
$name = $request->input('name');
~~~
你可以給?`input`?方法的第二個參數傳入一個默認值。如果請求的輸入值不存在請求上,就返回默認值:
~~~
$name = $request->input('name', 'Sally');
~~~
如果傳輸表單數據中包含「數組」形式的數據,那么可以使用「點」式語法來獲取數組:
~~~
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
~~~
#### 從查詢字符串獲取輸入
使用?`input`?方法可以從整個請求中獲取輸入數據(包括查詢字符串),而?`query`?方法可以只從查詢字符串中獲取輸入數據:
~~~
$name = $request->query('name');
~~~
如果請求的查詢字符串數據不存在,則將返回這個方法的第二個參數:
~~~
$name = $request->query('name', 'Helen');
~~~
你可以不提供參數調用?`query`?方法來以關聯數組的形式檢索所有查詢字符串值:
~~~
$query = $request->query();
~~~
#### 通過動態屬性獲取輸入
你也可以通過?`Illuminate\Http\Request`?實例的動態屬性來獲取用戶輸入。例如,如果你應用的表單中包含?`name`字段,那么可以像這樣訪問該字段的值:
~~~
$name = $request->name;
~~~
Laravel 在處理動態屬性的優先級是,先在請求的數據中查找,如果沒有,再到路由參數中查找。
#### 獲取 JSON 輸入信息
如果發送到應用程序的請求數據是 JSON,只要請求的?`Content-Type`?標頭正確設置為?`application/json`,就可以通過?`input`?方法訪問 JSON 數據。你甚至可以使用 「點」式語法來讀取 JSON 數組:
~~~
$name = $request->input('user.name');
~~~
#### 獲取部分輸入數據
如果你需要獲取輸入數據的子集,則可以用?`only`?和?`except`?方法。這兩個方法都接收?`array`?或動態列表作為參數:
~~~
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
~~~
> {tip}?`only`?方法會返回所有你指定的鍵值對,但不會返回請求中不存在的鍵值對。
#### 確定是否存在輸入值
要判斷請求是否存在某個值,可以使用?`has`?方法。如果請求中存在該值,`has`?方法就會返回?`true`:
~~~
if ($request->has('name')) {
//
}
~~~
當提供一個數組作為參數時,`has`?方法將確定是否存在數組中所有給定的值:
~~~
if ($request->has(['name', 'email'])) {
//
}
~~~
如果你想確定請求中是否存在值并且不為空,可以使用?`filled`?方法:
~~~
if ($request->filled('name')) {
//
}
~~~
### 舊輸入
Laravel 允許你將本次請求的數據保留到下一次請求發送前。如果第一次請求的表單不能通過驗證,就可以使用這個功能重新填充表單。但是,如果你使用了 Laravel 的?[驗證功能](http://www.hmoore.net/tonyyu/laravel_5_6/786181),你就不需要在手動實現這些方法,因為 Laravel 內置的驗證工具會自動調用他們。
#### 將輸入閃存至 Session
`Illuminate\Http\Request`?的?`flash`?方法會將當前輸入的數據存進?[session](http://www.hmoore.net/tonyyu/laravel_5_6/786180)?中,以便在用戶下次發送請求到應用程序之前可以使用它們:
~~~
$request->flash();
~~~
你也可以使用?`flashOnly`?和?`flashExcept`?方法將請求數據的一部分閃存到 session。這些方法對敏感信息(例如密碼)的保護非常有用:
~~~
$request->flashOnly(['username', 'email']);
$request->flashExcept('password');
~~~
#### 閃存輸入后重定向
你可能需要把輸入閃存到 session 然后重定向到上一頁,這時只需要在重定向方法后加上?`withInput`?即可:
~~~
return redirect('form')->withInput();
return redirect('form')->withInput(
$request->except('password')
);
~~~
#### 獲取舊輸入
若要獲取上一次請求中閃存的輸入,則可以使用?`Request`?實例中的?`old`?方法。`old`?方法會從?[Session](http://www.hmoore.net/tonyyu/laravel_5_6/786180)?取出之前被閃存的輸入數據:
~~~
$username = $request->old('username');
~~~
Laravel 也提供了全局輔助函數?`old`。如果你要在?[Blade 模板](http://www.hmoore.net/tonyyu/laravel_5_6/786198)?中顯示舊的輸入,使用?`old`?會更加方便。如果給定字段沒有舊的輸入,則返回?`null`:
~~~
<input type="text" name="username" value="{{ old('username') }}">
~~~
### Cookies
#### 從請求中獲取 Cookie
Laravel 框架創建的每個 cookie 都會被加密并使用驗證碼進行簽名,這意味著如果客戶端更改了它們,便視為無效。若要從請求中獲取 cookie 值,你可以在?`Illuminate\Http\Request`?實例上使用?`cookie`?方法:
~~~
$value = $request->cookie('name');
~~~
或者,您可以使用?`Cookie`?Facade 來訪問 cookie 的值:
~~~
$value = Cookie::get('name');
~~~
#### 將 Cookies 附加到響應
你可以使用?`cookie`?方法將 cookie 附加到傳出的?`Illuminate\Http\Response`?實例。你需要傳遞 Cookie 名稱、值、以及有效期(分鐘)到這個方法:
~~~
return response('Hello World')->cookie(
'name', 'value', $minutes
);
~~~
`cookie`?方法還接受一些不太頻繁使用的參數。通常,這些參數與 PHP 原生?[setcookie](https://secure.php.net/manual/en/function.setcookie.php)?方法的參數具有相同的目的和意義:
~~~
return response('Hello World')->cookie(
'name', 'value', $minutes, $path, $domain, $secure, $httpOnly
);
~~~
或者,您也可以使用?`Cookie`?Facade 來?`queue`?Cookie,以將其與應用程序的傳出響應連接起來。`queue`?方法接受?`Cookie`?實例或創建?`Cookie`?實例所需的參數。在發送到瀏覽器之前,這些 cookie 將被附加到輸出響應:
~~~
Cookie::queue(Cookie::make('name', 'value', $minutes));
Cookie::queue('name', 'value', $minutes);
~~~
#### 生成 Cookie 實例
如果你想要在一段時間以后生成一個可以給定?`Symfony\Component\HttpFoundation\Cookie`?的響應實例,你可以使用全局輔助函數?`cookie`。除非此 cookie 被附加到響應實例,否則不會發送回客戶端:
~~~
$cookie = cookie('name', 'value', $minutes);
return response('Hello World')->cookie($cookie);
~~~
## 文件
### 獲取上傳文件
你可以使用?`file`?方法或使用動態屬性從?`Illuminate\Http\Request`?實例中訪問上傳的文件。該?`file`?方法返回一個?`Illuminate\Http\UploadedFile`?類的實例,該類繼承了 PHP 的?`SplFileInfo`?類的同時也提供了各種與文件交互的方法:
~~~
$file = $request->file('photo');
$file = $request->photo;
~~~
你可以使用?`hasFile`?方法確認請求中是否存在文件:
~~~
if ($request->hasFile('photo')) {
//
}
~~~
#### 驗證成功上傳
除了檢查上傳的文件是否存在外,你也可以通過?`isValid`?方法驗證上傳的文件是否有效:
~~~
if ($request->file('photo')->isValid()) {
//
}
~~~
#### 文件路徑 & 擴展名
`UploadedFile`?類還包含訪問文件的完整路徑及其擴展名方法。`extension`?方法會根據文件內容判斷文件的擴展名。該擴展名可能會和客戶端提供的擴展名不同:
~~~
$path = $request->photo->path();
$extension = $request->photo->extension();
~~~
#### 其它文件方法
`UploadedFile`?實例上還有許多可用的方法,可以查看該類的?[API 文檔](http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/File/UploadedFile.html)?了解這些方法的詳細信息。
### 存儲上傳文件
要存儲上傳的文件,先配置好?[文件系統](http://www.hmoore.net/tonyyu/laravel_5_6/786243)。你可以使用?`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');
~~~
## 配置可信代理
如果你的應用程序運行在失效的 TLS / SSL 證書的負載均衡器后,你可能會注意到你的應用程序有時不能生成 HTTPS 鏈接。通常這是因為你的應用程序正在從端口 80 上的負載平衡器轉發流量,卻不知道是否應該生成安全鏈接。
解決這個問題需要在 Laravel 應用程序中包含?`App\Http\Middleware\TrustProxies`?中間件,這使得你可以快速自定義應用程序信任的負載均衡器或代理。你的可信代理應該作為這個中間件的?`$proxies`?屬性的數組列出。除了配置受信任的代理之外,還可以配置應該信任的代理?`$header`:
~~~
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
/**
* 這個應用程序的可信代理列表
*
* @var array
*/
protected $proxies = [
'192.168.1.1',
'192.168.1.2',
];
/**
* 應該用來檢測代理的頭信息。
*
* @var string
*/
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}
~~~
> {tip} 如果您使用 AWS 彈性負載平衡,您的?`$header`?值應該是?`Request::HEADER_X_FORWARDED_AWS_ELB`。常量的更多信息,可用于?`$headers`?屬性,看看 Symfony 的 文檔?[信任代理](http://symfony.com/doc/current/deployment/proxies.html)。
#### 信任所有代理
如果你使用 Amazon AWS 或其他的「云」負載均衡器提供程序,你可能不知道負載均衡器的實際 IP 地址。在這種情況下,你可以使用?`*`?來信任所有代理:
~~~
/**
* 這個應用程序的可信代理列表
*
* @var array
*/
protected $proxies = '*';
~~~
- 前言
- 翻譯說明
- 發行說明
- 升級指南
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- Homestead
- Valet
- 部署
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- Facades
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- URL
- Session
- 表單驗證
- 錯誤
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全相關
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試相關
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Scout 全文搜索
- Socialite 社會化登錄