請求


HTTP 請求

  • 接收請求
    • 請求路徑& 方法
    • PSR-7 請求Requests
  • 輸入預處理& 規範化
  • 接收資料
    • 舊資料
    • Cookies
  • 檔案
    • 接收上傳的檔案
    • 。儲存上傳的檔案
  • #設定信任代理程式

接受請求

要透過依賴注入來取得目前HTTP 請求實例,你應該在控制器上引入

Illuminate\Http\Request 類, 傳入的請求實例將會由服務容器自動注入:

<?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 實例提供了一系列方法來驗證HTTP 請求參數,並繼承了Symfony\Component\HttpFoundation\Request 類別 。以下是該類別的一些重要方法:

取得請求路徑

path  方法傳回請求的路徑資訊。所以,如果請求的路徑是http://domain.com/foo/barpath# 方法將會回傳foo/bar:

$uri = $request->path();

is 可以驗證傳入的請求路徑是否與給定的模式相符。在這個方法中,你也可以使用 * 字元作為通配符:

if ($request->is('admin/*')) {  
  //
 }

來取得請求URL

可以使用urlfullUrl 方法取得完整的請求URL。 url 方法傳回不含查詢字串的URL,fullUrl 取得包含查詢字串的URL:

// 不附带查询串...
$url = $request->url();
// 附带查询串...
$url = $request->fullUrl();

取得請求Method

#method 方法傳回請求的HTTP 動作。也可以使用isMethod 方法校驗HTTP 動作是否與給定的客串上相符:

$method = $request->method();if ($request->isMethod('post')) { 
   //
}

PSR -7 請求

PSR-7 standard 定義了HTTP 訊息接口,包括請求和回應。如果你想用 PSR-7 請求取代 Laravel 請求,需要先安裝幾個函式庫。 Laravel 使用Symfony HTTP Message Bridge 元件將典型的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 在應用的全域中間件堆疊中包含了TrimStringsConvertEmptyStringsToNull 中間件。這些中間件被放在 App\Http\Kernel 類別的堆疊清單中。它們會自動裁切請求中的所有輸入字串域,同時將空字串域轉換為 null。這樣一來,你就不必擔心路由和控制器中的標準化規約問題。

如果想要停用這個行為,只需要透過從App\Http\Kernel 類別的$middleware 屬性移除它(相當於從應用程式的中間件堆疊中移除)。

取得輸入

#取得所有的輸入資料

#可以使用all 方法取得所有輸入資料數組:

$input = $request->all();

取得單一輸入值

使用一些簡單方法,就可以通實例過 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();

從查詢字串中取得輸入

##input 方法從整個請求載體中取得值(包括查詢字串),query 方法則只從查詢字串中取得值:

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

如果查詢字串值不存在,

query 方法的第二個參數將會被傳回作為該參數的預設值:

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

不帶參數呼叫

query 方法,能夠取得查詢字串的所有值(關聯數組形式):

$query = $request->query();

透過動態屬性取得輸入

#可以透過

Illuminate\Http\Request 實例的動態屬性存取使用者輸入。例如,如果應用程式表單包含 name 域,可以像下面這樣存取該域的值:

$name = $request->name;

在使用動態屬性時,Laravel 首先會在請求載體中尋找參數的值。如果該值不存在,Lavarel 將在路由參數中搜尋。

取得JSON 輸入

當向應用程式傳遞JSON 請求時,可以透過

input 方法存取JSON 數據,只要將請求的  Content-Type 頭設定為application/json。同樣可以使用「點」語法存取JSON 陣列:

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

來取得部分輸入資料

如果需要取得輸入資料的子集,可以使用

onlyexcept 方法。它們接受單一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 允許你在兩個請求之間保持資料。這個特性在有效性校驗出錯後重新填入表單時非常有用。不過,如果你使用 Lavarel 自帶 驗證特性,不需要自己手動呼叫這些方法因為一些 Laravel 內建的驗證功能會自動呼叫它們。

將輸入資料傳送到Session

Illuminate\Http\Request 類別的flash 方法將把目前的輸入傳送到session ,在使用者向應用程式發出這次請求時它們仍然可用:

$request->flash();

可以使用flashOnlyflashExcept 方法將請求資料的子集傳送給session。這些方法常用於將密碼之類的敏感資料排除在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 拉取先前傳送的值:

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

Laravel 也提供了全域的 old 助手。如果要在 Blade 範本中 顯示舊數據, old 助手更容易使用。如果給定網域的舊值不存在,它將傳回null

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

Cookies

從請求中取得Cookies

Lavarel 框架產生的全部cookies 都是加密的,並且已經用授權碼簽名,這表示如果它們被客戶端改變就會失效。使用Illuminate\Http\Request 實例的cookie 方法可以從請求中取得cookie 值:

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

也可以使用 #Cookie facade 存取cookie值:

$value = Cookie::get('name');

將Cookies 附加到回應中

#可以使用cookie 方法向輸出的Illuminate\Http\Response 實例附加cookie。需要傳遞 名稱、值、cookie 的過期時間(以分鐘為單位)給該方法:

return response('Hello World')->cookie( 
   'name','value',$minutes
  );

cookie 還可以接受另外幾個不太常用的參數。通常這些參數和PHP 內建的setcookie 方法的參數有著相同的作用和意義:

return response('Hello World')->cookie( 
   'name', 'value', $minutes, $path, $domain, $secure, $httpOnly
  );

同樣,你可以使用Cookie facade 來「排列」 用於從應用中附加到輸出響應的cookies。 queue 方法接受一個 Cookie 實例或用於建立 Cookie 所需的參數清單。這些 cookies 將在輸出回應被傳送至瀏覽器前被附加:

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);

檔案

##取得上傳的檔案可以使用Illuminate\Http\Request 實例的file 方法或者動態屬性存取上傳檔案。 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 文件 可以取得這些方法的更多資訊。

儲存上傳文件

要儲存上傳的文件,先配置好 文件系統。你可以使用UploadedFilestore

方法把上傳檔案移到你的某個磁碟上,該檔案可能是本機檔案系統中的一個位置,甚至像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 的文檔信任代理.

##信任所有代理

如果你使用Amazon AWS 或其他的「雲端」負載平衡器提供程序,你可能不知道負載平衡器的實際IP 位址。在這種情況下,你可以使用

* 來信任所有代理:

/**
 * 应用程序的可信代理列表
 *
 * @var array
 */
 protected $proxies = '*';

本文章首發在
LearnKu.com 網站上。