天天看點

什麼是web架構?

英文原文:http://jeffknupp.com/blog/2014/03/03/what-is-a-web-framework/ 在原文基礎上加上了自己在翻譯過程中,檢視的資料和自己的一些了解,同時簡化了一些不好了解的地方和加入了一些通俗易懂的語言。

統一詞彙:

web:網絡

application:應用(程式設計語言寫的程式)

web application:網絡應用(程式設計語言寫的程式,用于處理網絡上的資料)

request:請求

response:響應

什麼是web架構?

Web application frameworks(網絡應用架構),簡稱:web架構,用于建構web應用。不管是簡單的部落格網站,還是複雜的<code>AJAX</code>應用,每一個頁面都是通過代碼生成。我發現許多開發者喜歡學習web架構,像:<code>Flask</code>或<code>Django</code>。但是,他們卻不真正了解什麼是web架構、web架構的目的是什麼、web架構是如何工作的。這篇文章,我将探究web架構中的那些不為人知的基本原理(通過探究,解答上面的三個問題)。讀完這篇文章,你可以完全了解什麼是web架構,為什麼web架構這麼重要。同時,你将能夠:更快的了解一個新的架構;知曉一個架構的優劣,進而根據需求(實際情況),選擇更合适的架構。(這篇文章會讓你真正的了解web架構,而不是隻會用架構,按照文檔‘按部就班’。)

在我們開始談論web架構之前,我們需要知道web是如何工作的。我們将弄清楚:當你在浏覽器中輸入URL,按下回車,之後都發生了什麼。在你的浏覽器打開一個新的視窗,通路:<code>http://www.jeffknupp.com</code>(任何一個網址都可以,推薦:http://www.xueweihan.com ????)。我們将一步步的來探究你的浏覽器,在展示這個通路的頁面過程中都做了什麼。

每個網頁傳都是以<code>HTML</code>格式傳到你的浏覽器,<code>HTML</code>是一種用于描述網頁内容和結構的語言。響應并發送<code>HTML</code>給浏覽器的應用叫做web伺服器。容易令人迷惑的是:運作剛才所說的應用(響應并發送HTML給浏覽器的應用)的機器也叫做web伺服器。

需要注意,截止目前為止所有的伺服器都是發送<code>HTML</code>給浏覽器(注意:暫不考慮web伺服器是發送Json給浏覽器)。不論多麼複雜的應用,最終結果都是發送<code>HTML</code>給浏覽器。

web應用是怎麼知道發送什麼東西給浏覽器?它是根據浏覽器的請求傳回響應的内容。

浏覽器通過HTTP協定向伺服器請求網站的資料(HTTP協定在程式設計界是通用的、應用範圍極廣)。HTTP協定是‘請求-響應’模式的基礎。用戶端(浏覽器)從伺服器請求資料。web應用則是反過來響應客戶的請求,發送響應資料給用戶端(浏覽器)。

需要記住的一點是:通信是有用戶端(浏覽器)發起的。伺服器無法向用戶端,啟發(首先發起)連接配接或者主動發送資料給用戶端。如果你接收到從伺服器發來的資料,那麼一定是你的浏覽器請求的。

每一條資訊都有一個方法和HTTP聯系起來(換句話說:每個請求都需要一個指定HTTP方法)。不同的<code>HTTP</code>方法代表着不同的用戶端請求邏輯和目的。以請求<code>HTML</code>網頁為例(詳情請參考:form表單):

送出表單有不同的邏輯,這兩個不同的方法(method)用于兩種不同的需求。

<code>GET</code>方法顧名思義:從伺服器,得到(請求)資料。<code>GET</code>請求是最常見的<code>HTTP</code>請求。<code>GET</code>請求web應用的過程中隻需要響應網頁的HTML(内容),而不需要任何其他的額外操作。注意:<code>GET</code>請求不應該改變web應用的狀态(例如:get不應該請求建立新的使用者)。 原因是:<code>GET</code>請求通常被認為是“安全”的,因為它不修改網站的資料。

<code>POST</code>請求,它和網站有更多的互動,不像<code>GET</code>方法隻是擷取資料。我們也可以通過表單發送資料給web應用,隻需要請求時:<code>method="post"</code>。<code>POST</code>請求是把使用者的輸入的資料,傳遞給web應用,例如:網站上的注冊功能,就是在表單中把你的資訊輸入完成,然後通過<code>POST</code>方法,把這些資料發送給web應用,web應用在處理你的注冊請求,傳回注冊成功或失敗的結果。

