欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python模塊WSGI使用詳解

 更新時(shí)間:2018年02月02日 09:41:38   作者:Jack Big  
這篇文章主要為大家詳細(xì)介紹了Python模塊WSGI使用的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

WSGI(Web Server Gateway Interface):Web服務(wù)網(wǎng)關(guān)接口,是Python中定義的服務(wù)器程序和應(yīng)用程序之間的接口。

Web程序開發(fā)中,一般分為服務(wù)器程序和應(yīng)用程序。服務(wù)器程序負(fù)責(zé)對socket服務(wù)的數(shù)據(jù)進(jìn)行封裝和整理,而應(yīng)用程序則負(fù)責(zé)對Web請求進(jìn)行邏輯處理。

Web應(yīng)用本質(zhì)上也是一個(gè)socket服務(wù)器,用戶的瀏覽器就是一個(gè)socket客戶端。

我們先用socket編程實(shí)現(xiàn)一個(gè)簡單的Web服務(wù)器:

import socket 
 
def handle_request(client): 
  buf = client.recv(1024) 
  print(buf) 
  msg = "HTTP/1.1 200 OK\r\n\r\n" #HTTP頭信息 
  client.send(('%s' % msg).encode()) 
  msg = "Hello, World!" 
  client.send(('%s' % msg).encode()) 
 
def main(): 
  ip_port = ("localhost", 8000) 
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
  sock.bind(ip_port) 
  sock.listen(5) 
 
  while True: 
    conn, addr = sock.accept() 
    handle_request(conn) 
    conn.close() 
 
if __name__ == "__main__": 
  main() 

上述代碼中,main()函數(shù)就是服務(wù)器函數(shù),handle_request()就是應(yīng)用程序。
下面我們再用python的wsgiref模塊來實(shí)現(xiàn)跟上述代碼一樣的Web服務(wù)器:

from wsgiref.simple_server import make_server 
 
def handle_request(env, res): 
  res("200 OK",[("Content-Type","text/html")]) 
  body = "<h1>Hello World!</h1>" 
  return [body.encode("utf-8")] 
 
if __name__ == "__main__": 
  httpd = make_server("",8000,handle_request) 
  print("Serving http on port 80000") 
  httpd.serve_forever() 

上面兩份代碼實(shí)現(xiàn)的效果是一樣的,調(diào)用wsgiref模塊則明顯節(jié)省了代碼量,是整個(gè)程序更加簡潔。
wsgiref模塊封裝了socket服務(wù)端的代碼,只留下一個(gè)調(diào)用的接口,省去了程序員的麻煩,程序員可以將精力放在Web請求的邏輯處理中。

以上述的代碼為例,詳細(xì)看一下wsgiref模塊的源碼中一些關(guān)鍵的地方:

if __name__ == "__main__": 
  httpd = make_server("",8000,handle_request) 
  print("Serving http on port 80000") 
  httpd.serve_forever() 

1、整個(gè)程序的入口為make_server()函數(shù):

def make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler): 
  """Create a new WSGI server listening on `host` and `port` for `app`""" 
  server = server_class((host, port), handler_class) #默認(rèn)創(chuàng)建一個(gè)WSGIServer類 
  server.set_app(app) #將應(yīng)用程序,即邏輯處理函數(shù)傳給類 
  return server 

2、make_server()函數(shù)默認(rèn)生成一個(gè)WSGIServer類:

class WSGIServer(HTTPServer):
class HTTPServer(socketserver.TCPServer):
class TCPServer(BaseServer):

WSGIServer,HTTPServer兩個(gè)類沒有初始化函數(shù),調(diào)用父類的初始化函數(shù),TCPServer類的__init__()函數(shù)拓展了BaseServer

類的__init__()函數(shù):

#BaseServer類的__init__()函數(shù): 
def __init__(self, server_address, RequestHandlerClass): 
  """Constructor. May be extended, do not override.""" 
  self.server_address = server_address 
  self.RequestHandlerClass = RequestHandlerClass 
  self.__is_shut_down = threading.Event() 
  self.__shutdown_request = False 
#TCPServer類的__init__()函數(shù): 
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): 
  """Constructor. May be extended, do not override.""" 
  BaseServer.__init__(self, server_address, RequestHandlerClass) 
  self.socket = socket.socket(self.address_family,self.socket_type) 
    if bind_and_activate: 
      try: 
        self.server_bind() 
        self.server_activate() 
      except: 
        self.server_close() 
        raise 

TCPServer類的初始化函數(shù)還調(diào)用了server_bind(self),server_bind(self)兩個(gè)函數(shù):

