Python wsgiref 模塊源碼淺析

原文出處: 人世間(@-人世間-)   歡迎分享原創到伯樂頭條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是如何實現這個協議的。

WSGIServer

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

WSGIRequestHandler 也不復雜,只有3個方法,get_environ用來設置並返回環境變量的字典,get_stderr用於獲取標準錯誤輸出。handle則是重寫基類BaseRequestHandler的方法。前文咱們也提到,handle用於不一樣協議處理客戶端的入口。

handler

 

 

 

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協議的通訊。

BaseHandler 和 ServerHandler

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給客戶端。

finish_response

 

 

 

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方法把數據寫入緩衝可寫文件,而後發送給客戶端。

send_preamble

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行業人員進入!

相關文章
相關標籤/搜索