[Django 0-1] Core.Handlers 模块

2024-03-16 05:04
文章标签 模块 django core handlers

本文主要是介绍[Django 0-1] Core.Handlers 模块,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Core.Handlers 模块

这个模块封装了 wsgi,asgi 两个类,分别用于处理外部的请求信息,asgi 提供异步处理能力。

Handler 模块将请求Request封装包裹了Middleware中间件,并将处理结果返回为Response响应对象。

BaseHandler

重要函数

  • load_middleware: 先把 handler 函数套一层 exception handler, 在倒序包裹中间件。支持process_view,process_exception,process_template_response
def load_middleware(self, is_async=False):"""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 = []get_response = self._get_response_async if is_async else self._get_responsehandler = convert_exception_to_response(get_response)handler_is_async = is_asyncfor middleware_path in reversed(settings.MIDDLEWARE):middleware = import_string(middleware_path)middleware_can_sync = getattr(middleware, "sync_capable", True)middleware_can_async = getattr(middleware, "async_capable", False)if not middleware_can_sync and not middleware_can_async:raise RuntimeError("Middleware %s must have at least one of ""sync_capable/async_capable set to True." % middleware_path)elif not handler_is_async and middleware_can_sync:middleware_is_async = Falseelse:middleware_is_async = middleware_can_asynctry:# Adapt handler, if needed.# 异步兼容步骤adapted_handler = self.adapt_method_mode(middleware_is_async,handler,handler_is_async,debug=settings.DEBUG,name="middleware %s" % middleware_path,)mw_instance = middleware(adapted_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)continueelse:handler = adapted_handlerif mw_instance is None:# 避免你的middleware有问题raise ImproperlyConfigured("Middleware factory %s returned None." % middleware_path)if hasattr(mw_instance, "process_view"):self._view_middleware.insert(0,self.adapt_method_mode(is_async, mw_instance.process_view),)if hasattr(mw_instance, "process_template_response"):self._template_response_middleware.append(self.adapt_method_mode(is_async, mw_instance.process_template_response),)if hasattr(mw_instance, "process_exception"):# The exception-handling stack is still always synchronous for# now, so adapt that way.self._exception_middleware.append(self.adapt_method_mode(False, mw_instance.process_exception),)handler = convert_exception_to_response(mw_instance)handler_is_async = middleware_is_async# Adapt the top of the stack, if needed.handler = self.adapt_method_mode(is_async, handler, handler_is_async)# We only assign to this when initialization is complete as it is used# as a flag for initialization being complete.self._middleware_chain = handler
  • resolve_request: 通过get_resolver得到路由解析器,并将处理结果赋值给request.resolver_match

get_resolver使用了lru_cache装饰器来减少重复计算。

def resolve_request(self, request):"""Retrieve/set the urlconf for the request. Return the view resolved,with its args and kwargs."""# Work out the resolver.if hasattr(request, "urlconf"):urlconf = request.urlconfset_urlconf(urlconf)resolver = get_resolver(urlconf)else:resolver = get_resolver()# Resolve the view, and assign the match object back to the request.resolver_match = resolver.resolve(request.path_info)request.resolver_match = resolver_matchreturn resolver_match
  • _get_response: 调用resolve_request得到处理结果,并将结果赋值给response

看这段源码,你可以知道一个请求是如何被返回的,

  1. 首先得到 urlresolver 解析器,解析请求的 url,得到视图函数和参数。 由于实现了__getitem__可以支持自动解包
  2. 调用process_view函数
  3. 根据配置决定是否开启 atomic
  4. 调用视图函数,并将结果赋值给response
  5. 如果response支持模板渲染,则调用process_template_response函数
  6. 返回response
def _get_response(self, request):"""Resolve and call the view, then apply view, exception, andtemplate_response middleware. This method is everything that happensinside the request/response middleware."""response = Nonecallback, callback_args, callback_kwargs = self.resolve_request(request)# Apply view middlewarefor middleware_method in self._view_middleware:response = middleware_method(request, callback, callback_args, callback_kwargs)if response:breakif response is None:wrapped_callback = self.make_view_atomic(callback)# If it is an asynchronous view, run it in a subthread.if iscoroutinefunction(wrapped_callback):wrapped_callback = async_to_sync(wrapped_callback)try:response = wrapped_callback(request, *callback_args, **callback_kwargs)except Exception as e:response = self.process_exception_by_middleware(e, request)if response is None:raise# Complain if the view returned None (a common error).self.check_response(response, callback)# If the response supports deferred rendering, apply template# response middleware and then render the responseif 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).self.check_response(response,middleware_method,name="%s.process_template_response"% (middleware_method.__self__.__class__.__name__,),)try:response = response.render()except Exception as e:response = self.process_exception_by_middleware(e, request)if response is None:raisereturn response

WSGIHandler

重要函数
  • __call__: 处理每个进来的请求
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"):# If `wsgi.file_wrapper` is used the WSGI server does not call# .close on the response, but on the file wrapper. Patch it to use# response.close instead which takes care of closing all files.response.file_to_stream.close = response.closeresponse = environ["wsgi.file_wrapper"](response.file_to_stream, response.block_size)return response

ASGIHandler

重要函数
  • handle: 处理每个进来的请求
async def handle(self, scope, receive, send):"""Handles the ASGI request. Called via the __call__ method."""# Receive the HTTP request body as a stream object.try:body_file = await self.read_body(receive)except RequestAborted:return# Request is complete and can be served.set_script_prefix(get_script_prefix(scope))await signals.request_started.asend(sender=self.__class__, scope=scope)# Get the request and check for basic issues.request, error_response = self.create_request(scope, body_file)if request is None:body_file.close()await self.send_response(error_response, send)await sync_to_async(error_response.close)()returnasync def process_request(request, send):response = await self.run_get_response(request)try:await self.send_response(response, send)except asyncio.CancelledError:# Client disconnected during send_response (ignore exception).passreturn response# Try to catch a disconnect while getting response.tasks = [# Check the status of these tasks and (optionally) terminate them# in this order. The listen_for_disconnect() task goes first# because it should not raise unexpected errors that would prevent# us from cancelling process_request().asyncio.create_task(self.listen_for_disconnect(receive)),asyncio.create_task(process_request(request, send)),]await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)# Now wait on both tasks (they may have both finished by now).for task in tasks:if task.done():try:task.result()except RequestAborted:# Ignore client disconnects.passexcept AssertionError:body_file.close()raiseelse:# Allow views to handle cancellation.task.cancel()try:await taskexcept asyncio.CancelledError:# Task re-raised the CancelledError as expected.passtry:response = tasks[1].result()except asyncio.CancelledError:await signals.request_finished.asend(sender=self.__class__)else:await sync_to_async(response.close)()body_file.close()

可以学习的地方

  • asyncio.wait 的参数return_when=asyncio.FIRST_COMPLETED,可以让任务在第一个完成的时候返回,而不是等待所有任务完成。

总结

Handler 模块封装了 wsgi,asgi 两个类,分别用于处理外部的请求信息,asgi 提供异步处理能力。很好的实现了请求的处理流程,并提供了中间件的功能。

这篇关于[Django 0-1] Core.Handlers 模块的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/814362

相关文章

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

无法启动此程序因为计算机丢失api-ms-win-core-path-l1-1-0.dll修复方案

《无法启动此程序因为计算机丢失api-ms-win-core-path-l1-1-0.dll修复方案》:本文主要介绍了无法启动此程序,详细内容请阅读本文,希望能对你有所帮助... 在计算机使用过程中,我们经常会遇到一些错误提示,其中之一就是"api-ms-win-core-path-l1-1-0.dll丢失

Python logging模块使用示例详解

《Pythonlogging模块使用示例详解》Python的logging模块是一个灵活且强大的日志记录工具,广泛应用于应用程序的调试、运行监控和问题排查,下面给大家介绍Pythonlogging模... 目录一、为什么使用 logging 模块?二、核心组件三、日志级别四、基本使用步骤五、快速配置(bas

对Django中时区的解读

《对Django中时区的解读》:本文主要介绍对Django中时区的解读方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景前端数据库中存储接口返回AI的解释问题:这样设置的作用答案获取当前时间(自动带时区)转换为北京时间显示总结背景设置时区为北京时间 TIM

Django之定时任务django-crontab的实现

《Django之定时任务django-crontab的实现》Django可以使用第三方库如django-crontab来实现定时任务的调度,本文主要介绍了Django之定时任务django-cront... 目录crontab安装django-crontab注册应用定时时间格式定时时间示例设置定时任务@符号

Python datetime 模块概述及应用场景

《Pythondatetime模块概述及应用场景》Python的datetime模块是标准库中用于处理日期和时间的核心模块,本文给大家介绍Pythondatetime模块概述及应用场景,感兴趣的朋... 目录一、python datetime 模块概述二、datetime 模块核心类解析三、日期时间格式化与

Python如何调用指定路径的模块

《Python如何调用指定路径的模块》要在Python中调用指定路径的模块,可以使用sys.path.append,importlib.util.spec_from_file_location和exe... 目录一、sys.path.append() 方法1. 方法简介2. 使用示例3. 注意事项二、imp

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中