def server_bind(self): 
  """Called by constructor to bind the socket.May be overridden.""" 
  if self.allow_reuse_address: 
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
  self.socket.bind(self.server_address) 
  self.server_address = self.socket.getsockname()  
def self.server_activate(self): 
  """Called by constructor to activate the server.May be overridden.""" 
  self.socket.listen(self.request_queue_size)  

可以看到server.bind()函數(shù)調(diào)用了socket.bind()函數(shù),而server_activate()調(diào)用了socket.listen()函數(shù):

3、server.set_app(app),此處傳入Web請求的處理邏輯:

def set_app(self,application): 
  self.application = application 

4、httpd.serve_forever()函數(shù)調(diào)用BaseServer類的_handle_request_noblock()函數(shù)處理多路請求:

def _handle_request_noblock(self): 
  try: 
    request, client_address = self.get_request() #get_request()調(diào)用了socket.accept()函數(shù) 
  except OSError: 
    return 
  if self.verify_request(request, client_address): 
    try: 
      self.process_request(request, client_address) 
    except: 
      self.handle_error(request, client_address) 
      self.shutdown_request(request) 
  else: 
    self.shutdown_request(request) 
def process_request(self, request, client_address): 
  self.finish_request(request, client_address)   
  self.shutdown_request(request)#shutdown_request()調(diào)用socket.close()關(guān)閉socket 
     
def finish_request(self, request, client_address): 
  """Finish one request by instantiating RequestHandlerClass.""" 
  self.RequestHandlerClass(request, client_address, self) 

5、process_request()函數(shù)調(diào)用了finish_request()函數(shù),簡介調(diào)用了make_server函數(shù)的默認(rèn)參數(shù)WSGIRequestHandler類:

class WSGIRequestHandler(BaseHTTPRequestHandler):
class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
class StreamRequestHandler(BaseRequestHandler):

#調(diào)用BaseRequestHandler類的初始化函數(shù): 
def __init__(self, request, client_address, server): 
  self.request = request 
  self.client_address = client_address 
  self.server = server 
  self.setup() 
  try: 
    self.handle() 
  finally: 
    self.finish() 

6、初始化函數(shù)調(diào)用之后調(diào)用WSGIRequestHandler類的handle()函數(shù)獲取server的邏輯處理函數(shù):

def handle(self): 
  """Handle a single HTTP request""" 
  try: 
    handler = ServerHandler(self.rfile, stdout, self.get_stderr(), self.get_environ()) 
    handler.request_handler = self   # backpointer for logging 
    handler.run(self.server.get_app()) #此處調(diào)用server的邏輯處理函數(shù) 
  finally: 
    stdout.detach() 

7、BaseHandler類的handler.run()函數(shù)執(zhí)行邏輯處理:

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  # ...and let the actual server figure it out. 

self.environ:一個(gè)包含所有HTTP請求信息的dict對象
self.start_response:一個(gè)發(fā)送HTTP響應(yīng)的函數(shù)。

在application函數(shù)中,調(diào)用:

res("200 OK",[("Content-Type","text/html")]) 

這樣就發(fā)送了HTTP響應(yīng)的頭信息

8、BaseHandler類的setup_environ()函數(shù)獲取HTTP請求的頭信息:

def setup_environ(self): 
  """Set up the environment for one request""" 
  env = self.environ = self.os_environ.copy() 
   
os_environ= read_environ() 
 
read_environ()函數(shù): 
 
def read_environ(): 
  """Read environment, fixing HTTP variables""" 
  enc = sys.getfilesystemencoding() 
  esc = 'surrogateescape' 
  try: 
    ''.encode('utf-8', esc) 
  except LookupError: 
    esc = 'replace' 
  environ = {} 
 
  # Take the basic environment from native-unicode os.environ. Attempt to 
  # fix up the variables that come from the HTTP request to compensate for 
  # the bytes->unicode decoding step that will already have taken place. 
  for k, v in os.environ.items(): 
    if _needs_transcode(k): 
 
      # On win32, the os.environ is natively Unicode. Different servers 
      # decode the request bytes using different encodings. 
      if sys.platform == 'win32': 
        software = os.environ.get('SERVER_SOFTWARE', '').lower() 
 
        # On IIS, the HTTP request will be decoded as UTF-8 as long 
        # as the input is a valid UTF-8 sequence. Otherwise it is 
        # decoded using the system code page (mbcs), with no way to 
        # detect this has happened. Because UTF-8 is the more likely 
        # encoding, and mbcs is inherently unreliable (an mbcs string 
        # that happens to be valid UTF-8 will not be decoded as mbcs) 
        # always recreate the original bytes as UTF-8. 
        if software.startswith('microsoft-iis/'): 
          v = v.encode('utf-8').decode('iso-8859-1') 
 
        # Apache mod_cgi writes bytes-as-unicode (as if ISO-8859-1) direct 
        # to the Unicode environ. No modification needed. 
        elif software.startswith('apache/'): 
          pass 
 
        # Python 3's http.server.CGIHTTPRequestHandler decodes 
        # using the urllib.unquote default of UTF-8, amongst other 
        # issues. 
        elif ( 
          software.startswith('simplehttp/') 
          and 'python/3' in software 
        ): 
          v = v.encode('utf-8').decode('iso-8859-1') 
 
        # For other servers, guess that they have written bytes to 
        # the environ using stdio byte-oriented interfaces, ending up 
        # with the system code page. 
        else: 
          v = v.encode(enc, 'replace').decode('iso-8859-1') 
 
      # Recover bytes from unicode environ, using surrogate escapes 
      # where available (Python 3.1+). 
      else: 
        v = v.encode(enc, esc).decode('iso-8859-1') 
 
    environ[k] = v 
  return environ 

