欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

python WSGI框架詳解

系統(tǒng) 1879 0

python WSGI框架詳解

?

WSGI

?

幾個關(guān)于WSGI相關(guān)的概念

            
              WSGI:全稱是Web Server Gateway Interface,WSGI不是服務(wù)器,python模塊,框架,API或者任何軟件,只是一種規(guī)范,描述web server如何與web application通信的規(guī)范。server和application的規(guī)范在PEP 3333中有具體描述。要實現(xiàn)WSGI協(xié)議,必須同時實現(xiàn)web server和web application,當(dāng)前運行在WSGI協(xié)議之上的web框架有Torando,Flask,Django

uwsgi:與WSGI一樣是一種通信協(xié)議,是uWSGI服務(wù)器的獨占協(xié)議,用于定義傳輸信息的類型(type of information),每一個uwsgi packet前4byte為傳輸信息類型的描述,與WSGI協(xié)議是兩種東西,據(jù)說該協(xié)議是fcgi協(xié)議的10倍快。

uWSGI:是一個web服務(wù)器,實現(xiàn)了WSGI協(xié)議、uwsgi協(xié)議、http協(xié)議等。
            
          

?

?

PEP 0333 – Python Web Server Gateway Interface?是一種?web server or gateway?和 python?web application or framework?之間簡單通用的接口,符合這種接口的 application 可運行在所有符合該接口的 server 上。通俗的講,WSGI 規(guī)范了一種簡單的接口,解耦了 server 和 application,使得雙邊的開發(fā)者更加專注自身特性的開發(fā)。

?

WSGI 協(xié)議主要包括 server application 兩部分:

  • Web server/gateway: 即 HTTP Server,處理 HTTP 協(xié)議,接受用戶 HTTP 請求和提供并發(fā),調(diào)用 web application 處理業(yè)務(wù)邏輯。通常采用 C/C++ 編寫,代表:apache, nginx 和 IIS。 WSGI server負(fù)責(zé)從客戶端接收請求,將 request轉(zhuǎn)發(fā)給 application,將 application返回的 response返回給客戶端;
  • Python Web application/framework: WSGI application接收由 server轉(zhuǎn)發(fā)的 request,處理請求,并將處理結(jié)果返回給 server。 application中可以包括多個棧式的中間件 ( middlewares ),這些中間件需要同時實現(xiàn) server與 application,因此可以在 WSGI服務(wù)器與 WSGI應(yīng)用之間起調(diào)節(jié)作用:對服務(wù)器來說,中間件扮演應(yīng)用程序,對應(yīng)用程序來說,中間件扮演服務(wù)器。
  •                 WSGI協(xié)議其實是定義了一種server與application解耦的規(guī)范,即可以有多個實現(xiàn)WSGI server的服務(wù)器,也可以有多個實現(xiàn)WSGI application的框架,那么就可以選擇任意的server和application組合實現(xiàn)自己的web應(yīng)用。例如uWSGI和Gunicorn都是實現(xiàn)了WSGI server協(xié)議的服務(wù)器,Django,F(xiàn)lask是實現(xiàn)了WSGI application協(xié)議的web框架,可以根據(jù)項目實際情況搭配使用。
                  

python WSGI框架詳解_第1張圖片

?

?

Application/Framework

Application/framework 端必須定義一個 callable object,callable object 可以是以下三者之一:

  • function, method
  • class
  • instance with a __call__ method

Callable object 必須滿足以下兩個條件:

  • 接受兩個參數(shù):字典(environ),回調(diào)函數(shù)(start_response,返回 HTTP status,headers 給 web server)
  • 返回一個可迭代的值

基于 callable function 的 application/framework 樣例如下:

            
              def
            
            
               application(environ, start_response):
    start_response(
            
            
              '
            
            
              200 OK
            
            
              '
            
            , [(
            
              '
            
            
              Content-Type
            
            
              '
            
            , 
            
              '
            
            
              text/plain
            
            
              '
            
            
              )])
    
            
            
              return
            
             [
            
              '
            
            
              This is a python application!
            
            
              '
            
            ]
          

