0. 前言
基本概念:
WSGI:全称是Web Server Gateway Interface
,WSGI
是一种规范,用来描述web server
如何与web application
通信的规范。server
和application
的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI
协议之上的web
框架有 Flask
, Django等
。
WSGI协议主要包括server
和application
两部分:
WSGI server
负责从客户端接收请求,将request
转发给application
,将application
返回的response
返回给客户端;WSGI application
接收由server
转发的request
,处理请求,并将处理结果返回给server
。application
中可以包括多个栈式的中间件(middlewares
),这些中间件需要同时实现server与application,因此可以在WSGI服务器与WSGI应用之间起调节作用:对服务器来说,中间件扮演应用程序(执行程序),对应用程序来说,中间件扮演服务器(WSGI服务器)。WSGI
协议其实是定义了一种server
与application解耦
的规范,即可以有多个实现WSGI server
的服务器,也可以有多个实现WSGI application
的框架,那么就可以选择任意的server
和application
组合实现自己的web
应用。例如uWSGI
和Gunicorn
都是实现了WSGI server
协议的服务器,Django
,Flask
是实现了WSGI application
协议的web
框架,可以根据项目实际情况搭配使用。
注:
一. 程序入口:runserver命令
python manage.py runserver 0.0.0.0:8000
注:runserver文件里的Command类继承了Django的BaseCommand,从而可以通过python manage.py <文件名> 运行该文件,命令运行的函数为handle()
文件地址:
/<我自己的虚拟环境地址>/lib/python3.7/site-packages/django/core/management/commands/runserver.py
注:可以找到文件从这里开始查看源码
二. WSGI 入口:basehttp模块
注:由于inner_run()时调用了basehttp模块的WSGI服务入口函数run(),执行的文件变成了basehttp.py(文件名即模块名)
文件地址:
/<我自己的虚拟环境地址>/lib/python3.7/site-packages/django/core/servers/basehttp.py
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
server_address = (addr, port)
if threading:
httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
else:
httpd_cls = server_cls
# 实例化WSGIServer,即WSGI协议的server部分
# 传入了WSGIRequestHandler参数,会在WSGIServer内部调用来处理请求
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
if threading:
httpd.daemon_threads = True
# 设置WSGI协议的web application部分,即WSGIHandler
httpd.set_app(wsgi_handler)
# 启动监听,该方法继承自父类BaseServer
httpd.serve_forever()
三. WSGI 协议server 部分:
server部分主要分别由以下三个类(皆继承自python自带类)依次处理,将http请求转化为app(如django)可以处理的符合WSGI协议的请求:
1. WSGIServer:
继承关系:
WSGIServer(
simple_server.WSGIServer(
HTTPServer(
socketserver.TCPServer(
BaseServer # serve_forever()方法继承自它
))))
- 它的实例化对象的serve_forever()方法作为程序入口
- 接收http请求
- 实例化WSGIRequestHandler
- 将接收的http请求传给WSGIRequestHandler对象;
2. WSGIRequestHandler:
继承关系:
WSGIRequestHandler(
simple_server.WSGIRequestHandler(
BaseHTTPRequestHandler(
socketserver.StreamRequestHandler(
BaseRequestHandler))))
- 它主要起承上(对接WSGIServer)启下(对接ServerHandler)的连接作用;
- 接收到WSGIServer传来的http请求并处理;
- 它实例化时会自动调用handle()方法,该方法中会实例化ServerHandler;
- 将自己处理好的请求传给ServerHandler对象;
3. ServerHandler:
继承关系:
ServerHandler(
simple_server.ServerHandler(
SimpleHandler(
BaseHandle
)))
- 它主要起WSGI server部分和WSGI application(简称app,如django)部分的对接作用;
- 接收来自WSGIRequestHandler对象处理好的请求,并将其组装成环境变量;
- 实例化WSGI application(WSGIHandler);
- 将配置好的环境变量和回调函数start_response()传递给app对象(无外乎对数据库进行增删改查并返回响应,也就是我们写的那些代码);
- 通过回调函数start_response()设置好对象的部分属性将app的处理结果发送到客户端(状态码和响应头)的说法有待考证,因为回调函数只是返回了write函数对象,并没有去执行。
流程大概如下(盗个图,改了点):
接下来就是server部分的主要流程:
由于继承python自带的BaseServer类方法,所以文件地址:
/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socketserver.py
文件地址:
/<我自己的虚拟环境地址>/lib/python3.7/site-packages/django/core/servers/basehttp.py
由于继承python自带的BaseHandler类方法,所以文件地址:
/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/wsgiref/handlers.py
要是又有人问你怎么知道设置的这个 app是WSGIHandler?我...我......我.........就告诉你吧!!!
还记得我们开天辟地的启动命令
这个handler参数又是通过命令中的get_handler()方法获取的:
真的是老母猪的胸罩一套有一套...这个
这些找到这个WSGIHandler对象(注意是对象,不是类)了吧,就是我们的app。
四. WSGI 协议app 部分:
WSGI application
应该实现为一个可调用对象,例如函数、方法、类(包含`call`方法)。需要接收两个参数:
- 一个字典,该字典可以包含了客户端请求的信息以及其他信息,可以认为是请求上下文,一般叫做
environment
(编码中多简写为environ
、env
)- 一个用于发送HTTP响应状态(
HTTP status
)、响应头(HTTP headers
)的回调函数通过回调函数将响应状态和响应头返回给
server
,同时返回响应正文(response body
),响应正文是可迭代的、并包含了多个字符串。我们知道了实例化ServerHandler对象的run()方法传入的是app对象(WSGIHandler对象),为何给对象传参数就会返回数据呢?
那就顺便巩固下基础(复制过来的):
__call__():Python中,只要在创建类型的时候定义了__call__()方法,这个类型就是可调用的。
Python中的所有东西都是对象,其中包括Int/str/func/class这四类,它们都是对象,都是从一个类创建而来的。元类就是创建这些对象的东西,type就是Python的内建元类。
其中,func是可调用的对象,说明在创建它的类型(父类或它本身)的时候,定义了__call__()方法。
原来是因为WSGIHandler类中定义了<__call__>呀!大彻大悟,看来基础薄弱简直是洪水猛兽啊!
那下面就来看看WSGIHandler中是如何定义<__call__>的:
到这里我们的一个http请求主要的处理流程差不多就已经完了,可以不用往下看了,需要继续了解的如何返回响应的,那就往下瞧:
看嘛!我就说嘛,红框中明显就是设置ServerHandler对象的属性,先把响应需要使用到的对象熟悉先配好,然后返回了self.write......这是个对象呀,也没有变量接收它呀,所以回调到这儿就没啥事儿了,shutdown。
另外通过注释
看看都做了哪些事:1. 把接收到的app响应
上面未实现的两个方法在它的子类SimpleHandler中被实现了。
最后把上面左右的步骤串起来就是:
真相は一つしかない。(推一推眼镜)
<1>执行runserver命令
<2>调用WSGI的入口函数run()
<3>实例化WSGIServer并执行对象的server_forever()方法
<4>调用_handle_request_noblock()方法
<5>实例化WSGIRequestHandler,自动调用handle()方法;
<6>实例化ServerHandler并调用run()
<7>调用app处理请求
<8>解析环境变量并获取程序响应
<9>执行回调
<10>返回响应
终于ojbk了!
有不足或者错误请指正!どうぞ お願いしましょう。