WSGI將Web組件分成三類:
environ, start_response
): 這是一個app
什么是WSGI APP:
WSGI APP是一個可調用的對象(callable object),常用的可調用的對象有三種:
1.一個函數或者類的方法:
environ, start_response
): 這是一個app
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。
通常來說,它由兩部分組成: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 等相關數據
• 限制請求速率,設置白名單
等等等