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实例.
- 接着打开浏览器,即发起请求.服务器实例WSGIServerhttpd调用自身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/
defrun(self,application):
"""Invoketheapplication"""
try:
self.setup_environ()
#application在django中就是WSGIHandler类,他实现了__call__方法,所以行为和函数一样.
self.result=application(self.environ,self.start_response)
self.finish_response()
except:
#handleerror
deffinish_response(self):
try:
ifnotself.result_is_file()ornotself.sendfile():
fordatainself.result:
#向套接字写数据,将数据返回给客户端
self.write(data)
self.finish_content()
finally:
self.close()
defwrite(self,data):
"""'write()'callableasspecifiedbyPEP333"""
#必须是都是字符
asserttype(data)isStringType,"write()argumentmustbestring"
ifnotself.status:
raiseAssertionError("write()beforestart_response()")
#需要先发送HTTP头
elifnotself.headers_sent:
#Beforethefirstoutput,sendthestoredheaders
self.bytes_sent=len(data)#makesureweknowcontent-length
self.send_headers()
#再发送实体
else:
self.bytes_sent+=len(data)
#XXXcheckContent-Lengthandtruncateiftoomanybyteswritten?
self._write(data)
self._flush()
defwrite(self,data):
"""'write()'callableasspecifiedbyPEP3333"""
assertisinstance(data,bytes),"write()argumentmustbebytestring"
#必须先调用self.start_response()设置状态码
ifnotself.status:
raiseAssertionError("write()beforestart_response()")
#需要先发送HTTP头
elifnotself.headers_sent:
#Beforethefirstoutput,sendthestoredheaders
self.bytes_sent=len(data)#makesureweknowcontent-length
self.send_headers()
#再发送实体
else:
self.bytes_sent+=len(data)
#XXXcheckContent-Lengthandtruncateiftoomanybyteswritten?是否需要分段发送过大的数据?
#Ifdataistoolarge,socketwillchoke,窒息死掉sowritechunksnolarger
#than32MBatatime.
#分片发送
length=len(data)
iflength>33554432:
offset=0
whileoffset
接下来的事情,就是回到WSGIServer关闭套接字,清理现场,web应用程序由此结束;但服务器依旧在监听(WSGIServer用select实现)是否有新的请求,不展开了.
阶段性的总结
请求到来至数据相应的流程已经走了一遍,包括django内部服务器是如何运作的,请求到来是如何工作的,响应数据对象是如何产生的,url是如何调度的,views.py中定义的方法是何时调用的,响应数据是如何返回的...另外还提出了一个更好的url调度策略,如果你有更好的方法,不忘与大家分享.
我已经在github备份了Django源码的注释:Decode-Django,有兴趣的童鞋fork吧.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。