django请求到响应的整个过程

一、项目初始化的核心模块分析:

通过命令python manage.py runserver ip:port运行整个项目。 
执行完命令之后:
(1)在manage.py文件,添加settings.py的存储路径到系统环境变量中,方便其他django内置的模块获取settings.py文件中的内容;
(2)在manage.py文件,解析命令行参数:
①判断项目的"启动命令"。如果项目的启动命令不是runserver,那么就不会进行启动服务器相关的操作;
②如果是runserver,那么会进行启动服务器相关的操作:
a、此时会解析ip、port,并且设置到变量中。(注意:如果没有传递ip、port的话,那么会使用默认的ip和port,分别是127.0.0.1和8000);
 
b、django内部会调用django.core.servers.basehttp.get_internal_wsgi_application返回一个WSGIHandler类的实例--wsgi_handler对象(也指application对象)。用来进行处理请求和响应数据等操作;
get_internal_wsgi_application源码:
复制代码
def get_internal_wsgi_application():
    from django.conf import settings
    app_path = getattr(settings, 'WSGI_APPLICATION')
    if app_path is None:
        return get_wsgi_application() (返回一个WSGIHandler实例)
    ...
复制代码
WSGIHandler源码:
复制代码
class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest
 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.load_middleware()
 
 
    def __call__(self, environ, start_response):
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__, environ=environ)
        request = self.request_class(environ)
        response = self.get_response(request)
 
        response._handler_class = self.__class__
 
        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        start_response(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
复制代码
 
c、django内部调用django.core.servers.basehttp.run,同时将ip、port、wsgi_handler作为参数,生成一个WSGIServer服务器对象。用来进行接受请求,返回响应等操作。
run源码:
复制代码
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
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
    if threading:
        # ThreadingMixIn.daemon_threads indicates how threads will behave on an
        # abrupt shutdown; like quitting the server by the user or restarting
        # by the auto-reloader. True means the server will not wait for thread
        # termination before it quits. This will make auto-reloader faster
        # and will prevent the need to kill the server manually if a thread
        # isn't terminating correctly.
        httpd.daemon_threads = True
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()
复制代码

 

到这里,项目的初始化完成。通过WSGIServer来监听请求,通过WSGIHandler来处理请求。

二、项目运行时处理request和response的核心过程分析:

1、在项目运行过程中,一旦WSGIServer监听到请求,那么WSGIServer会创建一个WSGIRequestHandler对象。通过调用WSGIRequestHandler对象的handler方法来处理请求。handler方法内部实际上是调用WSGIHandler对象来处理请求。(在调用WSGIHandler对象的时候会传递两个参数:environ(请求的相关信息)、start_response(callback对象))
 
在WSGIHandler对象中的核心处理过程分析: (在其中处理request和response的过程中都会经过中间件)
 
a、处理request:通过django.core.handlers.wsgi.WSGIRequest创建一个WSGIRequest对象,接受environ参数来处理request,然后生成一个request实例;
 
b、获取response:调用get_response方法处理响应信息,并构建一个response;
  在get_response方法中的核心处理过程分析:首先会加载Django项目的ROOT_URLCONF,然后根据url规则找到对应的视图,视图会根据request实例进行一定的业务逻辑处理然后生成一个具体的response。
 
c、调用WSGIServer的start_response方法设置status以及headers;
 
d、返回response到WSGIServer。
 

2、WSGIServer接受到response后,把status、headers、response以及其他相关的信息组合在一起构造成一个响应报文,然后返回给客户端。

三、从请求到响应过程中与中间件的交互:

复制代码
1.请求到达Request Middlewares,
2.URLConf通过urls.py文件和请求的URL找到相应的View
3.View Middlewares被访问,它同样可以对request做一些处理或者直接返回response
4.调用View中的函数
5.View中的方法可以选择性的通过Models访问底层的数据
6.所有的Model-to-DB的交互都是通过manager完成的
7.如果需要,Views可以使用一个特殊的Context
8.Context被传给Template用来生成页面
  a.Template使用Filters和Tags去渲染输出
  b.输出被返回到View
  c.HTTPResponse被发送到Response Middlewares
  d.任何Response Middlewares都可以丰富response或者返回一个完全不同的response
  e.Response返回到浏览器,呈现给用户
复制代码
 
注意:在MIDDLEWARE列表中,request是从上往下访问的,而response、exception等都是从下往上访问的。

中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

Django默认的Middleware

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

每一个中间件都有具体的功能。

自定义中间件

中间件中一共有四个方法:

process_request

process_view

process_exception

process_response

process_request,process_response

当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。

上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin

导入语法:

from django.utils.deprecation import MiddlewareMixin

in views:

def index(request):

    print("view函数...")
    return HttpResponse("OK")

in Mymiddlewares.py:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
 
    def process_response(self,request,response):
        print("Md1返回")
        return response

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        #return HttpResponse("Md2中断")
    def process_response(self,request,response):
        print("Md2返回")
        return response

结果:

Md1请求
Md2请求
view函数...
Md2返回
Md1返回

注意:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者,结果如下:

返回Md2中断的页面,后台打印如下:

 

Md1请求
Md2请求
Md2返回
Md1返回

 

流程图如下:

process_view

process_view(self, request, callback, callback_args, callback_kwargs)

Mymiddlewares.py修改如下

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md1view")

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        return HttpResponse("Md2中断")
    def process_response(self,request,response):
        print("Md2返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md2view")

结果如下:
Md1请求
Md2请求
Md1view
Md2view
view函数...
Md2返回
Md1返回
posted @ 2019-10-20 11:24  nihaoshangjun  阅读(...)  评论(... 编辑 收藏