基于 callable class 的 application/framework 樣例如下:

              
                class
              
              
                 ApplicationClass(object):
    
              
              
                def
              
              
                __init__
              
              
                (self, environ, start_response):
        self.environ 
              
              =
              
                 environ
        self.start_response 
              
              =
              
                 start_response
 
    
              
              
                def
              
              
                __iter__
              
              
                (self):
        self.start_response(
              
              
                '
              
              
                200 OK
              
              
                '
              
              , [(
              
                '
              
              
                Content-type
              
              
                '
              
              , 
              
                '
              
              
                text/plain
              
              
                '
              
              
                )])
        
              
              
                yield
              
              
                "
              
              
                Hello world!n
              
              
                "
              
            

?

?

Server/Gateway?

Server/gateway 端主要專注 HTTP 層面的業(yè)務(wù),重點是接收 HTTP 請求和提供并發(fā)。每當(dāng)收到 HTTP 請求,server/gateway 必須調(diào)用 callable object:

  • 接收 HTTP 請求,但是不關(guān)心 HTTP url, HTTP method 等
  • 為?environ?提供必要的參數(shù),實現(xiàn)一個回調(diào)函數(shù)?start_response,并傳給 callable object
  • 調(diào)用 callable object

我們直接使用支持 WSGI 框架的?wsgiref?庫,編寫一個樣例:

            
              #
            
            
               application/framework side
            
            
              def
            
            
               application(environ, start_response):
    start_response(
            
            
              '
            
            
              200 OK
            
            
              '
            
            , [(
            
              '
            
            
              Content-Type
            
            
              '
            
            , 
            
              '
            
            
              text/plain
            
            
              '
            
            
              )])
    
            
            
              return
            
             [
            
              '
            
            
              This is a python application!
            
            
              '
            
            
              ]
 

            
            
              #
            
            
               server/gateway side
            
            
              if
            
            
              __name__
            
             == 
            
              '
            
            
              __main__
            
            
              '
            
            
              :
    
            
            
              from
            
             wsgiref.simple_server 
            
              import
            
            
               make_server
    server 
            
            = make_server(
            
              '
            
            
              0.0.0.0
            
            
              '
            
            , 8080
            
              , application)
    server.serve_forever()
            
          

?

Middleware: Components that Play Both Sides

            Unix philosophy: do one thing 
            
              and
            
             do it well.
          

python WSGI框架詳解_第2張圖片

Middleware 處于 server/gateway 和 application/framework 之間,對 server/gateway 來說,它相當(dāng)于 application/framework;對 application/framework 來說,它相當(dāng)于 server/gateway。每個 middleware 實現(xiàn)不同的功能,我們通常根據(jù)需求選擇相應(yīng)的 middleware 并組合起來,實現(xiàn)所需的功能。比如,可在 middleware 中實現(xiàn)以下功能:

  • 根據(jù) url 把用戶請求調(diào)度到不同的 application 中。
  • 負(fù)載均衡,轉(zhuǎn)發(fā)用戶請求
  • 預(yù)處理 XSL 等相關(guān)數(shù)據(jù)
  • 限制請求速率,設(shè)置白名單

? python WSGI框架詳解_第3張圖片

WSGI 的 middleware 體現(xiàn)了 unix 的哲學(xué)之一:do one thing and do it well。事實上,在定義 WSGI 框架的時候,設(shè)計者就要求 server/gateway 和 application/framework 雙方盡可能的簡單,同時也要求 middleware 設(shè)計的簡單而專一,PEP 333 提到:

If middleware can be both simple and robust, and WSGI is widely available in servers and frameworks, it allows for the possibility of an entirely new kind of Python web application framework: one consisting of loosely-coupled WSGI middleware components.

本例實現(xiàn)了一個 IPBlacklist 的 middleware:

