WSGI初探

web服務器和web框架

web服務器便是用來接受客戶端請求,創建鏈接的程序, web框架則是用來處理業 務邏輯的,好比能夠有不少的服務器nginxapche,uWSGI也能夠有不少的框 架,django,flask,那這些東西如何搭配就會有問題,那麼這個問題的解決方就是 WSGI。php

因此WSGI 就如其名是一個網關接口,提供服務器和框架之間數據轉發的一 個接口,要經過這個接口固然就須要必定的規範。下面就是這種規範的具體內容python

WSGI

在PEP 333 中的摘要給出,nginx

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.web

也就是說 WSGI 是指定Web服務器與Python Web應用程序或框架之間的標準接口, 以促進Web應用程序在各類Web服務器之間的可移植性。django

並且因爲早期的框架和服務器並不支持WSGI,而爲了推廣WSGI, WSGI 就必須簡單易於實現,使得框架做者的實現成本下降。flask

django 中的WSGI

在django中的 wsgi.py 能夠看到它是經過get_application()返回WSIGHandlers() 而在WSIGHandlers中實現了__call__使得其被調用時返回responseapi

其中兩個參數是必須的 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,中給出了一個更簡單的 事例,下面 對該事例進行了修改cookie

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 = []
複製代碼

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

參考

相關文章
相關標籤/搜索