web框架解析

1、白手起家

  要想模擬出web請求響應的流程,先想一想平時咱們是怎麼上網瀏覽網頁的?首先打開瀏覽器,而後在地址欄中輸入咱們想要訪問的頁面,緊接着按下回車鍵Enter,最後跳轉至目標頁面(固然咱們也會出現訪問失敗的狀況,暫時不討論這種狀況,之後另作講解)。python

  總結一下咱們能夠將此流程分解爲下面幾步:web

  1. 瀏覽器發送一個HTTP請求;
  2. 服務器收到請求,生成一個HTML文檔;
  3. 服務器把HTML文檔做爲HTTP響應的Body發送給瀏覽器;
  4. 瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔並顯示。

  發送請求和響應請求其實就是基於socket套接字的網絡通訊,那咱們如何獲得用戶請求訪問的路徑呢?瀏覽器

  這是以前提到的HTTP get請求的數據格式服務器

  咱們能夠看到在請求行內有用戶想要訪問的頁面路徑URL,能夠經過字符串的分割得到:網絡

  1. 將請求bytes轉成字符串(decode)
  2. 用split方法按/r/n切,取列表的第一個元素,即取到請求首行
  3. 再按空格切,取第二元素獲得URL,即用戶訪問的頁面路徑。

  以後咱們能夠根據用戶想要訪問的URL返回不一樣的信息給他,這樣一看非常艱辛,但事實上對於真實開發中的python web程序來講,通常會分爲兩部分:服務器程序和應用程序。框架

  服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的各類數據進行整理。socket

  應用程序則負責具體的邏輯處理。爲了方便應用程序的開發,就出現了衆多的Web框架,例如:Django、Flask等。不一樣的框架有不一樣的開發方式,可是不管如何,開發出的應用程序都要和服務器程序配合,才能爲用戶提供服務。函數

  這樣,服務器程序就須要爲不一樣的框架提供不一樣的支持。這樣混亂的局面不管對於服務器仍是框架,都是很差的。對服務器來講,須要支持各類不一樣框架,對框架來講,只有支持它的服務器才能被開發出的應用使用。編碼

  這時候,標準化就變得尤其重要。咱們能夠設立一個標準,只要服務器程序支持這個標準,框架也支持這個標準,那麼他們就能夠配合使用。一旦標準肯定,雙方各自實現。這樣,服務器能夠支持更多支持標準的框架,框架也可使用更多支持標準的服務器,WSGI應運而生。url

2、WSGI

  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框架的模式,以後會詳細說明。

相關文章
相關標籤/搜索