在之前的文章中已经提到每当客户端的请求过来的时候都会将请求交给WSGIHandler类,在WSGIHandler对象的call方法中会调用到WSGIHandler的父类django.core.handlers.base.BaseHandler的get_response方法
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() #加载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) #实例化request类 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 = list(response.items()) 18 for c in response.cookies.values(): 19 response_headers.append(('Set-Cookie', c.output(header=''))) 20 start_response(status, response_headers) 21 if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'): 22 response = environ['wsgi.file_wrapper'](response.file_to_stream) 23 return response
首先在初始化中调用load_middleware方法
def load_middleware(self): """ Populate middleware lists from settings.MIDDLEWARE. Must be called after the environment is fixed (see __call__ in subclasses). """ self._view_middleware = [] self._template_response_middleware = [] self._exception_middleware = [] handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): #反转并循环settings中定义的中间件 middleware = import_string(middleware_path) try: mw_instance = middleware(handler) except MiddlewareNotUsed as exc: if settings.DEBUG: if str(exc): logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc) else: logger.debug('MiddlewareNotUsed: %r', middleware_path) continue if mw_instance is None: raise ImproperlyConfigured( 'Middleware factory %s returned None.' % middleware_path ) if hasattr(mw_instance, 'process_view'): #如果该实例对象包含process_view方法,则将其插入到_view_middleware列表的第一个位置 self._view_middleware.insert(0, mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): 以下同上 self._template_response_middleware.append(mw_instance.process_template_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.append(mw_instance.process_exception) handler = convert_exception_to_response(mw_instance) #最后把该实例对象当做参数传入做判断 # We only assign to this when initialization is complete as it is used # as a flag for initialization being complete. self._middleware_chain = handler #获取响应
def convert_exception_to_response(get_response): """ Wrap the given get_response callable in exception-to-response conversion. All exceptions will be converted. All known 4xx exceptions (Http404, PermissionDenied, MultiPartParserError, SuspiciousOperation) will be converted to the appropriate response, and all other exceptions will be converted to 500 responses. This decorator is automatically applied to all middleware to ensure that no middleware leaks an exception and that the next middleware in the stack can rely on getting a response instead of an exception. """ @wraps(get_response) def inner(request): try: response = get_response(request) except Exception as exc: response = response_for_exception(request, exc) #对于中间件抛出的异常进行拦截,判断响应的是什么错误,已知的抛出4xx,未知的都是500 return response return inner
在get_response方法中
def get_response(self, request): """Return an HttpResponse object for the given HttpRequest.""" # Setup default url resolver for this thread set_urlconf(settings.ROOT_URLCONF) #加载settings中的urlconf response = self._middleware_chain(request) #获取response response._closable_objects.append(request) # If the exception handler returns a TemplateResponse that has not # been rendered, force it to be rendered. if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)): response = response.render() if response.status_code >= 400: log_response( '%s: %s', response.reason_phrase, request.path, response=response, request=request, ) return response
找_get_response方法中
def _get_response(self, request): """ Resolve and call the view, then apply view, exception, and template_response middleware. This method is everything that happens inside the request/response middleware. """ response = None if hasattr(request, 'urlconf'): urlconf = request.urlconf set_urlconf(urlconf) resolver = get_resolver(urlconf) #获取路由解析类 else: resolver = get_resolver() resolver_match = resolver.resolve(request.path_info) #根据用户请求的路由获取相对应的路由结果 callback, callback_args, callback_kwargs = resolver_match #callback是views.py中定义的view函数 request.resolver_match = resolver_match # Apply view middleware for middleware_method in self._view_middleware: response = middleware_method(request, callback, callback_args, callback_kwargs) if response: break if response is None: wrapped_callback = self.make_view_atomic(callback) try: response = wrapped_callback(request, *callback_args, **callback_kwargs) except Exception as e: response = self.process_exception_by_middleware(e, request) # Complain if the view returned None (a common error). if response is None: if isinstance(callback, types.FunctionType): # FBV view_name = callback.__name__ else: # CBV view_name = callback.__class__.__name__ + '.__call__' raise ValueError( "The view %s.%s didn't return an HttpResponse object. It " "returned None instead." % (callback.__module__, view_name) ) # If the response supports deferred rendering, apply template # response middleware and then render the response elif hasattr(response, 'render') and callable(response.render): #如果返回的响应对象有render for middleware_method in self._template_response_middleware: #加载到template中 response = middleware_method(request, response) # Complain if the template response middleware returned None (a common error). if response is None: raise ValueError( "%s.process_template_response didn't return an " "HttpResponse object. It returned None instead." % (middleware_method.__self__.__class__.__name__) ) try: response = response.render() except Exception as e: response = self.process_exception_by_middleware(e, request) return response
在路由解析函数resolve中
def resolve(self, path): path = str(path) # path may be a reverse_lazy object tried = [] match = self.pattern.match(path) #正则匹配路由,匹配成功则进行下一步解析 if match: new_path, args, kwargs = match for pattern in self.url_patterns: try: sub_match = pattern.resolve(new_path) #循环匹配 except Resolver404 as e: #失败就抛出404错误 sub_tried = e.args[0].get('tried') if sub_tried is not None: tried.extend([pattern] + t for t in sub_tried) else: tried.append([pattern]) else: if sub_match: # Merge captured arguments in match with submatch sub_match_dict = {**kwargs, **self.default_kwargs} # Update the sub_match_dict with the kwargs from the sub_match. sub_match_dict.update(sub_match.kwargs) # If there are *any* named groups, ignore all non-named groups. # Otherwise, pass all non-named arguments as positional arguments. sub_match_args = sub_match.args if not sub_match_dict: sub_match_args = args + sub_match.args return ResolverMatch( sub_match.func, #这个是views.py中定义的视图函数 sub_match_args, sub_match_dict, sub_match.url_name, [self.app_name] + sub_match.app_names, [self.namespace] + sub_match.namespaces, ) tried.append([pattern]) raise Resolver404({'tried': tried, 'path': new_path}) raise Resolver404({'path': path})