WSGI

本文介紹了 WSGI 是什麼以及 WSGI 的處理流程。python

服務器網關接口(WSGI)是 web 服務器和 web 應用(或 Python 框架)之間的接口規範,旨在提升 web 應用在 web 服務器上的可遷移性。若是一個應用遵循了 WSGI 規範,那麼這個應用能夠運行在任何遵循 WSGI 規範的服務器上。web

服務器指任何實現了 WSGI 規範的服務器,好比 Gunicorn、uWSGI。服務器

WSGI 有兩端:app

  1. 服務器或者說網關端
  2. 應用端或者說框架端

服務器調用一個由應用端提供的可調用對象。由服務器定義客戶端應該如何提供這個對象。好比一些服務器須要應用的部署者去寫一個簡短的腳原本建立一個服務器的實例,並向服務器實例提供應用對象。另外一些服務器可能使用配置文件或者其餘機制來指定應用對象應該從哪裏導入。框架

除了單純的服務器和應用端,也能夠建立一箇中間件來實現兩邊的定義。這樣的組件對於服務器來講是應用端,而對於應用端來講是服務器,而且能夠被用來提供擴展 APIs、內容轉換、導航和其餘功能。函數

可調用對象能夠指一個函數、方法、類或者一個擁有 __call__ 方法的實例。由服務器或實現其的應用端來選擇針對他們需求的合適技術。相反的,一個執行可調用對象的服務器或者客戶端對提供給它們的可調用對象不能有任何假設。可調用對象只是被用來調用,不須要檢查它。ui

流程

  1. 客戶端發起請求到 WSGI 服務器
  2. 服務器調用參數爲以請求數據組成的字典處理函數的應用可調用對象
  3. 應用可調用對象經過處理函數設置 HTTP status、返回頭
  4. 應用可調用對象返回響應體
  5. 服務器發送響應的 HTTP 狀態、頭部、響應體給客戶端

若是有中間件,那麼中間件位於服務器和應用之間,中間件相對於服務器是應用,相對於應用是服務器。this

字符串類型

WSGI 定義了兩種字符串:.net

  • 原生字符串,用於請求/響應頭和元數據(Python 3 中的 str
  • 二進制字符串(在Python 3 中使用 bytes 實現,Python 2 使用 str),用於請求和響應的 body(好比 POST/PUT 的輸入數據和 HTML 輸出)

應用端

  1. 應用對象是一個接收兩個參數的可調用對象:
    • 一個包含請求數據的字典
    • 一個用來設置響應 HTTP 狀態和頭部的函數
  2. 向服務器返回包含在可迭代對象中的字符串(好比 ['str1', 'str2', ])做爲響應體

應用對象必須能夠被執行屢次,實際上全部的服務器(除了 CGI) 都會發送重複的請求。code

服務器

每當服務器收到一個 HTTP 客戶端的請求,服務器會執行應用的可調用對象。獲取結果後,將其發送給客戶端。

代碼

定義可調用應用對象,並啓動 WSGI 服務器:

#! /usr/bin/env python

# Python's bundled WSGI server
from wsgiref.simple_server import make_server


def application(environ, start_response):
    # Sorting and stringifying the environment key, value pairs
    response_body = [
        '%s: %s' % (key, value) for key, value in sorted(environ.items())
    ]
    response_body = '\n'.join(response_body)
    # Response body must be bytes
    response_body = response_body.encode()

    status = '200 OK'
    response_headers = [
        ('Content-Type', 'text/plain'),
        ('Content-Length', str(len(response_body)))
    ]
    start_response(status, response_headers)

    return [response_body]


# Instantiate the server
httpd = make_server(
    'localhost',  # The host name
    8051,  # A port number where to wait for the request
    application  # The application object name, in this case a function
)

# Wait for a single request, serve it and quit
httpd.handle_request()

以上代碼來自 http://wsgi.tutorial.codepoint.net/environment-dictionary

啓動 WSGI 服務後,訪問 http://localhost:8051/ 可得到響應。

服務器調用應用獲得響應後,將其發送給客戶端

# 來自 wsgiref.handlers.BaseHandler#finish_response
def finish_response(self):
    try:
        if not self.result_is_file() or not self.sendfile():
            for data in self.result:
                self.write(data)
            self.finish_content()
    finally:
        self.close()

參考

  1. https://www.python.org/dev/peps/pep-3333/
  2. http://wsgi.tutorial.codepoint.net/application-interface
  3. https://serverfault.com/a/590833
  4. https://stackoverflow.com/a/31727503/5238892
相關文章
相關標籤/搜索