摘要:原地址介紹要很好地理解下面的代碼,最好有一定的編程基礎,了解的基本概念和流程。這個文件主要是的處理過程,定義調用處理等等。
原地址:http://cizixs.com/2014/11/09/...1. 介紹
要很好地理解下面的代碼,最好有一定的 socket 編程基礎,了解 socket 的基本概念和流程。
wsgiref 是 PEP 333 定義的 wsgi 規范的范例實現,里面的功能包括了:
操作 wsgi 的環境變量
應答頭部的處理
實現簡單的 HTTP server
簡單的對程序端和服務器端校驗函數
我們先看一個簡單的代碼實例,然后跟著例子去理解源碼:
1.1 app.py# pep333 定義的程序端可調用對象 def hello_world_app(environ, start_response): status = "200 OK" # HTTP Status headers = [("Content-type", "text/plain")] # HTTP Headers start_response(status, headers) # The returned object is going to be printed return ["Hello World"]1.2 server.py
from app import hello_world_app from wsgiref.simple_server import make_server httpd = make_server("", 8000, hello_world_app) print "Serving on port 8000..." # Serve until process is killed httpd.serve_forever()
然后執行 python server.py 啟動 sever,用 curl 發送一個請求 curl -i http://localhost:8000/,會有以下輸出:
HTTP/1.0 200 OK Date: Sat, 08 Nov 2014 09:08:05 GMT Server: WSGIServer/0.1 Python/2.7.3 Content-type: text/plain Content-Length: 12 Hello World
server 的終端會有一條記錄:
Serving on port 8000... localhost - - [08/Nov/2014 09:08:05] "GET / HTTP/1.1" 200 122. 源碼分析
你可以使用 python -c "import wsgiref; help(wsgiref)" 查看 wsgiref 庫的路徑和簡介等信息,wsgiref 文件夾的結構如下:
wsgiref |-- handlers.py # 核心代碼,負責 wsgi 程序的處理 |-- headers.py # 頭部處理的代碼 |-- __init__.py # |-- simple_server.py # 簡單的 wsgi HTTP 服務器實現 |-- util.py # 幫助函數 `-- validate.py # wsgi 格式檢查和校驗
主要的代碼結構如下圖所示:
我們先看一下 make_server 是怎么啟動一個 wsgi 服務器的:
def make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler): server = server_class((host, port), handler_class) server.set_app(app) return server
這個函數做的事情就是:監聽在本地的端口上,接受來自客戶端的請求,通過 WSGIServer 和 WSGIRequestHandler 處理后,把請求交給程序的的可調用對象 app,然后返回 app 的結果給客戶端。
這里有兩個重要的類:WSGIServer 和 WSGIRequestHandler。下面分別看一下它們的代碼和執行的功能。
2.2 WSGIServerclass WSGIServer(HTTPServer): """BaseHTTPServer that implements the Python WSGI protocol""" application = None def server_bind(self): """Override server_bind to store the server name.""" HTTPServer.server_bind(self) self.setup_environ() def setup_environ(self): # Set up base environment env = self.base_environ = {} env["SERVER_NAME"] = self.server_name env["GATEWAY_INTERFACE"] = "CGI/1.1" env["SERVER_PORT"] = str(self.server_port) env["REMOTE_HOST"]="" env["CONTENT_LENGTH"]="" env["SCRIPT_NAME"] = "" def get_app(self): return self.application def set_app(self,application): self.application = application
WSGIServer 在原來的 HTTPServer 上面封裝了一層,在原來的 HTTPServer 的基礎上又額外做了下面的事情:
覆寫原來的 server_bind 函數,添加初始化 environ 變量的動作
添加了處理滿足 wsgi 的 app 函數:set_app 和 get_app
2.3 WSGIRequestHandlerclass WSGIRequestHandler(BaseHTTPRequestHandler): server_version = "WSGIServer/" + __version__ def get_environ(self): env = self.server.base_environ.copy() env["SERVER_PROTOCOL"] = self.request_version env["REQUEST_METHOD"] = self.command if "?" in self.path: path,query = self.path.split("?",1) else: path,query = self.path,"" env["PATH_INFO"] = urllib.unquote(path) env["QUERY_STRING"] = query host = self.address_string() if host != self.client_address[0]: env["REMOTE_HOST"] = host env["REMOTE_ADDR"] = self.client_address[0] if self.headers.typeheader is None: env["CONTENT_TYPE"] = self.headers.type else: env["CONTENT_TYPE"] = self.headers.typeheader length = self.headers.getheader("content-length") if length: env["CONTENT_LENGTH"] = length for h in self.headers.headers: k,v = h.split(":",1) k=k.replace("-","_").upper(); v=v.strip() if k in env: continue # skip content length, type,etc. if "HTTP_"+k in env: env["HTTP_"+k] += ","+v # comma-separate multiple headers else: env["HTTP_"+k] = v return env def get_stderr(self): return sys.stderr def handle(self): """Handle a single HTTP request""" self.raw_requestline = self.rfile.readline() if not self.parse_request(): # An error code has been sent, just exit return handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self # backpointer for logging handler.run(self.server.get_app())
這個類從名字就能知道它的功能——處理客戶端的 HTTP 請求,它也是在原來處理 http 請求的BaseHTTPRequestHandler 類上添加了 wsgi 規范相關的內容。
get_environ: 解析 environ 變量
handle: 處理請求,把封裝的環境變量交給 ServerHandler,然后由 ServerHandler 調用 wsgi app,ServerHandler 類會在下面介紹。
2.4 handler.py這個文件主要是 wsgi server 的處理過程,定義 start_response、調用 wsgi app 、處理 content-length 等等。
2.5 UML類圖 3. 一條 HTTP 請求的過程服務器端啟動服務,等到客戶端輸入 curl -i http://localhost:8000/ 命令,摁下回車鍵,看到終端上的輸出,整個過程中,wsgi 的服務器端發生了什么呢?
服務器程序創建 socket,并監聽在特定的端口,等待客戶端的連接
客戶端發送 http 請求
socket server 讀取請求的數據,交給 http server
http server 根據 http 的規范解析請求,然后把請求交給 WSGIServer
WSGIServer 把客戶端的信息存放在 environ 變量里,然后交給綁定的 handler 處理請求
HTTPHandler 解析請求,把 method、path 等放在 environ,然后 WSGIRequestHandler 把服務器端的信息也放到 environ 里
WSGIRequestHandler 調用綁定的 wsgi ServerHandler,把上面包含了服務器信息,客戶端信息,本次請求信息得 environ 傳遞過去
wsgi ServerHandler 調用注冊的 wsgi app,把 environ 和 start_response 傳遞過去
wsgi app 將reponse header、status、body 回傳給 wsgi handler
然后 handler 逐層傳遞,最后把這些信息通過 socket 發送到客戶端
客戶端的程序接到應答,解析應答,并把結果打印出來。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41435.html
摘要:對背后運行機制感興趣,參考網上資料,結合源碼分析函數運行時的機制,主要整理出函數調用棧。以分析首先官方文檔經典示例現在來分析啟動時發生了什么代碼只列出用到的函數,去掉注釋等函數導入運行函數主要運行調用返回類,然后調用返回類的。 對flask背后運行機制感興趣,參考網上資料,結合源碼分析run函數運行時的機制,主要整理出函數調用棧。以flask0.1分析 首先Flask官方文檔經典示例 ...
摘要:一般來說,這一例行程序用于處理請求的每一部分,例如把路徑作為一系列字典鍵值進行處理。,必須是按照中所規定地鍵值元組列表。行為時回車換行。這個包裝器也可能用模塊指明那些有問題的,但不完全違反的行為。 wsgirf-WSGI功能及參考實現 源碼:Lib/wsgiref Web服務器網關接口(Web Server Gateway Interface, WSGI),是用Python寫的一個服務...
摘要:所以,我按照自己的邏輯總結了一下項目的運行方式和對的基本處理流程。二請求處理流程和其他框架一樣,的處理流程基本類似接受,返回內容。在中,中間件組件用字符串表示指向中間件類名的完整路徑。 之前在網上看過一些介紹Django處理請求的流程和Django源碼結構的文章,覺得了解一下這些內容對開發Django項目還是很有幫助的。所以,我按照自己的邏輯總結了一下Django項目的運行方式和對Re...
摘要:回顧通過前幾篇文章的內容我們已經搭建了基于框架的一個簡單的應用的代碼如下此外我們還為其申請了公網和域名并且部署了的證書現在當我們在瀏覽器地址欄輸入即可訪問我們的網站不過我們的網站目前還存在幾個問題無法訪問每次都需要用戶手動輸入前綴以制定形式 回顧 通過前幾篇文章的內容, 我們已經搭建了基于 Flask 框架的一個簡單的 Web 應用, server.py 的代碼如下 from f...
閱讀 1858·2021-09-22 15:45
閱讀 1640·2019-08-30 15:55
閱讀 1829·2019-08-29 11:16
閱讀 3302·2019-08-26 11:44
閱讀 702·2019-08-23 17:58
閱讀 2698·2019-08-23 12:25
閱讀 1624·2019-08-22 17:15
閱讀 3597·2019-08-22 16:09