9、BaseHandler類的start_response()函數(shù):

def start_response(self, status, headers,exc_info=None): 
  """'start_response()' callable as specified by PEP 3333""" 
  if exc_info: 
    try: 
      if self.headers_sent: 
        # Re-raise original exception if headers sent 
        raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) 
    finally: 
      exc_info = None    # avoid dangling circular ref 
  elif self.headers is not None: 
    raise AssertionError("Headers already set!") 
 
  self.status = status 
  self.headers = self.headers_class(headers) 
  status = self._convert_string_type(status, "Status") 
  assert len(status)>=4,"Status must be at least 4 characters" 
  assert status[:3].isdigit(), "Status message must begin w/3-digit code" 
  assert status[3]==" ", "Status message must have a space after code" 
 
  if __debug__: 
    for name, val in headers: 
      name = self._convert_string_type(name, "Header name") 
      val = self._convert_string_type(val, "Header value")   
  return self.write 

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • python實(shí)現(xiàn)將excel文件轉(zhuǎn)化成CSV格式

    python實(shí)現(xiàn)將excel文件轉(zhuǎn)化成CSV格式

    下面小編就為大家分享一篇python實(shí)現(xiàn)將excel文件轉(zhuǎn)化成CSV格式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • python ipset管理 增刪白名單的方法

    python ipset管理 增刪白名單的方法

    今天小編就為大家分享一篇python ipset管理 增刪白名單的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • python3中的md5加密實(shí)例

    python3中的md5加密實(shí)例

    今天小編就為大家分享一篇python3中的md5加密實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Python實(shí)現(xiàn)模擬分割大文件及多線程處理的方法

    Python實(shí)現(xiàn)模擬分割大文件及多線程處理的方法

    這篇文章主要介紹了Python實(shí)現(xiàn)模擬分割大文件及多線程處理的方法,涉及Python文件讀取、分割及多線程相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • Python字符串的索引與切片

    Python字符串的索引與切片

    這篇文章主要介紹了Python字符串的索引與切片,文章圍繞主題展開詳細(xì)的相關(guān)資料,需要的小伙伴可以參考一下
    2022-04-04
  • Python中re模塊的元字符使用小結(jié)

    Python中re模塊的元字符使用小結(jié)

    元字符是正則表達(dá)式中具有特殊意義的專用字符,本文主要介紹了Python中re模塊的元字符使用小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • 詳解用Python調(diào)用百度地圖正/逆地理編碼API

    詳解用Python調(diào)用百度地圖正/逆地理編碼API

    這篇文章主要介紹了詳解用Python調(diào)用百度地圖正/逆地理編碼API,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Python Numpy 高效的運(yùn)算工具詳解

    Python Numpy 高效的運(yùn)算工具詳解

    這篇文章主要介紹了Python numpy矩陣處理運(yùn)算工具用法匯總,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-10-10
  • 橫向?qū)Ρ确治鯬ython解析XML的四種方式

    橫向?qū)Ρ确治鯬ython解析XML的四種方式

    這篇文章主要以橫向?qū)Ρ确绞椒治鯬ython解析XML的四種方式,感興趣的小伙伴們可以參考一下
    2016-03-03
  • python遞歸計(jì)算N!的方法

    python遞歸計(jì)算N!的方法

    這篇文章主要介紹了python遞歸計(jì)算N!的方法,涉及Python遞歸計(jì)算階乘的技巧,非常簡單實(shí)用,需要的朋友可以參考下
    2015-05-05

最新評論