?
              
                class
              
              
                 IPBlacklistMiddleware(object):
    
              
              
                def
              
              
                __init__
              
              
                (self, app):
        self.app 
              
              =
              
                 app
 
    
              
              
                def
              
              
                __call__
              
              
                (self, environ, start_response):
        ip_addr 
              
              = environ.get(
              
                '
              
              
                HTTP_HOST
              
              
                '
              
              ).split(
              
                '
              
              
                :
              
              
                '
              
              
                )[0]
        
              
              
                if
              
               ip_addr 
              
                not
              
              
                in
              
               (
              
                '
              
              
                127.0.0.1
              
              
                '
              
              
                ):
            
              
              
                return
              
              
                 forbidden(start_response)
 
        
              
              
                return
              
              
                 self.app(environ, start_response)
 

              
              
                def
              
              
                 forbidden(start_response):
    start_response(
              
              
                '
              
              
                403 Forbidden
              
              
                '
              
              , [(
              
                '
              
              
                Content-Type
              
              
                '
              
              , 
              
                '
              
              
                text/plain
              
              
                '
              
              
                )])
    
              
              
                return
              
               [
              
                '
              
              
                Forbidden
              
              
                '
              
              
                ]
 

              
              
                def
              
              
                 application(environ, start_response):
    start_response(
              
              
                '
              
              
                200 OK
              
              
                '
              
              , [(
              
                '
              
              
                Content-Type
              
              
                '
              
              , 
              
                '
              
              
                text/plain
              
              
                '
              
              
                )])
    
              
              
                return
              
               [
              
                '
              
              
                This is a python application!
              
              
                '
              
              
                ]
 

              
              
                if
              
              
                __name__
              
               == 
              
                '
              
              
                __main__
              
              
                '
              
              
                :
    
              
              
                from
              
               wsgiref.simple_server 
              
                import
              
              
                 make_server
    application 
              
              =
              
                 IPBlacklistMiddleware(application)
    server 
              
              = make_server(
              
                '
              
              
                0.0.0.0
              
              
                '
              
              , 8080
              
                , application)
    server.serve_forever()
              
            

測試如下:

            
              #
            
            
               從本機(jī)測試
            
            
$ curl 127.0.0.1:8080/
            
              test
This 
            
            
              is
            
            
               a python application!
 

            
            
              #
            
            
               從其它主機(jī)測測試                                                                                                                                                                                                 
            
            
$ curl 10.10.10.2:8080/
            
              test                                                                                                                                                                                                                                    
Forbidden
            
          

?

?

?

Path Dispatching

?

至此樣例的一個不足之處是對于任意的 url 和 method,程序的返回值均為 ‘This is a python application!’,所以我們需要增加 path dispatch 功能。由于 WSGI 框架下的 server/gateway 不處理 url 和 method,所以 url mapping 需由 application/framework 端完成。注意到參數(shù)?environ,它包含以下變量:

  • REQUEST_METHOD: 即 HTTP method
  • PATH_INFO: 即 HTTP url

所以 application/framework 可以根據(jù) environ 的 REQUEST_METHOD 和 PATH_INFO 實現(xiàn) path dispatch,樣例如下:

