深刻淺出wsgi

前言

相信每一個剛接觸python web開發的同窗,在學習flask、django這些框架的時候,確定會被告知說正式環境部署時,不該該用框架自帶的web服務器啓動對外提供服務,而應該搭配專門的wsgi服務器(uwsgi、gunicorn等)提供服務,爲何?在這套推薦的部署方案中,wsgi服務器和我們使用的框架都各自扮演着什麼角色?本文將盡量用大白話通俗易懂的講清楚。html

爲何須要wsgi

首先,先思考一個問題,一個http請求從客戶端發起處處理完成須要進過哪些流程?
image.png
服務端的處理能夠分爲兩部分:python

  • 與客戶端進行交互(接收並解析request,封裝併發送response)
  • 根據request參數進行相關的處理

python將這兩部分分開來,即有專門處理客戶端交互的gateway框架。而flask、django這些web框架,則是專門用於進行請求邏輯處理的工做,稱爲application。web

分開後,再看上圖,步驟二、四、5是由gateway框架負責;步驟3由application負責。django

你們都知道,pythoner圈裏個個都是人才,說話又好聽,技術還強的不行,很快就涌現出各類各樣優秀的gateway框架和application框架了,那怎麼能讓這些框架實現「混搭」呢?
咱們能夠規定一個協議,或者說是一個對gateway框架和application的設計要求;規定gateway和application分別都要須要實現什麼方法,方法要怎麼調用;這樣,當市面上出現一個更好的gateway框架時,咱們能夠零成本的將咱們的application跟新的gateway搭配起來。flask

而這套協議,就是wsgi,簡單說,它規定了gateway如何和application交互緩存

wsgi具體是如何定義的

wsgi對於server端有如下要求:

1.提供一個接收客戶端請求的服務服務器

  1. 提供一個start_response函數,被application調用,start_response函數接收status和headers,用於設置響應狀態和響應頭部信息(def start_response(self, status, headers,exc_info=None):
  2. 將application返回的結果發送給客戶端

Server端實現僞碼併發

class WsgiServer:
    def __init__(self, host, port, app):
    def serve_forever(self):    # 啓動監聽端口服務,接收請求
    def start_response(self, status, headers):  # 用於被application調用,設置status和headers
        ...
        self.status = status
        self.headers = headers
        ...
    def handle_request(self):   # 請求處理函數
        environ = {             # 請求相關變量
            "wsgi.input": self.stdin  # request內容
            "wsgi.version": self.wsgi_version # wsgi版本信息
            ...
        }
        iterResult = self.app(environ, self.start_response)     # 業務邏輯處理請求,返回可迭代對象

        for data in iterResult:
            self.write(data)        # 將數據挨個發送到緩存區

        self.send_data()            # 將結果返回給客戶端

對於application有如下要求:

  1. 必須是一個可調用對象,而且接收environ、start_response兩個參數;environ爲server端解析的當前請求環境變量;
  2. 返回值是一個可迭代對象

application的簡單示例app

def application(environ, start_response):    # 接收environ、start\_response

    start_response('200 OK', [('Content-Type', 'text/html')])    # 調用start\_response 用於設置響應狀態和響應頭部信息

    return [b'<h1>Hello, web!</h1>']    # 返回一個可迭代對象,做爲響應內容
相關文章
相關標籤/搜索