Django学习笔记(一)WSGI

本文介绍了Python Web开发中的服务器程序和应用程序两大部分,详细讲解了WSGI规范,包括应用程序必须是可调用对象,接收特定参数并返回可迭代值的要求。接着,通过实例展示了如何实现一个简单的WSGIServer,并探讨了中间件的作用。最后,深入到WSGIServer的内部工作原理,解析了请求处理流程,从WSGIServer到WSGIRequestHandler,直至调用应用程序完成数据处理。

前言:

转眼距离上一篇博客已经过了两年,并没有达到最初设想的目标,希望后续能给点力吧。。不多废话了,接下来的几天将会把近期关于Django学习的一系列知识点做个总结。算是留个记录吧。

1. Python Web 开发中的两部分

  1. 服务器程序 Server

    负责接收请求,将客户端发来的请求数据传向后台,并将后台处理后的响应数据回传给客户端。

  2. 应用程序 Application

    这部分就是咱们主要开发的部分,定义了数据处理的逻辑。接收到了服务器程序Server发来的请求后,将数据做处理,并将结果返回。

那应用程序和服务器程序如何沟通呢?

2. WSGI规范

WSGI全称:Web Server Gateway Interface,用来定义服务器程序如何与应用程序交互。

WSGI要求如下:

  1. 应用程序 Application 必须是一个可调用的对象

    1. 可以是函数

    2. 可以是示例,必须实现__call__方法

    3. 可以是类,为该类创建对象时(调用__init__方法)相当于调用这个类

      class Person():
          def __init__(self,name):
              self.name = name
              print('My name is {}'.format(name))
      
          def __call__(self):
              print('My name is {}'.format(self.name))
      
      if __name__ == "__main__":
          p = Person('Xiao Ming')
          p()
          # 上面两行都会输出My name is Xiao Ming
      
  2. 可调用的对象需接收两个参数

    # 对于方法,没什么好说的
    def xxxFunc(environ, start_response):
    	xxx
    
    # 对于类 需要在__init__中定义
    class Person():
        def __init__(self,environ, start_response):
        	xxx
    	# 对于实例对象,需要在__call__中定义
        def __call__(self,environ, start_response):
            xxx
    
  3. 可调用的对象需要返回一个可迭代的值

3. 实现一个简单的WSGI Server

from wsgiref.simple_server import make_server

def application(env, res):
    print(env)
    res("200 OK", [("Content-Type", "text/html")])
    body = "<h1>Hello World!, this is the wsgi response!</h1>"
    return [body.encode("utf-8")]

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

4. 中间件middleware

在服务器程序 Server与应用程序 Application之间,还有一些承上启下的功能。例如服务端收到一个请求后,需要根据不同的地址选择不同的应用程序做处理,相当于请求的分发。此时就需要中间件来完成此业务。

5. 向下挖掘

进入主函数的make_server(“127.0.0.1”, 8000, application)方法,可以发现如下内容

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)
    server.set_app(app)
    return server

可知生成一个Server的三元素:

  • (host, port)主机名与端口号
  • handler_class 处理请求的handler类
  • app对应开局的application
  1. 先查看WSGIServer

    向下查看会发现WSGIServer继承HTTPServer,HTTPServer继承TCPServer,TCPServer又继承BaseServer

      # 1.BaseServer初始化方法
      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
            
      # 2.BaseServer子类TCPServer的初始化方法
      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
    
    

    因此WSGIServer的初始化过程可以理解为对Socket进行了初始化

    # 3.在BaseServer中有_handle_request_noblock()方法
    def _handle_request_noblock(self):
        """Handle one request, without blocking.
    
        I assume that selector.select() has returned that the socket is
        readable before this function was called, so there should be no risk of
        blocking in get_request().
        """
        try:
            request, client_address = self.get_request()
        except OSError:
            return
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
                self.shutdown_request(request)
            except:
                self.shutdown_request(request)
                raise
        else:
            self.shutdown_request(request)
    
    # 4.进入process_request()
    def process_request(self, request, client_address):
        """Call finish_request.
    
        Overridden by ForkingMixIn and ThreadingMixIn.
    
        """
        self.finish_request(request, client_address)
        self.shutdown_request(request)
    
    # 5.进入finish_request()
    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)
    

    这里的RequestHandlerClass就是BaseServer初始化时声明的RequestHandlerClass,也就是server_class((host, port), handler_class)中的handler_class

  2. 再查看WSGIRequestHandler

    向下查看会发现WSGIRequestHandler继承BaseHTTPRequestHandler,BaseHTTPRequestHandler又继承StreamRequestHandler,又继承BaseRequestHandler

    class BaseRequestHandler:
    
        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()
    
        def setup(self):
            pass
    
        def handle(self):
            pass
    
        def finish(self):
            pass
    

    发现BaseRequestHandler在初始化后直接调用了self.handle()方法,那么这个方法具体做了什么?

    class WSGIRequestHandler(BaseHTTPRequestHandler)
    	 def handle(self):
       """Handle a single HTTP request"""
    
       self.raw_requestline = self.rfile.readline(65537)
       if len(self.raw_requestline) > 65536:
           self.requestline = ''
           self.request_version = ''
           self.command = ''
           self.send_error(414)
           return
    
       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(),
           multithread=False,
       )
       handler.request_handler = self      # backpointer for logging
       handler.run(self.server.get_app())
    

    可以发现在这里,最终run了传入的app

  3. run是什么?

    进入ServerHandler 发现 ServerHandler继承SimpleHandler,SimpleHandler继承BaseHandler

    class BaseHandler:
      def run(self, application):
        """Invoke the application"""
        # Note to self: don't move the close()!  Asynchronous servers shouldn't
        # call close() from finish_response(), so if you close() anywhere but
        # the double-error branch here, you'll break asynchronous servers by
        # prematurely closing.  Async servers must return from 'run()' without
        # closing if there might still be output to iterate over.
        try:
            self.setup_environ()
            self.result = application(self.environ, self.start_response)
            self.finish_response()
        except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
            # We expect the client to close the connection abruptly from time
            # to time.
            return
        except:
            try:
                self.handle_error()
            except:
                # If we get an error handling an error, just give up already!
                self.close()
                raise   # ...and let the actual server figure it out.
    

至此,形成闭环,可以这么说

  • WSGIServer 底层实现了socket的初始化
  • WSGIRequestHandler 负责处理HTTP请求,并最终调用app完成数据的处理
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值