?
              
                class
              
              
                 IPBlacklistMiddleware(object):
    
              
              
                def
              
              
                __init__
              
              
                (self, app):
        self.app 
              
              =
              
                 app
 
    
              
              
                def
              
              
                __call__
              
              
                (self, environ, start_response):
        ip_addr 
              
              = environ.get(
              
                '
              
              
                HTTP_HOST
              
              
                '
              
              ).split(
              
                '
              
              
                :
              
              
                '
              
              
                )[0]
        
              
              
                if
              
               ip_addr 
              
                not
              
              
                in
              
               (
              
                '
              
              
                127.0.0.1
              
              
                '
              
              
                ):
            
              
              
                return
              
              
                 forbidden(start_response)
 
        
              
              
                return
              
              
                 self.app(environ, start_response)
 

              
              
                def
              
              
                 dog(start_response):
    start_response(
              
              
                '
              
              
                200 OK
              
              
                '
              
              , [(
              
                '
              
              
                Content-Type
              
              
                '
              
              , 
              
                '
              
              
                text/plain
              
              
                '
              
              
                )])
    
              
              
                return
              
               [
              
                '
              
              
                This is dog!
              
              
                '
              
              
                ]
 

              
              
                def
              
              
                 cat(start_response):
    start_response(
              
              
                '
              
              
                200 OK
              
              
                '
              
              , [(
              
                '
              
              
                Content-Type
              
              
                '
              
              , 
              
                '
              
              
                text/plain
              
              
                '
              
              
                )])
    
              
              
                return
              
               [
              
                '
              
              
                This is cat!
              
              
                '
              
              
                ]
 

              
              
                def
              
              
                 not_found(start_response):
    start_response(
              
              
                '
              
              
                404 NOT FOUND
              
              
                '
              
              , [(
              
                '
              
              
                Content-Type
              
              
                '
              
              , 
              
                '
              
              
                text/plain
              
              
                '
              
              
                )])
    
              
              
                return
              
               [
              
                '
              
              
                Not Found
              
              
                '
              
              
                ]
 

              
              
                def
              
              
                 forbidden(start_response):
    start_response(
              
              
                '
              
              
                403 Forbidden
              
              
                '
              
              , [(
              
                '
              
              
                Content-Type
              
              
                '
              
              , 
              
                '
              
              
                text/plain
              
              
                '
              
              
                )])
    
              
              
                return
              
               [
              
                '
              
              
                Forbidden
              
              
                '
              
              
                ]
 

              
              
                def
              
              
                 application(environ, start_response):
    path 
              
              = environ.get(
              
                '
              
              
                PATH_INFO
              
              
                '
              
              , 
              
                ''
              
              ).lstrip(
              
                '
              
              
                /
              
              
                '
              
              
                )
    mapping 
              
              = {
              
                '
              
              
                dog
              
              
                '
              
              : dog, 
              
                '
              
              
                cat
              
              
                '
              
              
                : cat}
 
    call_back 
              
              = mapping[path] 
              
                if
              
               path 
              
                in
              
               mapping 
              
                else
              
              
                 not_found
    
              
              
                return
              
              
                 call_back(start_response)
 

              
              
                if
              
              
                __name__
              
               == 
              
                '
              
              
                __main__
              
              
                '
              
              
                :
    
              
              
                from
              
               wsgiref.simple_server 
              
                import
              
              
                 make_server
    application 
              
              =
              
                 IPBlacklistMiddleware(application)
    server 
              
              = make_server(
              
                '
              
              
                0.0.0.0
              
              
                '
              
              , 8080
              
                , application)
    server.serve_forever()
              
            

測試如下:

            $ curl 127.0.0.1:8080/
            
              dog
This 
            
            
              is
            
            
               dog!                                                                                                                                                                                                                                                                   
 
$ curl 
            
            127.0.0.1:8080/
            
              cat
This 
            
            
              is
            
            
               cat!                                                                                                                                                                                                                                                                   
 
$ curl 
            
            127.0.0.1:8080/
            
              monkey
Not Found
            
          

?

?

?

Django框架分析WSGI

下面我們以 django 為例,分析一下 wsgi 的整個流程

?

django WSGI application

WSGI application 應(yīng)該實現(xiàn)為一個可調(diào)用 iter 對象,例如函數(shù)、方法、類(包含 **call** 方法)。需要接收兩個參數(shù):一個字典,該字典可以包含了客戶端請求的信息以及其他信息,可以認(rèn)為是請求上下文,一般叫做 environment (編碼中多簡寫為environ、env),一個用于發(fā)送HTTP響應(yīng)狀態(tài)(HTTP status)、響應(yīng)頭(HTTP headers)的回調(diào)函數(shù),也就是 start_response() 。通過回調(diào)函數(shù)將響應(yīng)狀態(tài)和響應(yīng)頭返回給server,同時返回響應(yīng)正文(response body),響應(yīng)正文是可迭代的、并包含了多個字符串。

