django進階---從WSGI的介紹到django原理解析


     WSGI(Web 服務器網關接口)是python中所定義的Web Server和Web APP之間或框架之間的接口標准規范。當使用 Python 進行 web 開發時,要深刻理解 Django、Flask、Tornado等 web 框架,WSGI是你繞不過去的檻兒。
     WSGI接口規范的目的就是規范Web服務器與Web應用之間的交互,在協議之間進行轉換。
     WSGI將Web組件分成三類:
     1. Web服務器(Server): 監聽某個端口的http服務器
     2. Web中間件(Middleware): 處於服務器和應用中間,起到承接的作用,用python的術語來說,中間件就類似於一個裝飾器
例如: def app( environ, start_response):   這是一個app
              return []
 
那么中間件通常是這樣定義:
         def  middleware(environ, start_response):
                //這里編寫中間件的代碼
                return app(environ, start_response)
 
     3. Web應用程序(APP): 指的是可以被調用的一個對象,一般指的是一個函數 或者 包含一個__call__方法的類的實例
 
django 整個項目實際上也是這三部分組成,我們在執行python manage.py runserver 的時候,
就首先啟動了一個8000端口的http服務器(這個就是Web服務器)
然后 django里面的中間件(這個就是上述所說的Web中間件),這個是定義在 settings.py 文件的 MIDDLEWARE
最后 django加載里面的app(這個就是上述所說的Web應用程序),這個是定義在 settings.py 文件的 INSTALLED_APPS

什么是WSGI APP:

WSGI APP是一個可調用的對象(callable object),常用的可調用的對象有三種:

1.一個函數或者類的方法:

 

def app( environ, start_response):   這是一個app
      return []
 
2.一個實現__call__()方法的類的實例:

 

class app:

    def __call__(environ, start_response):

         start_response('200 OK', [('Content-Type', 'text/html')])

         return []   

      

這個可調用的對象有幾點需要說明一下:

1. 接收兩個參數environ和start_response:
environ是一個字典,里面儲存了HTTP request的所有內容。在django里面,通常會把environ 封裝成為一個request。

start_response是一個WSGI Server(http 服務器)傳遞過來的函數,用於將response header,  status傳遞給Server。

start_response(status, headers), 它的作用是返回狀態碼 以及 頭部信息, status必須是一個字符串,格式是 “狀態碼 + 說明”。

headers 是一個數組,按照 [(key, value), (key, value) ] 這樣的格式來組織。

2.它需要返回一個可迭代的值,用於將response body傳遞給Server。

["hello world", "baby"]

 

WSGI Server

WSGI Server可以理解為就是一個實現了wsgi協議的http服務器,使用wsgi協議的方式來調用WSGI APP。

通常來說,它由兩部分組成:
1. http 服務器: 這里具體的代碼就不寫了,大概就是
 
socket = eventlet.listen(('localhost', '8000'), backlog = 10)  定義一個wsgi http服務器
server = eventlet.spawn(event.wsgi.server, socket, app) 把service 和 app進行綁定
                                  
2. 調用app的主方法:
def run(application): #服務器程序調用應用程序

    environ = {}#設定參數
def start_response(status, headers): #設定狀態和頭部參數的回調函數 pass result = application(environ, start_response)#調用APP def write(data): # 這是把響應發到前端的函數 pass def data in result: # 迭代訪問,把響應發到前端 write(data)
服務器程序主要做了以下的事:
  1. 設定app所需要的參數(environ,start_response)
  2. 調用app
  3. 迭代訪問app的返回結果(response body),並傳給客戶端

但實際上已經有很多已經封裝好的WSGI Server供我們使用,只需簡單的將APP與一些其他的參數綁定來創建一個Server
而這個Server會將它接收到的request傳遞給綁定的APP。

下面是django自帶的服務器:

from wsgiref.simple_server import make_server

# 定義我們一個最簡單的app
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']

# 創建一個服務器,IP地址為空,端口是8000,處理函數是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')  # 開始監聽HTTP請求:
httpd.serve_forever()

  


看, 我們已經自己編寫了一個最基礎的django,是不是很激動,django的本質就是這樣的一種形式,是不是感覺發現了新大陸。

WSGI Middleware

middleware的概念沒有appllication和server那么容易理解。
假設一個符合application標准的可調用對象,它接受可調用對象作為參數,返回一個可調用對象的對象。
那么對於server來說,它是一個符合標准的可調用對象,因此是application。
而對於application來說,它可以調用application,因此是server。
這樣的可調用對象稱為middleware。

middleware的概念非常接近decorator。

中間件對於app來說,它是一個service. 但是對於service來說,它確實一個app。文字說的不清晰,還是用代碼來說比較好。

 

# 這是一個標准的application object
def index(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ['index page']

# 這是一個標准的application object
def hello(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ['hello page']

# 這是一個標准的application object
def not_found(environ, start_response):
    start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
    return ['Not Found Page']
 
###上面我們定義了三個app
### 然后我們定義一個中間件 middleware, 看到沒有,這個中間件的形式是跟app是一樣的
def application(environ, start_response):
    path = environ.get('PATH_INFO', '').lstrip('/')  #這句代碼是獲取url
    
     urls = [  # 這里定義路由
         ('index', index),
         ('hello', hello)
     ]
     
     for item in urls:  # 這里根據路由,執行不同的app
          if item[0] == path:
               app = item[1]
               return app(environ, start_response)
     else:     return not_found(environ, start_response) # 如果找不到,則執行默認的app
from wsgiref.simple_server import make_server

# 創建一個服務器,IP地址為空,端口是8000,處理函數是application:
httpd = make_server('', 8000, application)
httpd.serve_forever()

  

 
看到沒有,這個例子比上面的更加完善,利用中間件實現了路由的功能,把django最基礎的功能完整的展示出來
 
中間件除了路由之外,還可以做很多事情,最常見的還有:
• 負載均衡,轉發用戶請求
• 預處理 XSL 等相關數據
• 限制請求速率,設置白名單
等等等
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM