前言:
转眼距离上一篇博客已经过了两年,并没有达到最初设想的目标,希望后续能给点力吧。。不多废话了,接下来的几天将会把近期关于Django学习的一系列知识点做个总结。算是留个记录吧。
1. Python Web 开发中的两部分
-
服务器程序 Server
负责接收请求,将客户端发来的请求数据传向后台,并将后台处理后的响应数据回传给客户端。
-
应用程序 Application
这部分就是咱们主要开发的部分,定义了数据处理的逻辑。接收到了服务器程序Server发来的请求后,将数据做处理,并将结果返回。
那应用程序和服务器程序如何沟通呢?
2. WSGI规范
WSGI全称:Web Server Gateway Interface,用来定义服务器程序如何与应用程序交互。
WSGI要求如下:
-
应用程序 Application 必须是一个可调用的对象
-
可以是函数
-
可以是示例,必须实现__call__方法
-
可以是类,为该类创建对象时(调用__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
-
-
可调用的对象需接收两个参数
# 对于方法,没什么好说的 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. 实现一个简单的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
-
先查看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
-
再查看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
-
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完成数据的处理