要想模擬出web請求響應的流程,先想一想平時咱們是怎麼上網瀏覽網頁的?首先打開瀏覽器,而後在地址欄中輸入咱們想要訪問的頁面,緊接着按下回車鍵Enter,最後跳轉至目標頁面(固然咱們也會出現訪問失敗的狀況,暫時不討論這種狀況,之後另作講解)。python
總結一下咱們能夠將此流程分解爲下面幾步:web
發送請求和響應請求其實就是基於socket套接字的網絡通訊,那咱們如何獲得用戶請求訪問的路徑呢?瀏覽器
這是以前提到的HTTP get請求的數據格式服務器
咱們能夠看到在請求行內有用戶想要訪問的頁面路徑URL,能夠經過字符串的分割得到:網絡
以後咱們能夠根據用戶想要訪問的URL返回不一樣的信息給他,這樣一看非常艱辛,但事實上對於真實開發中的python web程序來講,通常會分爲兩部分:服務器程序和應用程序。框架
服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的各類數據進行整理。socket
應用程序則負責具體的邏輯處理。爲了方便應用程序的開發,就出現了衆多的Web框架,例如:Django、Flask等。不一樣的框架有不一樣的開發方式,可是不管如何,開發出的應用程序都要和服務器程序配合,才能爲用戶提供服務。函數
這樣,服務器程序就須要爲不一樣的框架提供不一樣的支持。這樣混亂的局面不管對於服務器仍是框架,都是很差的。對服務器來講,須要支持各類不一樣框架,對框架來講,只有支持它的服務器才能被開發出的應用使用。編碼
這時候,標準化就變得尤其重要。咱們能夠設立一個標準,只要服務器程序支持這個標準,框架也支持這個標準,那麼他們就能夠配合使用。一旦標準肯定,雙方各自實現。這樣,服務器能夠支持更多支持標準的框架,框架也可使用更多支持標準的服務器,WSGI應運而生。url
WSGI(Web Server Gateway Interface)就是一種規範,它定義了使用Python編寫的web應用程序與web服務器程序之間的接口格式,實現web應用程序與web服務器程序間的解耦。
經常使用的WSGI服務器有uwsgi、Gunicorn。而Python標準庫提供的獨立WSGI服務器叫wsgiref,Django開發環境用的就是這個模塊來作服務器。
有了WSGI咱們不須要接觸到TCP鏈接、HTTP原始請求和響應格式等底層代碼,咱們能夠用Python專一編寫web業務。下面是利用wsgiref模塊編寫的簡易web框架
from wsgiref.simple_server import make_server from urls import * def run(env,response): """ :param env: 請求相關的信息 :param response: 響應相關的信息 :return: """ print(env) # 是一個大字典 裏面裝了一堆處理好了的鍵值對數據 response('200 OK',[('username','jason'),('password','123')]) # 固定寫法 後面列表裏面一個個元祖會以響應頭kv鍵值對的形式返回給客戶端 # 獲取用戶訪問的路徑 current_path = env.get('PATH_INFO') if current_path == '/index': return [b'index'] elif current_path == '/login': return [b'login'] return [b'hello] if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) server.serve_forever()
固然咱們還能略微升華代碼,能夠看到在判斷用戶訪問路徑的時候,過多的if判斷會顯得整個代碼冗長累贅,可讀性差,因此咱們要拆分代碼。定義一個字典來對應函數功能。
from wsgiref.simple_server import make_server from urls import * def index(env): return 'index' def login(env): return 'login' def error(env): return '404 error' urls = { ('/index',index), ('/login',login), } def run(env,response): """ :param env: 請求相關的信息 :param response: 響應相關的信息 :return: """ print(env) # 是一個大字典 裏面裝了一堆處理好了的鍵值對數據 response('200 OK',[('username','jason'),('password','123')]) # 固定寫法 後面列表裏面一個個元祖會以響應頭kv鍵值對的形式返回給客戶端 # 獲取用戶訪問的路徑 current_path = env.get('PATH_INFO') func = None # 循環比對路由與試圖函數的映射關係 for url_map in urls: # url_map = ('/index',index) if current_path == url_map[0]: func = url_map[1] # 只要匹配成功 直接結束循環 break if func: res = func(env) else: res = error(env) return [res.encode('utf-8')] # 最後再統一編碼 if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) server.serve_forever()
固然這也不是最優方案,最終咱們能夠將視圖函數歸於一個文件views.py,映射關係歸於另外一個文件urls.py。這樣當咱們須要增長用戶路徑的時候只須要在urls.py中添一條對應關係,在views.py中定義函數功能便可,實現瞭解耦合操做。哈哈,這已經稍微劇透成型的web框架的模式,以後會詳細說明。