下面是Django中application的具體實現(xiàn)部分:

            
              class
            
            
               WSGIHandler(base.BaseHandler): 
   initLock 
            
            =
            
               Lock() 
   request_class 
            
            =
            
               WSGIRequest 
   
            
            
              def
            
            
              __call__
            
            
              (self, environ, start_response): 
   
            
            
              #
            
            
               加載中間件 
            
            
              if
            
             self._request_middleware 
            
              is
            
            
               None: 
         with self.initLock: 
             
            
            
              try
            
            : 
            
              #
            
            
               Check that middleware is still uninitialized. 
            
            
              if
            
             self._request_middleware 
            
              is
            
            
               None: 
                    self.load_middleware() 
             
            
            
              except
            
            : 
            
              #
            
            
               Unload whatever middleware we got 
            
            
                    self._request_middleware = None 
            
              raise
            
            
                        
     set_script_prefix(get_script_name(environ)) 
            
            
              #
            
            
               請求處理之前發(fā)送信號   
            
            
     signals.request_started.send(sender=self.
            
              __class__
            
            , environ=
            
              environ) 
     
            
            
              try
            
            
              : 
          request 
            
            =
            
               self.request_class(environ)  
     
            
            
              except
            
            
               UnicodeDecodeError: 
           logger.warning(
            
            
              '
            
            
              Bad Request (UnicodeDecodeError)
            
            
              '
            
            ,exc_info=sys.exc_info(), extra={
            
              '
            
            
              status_code
            
            
              '
            
            : 400
            
              ,}
           response 
            
            =
            
               http.HttpResponseBadRequest() 
     
            
            
              else
            
            
              : 
           response 
            
            =
            
               self.get_response(request) 
     response._handler_class 
            
            = self.
            
              __class__
            
             status = 
            
              '
            
            
              %s %s
            
            
              '
            
             %
            
               (response.status_code, response.reason_phrase) 
     response_headers 
            
            = [(str(k), str(v)) 
            
              for
            
             k, v 
            
              in
            
             response.items()] 
            
              for
            
             c 
            
              in
            
             response.cookies.values(): response_headers.append((str(
            
              '
            
            
              Set-Cookie
            
            
              '
            
            ), str(c.output(header=
            
              ''
            
            
              )))) 
     
            
            
              #
            
            
               server提供的回調(diào)方法,將響應(yīng)的header和status返回給server     
            
            
                   start_response(force_str(status), response_headers) 
     
            
            
              if
            
             getattr(response, 
            
              '
            
            
              file_to_stream
            
            
              '
            
            , None) 
            
              is
            
            
              not
            
             None 
            
              and
            
             environ.get(
            
              '
            
            
              wsgi.file_wrapper
            
            
              '
            
            
              ): 
          response 
            
            = environ[
            
              '
            
            
              wsgi.file_wrapper
            
            
              '
            
            
              ](response.file_to_stream) 
     
            
            
              return
            
             response
          

?

django WSGI Server

負(fù)責(zé)獲取http請求,將請求傳遞給WSGI application,由application處理請求后返回response。以Django內(nèi)建server為例看一下具體實現(xiàn)。通過runserver運行django
項目,在啟動時都會調(diào)用下面的run方法,創(chuàng)建一個WSGIServer的實例,之后再調(diào)用其serve_forever()方法啟動服務(wù)。

?
              
                def
              
               run(addr, port, wsgi_handler, ipv6=False, threading=
              
                False): 
   server_address 
              
              =
              
                 (addr, port) 
   
              
              
                if
              
              
                 threading: 
        httpd_cls 
              
              = type(str(
              
                '
              
              
                WSGIServer
              
              
                '
              
              
                ), (socketserver.ThreadingMixIn, WSGIServer), {}) 
   
              
              
                else
              
              
                : 
        httpd_cls 
              
              = WSGIServer 
              
                #
              
              
                 這里的wsgi_handler就是WSGIApplication 
              
              
   httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=
              
                ipv6) 
    
              
              
                if
              
              
                 threading: 
        httpd.daemon_threads 
              
              =
              
                 True httpd.set_app(wsgi_handler)    
     httpd.serve_forever()
              
            