<code>POST</code>請求會導緻網站資料的改變。例如:通過<code>POST</code>表單,建立一個新的使用者賬号。<code>POST</code>請求的結果一般不請求接收新的HTML頁面。而是,用戶端根據響應的“響應狀态碼”做決定,例如:傳回狀态碼200,代表伺服器端操作成功,則用戶端響應作出成功的操作。

正常情況下,伺服器傳回響應碼:200,代表着:“我做了你要求的任何事情,一切都很好。”響應碼一般是三位數字。web應用必須給每個請求都傳回請求的處理結果,響應狀态碼:200,意思是“OK”,通常用于響應<code>GET</code>請求。<code>POST</code>請求,可能接收到<code>204</code>(“沒有内容”),意思是:“一起看起來沒有問題,但是我還沒有任何東西可以展示給你”。

注意:繼續說上面<code>form</code>表單的例子,<code>POST</code>請求的位址,決定于<code>action</code>字段的值。也就是說:<code>POST</code>請求的位址,是由HTML頁面中的字段決定的。

<code>GET</code>和<code>POST</code>方法是兩個最常見的<code>HTTP</code>方法。web應用責任是:接收的<code>HTTP</code>請求,并傳回相應的<code>HTTP</code>響應,傳回的請求結果通常包含HTML。<code>POST</code>請求是讓web應用做一些操作或者增加一條新的紀錄到資料庫。當然<code>HTTP</code>還有一些其他的方法,但是我們接下來隻說<code>GET</code>和<code>POST</code>。

最簡單的web應用是什麼樣?我們可以寫一個監聽<code>80</code>端口,等待連接配接(HTTP預設端口号就是80)的應用。它建立連接配接,等待接收用戶端發來的請求,接收到請求後,傳回一些簡單的HTML作為響應。

最簡單的web應用代碼:

(如果上面的代碼不能運作,嘗試把端口号(PORT)更換為<code>8080</code>)

這段代碼接收連接配接信号和請求信号,不管請求任何的URL,它都回複<code>HTTP 200</code>響應(是以這段代碼不是一個真正的web伺服器)。<code>Content-type: text/html</code>是頭(header)字段,被用來表示請求和響應的元資訊(meta-information:元資訊可用于浏覽器(如何顯示内容或重新加載頁面),搜尋引擎(關鍵詞)參考:meta)。這例子中,我們告訴用戶端資料類型是HTML:<code>Content-type: text/html</code>(而不是JSON:<code>Content-Type: application/json</code>)。

web應用接收到了請求,需要分析request,進而作出正确的處理。還需要傳回正确的response,是以應用需要能夠分析request和生成response,下面就說說什麼是:request和response。

