django框架在正式环境中的请求处理流程分析

先推荐一个个人认为更好的:http://www.jianshu.com/p/679dee0a4193
django程序在正式环境中往往是通过wsgi程序去启动的,所以运行开始的入口就是django项目的wsgi.py ,这个文件的重点就是调用get_wsgi_application函数

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(set_prefix=False)

return WSGIHandler()

函数获取一个UWSGIhandler对象,这个UWSGIhandler是一个符合UWSGI协议的对象,这个协议就是自己必须有一个call方法,这个call方法必须要有两个参数,一个environ参数,这个是web服务器传递过来的参数字典,包括环境变量; 还有一个start_response函数去处理http的请求。

这个UWSGIhanler在初始化函数init中去调用load_middleware去装载在settings里面的middleware,其实这些middleware都是一个类,最后会被实例化然后调用,同时这个对象有一个call函数,每来一个url请求,都会去调用UWSGIhandler对象,触发call函数去执行后续流程,这个推测可以在django自身的manage.py runserver分析中可以得到验证,代码如下:


class WSGIHandler(base.BaseHandler):

request_class = WSGIRequest

def __init__(self, *args, **kwargs):

super(WSGIHandler, self).__init__(*args, **kwargs)

self.load_middleware()

def __call__(self, environ, start_response):

set_script_prefix(get_script_name(environ))

signals.request_started.send(sender=self.__class__, environ=environ)

try:

request = self.request_class(environ)

print "request.COOKIES: ", request.COOKIES

print "request.HTTP_AUTHORIZATION: ", request.META.get('HTTP_AUTHORIZATION','No HTTP_AUTHORIZATION')

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)

response._handler_class = self.__class__

status = '%d %s' % (response.status_code, response.reason_phrase)

response_headers = [(str(k), str(v)) for k, v in response.items()]

for c in response.cookies.values():

response_headers.append((str('Set-Cookie'), str(c.output(header=''))))

start_response(force_str(status), response_headers)

if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):

response = environ['wsgi.file_wrapper'](response.file_to_stream)

print "type(response), response: ", type(response), response

#        print "response.cookies: ", response.items()[0][1]

#        print "response.headers: ", response._headers

return response

而最终UWSGI服务器会调去处理UWSGIhandler,下面代码中的application就是UWSGIhandler的实例

class BaseHandler:

def run(self, application):

    """Invoke the application"""

    # Note to self: don't move the close()!  Asynchronous servers shouldn't

    # call close() from finish_response(), so if you close() anywhere but

    # the double-error branch here, you'll break asynchronous servers by

    # prematurely closing.  Async servers must return from 'run()' without

    # closing if there might still be output to iterate over.

    try:

        self.setup_environ()

        self.result = application(self.environ, self.start_response)

上面的self.result = application(self.environ, self.start_response)就是调用application实例,从而触发call,这里的application就是

get_uwsgi_application的返回,也就是WSGIhandler的实例对象)。

从WSGIhanler对象中的call中可以看出,首先去构造一个request请求,这个request对象中的信息(主要是在view 函数中用到的信息)都是来自call函数的参数environment,猜测是http客户端传过来的请求信息。初始化好request后,就开始调用get_response()构造要返回的response了。

get_response()中调用了_middleware_chain(request)函数,其实就是调用了_get_response()函数,_get_response函数是处理关键,所以,往下看_get_response函数就好了。

_get_response函数首先做url匹配,即调用resolver.resolve(request.path_info),获得callback,callback其实就是与url匹配的view(视图函数),最后调用视图函数处理request,在_get_response中你可以看到,

for middleware_method in self._view_middleware: #self._view_middleware是在load_middleware函数里面被赋值的。

response = middleware_method(request, callback, callback_args, callback_kwargs)

if response:

break

首先判断middleware_method是否处理了request并返回了response,如果返回了response,那么就不会走到与url匹配的视图函数,也就是下面这段代码:

if response is None: #这里response为 None的情况就是 view_middleware没又返回response对象。

wrapped_callback = self.make_view_atomic(callback) #这一步使视图事务化,因为视图的处理很可能涉及到数据库操作

try:

response = wrapped_callback(request, *callback_args, **callback_kwargs) #真正调用视图函数去处理request请求,也就到了我们自己写的django业务了,即我们自己写的view

except Exception as e:

response = self.process_exception_by_middleware(e, request)

从代码中可以看出,如果response为None,也就是middleware没有返回response,那么就交由我们自己写的view函数去处理。我们自己写的django业务的主要作用是处理我们需要的逻辑,然后将结果封装成一个HttpResponse对象返回。

推荐一个写的更清晰的文章:http://www.jianshu.com/p/679dee0a4193
借用一张图备份:

image.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容