laravel 學習筆記——請求與響應

我們在前面的一篇文章 laravel學習筆記——路由(基礎) 中提到了 HTTP 請求的大致內容。關於 HTTP 協議,一定要有個大致瞭解。

本文主要是幫助大家理解 laravel 的請求和響應部分。但我們在學習這一塊之前,我會脫離 laravel 框架,單獨講述一些概念,讓大家消除很多疑慮,這有助於降低 laravel 的學習難度(至少從思想層面)。本文還希望通過介紹,讓大家清晰一些概念,讓框架本身不再神祕。

很多人常常疑惑,爲什麼在 laravel 中控制器的方法、路由的匿名函數裏,我們用的不是類似 TP 框架中的 $this->display() 輸出視圖,而是用 return view() 這種方式,或者說,爲什麼不是通過 echo、print這類輸出內容而是一定要 return 呢?返回的數據究竟怎麼被框架所處理?這期間發生了什麼?直接輸出和返回兩者的區別在哪裏?我們這篇文章不但要告訴你發生什麼,還會就這一塊諸多已有的疑惑、可能有的疑惑做出詳細講解。

本文中的例子依舊大致參考官方文檔(或各類翻譯的版本),因此在閱讀本文的同時,一定不要脫離文檔。

再次強調:請閱讀本文之前,務必大致瞭解 HTTP 協議!

先不談 laravel

再複雜的框架,也只是幫你做了更多事情、幫你寫了更多經常使用的代碼的一個程序包。無論如何,一個框架再怎麼神祕,也只是思想上的。

我們先不談 laravel。爲了讓大家消除過多的疑慮,我們需要一點小小的轉變。

假設通過設置,我們訪問根域名 http://yourdomain 實際上都會請求至 index.php,這個文件就算是一個入口文件。一般大家學習的開始,都是這樣。我們現在編輯index.php

  1. <?php
  2. echo 'hello, world';

php 初學者都會寫的代碼,對嗎?任何一個請求,都會響應一段文字 Hello, world。事實上,框架做的事,只不過多了些判斷、提供了一些工具,本質上而言,就是輸出了一堆數據而已(學院派勿噴)。

我們再看一段代碼:

  1. <?php
  2. if (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/about') {
  3. echo 'about page';
  4. } else {
  5. echo 'other page';
  6. }

這段代碼就比較有意義了。其實這段代碼就是一個路由的粗糙實現原理。判斷語句中的'/home' 就是我們的路由匹配規則。假如你的服務器配置好了 Rewrite,當我們訪問http://yourdomain/ 頁面會出現 other page,當訪問 http://yourdomain/about 頁面則會出現 about page

我們也可以叫這段代碼爲一個控制器,因爲響應請求的邏輯都定義在這裏了。這也算是個視圖,因爲呈現的樣式和內容全部由這段代碼負責。

其實,一個強大的框架只是將很多東西拆分開來,並且做得更多、更細緻。我們在 laravel 定義了路由規則,當請求開始,laravel 會根據我們所定義的規則去匹配、判斷,並將任務派發至具體的邏輯代碼,比如我們定義在路由裏的代碼、或者外部的控制器等等。這期間的調度都是由框架執行,而不需要我們自己去引用文件、派發任務、渲染視圖、連接數據庫等等。框架的意義,就是這些。只是一個優秀的框架做的更爲優雅而已。

一切都從一個請求開始

做 web 開發,尤其是基於 HTTP 協議的,一定要貫徹一個意識:沒有來自客戶端的請求,程序就不會有任何響應。

Laravel 框架爲什麼會執行?就是因爲客戶端發送一個 HTTP 請求,遞交到你的服務器,服務器的 web 服務端程序(Apache、Nginx、IIS 等)將請求的數據派發至一個指定的(入口) CGI 程序,這個入口程序的啓動意味着一切開始了。

一般的,在 laravel 中,我們默認的入口 CGI 程序是 laravel 框架下的public\index.php(學院派看到這裏準備開噴前請務必往下閱讀)。

說到 CGI,其實我們剛剛提到的 index.php 這個文件其實並不是 CGI 程序,但是由於我們通過在 apache、nginx、iis 之類的軟件的設置(如 fastCGI),這類文件會統一由 PHP CGI 解釋器進行解釋執行,因此我們可以變相的認爲一個 php 腳本文件算是一個 CGI 程序。雖然這樣說會被學院派噴,但大家理解這個意思就行。

框架和原生程序的區別只是在於框架幫你做了一些基本上都會做的事情,這一點我們已經在上文中講解了。

Laravel 也是一樣的,當請求(Request)和數據被派發至入口文件,框架開始啓動,載入一系列組件,最後調用用戶自己創建的一些邏輯:定義的路由、控制器等。最後將這些邏輯中產生的數據反饋給客戶端,反饋數據的過程可稱作一個響應(Response)。

