Django 响应数据response的返回源码详解

响应数据的返回

在 WSGIHandler.__call__(self, environ, start_response) 方法调用了 WSGIHandler.get_response() 方法, 由此得到响应数据对象 response. 如今所要做的, 便是将其返回给客户端. 在 Django 源码小剖: 初探 WSGI中, 简要的概括了请求到来时 django 自带服务器的执行关系, 摘抄如下:

  • make_server() 中 WSGIServer 类已经作为服务器类, 负责接收请求, 调用 application 的处理, 返回相应;
  • WSGIRequestHandler 作为请求处理类, 并已经配置在 WSGIServer 中;
  • 接着还设置了 WSGIServer.application 属性(set_app(app));
  • 返回 server 实例.
  • 接着打开浏览器, 即发起请求. 服务器实例 WSGIServer httpd 调用自身 handle_request() 函数处理请求. handle_request() 的工作流程如下:请求-->WSGIServer 收到-->调用 WSGIServer.handle_request()-->调用 _handle_request_noblock()-->调用 process_request()-->调用 finish_request()-->finish_request() 中实例化 WSGIRequestHandler-->实例化过程中会调用 handle()-->handle() 中实例化 ServerHandler-->调用 ServerHandler.run()-->run() 调用 application() 这才是真正的逻辑.-->run() 中在调用 ServerHandler.finish_response() 返回数据-->回到 process_request() 中调用 WSGIServer.shutdown_request() 关闭请求(其实什么也没做)

事实上, WSGIServer 并没有负责将响应数据返回给客户端, 它将客户端的信息(如最重要的客户端 socket 套接字)交接给了 WSGIRequestHandler, WSGIRequestHandler 又将客户端的信息交接给了 ServerHandler, 所以 ServerHandler 产生响应数据对象后, 会直接返回给客户端.

代码剖析

从「调用 ServerHandler.run()-->run() 调用 application() 这才是真正的逻辑.-->run() 中在调用 ServerHandler.finish_response() 返回数据」开始说起, 下面是主要的代码解说:

# 下面的函数都在 ServerHandler 的继承链上方法, 有些方法父类只定义了空方法, 具体逻辑交由子类实现. 有关继承链请参看: http://daoluan.net/blog/decode-django-wsgi/
def run(self, application):
  """Invoke the application"""
  try:
    self.setup_environ()
    # application 在 django 中就是 WSGIHandler 类, 他实现了 __call__ 方法, 所以行为和函数一样.
    self.result = application(self.environ, self.start_response)
    self.finish_response()
  except:
    # handle error

def finish_response(self):
  try:
    if not self.result_is_file() or not self.sendfile():
      for data in self.result:
        # 向套接字写数据, 将数据返回给客户端
        self.write(data)
      self.finish_content()
  finally:
    self.close()

def write(self, data):
  """'write()' callable as specified by PEP 333"""
  # 必须是都是字符
  assert type(data) is StringType,"write() argument must be string"
  if not self.status:
    raise AssertionError("write() before start_response()")
  # 需要先发送 HTTP 头
  elif not self.headers_sent:
    # Before the first output, send the stored headers
    self.bytes_sent = len(data)  # make sure we know content-length
    self.send_headers()
  # 再发送实体
  else:
    self.bytes_sent += len(data)

  # XXX check Content-Length and truncate if too many bytes written?
  self._write(data)
  self._flush()

def write(self, data):
  """'write()' callable as specified by PEP 3333"""

  assert isinstance(data, bytes), "write() argument must be bytestring"

  # 必须先调用 self.start_response() 设置状态码
  if not self.status:
    raise AssertionError("write() before start_response()")

  # 需要先发送 HTTP 头
  elif not self.headers_sent:
    # Before the first output, send the stored headers
    self.bytes_sent = len(data)  # make sure we know content-length
    self.send_headers()
  # 再发送实体
  else:
    self.bytes_sent += len(data)

  # XXX check Content-Length and truncate if too many bytes written? 是否需要分段发送过大的数据?

  # If data is too large, socket will choke, 窒息死掉 so write chunks no larger
  # than 32MB at a time.

  # 分片发送
  length = len(data)
  if length > 33554432:
    offset = 0
    while offset < length:
      chunk_size = min(33554432, length)
      self._write(data[offset:offset+chunk_size])
      self._flush()
      offset += chunk_size
  else:
    self._write(data)
    self._flush()

def _write(self,data):
  # 如果是第一次调用, 则调用 stdout.write(), 理解为一个套接字对象
  self.stdout.write(data)
  # 第二次调用就是直接调用 stdout.write() 了
  self._write = self.stdout.write