如果仔細觀察<code>HTTP</code>請求,你會發現它和響應長的特别像。第一行是<code>&lt;HTTP Method&gt; &lt;URL&gt; &lt;HTTP version&gt;</code>(HTTP方法,請求的URL,HTTP協定版本),例如:<code>GET / HTTP/1.1</code>。接下來,就是一些header(頭)字段,例如:<code>Accept: */*</code>(意思是:可以接收任何類型的響應)。這裡說的比較籠統,想要深究的同學可以參考:HTTP真的很簡單

上面說了Request的格式,下面該說說Response的格式:<code>&lt;HTTP version&gt; &lt;HTTP Status-Code&gt; &lt;Status-Code Reason-Phrase&gt;</code>(HTTP協定版本,HTTP狀态碼,HTTP狀态碼描述),例如:<code>HTTP/1.1 200 OK</code>。接下來和請求的格式一樣,也是頭字段,最後就是response包含的實際内容了。内容可以是字元串或者二進制對象(比如:圖檔和檔案就是二進制對象),<code>Content-type</code>頭字段指出了,内容類型,用于定義網絡檔案的類型,讓用戶端知道響應回來的資料類型,得到正确的響應結果。

如果我們要在上面那個簡單的web應用的基礎上繼續,搭建出一個web應用,我們還需要解決以下幾個問題:

如何解析url使得,傳回url對應的結果。(路由:route)

如何在支援GET的基礎上,支援POST。

如何處理cookie和session。

如何處理上千的并發量。

沒有人願意每次建立web應用的時候都需要去處理這些問題。是以,就出現解決這些問題和HTTP協定的packages(包)。記住:這些包的核心方法我們上面的例子是一樣的:監聽端口,接收請求,傳回<code>HTTP</code>響應和HTML。

上面列出的建立web應用的問題,這裡挑出兩個:

如何把請求的URL對應到處理這個請求的方法上?

如何根據處理完的結果,動态的生成請求的HTML?

每一個web架構解決這兩個問題用的都是不同的方式,有許多不同的方法。舉例子說明,應該跟有助于了解。是以,下面我們講讨論:Django和Flask的解決這兩個問題的方法。在此之前,我們需要簡單的說一下MVC模式。

Django使用了MVC模式,MVC:“Model-View-Controller”(模型(Model)、視圖(View)和控制器(Controller)),把應用中的邏輯分成三個部分。資源,資料庫中的表相當于<code>Model</code>資料層。<code>Controller</code>控制器包含應用的業務邏輯和操作資料的操作。<code>View</code>視圖,用于展示資訊,動态的生成HTML,作為響應結果。

在Django中,控制器(Controller)被叫做視圖(Views),視圖(Views)被叫做模版(template)。這種叫法是有些奇怪,但是Django是一個簡單,優雅的MVC結構的實作。

路由是:把請求的URL和處理這個請求的代碼,處理結果聯系起來。拿咱們上面那個“最簡單的web應用例子”來說,所有的請求,都是被同一段代碼處理。正常的都是每個URL都有對應一個處理(handler)的函數,比如:我們通路<code>www.foo.com/bar</code>,它就對應<code>handle_bar()</code>函數,這個函數負責傳回響應。我們可以把應用中的每個URLs都和一個方法一一對應起來。

如果請求的url中帶有參數,我們如果擷取url中的參數?并把參數傳遞給對應的處理函數?例如:<code>www.foo.com/users/3/</code>,我們想要顯示user的id:3。

Django的解決辦法是,通過正規表達式得到url中的的參數。比如:把url比對<code>^/users/(?P&lt;id&gt;\d+)/$</code>的結果傳入<code>display_user(id)</code>函數,這個<code>id</code>參數就是url比對出來的結果。通過這種方法,形如:<code>/users/&lt;some number&gt;/</code>的URL都将調用<code>display_user</code>函數。

Flask的路由管理機制和Django的有所不同,它使用的是<code>route()</code>裝飾器。如下:

這如上面所展示的,使用裝飾器實作URL和方法的一一對應,更加簡潔明了。參數通過<code>&lt;name:type&gt;</code>格式,專遞給修飾的方法,靜态的URLs比如:<code>/info/about_us.html</code>,你可以這樣處理:<code>@app.route('/info/about_us.html')</code>。

我們說完如何把‘URL和處理函數一一對應起來并傳遞參數到函數中’,這次我們需要把URL中的參數展示到頁面上,也就是根據請求動态的生成頁面(HTML)。Django和Flask都是用HTML模版來決解這種情況。

HTML模版類似于使用<code>str.format()</code>:它把動态的值(根據請求傳回的值)有占位符來代替,最後輸出的時候,再把通過<code>str.format()</code>函數,把占位符轉化成具體的值。把一個頁面想象成一個很長的字元串,裡面的動态變量用占位符來替代,最後調用<code>str.format()</code>函數。Django和Flask使用的都是jinjia2模版引擎。

模版引擎是為了動态生成頁面,是以它的主要作用就是:生成一個模版,用于根據請求傳回的值,生成頁面,就像‘填空’。例如:模版内容:我是__程式員,而我想要展示:我是python程式員,而你沒準想要顯示:我是java程式員。具體實作,參考上面給的連接配接。

Django有着‘自帶電池’的設計哲學,包含了ORM(對象關系映射:資料庫中的表對應成代碼中的類),使得操作資料就像操作變得簡單。Flask是‘微型架構’,它沒有自帶資料互動的模版,但是你可以使用SQLAlchemy。Flask和Django通過使用ORM使得資料:增,删,改,查;變得十分友善,簡單。

到此為止,web架構到底做了什麼就變得很清晰了:把<code>HTTP</code>的請求和響應,根據特定的規則對應到具體的處理函數上。把處理完的結果,傳遞到模版引擎上。Django和Flask是兩個極端。Django包含了各種功能;Flask是‘微型架構’,隻包含web架構的基本功能,但可以通過第三方包來擴充功能。

記住,Python web架構做的都是同樣一件事情:接收<code>HTTP</code>請求,配置設定處理的方法,生成HTML作為<code>HTTP</code>響應,傳回給用戶端。實際上,幾乎所有的web架構都是做了這些工作。但願,你現在能夠根據自己的需求,挑選最适合的架構了。

繼續閱讀