下面表示W(wǎng)SGI server服務(wù)器處理流程中關(guān)鍵的類和方法。

python WSGI框架詳解_第4張圖片

WSGIServer run()方法會創(chuàng)建 WSGIServer 實例,主要作用是接收客戶端請求,將請求傳遞給 application ,然后將 application 返回的 response 返回給客戶端。

創(chuàng)建實例時會指定 HTTP 請求的 handler:WSGIRequestHandler 類,通過 set_app get_app 方法設(shè)置和獲取 WSGIApplication 實例 wsgi_handler。

處理http請求時,調(diào)用 handler_request 方法,會創(chuàng)建 WSGIRequestHandler, 實例處理http請求。WSGIServer中 get_request 方法通過 socket 接受請求數(shù)據(jù)。

WSGIRequestHandler 由WSGIServer在調(diào)用handle_request時創(chuàng)建實例,傳入 request cient_address 、 WSGIServer 三個參數(shù),__init__方法在實例化同時還會調(diào)用自身的 handle 方法handle方法會創(chuàng)建 ServerHandler 實例,然后調(diào)用其 run 方法處理請求

ServerHandler WSGIRequestHandler在其handle方法中調(diào)用run方法,傳入self.server.get_app()參數(shù),獲取 WSGIApplication ,然后調(diào)用實例(__call__),獲取 response ,其中會傳入 start_response 回調(diào),用來處理返回的 header status 。通過application獲取response以后,通過finish_response返回response

WSGIHandler WSGI協(xié)議中的application,接收兩個參數(shù),environ字典包含了客戶端請求的信息以及其他信息,可以認(rèn)為是請求上下文,start_response用于發(fā)送返回status和header的回調(diào)函數(shù)

雖然上面一個WSGI server涉及到多個類實現(xiàn)以及相互引用,但其實原理還是調(diào)用WSGIHandler,傳入請求參數(shù)以及回調(diào)方法start_response(),并將響應(yīng)返回給客戶端。

?

?

?renfence

http://python.jobbole.com/84372/

http://python.jobbole.com/88653/?utm_source=blog.jobbole.com&utm_medium=relatedPosts

?


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 一级片 在线播放 | 三级在线观看视频 | 欧美成人免费午夜全 | 男人电影天堂 | 网红主播vip福利视频 | 一区二区不卡在线观看 | 免费黄色大全 | 亚洲一区二区三区高清 | 一区二区三区免费看 | 久久极品| 日韩精品福利视频一区二区三区 | 成人午夜视频在线观看 | 亚洲一二三 | 亚洲一区在线观看视频 | 26uuu中文字幕 | 日韩欧美在线播放 | 热久久精品在线 | 成人免费一区二区三区视频网站 | 欧美精品午夜 | 99久久自偷自偷国产精品不卡 | 一区二区国产在线播放 | 欧美成人免费看片一区 | a网站| 欧美日韩精品乱国产 | 日本黄色一级视频 | 狠狠干中文字幕 | 午夜精品久久久久久久久久久久久 | 92手机看片福利永久国产 | 亚洲成人二区 | 欧美精品播放 | 嫩草影院在线看 | 成人欧美日韩一区二区三区 | 国产日韩视频 | 日韩欧美一区二区三区免费观看 | 亚洲中午字幕 | 国产下药迷倒白嫩美女96 | 党涛 | 欧美 日韩 中文字幕 | 国产精品综合色区在线观看 | 国产在线看一区 | 天天操操 |