当前位置: 首页 > 后端技术 > Python

Tornado持续返回304状态码

时间:2023-03-26 11:40:00 Python

Tornado处理get请求时源码分析---Etag实现Etag(URL的EntityTag):什么是Etag,请求过程,实现原理这里就不介绍了,大家可以参考链接如下:http://www.oschina.net/questi...https://zh.wikipedia.org/wiki...Tornado实现分析:先看Tornado处理一个请求的调用顺序(摘自文档:http://www.tornadoweb.cn/documentation):程序为每个请求创建一个RequestHandler对象。该程序调用initialize()函数。该函数的参数为??Application配置中的关键字参数定义。(initialize方法是Tornado1.1新加入的,旧版本需要重写__init__来达到同样的目的。)initialize方法一般只是把传入的参数存放在成员变量中,并不会产生一些输出或者调用之类的send_error等方法。程序调用prepare()。无论使用哪种HTTP方法都会调用prepare,所以这个方法通常定义在一个基类中,然后在子类中复用。prepare可以生成输出信息。如果它调用了finish(或诸如send_error`之类的函数),那么整个处理流程到此结束。程序调用HTTP方法:例如get()、post()、put()等。如果URL的正则表达式模式中存在组匹配,则相关匹配将作为参数传递给该方法。一个请求结束时,肯定会处理Etag,所以找到调用的finish()函数:finish()函数----地址:tornado/web.py(删除一些不在本题中的代码)deffinish(self,chunk=None):#如果我们还没有刷新任何内容,则自动支持ETag并添加Content-Length标头。如果不是self._headers_written:如果(self._status_code==200和self.request.methodin(“GET”,“HEAD”)和“Etag”不在self._headers中):self.set_etag_header()如果self.check_etag_header():self._write_buffer=[]self.set_status(304)ifself._status_codein(204,304):assertnotself._write_buffer,"Cannotsendbodywith%s"%self._status_codeself._clear_headers_for_304()elif"Content-Length"notinself._headers:content_length=sum(len(part)forpartinself._write_buffer)self.set_header("Content-Length",content_length)分析:  正在调用finish()函数,判断HTTP请求。如果状态码为200,请求方式为GET或HEAD,HTTP头信息中没有Etag,则表示请求是第一次。接下来调用set_etag_header()函数,将etag写入header信息set_etag_header()函数----地址:tornado/web.pydefset_etag_header(self):etag=self.compute_etag()ifetagisnotNone:self。set_header("Etag",etag)分析:  然后调用compute_etag()函数生成etag,如果返回成功,再调用set_header()函数将etag写入header的“Etag”字段信息。查看compute_etag()函数:compute_etag()函数----地址:tornado/web.pydefcompute_etag(self):hasher=hashlib.sha1()forpartinself._write_buffer:hasher.update(part)return'"%s"'%hasher.hexdigest()分析:  这里调用hashlib库生成对应的etag,然后通过循环forself._write_buffer,当服务器文件发生变化时,调用update()hashlib中的函数更新生成的新对象hasher,返回最新的etag  注意:初始化时已经定义了self._write_bufferself._write_buffer=[],如果页面发生了变化,会被记录下来,从而判断是否客户端请求的页面在服务器端发生了变化。到这里,etag生成函数set_etag_header()函数已经介绍完了,接下来分析check_etag_header()校验函数:check_etag_header()校验函数----地址:tornado/web.pydefcheck_etag_header(self):etags=re.findall(br'\*|(?:W/)?"[^"]*"',utf8(self.request.headers.get("If-None-Match","")))如果不是computed_etagornotetags:returnFalsematch=Falseifetags[0]==b'*':match=Trueelse:#在比较实体标签时使用弱比较defval(x):returnx[2:]ifx.startswith(b'W/')elsexforetaginetags:ifval(etag)==val(computed_etag):match=Truebreakreturn匹配分析:  首先服务端获取到发送的信息客户端通过header信息中的“If-None-Match”字段,获取etag,用正则表达式匹配,检查是否与服务端保存的etag相同。如果没有获取到header信息中的etag字段或者与服务器匹配到etag不匹配则返回False,如果被拒绝则返回True。  之后,如果check_etag_header()函数返回True,则说明请求中包含了etag并且etag与服务器保存的相同,然后t通过self._write_buffer=[]处理清空该字段(表示请求的页面暂未修改),返回状态码304给客户端。解决304问题,删除请求头中的'If-None-Match'delself.request.headers['If-None-Match']引用