我們稱一個請求到最終響應的過程,爲一個請求的生命週期。

我們獲取的外部數據,基本來自於請求。通過 GET 方式的請求,數據體現在查詢字符串(query string)上,php 引擎會自動幫你將字符串轉化爲一個數組 $_GET。來自於POSTPUT提交的數據除了查詢字符串上的,還有請求體上的請求正文中的數據(文本、二進制流等)。我們整個程序,基本都是在爲來自客戶端的請求服務。Laravel 提供了一系列處理 HTTP 請求的方法,這些強大的功能在處理請求數據時得心應手。

有時候,令人鬱悶的是官方文檔在請求、響應部分資料無比稀缺,但實際上,很多功能在文檔上並沒有體現。爲什麼呢?大家需要知道,在這一塊,laravel 的 HTTP 功能庫是基於 Symfony 框架的 HTTP 組件開發的,因此很多 API、文檔都應該去 Symfony 框架的文檔上去尋找。雖然這點很噁心,但是我還是要說—— laravel 的文檔還是夠用。

Laravel 關於請求部分的文檔,大多數是在講如何獲取來自客戶端的數據,一般的我們通過 Request 類獲取:

  1. $name = Request::input('name');

假如你的類或函數在某一命名空間下,需要使用 use Request; 導入該類。

上面的 Request 是一個 Facade ,關於這個 Facade 我們會在另一篇文章講述,現在大致理解爲訪問一個系統組件的快捷方式。

那麼還能怎樣使用 HTTP 的 Request 組件呢?我們從文檔中的例子來講:

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

我們在方法 store 中定義了一個只接受 Request 對象的參數。當這個控制器的這個方法被執行,laravel 框架會分析這個方法需要的依賴,現在這個依賴是一個 Request 類,那麼此時 laravel 便會在 IoC 容器裏尋找這個類的可創建的或直接可用的實例,並注入至該參數,我們便直接可以使用咯。一般框架提供的組件和開發者在 IoC 註冊的組件都可以通過這種方式訪問到,而不需要手動 new YourComponent();

關於這個 IoC 容器,我們會在 laravel 的服務容器部分講述,並會詳細介紹依賴注入( DI)的思想和相關的設計模式。

其他關於 HTTP 請求在 laravel 中的使用方法,基本在文檔中有着詳細的講解,沒有的,請查閱 Symfony 框架的相關文檔。在此不再贅述。

響應,用戶所需

響應,顧名思義,就是一種反饋。

當一個 HTTP 請求發送到服務器上,若得到的響應是客戶端所期待的,我們就視爲這一次請求是成功的,反之則是失敗的。請求成功通常服務端會響應的狀態代碼是 200。

狀態碼 代表意義
1xx 指示信息--表示請求已接收,繼續處理
2xx 成功--表示請求已被成功接收、理解、接受,如:200
3xx 重定向--要完成請求必須進行更進一步的操作,如:302
4xx 客戶端錯誤--請求有語法錯誤或請求無法實現,如:403,404
5xx 服務器端錯誤--服務器未能實現合法的請求:如:500

響應的內容相當豐富,客戶端會根據響應的情況合理的展現在客戶端,因此合理利用 HTTP 響應可以構建一個規範化的應用。Laravel 的 HTTP 組件我們很容易根據邏輯創建任何一個具體的響應。

除了 symfony、laravel等,其他大多數國產或者舊的國外框架,在這一塊思想十分保守。打個比方,實現一個提示用戶沒有權限訪問某一模塊時,很多框架只是簡單粗暴的輸出內容,並不會通過 header 產生一個 403 狀態。一個標準的 HTTP 響應不但會讓程序更爲規範,也更具有兼容性。

由於客戶端所看到的、接收到的內容都來自於服務端 HTTP 響應,因此,將響應(包括前面的請求)抽象出來,這樣的設計在開發時更易於組織邏輯。這樣,無論是輸出一段 html 代碼還是 json,或者二進制數據(圖片、音頻、視頻、其他文件等等),我們都可以通過 HTTP 響應組件進行組織,而不需要關心文件是怎麼輸出的,HTTP 組件會根據情況合理選擇響應頭、代碼等等。

這時候回到一個開始提到的問題:

在控制器、路由閉包中,使用 echo 輸出內容和使用 return 輸出內容有什麼區別?

控制器和路由閉包中返回的數據,最終會交由 laravel 的 HTTP 組件的 Response(響應)類處理,而直接輸出是由 php 引擎處理,php 會以默認的文件格式、響應頭輸出,除非使用header 函數改變。因此與其自己去調取 header() 調整響應頭還是其他,都不如 laravel 的 Response 來的簡潔實惠。

原文:https://www.insp.top/article/learn-laravel-request-and-response

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章