Django框架学习-请求到响应的过程
1、目录结构
2、Django基本流程
1、用户浏览器发起http请求;
2、请求首先到达 Request Middleware 中间件,它能在views 收到请求前对Request消息内容进行处理,发送响应;
3、urls.py 中的 URLConf 对收到请求的url进行匹配,找到相应的视图处理函数或视图类;
4、在View收到请求之前,View Middlewares 被调用, 可以进行一些预处理;
5、视图函数或视图类被调用;
6、视图函数可能访问模型数据,也可能调用 form 生成表单对象;
7、所有 model-to-DB 的交互都通过 manager 对象来完成;
8、Views 可通以通过context 对象来添加更多传给模板的内容;
9、Views 将 context 上下文数据传给模板进行渲染;
模板层使用 Filter与 Tags 渲染输出;
模板层将渲染结果 传回给 视图层;
视图层发送HTTPResponse 给Response Middlerwares 中间件;
Response middlewares中间件可以向Response 消息添加额外内容,或者用1个新消息替代 wsgi 网关发送 response 给用户浏览器;
3、Django代码层面启动流程
Django的运行是通过WSGI server运行起来的,
core\wsgi.py
- 使用settings.py加载配置项;
- 根据用户配置的INSTALLED_APPS,依次导入,并导入相应的models;
1 import django 2 from django.core.handlers.wsgi import WSGIHandler 3 4 def get_wsgi_application(): 5 """ 6 The public interface to Django's WSGI support. Return a WSGI callable. 7 8 Avoids making django.core.handlers.WSGIHandler a public API, in case the 9 internal WSGI implementation changes or moves in the future. 10 """ 11 django.setup(set_prefix=False) 12 return WSGIHandler()
其次,启动一个WSGIHandler用来接收并处理用户请求,Django的核心处理结构都在load_middleware中完成,会根据middleware建立一个层级的调用处理链;
core\handlers\wsgi.py
1 class WSGIHandler(base.BaseHandler): 2 request_class = WSGIRequest 3 4 def __init__(self, *args, **kwargs): 5 super().__init__(*args, **kwargs) 6 self.load_middleware() 7 8 def __call__(self, environ, start_response): 9 set_script_prefix(get_script_name(environ)) 10 signals.request_started.send(sender=self.__class__, environ=environ) 11 request = self.request_class(environ) 12 response = self.get_response(request) 13 14 response._handler_class = self.__class__ 15 16 status = "%d %s" % (response.status_code, response.reason_phrase) 17 response_headers = [ 18 *response.items(), 19 *(("Set-Cookie", c.output(header="")) for c in response.cookies.values()), 20 ] 21 start_response(status, response_headers) 22 if getattr(response, "file_to_stream", None) is not None and environ.get( 23 "wsgi.file_wrapper" 24 ): 25 # If `wsgi.file_wrapper` is used the WSGI server does not call 26 # .close on the response, but on the file wrapper. Patch it to use 27 # response.close instead which takes care of closing all files. 28 response.file_to_stream.close = response.close 29 response = environ["wsgi.file_wrapper"]( 30 response.file_to_stream, response.block_size 31 ) 32 return response
4、WSGI
WSGI:全称是Web Server Gateway Interface,用于描述web服务器如何与web应用通信的规范。
当客户端发送一次请求后,最先处理请求的实际上是 web 服务器(即经常说的 nginx、Apache 这类),然后web服务器再把请求交给web应用程序(如Django)处理,这中间的中介就是WSGI,它把 web 服务器和 web 框架 (Django) 连接起来。
- WSGI server 负责从客户端接收请求,将request转发给application,将application返回的response返回给客户端;
- WSGI application 接收由server转发的request,处理请求,并将处理结果返回给server。application中可以包括多个栈式的中间件(middlewares),这些中间件需要同时实现server与application;
5、中间件
位于Web服务器端和Web应用之间的,它可以添加额外的功能。比如,对来自用户的数据进行预处理,然后发送给应用;在应用将响应负载返回给用户之前,对结果数据进行一些最终的调整。通俗一点,Django中,中间件能够帮我们准备好request这个对象,然后应用可以直接使用request对象获取到各类数据,也帮我们将response添加头部,状态码等。
settings.py文件
1 MIDDLEWARE = [ 2 'django.middleware.security.SecurityMiddleware', 3 'django.contrib.sessions.middleware.SessionMiddleware', 4 'django.middleware.common.CommonMiddleware', 5 'django.middleware.csrf.CsrfViewMiddleware', # 跨站请求保护机制 6 'django.contrib.auth.middleware.AuthenticationMiddleware', 7 'django.contrib.messages.middleware.MessageMiddleware', 8 'django.middleware.clickjacking.XFrameOptionsMiddleware', 9 ]
当Django接受到一个请求,会初始化一个WSGIHandler,可以在项目下的wsgi.py文件进行跟踪。
Django 的中间件类至少含有以下四个方法中的一个:
process_request、 process_view、process_exception、process_response。
WSGIHandler通过load_middleware将这些方法分别添加到_request_middleware、_view_middleware、 _exception_middleware和_response_middleware 四个列表中。
责任链结构
所有的middleware都继承于MiddlewaMixin这个类,这个类实现了嵌套的层级调用逻辑,即责任链模式。
process_request
AuthenticationMiddleware 只有process_request,返回None或者HTTPResponse对象【返回None时,WSGIHandler会继续加载 process_request 中的方法】,说明它只在 request 这一步处理流入和流出 Django 应用的数据流。这个中间件会首先验证会话中间件是否被使用,然后通过调用 get_user 函数来设置用户。1 def get_user(request): 2 if not hasattr(request, "_cached_user"): 3 request._cached_user = auth.get_user(request) 4 return request._cached_user 5 6 class AuthenticationMiddleware(MiddlewareMixin): 7 def process_request(self, request): 8 if not hasattr(request, "session"): 9 raise ImproperlyConfigured( 10 "The Django authentication middleware requires session " 11 "middleware to be installed. Edit your MIDDLEWARE setting to " 12 "insert " 13 "'django.contrib.sessions.middleware.SessionMiddleware' before " 14 "'django.contrib.auth.middleware.AuthenticationMiddleware'." 15 ) 16 request.user = SimpleLazyObject(lambda: get_user(request))
路由
setting.py中ROOT_URLCONF,它指向urls.py文件,是url和view视图函数之间的映射表。
1 ROOT_URLCONF = 'djangoProject.urls'
process_view
经过url的匹配,会获得视图函数和相关参数,在调用view函数之前,Django会先加载_view_middleware中的各个process_view方法。
举例:CsrfViewMiddleware中的process_view方法功能,当 CSRF cookies 出现时,process_view 方法将会返回 None, 视图函数将会继续的执行。否则请求将会被拒绝,处理流程将会被'短路',会生成一个错误的信息。
1 class CsrfViewMiddleware(MiddlewareMixin): 2 def process_view(self, request, callback, callback_args, callback_kwargs): 3 if getattr(request, "csrf_processing_done", False): 4 return None 5 6 if getattr(callback, "csrf_exempt", False): 7 return None 8 9 if request.method in ("GET", "HEAD", "OPTIONS", "TRACE"): 10 return self._accept(request) 11 12 if getattr(request, "_dont_enforce_csrf_checks", False): 13 return self._accept(request) 14 15 if "HTTP_ORIGIN" in request.META: 16 if not self._origin_verified(request): 17 return self._reject( 18 request, REASON_BAD_ORIGIN % request.META["HTTP_ORIGIN"] 19 ) 20 elif request.is_secure(): 21 try: 22 self._check_referer(request) 23 except RejectRequest as exc: 24 return self._reject(request, exc.reason) 25 26 try: 27 self._check_token(request) 28 except RejectRequest as exc: 29 return self._reject(request, exc.reason) 30 31 return self._accept(request)
进入视图函数
满足三个条件:
(1)必须是可调用的;
(2)必须接受一个HTTPRequest对象作为第一个位置参数;
(3)必须返回一个HTTPResponse对象,或者抛出一个异常;
process_exception
如果视图函数抛出一个异常,WSGIHandler将会循环遍历_exception_middleware 列表,这些方法按照相反的顺序执行,从 settings.py 里面列出来的最后一个中间件到第一个。
如果一个异常被抛出,处理过程将会被短路,其他的 process_exception 将不会被执行。
process_response
此阶段,我们得到了一个 HTTPResponse 对象,这个对象可能是 process_view 返回的,也可能是视图函数返回的。现在我们将循环访问响应中间件。这是中间件调整数据的最后的机会。执行的顺序是从内向外执行。
举例:CsrfViewMiddleware在response中设置csrf cookies;
1 class CsrfViewMiddleware(MiddlewareMixin): 2 def process_response(self, request, response): 3 if request.META.get("CSRF_COOKIE_NEEDS_UPDATE"): 4 self._set_csrf_cookie(request, response) 5 request.META["CSRF_COOKIE_NEEDS_UPDATE"] = False 6 7 return response