接下来的事情, 就是回到 WSGIServer 关闭套接字, 清理现场, web 应用程序由此结束; 但服务器依旧在监听(WSGIServer 用 select 实现)是否有新的请求, 不展开了.

阶段性的总结

请求到来至数据相应的流程已经走了一遍, 包括 django 内部服务器是如何运作的, 请求到来是如何工作的, 响应数据对象是如何产生的, url 是如何调度的, views.py 中定义的方法是何时调用的, 响应数据是如何返回的...另外还提出了一个更好的 url 调度策略, 如果你有更好的方法, 不忘与大家分享.

我已经在 github 备份了 Django 源码的注释: Decode-Django, 有兴趣的童鞋 fork 吧.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 使用Django和Python创建Json response的方法

    使用jQuery的.post提交,并期望得到多个数据,Python后台要使用json格式. 不指定datatype为json,让jquery自行判断数据类型.(注:跨域名请求数据,则使用 jsonp字符串) 若post指定数据类型json,则python取post数据,我觉着麻烦.让jquery智能判断,python返回字典最方便. 一般使用字典,而不是列表来返回 JSON内容. import json from django.http import HttpResponse response_

  • 对django中render()与render_to_response()的区别详解

    render()与render_to_response()均是django中用来显示模板页面的,但是在django1.3之后,render()便比render_to_response()更加招人待见!最明显的就是前者会自动使用RequestContext,而后者需要coding进去, 例如: render(request,'share.html', {'registAdd': registAdd}) render_to_response('share.html',{'registAdd':reg

  • Django使用HttpResponse返回图片并显示的方法

    做了一个关于Django的小案例,想要在网页中显示图片,直接在img标签的src属性写图片的路径是不能显示的,查询资料发现在Django中使用图片这类的资源相当繁琐需要进行一定D的配置,摸索了一会没有整明白,想到了写Java时使用文件流返回图片,于是想到使用该种方式来显示图片. 使用实例如下: views.py def my_image(request,news_id): d = path.dirname(__file__) #parent_path = path.dirname(d) prin

  • Django的HttpRequest和HttpResponse对象详解

    本文研究的主要是Django的HttpRequest和HttpResponse对象的相关内容,具体如下. 请求一张页面时,Django把请求的metadata数据包装成一个HttpRequest对象,然后Django加载合适的view方法,把这个HttpRequest 对象作为第一个参数传给view方法.任何view方法都应该返回一个HttpResponse对象. 我们在本书中大量使用这两个对象:本附录详细解释HttpRequest和HttpResponse对象. HttpRequest Htt

  • Django框架中render_to_response()函数的使用方法

    通常的情况是,我们一般会载入一个模板文件,然后用 Context渲染它,最后返回这个处理好的HttpResponse对象给用户. 我们已经优化了方案,使用 get_template() 方法代替繁杂的用代码来处理模板及其路径的工作. 但这仍然需要一定量的时间来敲出这些简化的代码. 这是一个普遍存在的重复苦力劳动.Django为此提供了一个捷径,让你一次性地载入某个模板文件,渲染它,然后将此作为 HttpResponse返回. 该捷径就是位于 django.shortcuts 模块中名为 rend

  • 对django views中 request, response的常用操作详解

    request 获取post请求中的json数据 def hello(request): data = json.loads(request.body) ... json格式还有一些 非表单序列化 的格式,都可以从 request.body 中获取请求体中的数据,对于ajax请求可以使用 request.is_ajax() 来判断 根据请求的信息获取base url(有时候服务的域名比较多,还是需要动态的拼接一下url信息) # url http://wificdn.com:8888/wxpay

  • Django 响应数据response的返回源码详解

    响应数据的返回 在 WSGIHandler.__call__(self, environ, start_response) 方法调用了 WSGIHandler.get_response() 方法, 由此得到响应数据对象 response. 如今所要做的, 便是将其返回给客户端. 在 Django 源码小剖: 初探 WSGI中, 简要的概括了请求到来时 django 自带服务器的执行关系, 摘抄如下: make_server() 中 WSGIServer 类已经作为服务器类, 负责接收请求, 调用

  • Django Rest Framework实现身份认证源码详解

    目录 一.Django框架 二.身份认证的两种实现方式: 三.身份认证源码解析流程 一.Django框架 Django确实是一个很强大,用起来很爽的一个框架,在Rest Framework中已经将身份认证全都封装好了,用的时候直接导入authentication.py这个模块就好了.这个模块中5个认证类.但是我们在开发中很少用自带的认证类,而是根据项目实际需要去自己实现认证类.下面是内置的认证类 BaseAuthentication(object):所有的认证相关的类都继承自这个类,我们写的认证

  • Java8中AbstractExecutorService与FutureTask源码详解

    目录 前言 一.AbstractExecutorService 1.定义 2.submit 3.invokeAll 4.invokeAny 二.FutureTask 1.定义 2.构造方法 3.get 4.run/ runAndReset 5. cancel 三.ExecutorCompletionService 1.定义 2.submit 3.take/ poll 总结 前言 本篇博客重点讲解ThreadPoolExecutor的三个基础设施类AbstractExecutorService.F

  • python目标检测SSD算法训练部分源码详解

    目录 学习前言 讲解构架 模型训练的流程 1.设置参数 2.读取数据集 3.建立ssd网络. 4.预处理数据集 5.框的编码 6.计算loss值 7.训练模型并保存 开始训练 学习前言 ……又看了很久的SSD算法,今天讲解一下训练部分的代码.预测部分的代码可以参照https://blog.csdn.net/weixin_44791964/article/details/102496765 讲解构架 本次教程的讲解主要是对训练部分的代码进行讲解,该部分讲解主要是对训练函数的执行过程与执行思路进行详

  • Android开发数据结构算法ArrayList源码详解

    目录 简介 ArrayList源码讲解 初始化 扩容 增加元素 一个元素 一堆元素 删除元素 一个元素 一堆元素 修改元素 查询元素 总结 ArrayList优点 ArrayList的缺点 简介 ArrayList是List接口的一个实现类,它是一个集合容器,我们通常会通过指定泛型来存储同一类数据,ArrayList默认容器大小为10,自身可以自动扩容,当容量不足时,扩大为原来的1.5倍,和上篇文章的Vector的最大区别应该就是线程安全了,ArrayList不能保证线程安全,但我们也可以通过其

  • Android实现屏幕锁定源码详解

    最近有朋友问屏幕锁定的问题,自己也在学习,网上找了下也没太详细的例子,看的资料书上也没有有关屏幕锁定程序的介绍,下个小决心,自己照着官方文档学习下,现在做好了,废话不多说,先发下截图,看下效果,需要注意的地方会加注释,有问题的朋友可以直接留言,我们共同学习交流,共同提高进步!直接看效果图: 一:未设置密码时进入系统设置的效果图如下: 二:设置密码方式预览: 三:密码解密效果图 四:九宫格解密时的效果图 下面来简单的看下源码吧,此处讲下,这个小DEMO也是临时学习下的,有讲的不明白的地方请朋友直接

  • Spring AOP底层源码详解

    ProxyFactory的工作原理 ProxyFactory是一个代理对象生产工厂,在生成代理对象之前需要对代理工厂进行配置.ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术. // config就是ProxyFactory对象 // optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface if (config.isOptimize() || config.isProxy

  • Django中get()和filter()返回值区别详解

    先上官方文档! filter(**kwargs) 返回包含与给定查找参数匹配的对象的新查询集. 简单来说,返回一个又对象组成的查询集合 get(**kwargs) 返回与给定查找参数匹配的对象,该对象应采用字段查找中描述的格式. 例子 例如在Model中有一个Order类,包含一个id字段,输入 id 为2019 字段的 id 1.get()方法 orders = Orders.objects.get(id=20190003) print(order) 先查看orders是什么,结果为 Orde

  • Java并发编程之ConcurrentLinkedQueue源码详解

    一.ConcurrentLinkedQueue介绍 并编程中,一般需要用到安全的队列,如果要自己实现安全队列,可以使用2种方式: 方式1:加锁,这种实现方式就是我们常说的阻塞队列. 方式2:使用循环CAS算法实现,这种方式实现队列称之为非阻塞队列. 从点到面, 下面我们来看下非阻塞队列经典实现类:ConcurrentLinkedQueue (JDK1.8版) ConcurrentLinkedQueue 是一个基于链接节点的无界线程安全的队列.当我们添加一个元素的时候,它会添加到队列的尾部,当我们

  • python目标检测SSD算法预测部分源码详解

    目录 学习前言 什么是SSD算法 ssd_vgg_300主体的源码 学习前言 ……学习了很多有关目标检测的概念呀,咕噜咕噜,可是要怎么才能进行预测呢,我看了好久的SSD源码,将其中的预测部分提取了出来,训练部分我还没看懂 什么是SSD算法 SSD是一种非常优秀的one-stage方法,one-stage算法就是目标检测和分类是同时完成的,其主要思路是均匀地在图片的不同位置进行密集抽样,抽样时可以采用不同尺度和长宽比,然后利用CNN提取特征后直接进行分类与回归,整个过程只需要一步,所以其优势是速度

随机推荐