原文出處: 人世間(@-人世間-) 歡迎分享原創到伯樂頭條python
SimpleHTTPServer模塊提供了建立一個http服務的例子。Python web領域裏卻不多這麼作,而是使用了另一個協議 — WSGI協議。Python的wisiref模塊提供了demo_app,來演示如何使用wsgi協議。web
1編程 2flask 3服務器 4架構 5app 6框架 7socket 8函數 9 10 |
def demo_app(environ,start_response): from StringIO import StringIO stdout = StringIO() print >>stdout, "Hello world!" print >>stdout h = environ.items(); h.sort() for k,v in h: print >>stdout, k,'=', repr(v) start_response("200 OK", [('Content-Type','text/plain')]) return [stdout.getvalue()] |
demo_app便是一個標準的wsgi app。它接受兩個參數,一個包含cgi服務器的環境變量,另一個參數是一個函數,這個函數也接受兩個函數,一個是http狀態,另外是http協議的header信息。最後該app返回一個可迭代對象,這個對象即發送給客戶端的body內容。demo_app有一些對StringIO的操做,這些都是把environ進行格式化輸出。
Python的web框架,都是一個wsgi app。經過本身構造wsgi應用,很容易寫出一個框架的骨架。python定義了wsgi,讓web框架幾乎能夠大一統了。下面就來分析,python是如何實現這個協議的。
python使用WSGIServer和WSGIRequestHandler構建wsgi協議的服務。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class WSGIServer(HTTPServer):
application = None
def server_bind(self): HTTPServer.server_bind(self) self.setup_environ()
def setup_environ(self): # 甚至環境變量 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,重寫了server_bind彷彿,設置了一些專用的環境變量。比較簡單,咱們也知道,Server只是處理socket鏈接相關的邏輯,RequestHandler纔是處理客戶端請求邏輯。
WSGIRequestHandler 也不復雜,只有3個方法,get_environ用來設置並返回環境變量的字典,get_stderr用於獲取標準錯誤輸出。handle則是重寫基類BaseRequestHandler的方法。前文咱們也提到,handle用於不一樣協議處理客戶端的入口。
1 2 3 4 5 6 7 8 9 10 |
def handle(self): self.raw_requestline = self.rfile.readline() if not self.parse_request(): return
handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self handler.run(self.server.get_app()) |
handle方法和BaseHTTPRequestHanler的handle方法所作的相似,解析驗證客戶端的http的request是否合法。不一樣的在於,此時會綁定一個ServerHandler的實例對象,並把緩衝可讀可寫文件句柄,環境變量等傳入該類。同時調用這個對象的run方法。其實,咱們以前定義的app,偏偏就是傳給run方法,經過run方法的包裝,實現wsgi協議的通訊。
ServerHandler 來自wsgiref的handlers模塊,它繼承 BaseHandler類。又一個帶base類。BaseHandler主要用於操做WSGI app。run方法就是在該類定義的。
1 2 3 4 5 6 7 8 9 10 11 |
def run(self, application): try: self.setup_environ() self.result = application(self.environ, self.start_response) self.finish_response() except: try: self.handle_error() except: self.close() raise |
run方法最重要的就是調用自定義的wsgi app,並把在finish_reponse方法中把結果send給客戶端。
1 2 3 4 5 6 7 8 |
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() |
把可迭代對象數據返回。經過write方法把數據寫入緩衝可寫文件,而後發送給客戶端。
finish_response返回http的body是一方面,其中還須要返回http的headers。這個操做分別在wirte方法和finish_content中,它們都調用了send_headers方法,send_headers方法由經過調用send_preamble構造header數據,並最終經過_write 方法寫入到緩衝可寫文件中。完成服務器對客戶端的響應。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def send_preamble(self):
if self.origin_server: if self.client_is_modern(): self._write('HTTP/%s %s\r\n' % (self.http_version,self.status)) if 'Date' not in self.headers: self._write( 'Date: %s\r\n' % format_date_time(time.time()) ) if self.server_software and 'Server' not in self.headers: self._write('Server: %s\r\n' % self.server_software) else: self._write('Status: %s\r\n' % self.status) |
wsgiref模塊還包含了另外幾個子模塊,上面的的內容主要來自 simple_server 和 handler模塊,此外還有headers喝validata模塊,用於包裝headers和作驗證,暫且忽略了。
wsgi是 python web框架中的標準,實現了wsgi協議就能寫出一個web框架。python的世界裏很多知名的框架。接下來將會探究一下werkzeug和flask的源碼以及tornado的源碼。
問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com
QQ羣290551701 彙集不少互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!