当前位置: 首页 > news >正文

[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 提供异步处理能力。很好的实现了请求的处理流程,并提供了中间件的功能。

相关文章:

  • Apache Paimon 使用 MySQL CDC 获取数据
  • 如何用 UDP 实现可靠传输?并以LabVIEW为例进行说明
  • 项目中如何排查jvm问题
  • CXL-Enabled Enhanced Memory Functions——论文阅读
  • 第十四届蓝桥杯省赛真题 Java 研究生 组【原卷】
  • 神策分析 Copilot 成功通过网信办算法备案,数据分析 AI 化全面落地
  • 栈与队列|232.用栈实现队列
  • 音频数据如果在中断中会随机给的那就放入队列或者缓冲区;队列缓冲区对音频的作用
  • RabbitMQ基础
  • 在 Mac 上通过“启动转换助理”安装 Windows 10
  • swiftUI中的可变属性和封装
  • huawei services HK华为云服务
  • mysql启动报错:ERROR! The server quit without updating PID file
  • 从0开始回顾MySQL --- 三范式与表设计
  • 腾讯云对象存储的在Java使用步骤介绍
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • Android Volley源码解析
  • Angular2开发踩坑系列-生产环境编译
  • exports和module.exports
  • extract-text-webpack-plugin用法
  • Hibernate最全面试题
  • Idea+maven+scala构建包并在spark on yarn 运行
  • JavaScript对象详解
  • JDK9: 集成 Jshell 和 Maven 项目.
  • js操作时间(持续更新)
  • leetcode386. Lexicographical Numbers
  • Redis的resp协议
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • select2 取值 遍历 设置默认值
  • SpringBoot 实战 (三) | 配置文件详解
  • Sublime text 3 3103 注册码
  • v-if和v-for连用出现的问题
  • Vue.js源码(2):初探List Rendering
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 聊聊directory traversal attack
  • 三栏布局总结
  • 使用 @font-face
  • 试着探索高并发下的系统架构面貌
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 你对linux中grep命令知道多少?
  • hi-nginx-1.3.4编译安装
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • #微信小程序(布局、渲染层基础知识)
  • (16)Reactor的测试——响应式Spring的道法术器
  • (floyd+补集) poj 3275
  • (二十三)Flask之高频面试点
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (一)Neo4j下载安装以及初次使用
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • .NET Core 2.1路线图
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET单元测试
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .net图片验证码生成、点击刷新及验证输入是否正确