什么是web框架?web框架工作原理解剖

我們常用的web前端框架?其實簡單稱呼叫web框架,現階段web前端技術成熟,從視覺體驗到用戶體驗都是比較好的,這也是從簡單到復雜的web前端框架技術實現的,在國內前端技術開發(fā)人員也是非常的多,市面上的前端框架可以說是眼花繚亂,這里寫這篇文章就是讓你在使用不同的前端框架?的時候能夠明確的知道自己的選擇。


Web前端框架工作原理:

在我們討論框架之前,我們需要理解Web如何“工作”的。為此,我們將深入挖掘你在瀏覽器里輸入一個URL按下Enter之后都發(fā)生了什么。在你的瀏覽器中打開一個新的標簽,瀏覽http://www.uileader.com。我們討論為了顯示這個頁面,瀏覽器都做了什么事情(不關心DNS查詢)。

Web服務器

每個頁面都以HTML的形式傳送到你的瀏覽器中,HTML是一種瀏覽器用來描述頁面內容和結構的語言。那些負責發(fā)送HTML到瀏覽器的應用稱之為“Web服務器”,會讓你迷惑的是,這些應用運行的機器通常也叫做web服務器。

然而,最重要的是要理解,到最后所有的web應用要做的事情就是發(fā)送HTML到瀏覽器。不管應用的邏輯多么復雜,最終的結果總是將HTML發(fā)送到瀏覽器(我故意將應用可以響應像JSON或者CSS等不同類型的數據忽略掉,因為在概念上是相同的)。

HTTP

瀏覽器從web服務器(或者叫應用服務器)上使用HTTP協議下載網站,HTTP協議是基于一種 請求-響應(request-response)模型的。客戶端(你的瀏覽器)從運行在物理機器上的web應用請求數據,web應用反過來對你的瀏覽器請求進行響應。

重要的一點是,要記住通信總是由客戶端(你的瀏覽器)發(fā)起的,服務器(也就是web服務器)沒有辦法創(chuàng)建一個鏈接,發(fā)送沒有經過請求的數據給你的瀏覽器。如果你從web服務器上接收到數據,一定是因為你的瀏覽器顯示地發(fā)送了請求。

HTTP Methods

在HTTP協議中,每條報文都關聯方法(method或者verb),不同的HTTP方法對應客戶端可以發(fā)送的邏輯上不同類型的請求,反過來也代表了客戶端的不同意圖。例如,請求一個web頁面的HTML,與提交一個表單在邏輯上是不同的,所以這兩種行為就需要使用不同的方法。

HTTP GET

GET方法就像其聽起來的那樣,從web服務器上get(請求)數據。GET請求是到目前位置最常見的一種HTTP請求,在一次GET請求過程中,web應用對請求頁面的HTML進行響應之外,就不需要做任何事情了。特別的,web應用在GET請求的結果中,不應該改變應用的狀態(tài)(比如,不能基于GET請求創(chuàng)建一個新帳號)。正是因為這個原因,GET請求通常認為是“安全”的,因為他們不會導致應用的改變。

HTTP POST

顯然,除了簡單的查看頁面之外,應該還有更多與網站進行交互的操作。我們也能夠向應用發(fā)送數據,例如通過表單。為了達到這樣的目的,就需要一種不同類型的請求方法:POST。POST請求通常攜帶由用戶輸入的數據,web應用收到之后會產生一些行為。通過在表單里輸入你的信息登錄一個網站,就是POST表單的數據給web應用的。

不同于GET請求,POST請求通常會導致應用狀態(tài)的改變。在我們的例子中,當表單POST之后,一個新的賬戶被創(chuàng)建。不同于GET請求,POST請求不總是生成一個新的HTML頁面發(fā)送到客戶端,而是客戶端使用響應的響應碼(response code)來決定對應用的操作是否成功。

HTTTP Response Codes

通常來說,web服務器返回200的響應碼,意思是,“我已經完成了你要求我做的事情,一切都正常”。響應碼總是一個三位數字的代號,web應用在每個響應的同時都發(fā)送一個這樣的代號,表明給定的請求的結果。響應碼200字面意思是“OK”,是響應一個GET請求大多情況下都使用的代號。然而對于POST請求, 可能會有204(“No Content”)發(fā)送回來,意思是“一切都正常,但是我不準備向你顯示任何東西”。

