1. 程式人生 > 程式設計 >WSGI初探

WSGI初探

web伺服器和web框架

web伺服器即是用來接受客戶端請求,建立連線的程式, web框架則是用來處理業 務邏輯的,比如可以有很多的伺服器nginxapche,uWSGI也可以有很多的框 架,django,flask,那這些東西如何搭配就會有問題,那麼這個問題的解決方就是 WSGI。

所以WSGI 就如其名是一個閘道器介面,提供伺服器和框架之間資料轉發的一 個介面,要通過這個介面當然就需要一定的規範。下面就是這種規範的具體內容

WSGI

在PEP 333 中的摘要給出,

This document specifies a proposed standard interface between web servers and Python web applications or frameworks,to promote web application portability across a variety of web servers.

也就是說 WSGI 是指定Web伺服器與Python Web應用程式或框架之間的標準介面, 以促進Web應用程式在各種Web伺服器之間的可移植性。

而且由於早期的框架和伺服器並不支援WSGI,而為了推廣WSGI,WSGI 就必須簡單易於實現,使得框架作者的實現成本降低。

django 中的WSGI

在django中的 wsgi.py 可以看到它是通過get_application()返回WSIGHandlers() 而在WSIGHandlers中實現了__call__使得其被呼叫時返回response

其中兩個引數是必須的 environ,start_response

class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.load_middleware()

    def __call__(self,environ,start_response):
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__,environ=environ)
        request = self.request_class(environ)
        response = self.get_response(request)

        response._handler_class = self.__class__

        status = '%d %s' % (response.status_code,response.reason_phrase)
        response_headers = list(response.items())
        for c in response.cookies.values():
            response_headers.append(('Set-Cookie',c.output(header='')))
        start_response(status,response_headers)
        if getattr(response,'file_to_stream',None) is not None and environ.get('wsgi.file_wrapper'):
            response = environ['wsgi.file_wrapper'](response.file_to_stream)
        return response
複製程式碼

WSGI應用端

application 端的協議就是這樣的,這個api只需要兩個引數,可以看到是非 常簡單的,上面是框架中的東西,PEP 333,中給出了一個更簡單的 事例,下面 對該事例進行了修改

def simple_app(environ,start_response):
    stdout = "Hello world!"
    h = sorted(environ.items())
    for k,v in h:
        stdout += k + '=' + repr(v) + "\r\n"
    print(start_response)
    start_response("200 OK",[('Content-Type','text/plain; charset=utf-8')])
    return [stdout.encode("utf-8")]
複製程式碼

上面的程式碼就算一個滿足WSGI的Web應用程式,只要接收兩個引數即可,看起來很 像是API,其實它的確可以是當作API來用的但是這是給框架開發者使用的,

WSGI是面向框架、伺服器開發者的工具,而不是為應用開發者直接提供支援的。

WSGI服務端

下面通過標準庫中的wsgiref.simple_server 來實現一個簡單的伺服器,開啟之 後即可,通過網頁訪問本地埠8000得到請求

from wsgiref.simple_server import make_server

httpd = make_server('',8000,simple_app)
print('Serving HTTP on port 8000...')
httpd.serve_forever()
複製程式碼

當從HTTP客戶端收到一個請求,伺服器就呼叫simple_app去做邏輯處理並返回處理 的結果集。

中介軟體

中介軟體有著如下功能

  • 在重寫environ之後,相應地根據目標URL把請求發到對應的應用物件。
  • 允許多個應用或者框架並行允許。
  • 通過網路來轉發請求和相應,實現負載均衡和遠端處理。
  • 對內容進行後續處理,比如應用XSL樣式表

在web伺服器和應用程式之間存在著中介軟體,在的django中存在的中介軟體去處理請求 檢視,響應,模板,和異常,層層的包裹而形成了中介軟體棧(middleware stack)

    self._request_middleware = []
    self._view_middleware = []
    self._template_response_middleware = []
    self._response_middleware = []
    self._exception_middleware = []
複製程式碼

那麼這些中介軟體在出入棧的過程中,中介軟體的位置就成立相對位置,對伺服器他是 應用,對於應用則他是服務.

參考