【一】web框架
- web框架本質上可以看成是一個功能強大的socket服務端,使用者的瀏覽器可以看成是擁有視覺化介面的socket客戶端。
- 兩者透過網路請求實現資料互動,從架構層面上先簡單的將Web框架看做是對前端、資料庫的全方位整合
【二】手擼web框架
【1】原始版本
(1)服務端
# [一] 匯入模組
import socket
# [二]定義通訊ip和埠
IP = '127.0.0.1'
PORT = 8082
# [三] 建立socket物件
server = socket.socket()
# [四] 監聽埠
server.bind((IP, PORT))
# [五] 建立半連線池
server.listen(5)
while True:
# [六] 接收客戶端連結和地址
sock,addr = server.accept()
# [七] 接收資料
data = sock.recv(1024)
print(f'這是來自客戶端的資訊:>>>>{data.decode("utf-8")}')
# [八] 回送資料
sock.send(b"hello client ")
(2)客戶端
# [一] 匯入模組
import socket
# [二]定義通訊IP和埠
IP = '127.0.0.1'
PORT = 8082
# [三] 建立連結物件
client = socket.socket()
client.connect((IP, PORT))
while True:
# [四] 傳送資料
client.send(b"hello server")
# [五]接收資料
data = client.recv(1024)
print(f"這是來服務端的資料:>>>>{data.decode('utf-8')}")
- 出現了一個問題
- 使用瀏覽器來充當客戶端
- 服務端無法正常響應客戶端(瀏覽器)的請求
瀏覽器和服務端進行互動是基於HTTP協議
【1】HTTP協議是什麼
超文字傳輸協議:HTTP協議就是規範了瀏覽器和服務端之間進行資料互動和傳輸的標準
不僅僅能傳輸文字,還能傳輸圖片/音訊/影片/壓縮包 ...
【2】HTTP協議的特點
(1)無狀態
客戶端向服務端傳送請求,服務端正常響應資料。服務端不會儲存客戶端的任何資訊
(2)基於TCP協議/IP協議之上的應用層協議
底層也是TCP協議
(3)無連線(短連線)
客戶端向服務端傳送連線請求,服務端正常響應。資料傳輸完成自動斷開連線
(4)基於請求與響應模型
客戶端向服務端傳送連線請求,服務端才能正常響應客戶端的請求
請求資料格式
請求方式 請求路徑(地址)版本(Http1.0)
請求頭
請求體
響應資料格式
請求方式 請求路徑(地址) 狀態碼 版本(HTTP1.0)
響應頭
響應體
1xx:客戶端向服務端正常傳送請求
2xx:服務端正常響應客戶端資料
3xx:重定向
4xx:403:請求錯誤,404:訪問資源不存在
5xx : 伺服器當機
- 最佳化
- 基於響應資料格式相應資料
【2】瀏覽器傳送請求
- 遵循HTTP協議
- 四大特性
- 資料格式
- 響應狀態碼
# [一] 匯入模組
import socket
# [二]定義通訊ip和埠
IP = '127.0.0.1'
PORT = 8082
# [三] 建立socket物件
server = socket.socket()
# [四] 監聽埠
server.bind((IP, PORT))
# [五] 建立半連線池
server.listen(5)
while True:
# [六] 接收客戶端連結和地址
sock, addr = server.accept()
# [七] 接收資料
data = sock.recv(1024)
print(f'這是來自客戶端的資訊:>>>>{data.decode("utf-8")}')
# [八] 回送資料
# 服務端響應的資料需要符合HTTP響應格式
sock.send(b"HTTP1.1 200 OK\r\n\r\n hello client ")
- 弊端
- 根據訪問地址訪問到對應的資源
【3】路由對應響應
- 基於不同的字尾相應不同的內容
GET / HTTP/1.1
Host: 127.0.0.1:8082
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9
- 如何獲取使用者輸入的url字尾
- HTTP請求資料
/favicon.ico
直接忽略 不影響判斷
- 利用字串切割和索引取值獲取相應資料
# [一] 匯入模組
import socket
from _socket import SO_REUSEADDR, SOL_SOCKET
# [二]定義通訊ip和埠
IP = '127.0.0.1'
PORT = 8082
# [三] 建立socket物件
server = socket.socket()
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加
# [四] 監聽埠
server.bind((IP, PORT))
# [五] 建立半連線池
server.listen(5)
while True:
# [六] 接收客戶端連結和地址
sock, addr = server.accept()
# [七] 接收資料
data = sock.recv(1024)
# print(f'這是來自客戶端的資訊:>>>>{data.decode("utf-8")}')
# [八] 回送資料
# 服務端響應的資料需要符合HTTP響應格式
http_type = "HTTP1.1 200 OK\r\n\r\n"
# 將客戶端請求相關資料先轉成字串
option = data.decode('utf8')
# 研究發現可以採用字串切割獲取路由
current_path = option.split(' ')[1]
print(current_path)
# 根據字尾的不同返回不同的內容
if current_path == '/login':
data = f'{http_type} hello zhangsan login!!!1'
sock.send(data.encode('utf-8'))
elif current_path == '/register':
data = f'{http_type} hello zhangsan register!!!!'
sock.send(data.encode('utf-8'))
else:
data = f'{http_type}404 zhangsan error'
sock.send(data.encode('utf-8'))
# 匯入模組
import socket
from _socket import SO_REUSEADDR, SOL_SOCKET
# 建立服務端物件
server = socket.socket()
# 監聽埠和IP
PORT = 8989
IP = "127.0.0.1"
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加
server.bind((IP, PORT))
# 建立半連線池
server.listen(5)
# 接收到客戶端物件和客戶端地址
while True:
conn, addr = server.accept()
# 從客戶端接收到資訊
data_from_client = conn.recv(1024)
data_from_client = data_from_client.decode("utf-8")
# 從上述請求資料中切分出指定的請求方式和請求路徑
option = data_from_client.split(' ')
print(option)
# 請求方式
option_type = option[0]
# 請求路徑
option_path = option[1]
# print(option_path)
http_res_type = "HTTP1.1 200 OK\r\n\r\n"
# 根據請求路徑指定請求方法
if option_path == "/login":
res = f"{http_res_type} hello zhangsan login success"
conn.send(res.encode("utf-8"))
elif option_path == "/register":
res = f"{http_res_type} hello zhangsan register success"
conn.send(res.encode("utf-8"))
else:
res = f"{http_res_type} 404 not found"
conn.send(res.encode("utf-8"))
- 純手擼框架缺陷:
- socket程式碼過於重複(每次搭建服務端都需要反覆造輪子)
- 針對HTTP請求資料沒有完善的處理方式(目前只能定向切割)
- 無法實現服務端的併發
【三】基於wsgiref模組搭建web框架
【1】模組封裝功能
# [一] 匯入模組
import socket
# [二]定義通訊IP和埠
IP = '127.0.0.1'
PORT = 8082
# [三] 建立連結物件
client = socket.socket()
client.connect((IP, PORT))
while True:
# [四] 傳送資料
client.send(b"hello server")
# [五]接收資料
data = client.recv(1024)
print(f"這是來服務端的資料:>>>>{data.decode('utf-8')}")
【2】路由對應響應
- 路由指的是HTTP請求的URL對映到響應的處理函式(或者檢視函式)。
- 路由定義了不同URL請求應該由哪個程式中的哪個函式來處理,這種對映關係為路由規則
(1)wsgiref
1.0
from wsgiref import simple_server
def run(request, response):
"""
:param request: 請求相關的資料
:param response: 響應相關的資料
:return: 返回給客戶端的展示資料
"""
response('200 OK', []) # 固定編寫 無需掌握
return [b'hello zhangsan']
if __name__ == '__main__':
'''服務端監聽的IP埠'''
IP = '127.0.0.1'
PORT = 8080
'''建立一個服務端物件'''
server = simple_server.make_server(IP,PORT,run)
'''監聽本機8080埠 一旦有請求訪問 自動觸發run方法的執行'''
server.serve_forever()
# 模組封裝了socket程式碼並將請求資料處理成諸多k:v鍵值對
(2)wsgiref
2.0
from wsgiref import simple_server
# 重寫一個函式run函式
def run(request, response):
'''
:param request: 請求相關的資料
:param response: 響應相關的資料
:return:
'''
path = request.get("PATH_INFO")
response("200 OK",[]) # 固定的格式不需要更改
# 按照HTTP協議格式相應資料
# 建立response物件
if path == "/login":
return [b"zhangsan login"]
elif path == "/register":
return [b"zhangan register"]
else:
return [b"404 not found"]
if __name__ == '__main__':
# 指定伺服器的IP和埠
IP = "127.0.0.1"
PORT = 8080
# 建立一個服務端物件
server = simple_server.make_server(IP, PORT, run)
# 啟動服務端
server.serve_forever()
- 對request物件中的PATH_INFO屬性提取實現了路由的篩選
- 還想再最佳化程式碼。不利於解耦合
(3)wsgiref
3.0
# 匯入模組
import socket
from _socket import SO_REUSEADDR, SOL_SOCKET
# 建立服務端物件
server = socket.socket()
# 監聽埠和IP
PORT = 8989
IP = "127.0.0.1"
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 就是它,在bind前加
server.bind((IP, PORT))
# 建立半連線池
server.listen(5)
# 接收到客戶端物件和客戶端地址
while True:
conn, addr = server.accept()
# 從客戶端接收到資訊
data_from_client = conn.recv(1024)
data_from_client = data_from_client.decode("utf-8")
# 從上述請求資料中切分出指定的請求方式和請求路徑
option = data_from_client.split(' ')
# 請求方式
option_type = option[0]
# 請求路徑
option_path = option[1]
print(option_path)
http_res_type = "HTTP1.1 200 OK\r\n\r\n"
# 根據請求路徑指定請求方法
if option_path == "/login":
res = f"{http_res_type} hello zhangsan login success"
conn.send(res.encode("utf-8"))
elif option_path == "/register":
res = f"{http_res_type} hello zhangsan register success"
conn.send(res.encode("utf-8"))
else:
res = f"{http_res_type} 404 not found"
conn.send(res.encode("utf-8"))
- 根據請求資料,切分出請求路徑和請求方式,對不同的請求方式和路徑進行不容的處理
- 每次都得必須重新寫 socket 服務端
- 針對不同的請求路徑,不同的if ~ else 函式
- 沒有實現服務端的併發
(4)wsgiref
2.0
- 將每一個路由函式拆出去
- 新建一個路由和函式的對映關係
# 匯入模組、
from wsgiref import simple_server
def login(request):
return "dream login"
def register(request):
return "dream register"
def error(request):
return "404 not found"
# 請求路徑和請求函式的對應關係
urls = (
("/login", login),
("/register", register),
)
# 重寫一個函式 run函式 :負責返回響應資料
def run(request, response):
'''
:param request: 請求相關的資料
:param response: 響應相關的資料
:return:
'''
# print(request)
# print("-----------------")
# print(f"response :>>> {response}")
path = request.get("PATH_INFO")
response("200 OK", []) # 固定的格式不需要更改
# 按照HTTP協議格式相應資料
# 建立response物件
# 路由地址和對應的函式左對映
func_name = None
for url in urls:
if path == url[0]:
func_name = url[1]
print(func_name)
break
if func_name:
response_data = func_name(request)
else:
response_data = error(request)
return [response_data.encode("utf-8")]
# 請求函式和請求地址之間的對映關係
def main():
# 指定伺服器的IP和埠
IP = "127.0.0.1"
PORT = 8080
# 建立一個服務端物件
server = simple_server.make_server(IP, PORT, run)
# 啟動服務端
server.serve_forever()
if __name__ == '__main__':
# print(type(back_url(path="/login")[0]))
main()
(5)wsgiref
3.0
- 將路由函式拆分成單個檔案
views.py
:: 檢視函式
def login(request):
return "dream login"
def register(request):
return "dream register"
def error(request):
return "404 not found"
def home(request):
return f"這是 home 頁面"
- 將對映關係函式拆分成單個檔案
urls.py
:: 路由檢視
from views import login, register,error,home
# 請求路徑和請求函式的對應關係
url_pattern = (
("/login", login),
("/register", register),
("/home", home),
)
- 主函式檔案,負責排程和統一
# 匯入模組、
from wsgiref import simple_server
from urls import url_pattern, error
# 重寫一個函式 run函式 :負責返回響應資料
def run(request, response):
'''
:param request: 請求相關的資料
:param response: 響應相關的資料
:return:
'''
path = request.get("PATH_INFO")
response("200 OK", []) # 固定的格式不需要更改
func_name = None
for url in url_pattern:
if path == url[0]:
func_name = url[1]
print(func_name)
break
if func_name:
response_data = func_name(request)
else:
response_data = error(request)
return [response_data.encode("utf-8")]
def main():
# 指定伺服器的IP和埠
IP = "127.0.0.1"
PORT = 8080
# 建立一個服務端物件
server = simple_server.make_server(IP, PORT, run)
# 啟動服務端
server.serve_forever()
if __name__ == '__main__':
# print(type(back_url(path="/login")[0]))
main()
【三】模版檔案和靜態檔案
【1】模版檔案(templates)
- 儲存前端頁面的檔案
- 登入註冊頁面
【2】靜態檔案(static)
- 負責儲存靜態的資料
- jQuery原始碼檔案,bootstrap原始碼檔案,本地頭像或者音樂
【四】動態頁面和靜態頁面
【1】靜態頁面
- 死頁面:所有的資料都是固定不變的
- 404頁面
- 內容固定:頁面上的所有資料(文字、圖片、連結等)都直接寫入 HTML 檔案,不會因為使用者的不同請求或時間的變化而變化。
- 無需伺服器處理:當使用者訪問靜態網頁時,瀏覽器直接從伺服器下載對應的 HTML 檔案並顯示內容,伺服器主要負責儲存和分發已存在的網頁資源。
- 載入速度快:由於內容不需伺服器進一步處理,所以載入速度較快。
- 常見例子有:error.html、func.html等預定義的錯誤提示頁面、功能說明頁面等。
【2】動態頁面
- 動態的渲染資料
- 內容實時更新:頁面上的資料可以根據使用者的請求、資料庫查詢結果或其他伺服器端邏輯動態生成,這意味著同一頁面可以呈現不同的內容給不同的使用者或在不同時間訪問的使用者。
- 需要伺服器處理:當使用者訪問 動態網頁時,伺服器會根據請求執行相應的指令碼程式,呼叫後臺資料庫進行查詢、計算等操作,然後再將處理後的資料返回給瀏覽器,瀏覽器負責渲染這些動態內容。
- 資料互動性強:動態網頁支援與使用者互動,如表單提交、搜尋功能等,能更好地滿足使用者實時需求和個性化體驗。
- 動態網頁則更適用於需要實時互動、內容豐富且需要定期更新的場景,如新聞資訊、線上購物平臺等,透過伺服器端的動態處理,提供了更好的使用者體驗和更高的業務複雜性處理能力。
【五】jianjia2模版語法
【1】頁面展示當前時間
(1)後端
def get_time(request):
# 1.獲取當前時間
import time
c_time = time.strftime('%Y-%m-%d %X')
# 2.讀取html檔案
with open(r'templates/get_time.html','r',encoding='utf8') as f:
data = f.read()
# 3.思考:如何給字串新增一些額外的字串資料>>>:字串替換
new_data = data.replace('random_str',c_time)
return new_data
(2)前端
<h1>展示後端獲取的時間資料</h1>
<span>random_str</span>
【2】jinja2模板語法
(1)下載安裝
- 第三方模組需要先下載後使用
pip3 install jinja2
(2)功能
- 支援將資料傳遞到html頁面並提供近似於後端的處理方式簡單快捷的運算元據
(3)views.py
from jinja2 import Template
def get_dict(request):
user_dict = {'name': 'dream', 'pwd': 123, 'hobby': 'read'}
new_list = [11, 22, 33, 44, 55, 66]
with open(r'templates/get_dict.html', 'r', encoding='utf8') as f:
data = f.read()
temp_obj = Template(data)
res = temp_obj.render({'user':user_dict,'new_list':new_list})
return res
(4)templates
- --get_dict.html
<h1>字典資料展示</h1>
<p>{{ user }}</p>
<p>{{ user.name }}</p>
<p>{{ user['pwd'] }}</p>
<p>{{ user.get('hobby') }}</p>
<h1>列表資料展示</h1>
<p>
{% for i in new_list%}
<span>元素:{{ i }}</span>
{% endfor %}
</p>
【六】網路框架和MVC架構
【1】網路框架
- 所謂網路框架是指這樣的一組Python包,它能夠使開發者專注於網站應用業務邏輯的開發,而無須處理網路應用底層的協議、執行緒、程序等方面。這樣能大大提高開發者的工作效率,同時提高網路應用程式的質量。
- 在目前Python語言的幾十個開發框架中,幾乎所有的全棧網路框架都強制或引導開發者使用MVC架構開發Web應用。
- 所謂全棧網路框架,是指除了封裝網路和執行緒操作,還提供HTTP棧、資料庫讀寫管理、HTML模板引擎等一系列功能的網路框架。
- 本文重點講解的Django、Tornado和Flask是全棧網路框架的典型標杆;而Twisted更專注於網路底層的高效能封裝而不提供HTML模板引擎等介面功能,所以不能稱之為全棧框架。
【2】MVC架構
- MVC(Model-View-Controller)模式最早由Trygve Reenskaug在1978年提出,在20世紀80年代是程式語言Smalltalk的一種內部架構。
- 後來MVC被其他語言所借鑑,成為了軟體工程中的一種軟體架構模式。
- MVC把Web應用系統分為3個基本部分。
(1)模型(Model)
- 用於封裝與應用程式的業務邏輯相關的資料及對資料的處理方法,是Web應用程式中用於處理應用程式的資料邏輯的部分,Model只提供功能性的介面,透過這些介面可以獲取Model的所有功能。
- Model不依賴於View和Controller,它們可以在任何時候呼叫Model訪問資料。
- 有些Model還提供了事件通知機制,為在其上註冊過的View或Controller提供實時的資料更新。
(2)檢視(View)
- 負責資料的顯示和呈現,View是對使用者的直接輸出。
- MVC中的一個Model通常為多個View提供服務。
- 為了獲取Model的實時更新資料,View應該儘早地註冊到Model中。
(3)控制器(Controller)
- 負責從使用者端收集使用者的輸入,可以看成提供View的反向功能。
- 當使用者的輸入導致View發生變化時,這種變化必須是透過Model反映給View的。
- 在MVC架構下,Controller一般不能與View直接通訊,這樣提高了業務資料的一致性,即以Model作為資料中心。
【3】MVC架構圖
- 這3個基本部分互相分離,使得在改進和升級介面及使用者互動流程時,不需要重寫業務邏輯及資料訪問程式碼。MVC架構如圖1所示。
注意:MVC在除Python外的其他語言中也有廣泛應用,例如VC++的MFC、Java的Structs及Spring、C#的.NET開發框架,讀者應該有深刻的體會。
【七】Python主流後端框架介紹
【1】Django
(1)介紹
- 相對於Python的其他Web框架,Django的功能是最完整的,Django定義了服務釋出、路由對映、模板程式設計、資料處理的一整套功能。
- 這也意味著Django模組之間緊密耦合,開發者需要學習Django自己定義的這一整套技術。
(2)特點
[1]完善的文件
- 經過10多年的發展和完善,Django有廣泛的應用和完善的線上文件,開發者遇到問題時可以搜尋線上文件尋求解決方案。
[2]整合資料訪問元件
- Django的Model層自帶資料庫ORM元件,使開發者無須學習其他資料庫訪問技術(dbi、SQLAlchemy等)。
[3]強大的URL對映技術
- Django使用正規表示式管理URL對映,因此給開發者帶來了極高的靈活性。
[4]後臺管理系統自動生成
- 開發者只需透過簡單的幾行配置和程式碼就可以實現完整的後臺資料管理Web控制檯。
[5]錯誤資訊非常完整
- 在開發除錯過程中如果出現執行異常,則Django可以提供非常完整的錯誤資訊幫助開發者定位問題,比如缺少xxx元件的配置引用等,這樣可以使開發者馬上改正錯誤。
(3)組成結構
- Django是遵循MVC架構的Web開發框架,其主要由以下幾部分組成。
- 管理工具(Management):一套內建的建立站點、遷移資料、維護靜態檔案的命令工具。
- 模型(Model):提供資料訪問介面和模組,包括資料欄位、後設資料、資料關係等的定義及操作。
- 檢視(View):Django的檢視層封裝了HTTP Request和Response的一系列操作和資料流,其主要功能包括URL對映機制、繫結模板等。
- 模板(Template):是一套Django自己的頁面渲染模板語言,用若干內建的tags和filters定義頁面的生成方式。
- 表單(Form):透過內建的資料型別和控制元件生成HTML表單。
- 管理站(Admin):透過宣告需要管理的Model,快速生成後臺資料管理網站。
(4)總結
- 大而全
- 自帶的功能非常的多
- 但是有時候會略顯笨重
- 類似於'航空母艦'
【2】Flask
(1)介紹
- Flask是Python Web框架族裡比較年輕的一個,於2010年出現,這使得它吸收了其他框架的優點,並且把自己的主要領域定義在了微小專案上。
- 同時,它是可擴充套件的,Flask讓開發者自己選擇用什麼資料庫外掛儲存他們的資料。
- 很多功能簡單但效能卓越的網站就是基於Flask框架而搭建的,比如httpbin.org就是一個功能簡單但效能強大的HTTP測試專案。
- Flask是一個面向簡單需求和小型應用的微框架。
(2)特點
[1]內建開發伺服器和偵錯程式
- 網路程式除錯是在將編制好的網站投入實際執行前,用手工或編譯程式等方法進行測試,修正語法錯誤和邏輯錯誤的過程。
- 有經驗的開發者都知道,這是保證網站系統能夠正式應用的必要步驟。
- Flask 自帶的開發伺服器使開發者在除錯程式時無須再安裝其他任何網路伺服器,比如Tomcat、JBoss、Apache等。
- Flask預設處於除錯狀態,使得執行中的任何錯誤會同時向兩個目標傳送資訊:
- 一個是Python Console,即啟動Python程式的控制檯;
- 另一個是HTTP客戶端,即Flask開發伺服器將除錯資訊傳遞給了客戶端。
[2]與Python單元測試功能無縫銜接
- 單元測試是對最小軟體開發單元的測試,其重點測試程式的內部結構,主要採用白盒測試方法,由開發人員負責。
- 單元測試的主要目標是保證函式在給定的輸入狀態下,能夠得到預想的輸出,在不符合要求時能夠提醒開發人員進行檢查。
- Flask提供了一個與Python自帶的單元測試框架unitest無縫銜接的測試介面,即Flask物件的test_client()函式。
- 透過test_client()函式,測試程式可以模擬進行HTTP訪問的客戶端來呼叫Flask路由處理函式,並且獲取函式的輸出來進行自定義的驗證。
[3]使用Jinja2模板
- 將HTML頁面與後臺應用程式聯絡起來一直是網站程式框架的一個重要目標。
- Flask透過使用Jinja2模板技術解決了這個問題。
- Jinja2是一個非常靈活的HTML模板技術,它是從Django模板發展而來的,但是比Django模板使用起來更加自由且更加高效。
- Jinja2模板使用配製的語義系統,提供靈活的模板繼承技術,自動抗擊XSS跨站攻擊並且易於除錯。
[5]完全相容WSGI 1.0標準
- WSGI(Web Server Gateway Interface)具有很強的伸縮性且能執行於多執行緒或多程序環境下,因為Python執行緒全域性鎖的存在,使得WSGI的這個特性至關重要。
- WSGI已經是Python界的一個主要標準,各種大型網路伺服器對其都有良好的支援。
- WSGI位於Web應用程式與Web伺服器之間,與WSGI完全相容使得Flask能夠配置到各種大型網路伺服器中。
[6]基於Unicode編碼
- Flask是完全基於Unicode的。這對製作非純ASCII字符集的網站來說非常方便。
- HTTP本身是基於位元組的,也就是說任何編碼格式都可以在HTTP中傳輸。
- 但是,HTTP要求在HTTP Head中顯式地宣告在本次傳輸中所應用的編碼格式。
- 在預設情況下,Flask會自動新增一個UTF-8編碼格式的HTTP Head,使程式設計師無須擔心編碼的問題。
(3)總結
- 小而精
- 自帶的功能非常的少
- 但是第三方模組非常的多
- 類似於'遊騎兵'
- flask的第三方模組加到一起甚至比django還多
- 並且也越來越像django
- flask由於過多的依賴於第三方模組
- 有時候也會受制於第三方模組
【3】Tornado
(1)介紹
- Tornado是使用Python編寫的一個強大的可擴充套件的Web伺服器。
- 它在處理高網路流量時表現得足夠強健,卻在建立和編寫時有著足夠的輕量級,並能夠被用在大量的應用和工具中。
- Tornado作為FriendFeed網站的基礎框架,於2009年9月10日釋出,目前已經獲得了很多社群的支援,並且在一系列不同的場合中得到應用。
- 除FriendFeed和Facebook外,還有很多公司在生產上轉向Tornado,包括Quora、Turntable.fm、Bit.ly、Hipmunk及MyYearbook等。
(2)特點
- 完備的Web框架:與Django、Flask等一樣,Tornado也提供了URL路由對映、Request上下文、基於模板的頁面渲染技術等開發Web應用的必備工具。
- 是一個高效的網路庫,效能與Twisted、Gevent等底層Python框架相媲美:提供了非同步I/O支援、超時事件處理。這使得Tornado除了可以作為Web應用伺服器框架,還可以用來做爬蟲應用、物聯閘道器、遊戲伺服器等後臺應用。
- 提供高效HTTPClient:除了伺服器端框架,Tornado還提供了基於非同步框架的HTTP客戶端。
- 提供高效的內部HTTP伺服器:雖然其他Python網路框架(Django、Flask)也提供了內部HTTP伺服器,但它們的HTTP伺服器由於效能原因只能用於測試環境。而Tornado的HTTP伺服器與Tornado非同步呼叫緊密結合,可以直接用於生產環境。
- 完備的WebSocket支援:WebSocket是HTML5的一種新標準,實現了瀏覽器與伺服器之間的雙向實時通訊。
(3)總結
- 非同步非阻塞框架
- 速度極快
- 常被用作大型站點的介面服務框架
- 甚至可以用於充當遊戲伺服器
【4】Fastapi
(1)介紹
- FastAPI 是一個現代 Web 框架,速度相對較快,用於基於標準 Python 型別提示使用 Python 3.7+ 構建 API。
- FastAPI還幫助我們自動為我們的Web服務生成文件,以便其他開發人員可以快速瞭解如何使用它。
- FastAPI 具有許多功能,例如它可以顯著提高開發速度,還可以減少程式碼中的人為錯誤。
- 它很容易學習並且完全可以用於生產。
- FastAPI 與眾所周知的 API 標準(即OpenAPI 和JSON schema)完全相容。
(2)特點
[1]自動文件
- FastAPI 使用 OpenAPI 標準自動生成互動式 API 文件。
- 可以透過訪問應用程式中的特定端點來訪問此文件,這使得理解和測試 API 變得非常容易,而無需手動編寫大量文件。
[2]Python 型別提示
- FastAPI 的突出功能之一是它使用 Python 型別提示。
- 透過使用型別提示註釋函式引數和返回型別,不僅可以提高程式碼可讀性,還可以使 FastAPI 自動驗證傳入資料並生成準確的 API 文件。
- 此功能使我們的程式碼不易出錯並且更加自我記錄。
[3]資料驗證
- FastAPI 使用 Pydantic 模型進行資料驗證。
- 可以使用 Pydantic 的架構和驗證功能定義資料模型。
- 這可確保傳入資料自動驗證、序列化和反序列化,從而降低在應用程式中處理無效資料的風險。
[4]非同步支援
- 隨著Python非同步程式設計的興起,FastAPI完全擁抱非同步操作。
- 可以使用Python的async和await關鍵字來編寫非同步端點,使其非常適合處理I/O密集型任務並提高應用程式的整體響應能力。
[5]依賴注入
- FastAPI 支援依賴注入,允許宣告端點的依賴關係。
- 這有助於保持程式碼模組化、可測試和可維護。
- 我們可以將資料庫連線、身份驗證等依賴項無縫地注入到的路由中。
[6]安全功能
- FastAPI 包含各種開箱即用的安全功能,例如對 OAuth2、JWT(JSON Web 令牌)的支援以及請求資料的自動驗證,以防止 SQL 注入和跨站點指令碼 (XSS) 攻擊等常見安全漏洞。
補充:Python框架官網(部分)
框架的核心邏輯幾乎是一致的 我們在學習的時候只需要先學會一種之後就可以觸類旁通
- Django框架官網:https://www.djangoproject.com/
- Flask框架官網:https://flask.palletsprojects.com/en/3.0.x/
- Fastapi框架官網:https://fastapi.tiangolo.com/
- Pyramind框架官網:https://trypyramid.com/
- Tornado框架官網:https://www.tornadoweb.org/en/stable/
- Sanic框架官網:https://github.com/sanic-org/sanic
- Fastapi框架官網:https://fastapi.tiangolo.com/
- Aiohttp框架官網:https://docs.aiohttp.org/en/stable/
補充:Django框架版本
- Django 是一個高階的Python Web框架,由荷蘭人Armin Ronacher建立。
- 隨著版本的迭代和功能的不斷最佳化,Django在處理非同步請求方面也有了顯著的進步。
【1】Django1.x
- 預設不支援非同步
- Django 1.x主要集中在傳統的Web開發上,其設計思想傾向於同步HTTP請求處理。
- 預設情況下,並未內建對非同步程式設計的支援,開發者若要在Django 1.x中實現非同步處理,通常需要藉助第三方庫如
django-celery
或django-tornado
等來結合其他非同步框架(如Celery、Tornado等)來實現後臺任務的非同步執行。
【2】Django2.x
- 預設不支援非同步
- 在Django 2.x版本中,雖然核心框架並未直接提供對非同步HTTP請求的支援,但已經開始引入一些非同步相關的新特性和API,比如
asgi
(Asynchronous Server Gateway Interface) 標準的初步支援。 - 開發者可以透過安裝第三方ASGI伺服器(如
daphne
或uvicorn
),配合channels
庫使用,來實現Websockets和訊息佇列等場景下的部分非同步功能。
【3】Django3.x
- 自帶非同步功能
- Django 3.x標誌著其正式對非同步程式設計的支援,它引入了
channels
框架作為標準庫的一部分,實現了全棧的WebSocket支援以及與asyncio
的整合,使得開發者可以直接在檢視層、消費者層以及中介軟體層面編寫非同步程式碼,提供了ASGI
和HTTP/2
協議的底層支援。 - 此外,
django-redis
、django-socketio
等第三方庫也進一步豐富了非同步應用的構建能力。
【4】Django4.x
- 在Django 4.x版本之後,非同步功能得到了持續加強和完善。
- 例如,在4.0中,
channels
框架進行了重大重構,使其更加輕量級和模組化,同時引入了websockets
庫作為預設WebSocket支援,大大簡化了開發者配置和使用的複雜度。 - 此外,對於長期支援計劃(LTS)版本,Django會確保非同步相關的API和工具在後續更新中得到穩定且相容的維護和支援,以滿足現代Web應用對高效能、低延遲的需求。