英文原文:http://jeffknupp.com/blog/2014/03/03/what-is-a-web-framework/ 在原文基礎上加上了自己在翻譯過程中,查看的資料和自己的一些理解,同時簡化了一些不好理解的地方和加入了一些通俗易懂的語言。
統一詞匯:
- web:網絡
- application:應用(編程語言寫的程序)
- web application:網絡應用(編程語言寫的程序,用於處理網絡上的數據)
- request:請求
- response:響應
什么是web框架?
Web application frameworks(網絡應用框架),簡稱:web框架,用於構建web應用。不管是簡單的博客網站,還是復雜的AJAX
應用,每一個頁面都是通過代碼生成。我發現許多開發者喜歡學習web框架,像:Flask
或Django
。但是,他們卻不真正理解什么是web框架、web框架的目的是什么、web框架是如何工作的。這篇文章,我將探究web框架中的那些不為人知的基本原理(通過探究,解答上面的三個問題)。讀完這篇文章,你可以完全理解什么是web框架,為什么web框架這么重要。同時,你將能夠:更快的理解一個新的框架;知曉一個框架的優劣,從而根據需求(實際情況),選擇更合適的框架。(這篇文章會讓你真正的理解web框架,而不是只會用框架,按照文檔‘按部就班’。)
web框架如何工作的
在我們開始談論web框架之前,我們需要知道web是如何工作的。我們將弄清楚:當你在瀏覽器中輸入URL,按下回車,之后都發生了什么。在你的瀏覽器打開一個新的窗口,訪問:http://www.jeffknupp.com
(任何一個網址都可以,推薦:http://www.xueweihan.com 😊)。我們將一步步的來探究你的瀏覽器,在展示這個訪問的頁面過程中都做了什么。
1. web服務器
每個網頁傳都是以HTML
格式傳到你的瀏覽器,HTML
是一種用於描述網頁內容和結構的語言。響應並發送HTML
給瀏覽器的應用叫做web服務器。容易令人迷惑的是:運行剛才所說的應用(響應並發送HTML給瀏覽器的應用)的機器也叫做web服務器。
需要注意,截止目前為止所有的服務器都是發送HTML
給瀏覽器(注意:暫不考慮web服務器是發送Json給瀏覽器)。不論多么復雜的應用,最終結果都是發送HTML
給瀏覽器。
web應用是怎么知道發送什么東西給瀏覽器?它是根據瀏覽器的請求返回響應的內容。
2. HTTP
瀏覽器通過HTTP協議向服務器請求網站的數據(HTTP協議在編程界是通用的、應用范圍極廣)。HTTP協議是‘請求-響應’模式的基礎。客戶端(瀏覽器)從服務器請求數據。web應用則是反過來響應客戶的請求,發送響應數據給客戶端(瀏覽器)。
需要記住的一點是:通信是有客戶端(瀏覽器)發起的。服務器無法向客戶端,啟發(首先發起)連接或者主動發送數據給客戶端。如果你接收到從服務器發來的數據,那么一定是你的瀏覽器請求的。
2.1 HTTP方法
每一條信息都有一個方法和HTTP聯系起來(換句話說:每個請求都需要一個指定HTTP方法)。不同的HTTP
方法代表着不同的客戶端請求邏輯和目的。以請求HTML
網頁為例(詳情請參考:form表單):
<form action="接收這個請求的url" method="get或post">
<li>姓名:<input type="text" name="name">
<input type="subimt"/>
</li>
</from>
提交表單有不同的邏輯,這兩個不同的方法(method)用於兩種不同的需求。
2.1.1 HTTP GET方法
GET
方法顧名思義:從服務器,得到(請求)數據。GET
請求是最常見的HTTP
請求。GET
請求web應用的過程中只需要響應網頁的HTML(內容),而不需要任何其他的額外操作。注意:GET
請求不應該改變web應用的狀態(例如:get不應該請求創建新的用戶)。 原因是:GET
請求通常被認為是“安全”的,因為它不修改網站的數據。
2.1.2 HTTP POST方法
POST
請求,它和網站有更多的交互,不像GET
方法只是獲取數據。我們也可以通過表單發送數據給web應用,只需要請求時:method="post"
。POST
請求是把用戶的輸入的數據,傳遞給web應用,例如:網站上的注冊功能,就是在表單中把你的信息輸入完成,然后通過POST
方法,把這些數據發送給web應用,web應用在處理你的注冊請求,返回注冊成功或失敗的結果。
POST
請求會導致網站數據的改變。例如:通過POST
表單,創建一個新的用戶賬號。POST
請求的結果一般不請求接收新的HTML頁面。而是,客戶端根據響應的“響應狀態碼”做決定,例如:返回狀態碼200,代表服務器端操作成功,則客戶端響應作出成功的操作。
2.2 HTTP響應碼
正常情況下,服務器返回響應碼:200,代表着:“我做了你要求的任何事情,一切都很好。”響應碼一般是三位數字。web應用必須給每個請求都返回請求的處理結果,響應狀態碼:200,意思是“OK”,通常用於響應GET
請求。POST
請求,可能接收到204
(“沒有內容”),意思是:“一起看起來沒有問題,但是我還沒有任何東西可以展示給你”。
注意:繼續說上面form
表單的例子,POST
請求的地址,決定於action
字段的值。也就是說:POST
請求的地址,是由HTML頁面中的字段決定的。
3. web應用
GET
和POST
方法是兩個最常見的HTTP
方法。web應用責任是:接收的HTTP
請求,並返回相應的HTTP
響應,返回的請求結果通常包含HTML。POST
請求是讓web應用做一些操作或者增加一條新的紀錄到數據庫。當然HTTP
還有一些其他的方法,但是我們接下來只說GET
和POST
。
最簡單的web應用是什么樣?我們可以寫一個監聽80
端口,等待連接(HTTP默認端口號就是80)的應用。它建立連接,等待接收客戶端發來的請求,接收到請求后,返回一些簡單的HTML作為響應。
最簡單的web應用代碼:
import socket
HOST = ''
PORT = 80
listen_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("""HTTP/1.1 200 OK
Content-type: text/html
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>""")
connection.close()
(如果上面的代碼不能運行,嘗試把端口號(PORT)更換為8080
)
這段代碼接收連接信號和請求信號,不管請求任何的URL,它都回復HTTP 200
響應(所以這段代碼不是一個真正的web服務器)。Content-type: text/html
是頭(header)字段,被用來表示請求和響應的元信息(meta-information:元信息可用於瀏覽器(如何顯示內容或重新加載頁面),搜索引擎(關鍵詞)參考:meta)。這例子中,我們告訴客戶端數據類型是HTML:Content-type: text/html
(而不是JSON:Content-Type: application/json
)。
3.1 剖析Request
web應用接收到了請求,需要分析request,從而作出正確的處理。還需要返回正確的response,所以應用需要能夠分析request和生成response,下面就說說什么是:request和response。
如果仔細觀察HTTP
請求,你會發現它和響應長的特別像。第一行是<HTTP Method> <URL> <HTTP version>
(HTTP方法,請求的URL,HTTP協議版本),例如:GET / HTTP/1.1
。接下來,就是一些header(頭)字段,例如:Accept: */*
(意思是:可以接收任何類型的響應)。這里說的比較籠統,想要深究的同學可以參考:HTTP真的很簡單
上面說了Request的格式,下面該說說Response的格式:<HTTP version> <HTTP Status-Code> <Status-Code Reason-Phrase>
(HTTP協議版本,HTTP狀態碼,HTTP狀態碼描述),例如:HTTP/1.1 200 OK
。接下來和請求的格式一樣,也是頭字段,最后就是response包含的實際內容了。內容可以是字符串或者二進制對象(比如:圖片和文件就是二進制對象),Content-type
頭字段指出了,內容類型,用於定義網絡文件的類型,讓客戶端知道響應回來的數據類型,得到正確的響應結果。
3.2 web服務器,還要做的雜活
如果我們要在上面那個簡單的web應用的基礎上繼續,搭建出一個web應用,我們還需要解決以下幾個問題:
- 如何解析url使得,返回url對應的結果。(路由:route)
- 如何在支持GET的基礎上,支持POST。
- 如何處理cookie和session。
- 如何處理上千的並發量。
沒有人願意每次建立web應用的時候都需要去處理這些問題。所以,就出現解決這些問題和HTTP協議的packages(包)。記住:這些包的核心方法我們上面的例子是一樣的:監聽端口,接收請求,返回HTTP
響應和HTML。
3.3 解決兩個大問題:Routing(路由)和Templates(模版)
上面列出的建立web應用的問題,這里挑出兩個:
- 如何把請求的URL對應到處理這個請求的方法上?
- 如何根據處理完的結果,動態的生成請求的HTML?
每一個web框架解決這兩個問題用的都是不同的方式,有許多不同的方法。舉例子說明,應該跟有助於理解。所以,下面我們講討論:Django和Flask的解決這兩個問題的方法。在此之前,我們需要簡單的說一下MVC模式。
3.3.1 MVC在Django的應用
Django使用了MVC模式,MVC:“Model-View-Controller”(模型(Model)、視圖(View)和控制器(Controller)),把應用中的邏輯分成三個部分。資源,數據庫中的表相當於Model
數據層。Controller
控制器包含應用的業務邏輯和操作數據的操作。View
視圖,用於展示信息,動態的生成HTML,作為響應結果。
在Django中,控制器(Controller)被叫做視圖(Views),視圖(Views)被叫做模版(template)。這種叫法是有些奇怪,但是Django是一個簡單,優雅的MVC結構的實現。
3.3.2 Routing in Django(Django的路由)
路由是:把請求的URL和處理這個請求的代碼,處理結果聯系起來。拿咱們上面那個“最簡單的web應用例子”來說,所有的請求,都是被同一段代碼處理。正常的都是每個URL都有對應一個處理(handler)的函數,比如:我們訪問www.foo.com/bar
,它就對應handle_bar()
函數,這個函數負責返回響應。我們可以把應用中的每個URLs都和一個方法一一對應起來。
如果請求的url中帶有參數,我們如果獲取url中的參數?並把參數傳遞給對應的處理函數?例如:www.foo.com/users/3/
,我們想要顯示user的id:3。
Django的解決辦法是,通過正則表達式得到url中的的參數。比如:把url匹配^/users/(?P<id>\d+)/$
的結果傳入display_user(id)
函數,這個id
參數就是url匹配出來的結果。通過這種方法,形如:/users/<some number>/
的URL都將調用display_user
函數。
3.3.3 Routing in Flask(Flask的路由)
Flask的路由管理機制和Django的有所不同,它使用的是route()
裝飾器。如下:
@app.route('/users/<id:int>/')
def display_user(id):
#...
這如上面所展示的,使用裝飾器實現URL和方法的一一對應,更加簡潔明了。參數通過<name:type>
格式,專遞給修飾的方法,靜態的URLs比如:/info/about_us.html
,你可以這樣處理:@app.route('/info/about_us.html')
。
3.3.4 模版生成HTML
我們說完如何把‘URL和處理函數一一對應起來並傳遞參數到函數中’,這次我們需要把URL中的參數展示到頁面上,也就是根據請求動態的生成頁面(HTML)。Django和Flask都是用HTML模版來決解這種情況。
HTML模版類似於使用str.format()
:它把動態的值(根據請求返回的值)有占位符來代替,最后輸出的時候,再把通過str.format()
函數,把占位符轉化成具體的值。把一個頁面想象成一個很長的字符串,里面的動態變量用占位符來替代,最后調用str.format()
函數。Django和Flask使用的都是jinjia2模版引擎。
模版引擎是為了動態生成頁面,所以它的主要作用就是:生成一個模版,用於根據請求返回的值,生成頁面,就像‘填空’。例如:模版內容:我是__程序員,而我想要展示:我是python程序員,而你沒准想要顯示:我是java程序員。具體實現,參考上面給的連接。
4. 數據交互
Django有着‘自帶電池’的設計哲學,包含了ORM(對象關系映射:數據庫中的表對應成代碼中的類),使得操作數據就像操作變得簡單。Flask是‘微型框架’,它沒有自帶數據交互的模版,但是你可以使用SQLAlchemy。Flask和Django通過使用ORM使得數據:增,刪,改,查;變得十分方便,簡單。
web框架總結
到此為止,web框架到底做了什么就變得很清晰了:把HTTP
的請求和響應,根據特定的規則對應到具體的處理函數上。把處理完的結果,傳遞到模版引擎上。Django和Flask是兩個極端。Django包含了各種功能;Flask是‘微型框架’,只包含web框架的基本功能,但可以通過第三方包來擴充功能。
記住,Python web框架做的都是同樣一件事情:接收HTTP
請求,分配處理的方法,生成HTML作為HTTP
響應,返回給客戶端。實際上,幾乎所有的web框架都是做了這些工作。但願,你現在能夠根據自己的需求,挑選最適合的框架了。