轉載請注明原文地址:https://www.cnblogs.com/ygj0930/p/10826084.html
一:服務器、服務器軟件、應用程序(后台)
我們常說“服務器”,實際上服務器是一個很寬泛的概念。
服務器包括服務器硬件、服務器程序、以及部署在服務器上的應用程序。
服務器硬件:也稱伺服器,是提供計算服務的硬件設備,包括處理器、硬盤、內存、系統總線等。
服務器軟件:光有服務器硬件是無法提供服務的,至少需要有運行於服務器之上的操作系統、數據庫軟件、以及提供部署功能的web容器等程序。這些軟件與服務器硬件一起,共同組成了我們概念中的“服務器”。
應用程序(后台程序):應用程序是運行在服務器上,處理請求並返回響應的程序,我們日常所說的“web開發”、“后台開發”做的就是web應用程序的開發工作。一般,web應用程序需要部署於web容器中,並且與數據庫產生數據交互。三者關系大概為:web容器負責實現一些通信協議,並且監聽服務器硬件的網關、端口,接收請求,並轉發給web應用程序;web應用程序接收請求,提取請求相關信息與參數,調用中間件或者自身實現的業務邏輯(此過程或許會與數據庫產生數據交互),並將處理結果以http響應的形式返回給web容器;web容器再將接收到的響應返回給瀏覽器進行顯示。
在上面的過程中,提及到了 web容器 與 應用程序 之間的請求轉發和響應通信,那么問題來了:web容器 有 Apahce、Nginx、Gunicorn等多種選擇,而 應用程序 也可能選用Flask、Django等等各種框架進行開發,難道我們需要針對不同的容器或開發框架,都自己去實現一遍它們的通信邏輯嗎?當然不是。為了建立起web容器與應用程序之間的通信規范,於是有了我們所說的——WSGI,Web Server Gateway Interface,Python Web 服務器網關接口。
二:WSGI簡介
PythonWeb服務器網關接口(Python Web Server Gateway Interface,縮寫為WSGI)是一個協議,是 Python應用程序或框架 與 Web容器 之間的一種接口規范。
只要雙方都按照這個規范,分別去實現自己需要做的事,那么二者就可以順利地進行通信。
WSGI
協議主要包括server
和application
兩部分。
三:WSGI server接口
WSGI server接口
負責從客戶端接收請求,將request
轉發給application
,並將application
返回的response
返回給客戶端。
我們常用的web容器,如Apahce、Nginx、Gunicorn等都實現了這個接口。
接口實現方式:
def run(application): #服務器程序調用應用程序實例 environ = {} #設定參數 def start_response(xxx): #設定參數 pass result = application(environ, start_response) #調用應用程序實例的__call__函數 def write(data): pass def data in result: #迭代訪問 write(data)
服務器程序主要做了以下的事:
1. 設定應用程序所需要的參數
2. 調用應用程序
3. 迭代訪問應用程序的返回結果,並傳給客戶端
四:WSGI application接口
WSGI application接口
接收由server
轉發過來的request
,處理請求,並將處理結果返回給server
。
接口的實現方式:
- 應用程序必須是一個可調用的對象
可調用的對象有三種:- 一個函數
- 一個類,必須實現__call__()方法
- 一個類的實例
-
這個對象接收兩個參數
從源碼中,我們可以看到,這兩個參數是environ, start_response. 以可調用對象為一個類為例:class application: def __call__(self, environ, start_response): pass
-
可調用對象需要返回一個可迭代的值。以可調用對象為一個類為例:
class application: def __call__(self, environ, start_response): return [xxx]
五:Middleware 中間件
middleware是介於服務器程序和應用程序中間的部分,middleware對於服務器程序(web容器)和應用程序來說都是透明的:對服務器程序來說,中間件扮演應用程序,對應用程序來說,中間件扮演服務器程序。
因此,中間件程序需要同時實現wsgi server與wsgi application接口,可以在WSGI服務器與WSGI應用之間起調節作用。
中間件是一個很強大的領域,相信很多同學都聽說或正在擔任中間件的開發工作。
我們知道,應用程序主要是做業務邏輯實現的,那么,在請求到達應用程序之前,我們可以用來做些什么呢?一個很簡單的場景,就是做請求的預處理或者基本信息提取。
上面提到,WSGI Server調用WSGI Application時,需要兩個參數:environ
和start_response,其中,
environ
是一個字典,它來自CGI,詳情請看文檔:The Common Gateway Interface Specification
文中“Environment variables”,列舉了environ字典中包含的信息,主要有:
AUTH_TYPE
CONTENT_LENGTH #HTTP請求中Content-Length的部分 CONTENT_TYPE #HTTP請求中Content-Tpye的部分 GATEWAY_INTERFACE PATH_INFO #URL路徑除了起始部分后的剩余部分,用於找到相應的應用程序對象,如果請求的路徑就是根路徑,這個值為空字符串 PATH_TRANSLATED QUERY_STRING #URL路徑中?后面的部分 REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER REQUEST_METHOD #HTTP 請求方法,例如 "GET", "POST" SCRIPT_NAME #URL路徑的起始部分對應的應用程序對象,如果應用程序對象對應服務器的根,那么這個值可以為空字符串 SERVER_NAME SERVER_PORT SERVER_PROTOCOL #客戶端請求的協議(HTTP/1.1 HTTP/1.0) SERVER_SOFTWARE
以及客戶端發起HTTP時所攜帶過來的一些關於客戶端的信息:
HTTP_HOST = 客戶端host
HTTP_ACCEPT = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' HTTP_ACCEPT_ENCODING = 'gzip,deflate,sdch' HTTP_ACCEPT_LANGUAGE = 'en-US,en;q=0.8,zh;q=0.6,zh-CN;q=0.4,zh-TW;q=0.2' HTTP_CONNECTION = 'keep-alive' HTTP_USER_AGENT = 客戶端代理信息(瀏覽器、內核版本等)
六:總結
WSGI
協議其實是定義了一種
server
與
application
解耦的規范,即可以有多個實現
WSGI server
的服務器,也可以有多個實現
WSGI application
的框架,那么就可以選擇任意的
server
和
application
組合實現自己的
web
應用。例如
uWSGI
和
Gunicorn
都是實現了
WSGI server
協議的服務器,
Django
,
Flask
是實現了
WSGI application
協議的
web
框架,可以根據項目實際情況搭配使用。
七:擴展:uwsgi
uwsgi:與WSGI
一樣是一種通信協議,是
uWSGI
服務器的獨占協議,用於定義傳輸信息的類型(
type of information
),每一個
uwsgi packet
前
4byte
為傳輸信息類型的描述,與WSGI協議是兩種東西,據說該協議是
fcgi
協議的10倍快。
八:擴展:uWSGI
uWSGI
旨在為部署分布式集群的網絡應用開發一套完整的解決方案。主要面向web
及其標准服務。由於其可擴展性,能夠被無限制的擴展用來支持更多平台和語言。uWSGI
是一個web
服務器,實現了WSGI
協議,uwsgi
協議,http
協議等。uWSGI
的主要特點是:
- 超快的性能
- 低內存占用
- 多
app
管理 - 詳盡的日志功能(可以用來分析
app
的性能和瓶頸) - 高度可定制(內存大小限制,服務一定次數后重啟等)
uWSGI
服務器自己實現了基於uwsgi
協議的server
部分,我們只需要在uwsgi
的配置文件中指定application
的地址,uWSGI
就能直接和應用框架中的WSGI application
通信。