Web應用

你可以僅僅使用HTTP GET和POST做很多事情。一個應用程序負責去接收一個HTTP請求,同時給以HTTP響應,通常包含了請求頁面的HTML。POST請求會引起web應用做出一些行為,可能是往數據庫中添加一條記錄這樣的。還有很多其它的HTTP方法,但是我們目前只關注GET和POST。

那么最簡單的web應用是什么樣的呢?我們可以寫一個應用,讓它一直監(jiān)聽80端口(著名的HTTP端口,幾乎所有HTTP都發(fā)送到這個端口上)。一旦它接收到等待的客戶端發(fā)送的請求連接,然后它就會回復一些簡單的HTML。

下面是程序的代碼:

import socketHOST = ''PORT = 80listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)listen_socket.bind((HOST, PORT))listen_socket.listen(1)connection, address = listen_socket.accept()request = connection.recv(1024)connection.sendall(b"""HTTP/1.1 200 OKContent-type: text/html

(如果上面的代碼不工作,試著將PORT改為類似8080這樣的端口。)

這個代碼接收簡單的鏈接和簡單的請求,不管請求的URL是什么,它都會響應HTTP 200(所以,這不是一個真正意義上的web服務器)。Content-type:text/html行代碼的是header字段,header用來提供請求或者響應的元信息。這樣,我們就告訴了客戶端接下來的數據是HTML。

請求的剖析

如果看一下測試上面程序的HTTP請求,你會發(fā)現它和HTTP響應非常類似。第一行 ,在這個例子中是GET / HTTP/1.0。第一行之后就是一些類似Accept: */*這樣的頭(意思是我們希望在響應中接收任何內容)。

我們響應和請求有著類似的第一行,格式是 ,在外面的例子中是HTTP/1.1 200 OK。接下來是頭部,與請求的頭部有著相同的格式。最后是響應的實際包含的內容。注意,這會被解釋為一個字符串或者二進制文件,Content-type頭告訴客戶端怎樣去解釋響應。

解決路由和模板兩大問題

圍繞建立web應用的所有問題中,兩個問題尤其突出:

1.我們如何將請求的URL映射到處理它的代碼上?

2.我們怎樣動態(tài)地構造請求的HTML返回給客戶端,HTML中帶有計算得到的值或者從數據庫中取出來的信息?

每個web框架都以某種方法來解決這些問題,也有很多不同的解決方案。用例子來說明更容易理解,所以我將針對這些問題討論Django和Flask的解決方案。但是,首先我們還需要簡單討論一下MVC。

Django中的MVC

Django充分利用MVC設計模式。MVC,也就是Model-View-Controller(模型-視圖-控制器),是一種將應用的不同功能從邏輯上劃分開。models代表的是類似數據庫表的資源(與Python中用class來對真實世界目標建模使用的方法大體相同)。controls包括應用的業(yè)務邏輯,對models進行操作。為了動態(tài)生成代表頁面的HTML,需要views給出所有要動態(tài)生成頁面的HTML的信息。

在Django中有點讓人困惑的是,controllers被稱做views,而views被稱為templates。除了名字上的有點奇怪,Django很好地實現了MVC的體系架構。

Django中的路由

路由是處理請求URL到負責生成相關的HTML的代碼之間映射的過程。在簡單的情形下,所有的請求都是有相同的代碼來處理(就像我們之前的例子那樣)。變得稍微復雜一點,每個URL對應一個view function。舉例來說,如果請求www.foo.com/bar這樣的URL,調用handler_bar()這樣的函數來產生響應。我們可以建立這樣的映射表,枚舉出我們應用支持的所有URL與它們相關的函數。

然而,當URL中包含有用的數據,例如資源的ID(像這樣www.foo.com/users/3/) ,那么這種方法將變得非常臃腫。我們如何將URL映射到一個view函數,同時如何利用我們想顯示ID為3的用戶?

Django的答案是,將URL正則表達式映射到可以帶參數的view函數。例如,我假設匹配^/users/(?P\d+)/$的URL調用display_user(id)這樣的函數,這兒參數id是正則表達式中匹配的id。這種方法,任何/users//這樣的URL都會映射到display_user函數。這些正則表達式可以非常復雜,包含關鍵字和參數。

Flask中的路由

Flask采取了一點不同的方法。將一個函數和請求的URL關聯起來的標準方法是通過使用route()裝飾器。下面是Flask代碼,在功能上和上面正則表達式方法相同:

@app.route('/users//')

def display_user(id):

# ...

就像你看到的這樣,裝飾器使用幾乎最簡單的正則表達式的形式來將URL映射到參數。通過傳遞給route()的URL中包含的指令,可以提取到參數。路由像/info/about_us.html這樣的靜態(tài)URL,可以像你預想的這樣@app.route('/info/about_us.html')處理。

通過Templates產生HTML

繼續(xù)上面的例子,一旦我們有合適的代碼映射到正確的URL,我們如何動態(tài)生成HTML?對于Django和Flask,答案都是通過HTML Templating。

HTML Templating和使用str.format()類似:需要動態(tài)輸出值的地方使用占位符填充,這些占位符后來通過str.format()函數用參數替換掉。想象一下,整個web頁面就是一個字符串,用括號標明動態(tài)數據的位置,最后再調用str.format()。Django模板和Flask使用的模板引擎Jinja2都使用的是這種方法。

然而,不是所有的模板引擎都能相同的功能。Django支持在模板里基本的編程,而Jinja2只能讓你執(zhí)行特定的代碼(不是真正意義上的代碼,但也差不多)。Jinja2可以緩存渲染之后的模板,讓接下來具有相同參數的請求可以直接從緩存中返回結果,而不是用再次花大力氣渲染。

數據庫交互

Django有著“功能齊全”的設計哲學,其中包含了一個ORM(Object Realational Mapper,對象關系映射),ORM的目的有兩方面:一是將Python的class與數據庫表建立映射,而是剝離出不同數據庫引擎直接的差異。沒人喜歡ORM,因為在不同的域之間映射永遠不完美,然而這還在承受范圍之內。Django是功能齊全的,而Flask是一個微框架,不包括ORM,盡管它對SQLAlchemy兼容性非常好,SQLAlchemy是Django ORM的最大也是唯一的競爭對手。

內嵌ORM讓Django有能力創(chuàng)建一個功能豐富的CRUD應用,從服務器端角度來看,CRUD(CreateRead Update Delete)應用非常適合使用web框架技術。Django和Flask-SQLchemy可以直接對每個model進行不同的CRUD操作。

總結:

到現在為止,web前端框架的目的應該非常清晰了:向程序員隱藏了處理HTTP請求和響應相關的基礎代碼。至于隱藏多少這取決于不同的框架,Django和Flask走向了兩個極端:Django包括了每種情形,幾乎成了它致命的一點;Flask立足于“微框架”,僅僅實現web應用需要的最小功能,其它的不常用的web框架任務交由第三方庫來完成。

但是最后要記住的是,Python web框架都以相同的方式工作的:它們接收HTTP請求,分派代碼,產生HTML,創(chuàng)建帶有內容的HTTP響應。事實上,所有主流的服務器端框架都以這種方式工作的(JavaScript框架除外)。但愿了解了這些框架的目的,你能夠在不同的框架之間選擇適合你應用的框架進行開發(fā)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 22年12月更新:個人網站關停,如果仍舊對舊教程有興趣參考 Github 的markdown內容[https://...
    tangyefei閱讀 35,421評論 22 257
  • 本文系轉載于網絡。 Web 應用框架,或者簡單的說是“Web 框架”,其實是建立 web 應用的一種方式。從簡單的...
    莫莫33閱讀 316評論 0 2
  • 本文系轉載于網絡。 Web 應用框架,或者簡單的說是“Web 框架”,其實是建立 web 應用的一種方式。從簡單的...
    everfight閱讀 341評論 0 3
  • 可不要被名字迷惑,它可不是web網頁的框架,而是服務器用來產生web網頁時用到的工具。 Web應用框架(簡稱Web...
    約伯閱讀 3,906評論 0 3
  • # Python 資源大全中文版 我想很多程序員應該記得 GitHub 上有一個 Awesome - XXX 系列...
    aimaile閱讀 26,842評論 6 427

友情鏈接更多精彩內容