Django请求的生命周期(包括中间件的process_request 、 process_view 、process_response的执行顺序)的源码分析

分析一个请求的生命周期以及在该周期中 Django 框架的各个中间件的 process_request 、 process_view 、process_response 是怎么参与的

首先浏览器发起请求:当请求到 Django 框架的时候,
根据中间件的注册顺序依次执行:

  1. 根据注册顺序执行所有中间件的 process_request:
    [process_request, process_request, process_request, process_request, process_request]

  2. 根据注册顺序执行所有中间件的 process_view:
    [process_view, process_view, process_view, process_view, process_view]

  3. 执行根据 URL 找到的视图函数

  4. 根据注册顺序执行所有中间件的 process_response:
    [process_response, process_response, process_response, process_response, process_response]

源码分析:

D:\WorkSpace\HelloNG\src\testcode\djangoTest\robappdj\robappdj\wsgi.py:
	application = get_wsgi_application()  ----------------------------------------------step 1
	
C:\Python27\Lib\site-packages\django\core\wsgi.py
	def get_wsgi_application():
		"""
		The public interface to Django's WSGI support. Should return a WSGI
		callable.

		Allows us to avoid making django.core.handlers.WSGIHandler public API, in
		case the internal WSGI implementation changes or moves in the future.

		"""
		django.setup()
		return WSGIHandler() -----------------------------------------------------------step 2
	
	
C:\Python27\Lib\site-packages\django\core\handlers\wsgi.py:		
	class WSGIHandler(base.BaseHandler):
		initLock = Lock()
		request_class = WSGIRequest

	def __call__(self, environ, start_response):
		# Set up middleware if needed. We couldn't do this earlier, because
		# settings weren't available.
		if self._request_middleware is None:
			with self.initLock:
				try:
					# Check that middleware is still uninitialized.
					if self._request_middleware is None:
						self.load_middleware()
				except:
					# Unload whatever middleware we got
					self._request_middleware = None
					raise

		set_script_prefix(get_script_name(environ))
		signals.request_started.send(sender=self.__class__, environ=environ)
		try:
			request = self.request_class(environ)
		except UnicodeDecodeError:
			logger.warning('Bad Request (UnicodeDecodeError)',
				exc_info=sys.exc_info(),
				extra={
					'status_code': 400,
				}
			)
			response = http.HttpResponseBadRequest()
		else:
			response = self.get_response(request)  -------------------------------step 3
			
class BaseHandler(object):
	# Changes that are always applied to a response (in this order).
	response_fixes = [
		http.fix_location_header,
		http.conditional_content_removal,
	]

	def __init__(self):
		self._request_middleware = None
		self._view_middleware = None
		self._template_response_middleware = None
		self._response_middleware = None
		self._exception_middleware = None			
				
	def get_response(self, request):
		"Returns an HttpResponse object for the given HttpRequest"

		# Setup default url resolver for this thread, this code is outside
		# the try/except so we don't get a spurious "unbound local
		# variable" exception in the event an exception is raised before
		# resolver is set
		urlconf = settings.ROOT_URLCONF
		urlresolvers.set_urlconf(urlconf)
		resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
		try:
			response = None
			# Apply request middleware
			for middleware_method in self._request_middleware:   ------------------------step4_1: process_request
				response = middleware_method(request)
				if response:
					break

			if response is None:
				if hasattr(request, 'urlconf'):
					# Reset url resolver with a custom urlconf.
					urlconf = request.urlconf
					urlresolvers.set_urlconf(urlconf)
					resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)

				resolver_match = resolver.resolve(request.path_info)
				callback, callback_args, callback_kwargs = resolver_match
				request.resolver_match = resolver_match

				# Apply view middleware
				for middleware_method in self._view_middleware:      ------------------------step4_2: process_view
					response = middleware_method(request, callback, callback_args, callback_kwargs)
					if response:
						break

			if response is None:
				wrapped_callback = self.make_view_atomic(callback)    -----------------------step4_3: 根据 URL 找到的视图函数
				try:
					response = wrapped_callback(request, *callback_args, **callback_kwargs)
				except Exception as e:
					# If the view raised an exception, run it through exception
					# middleware, and if the exception middleware returns a
					# response, use that. Otherwise, reraise the exception.
					for middleware_method in self._exception_middleware:
						response = middleware_method(request, e)
						if response:
							break
					if response is None:
						raise

			# 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
			if hasattr(response, 'render') and callable(response.render):
				for middleware_method in self._template_response_middleware:
					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__))
				response = response.render()

		except http.Http404 as e:
			logger.warning('Not Found: %s', request.path,
						extra={
							'status_code': 404,
							'request': request
						})
			if settings.DEBUG:
				response = debug.technical_404_response(request, e)
			else:
				response = self.get_exception_response(request, resolver, 404)

		except PermissionDenied:
			logger.warning(
				'Forbidden (Permission denied): %s', request.path,
				extra={
					'status_code': 403,
					'request': request
				})
			response = self.get_exception_response(request, resolver, 403)

		except MultiPartParserError:
			logger.warning(
				'Bad request (Unable to parse request body): %s', request.path,
				extra={
					'status_code': 400,
					'request': request
				})
			response = self.get_exception_response(request, resolver, 400)

		except SuspiciousOperation as e:
			# The request logger receives events for any problematic request
			# The security logger receives events for all SuspiciousOperations
			security_logger = logging.getLogger('django.security.%s' %
							e.__class__.__name__)
			security_logger.error(
				force_text(e),
				extra={
					'status_code': 400,
					'request': request
				})
			if settings.DEBUG:
				return debug.technical_500_response(request, *sys.exc_info(), status_code=400)

			response = self.get_exception_response(request, resolver, 400)

		except SystemExit:
			# Allow sys.exit() to actually exit. See tickets #1023 and #4701
			raise

		except:  # Handle everything else.
			# Get the exception info now, in case another exception is thrown later.
			signals.got_request_exception.send(sender=self.__class__, request=request)
			response = self.handle_uncaught_exception(request, resolver, sys.exc_info())

		try:
			# Apply response middleware, regardless of the response
			for middleware_method in self._response_middleware:      ------------------------step4_4: process_response
				response = middleware_method(request, response)
				# Complain if the response middleware returned None (a common error).
				if response is None:
					raise ValueError(
						"%s.process_response didn't return an "
						"HttpResponse object. It returned None instead."
						% (middleware_method.__self__.__class__.__name__))
			response = self.apply_response_fixes(request, response)
		except:  # Any exception should be gathered and handled
			signals.got_request_exception.send(sender=self.__class__, request=request)
			response = self.handle_uncaught_exception(request, resolver, sys.exc_info())

		response._closable_objects.append(request)

		return response
发布了44 篇原创文章 · 获赞 0 · 访问量 3933

猜你喜欢

转载自blog.csdn.net/cpxsxn/article/details/104212667