Tornado Etag实现源码分析

Etag(URL的Entity Tag):

  对于具体Etag是什么,请求流程,实现原理,这里不进行介绍,可以参考下面链接:

    http://www.oschina.net/question/234345_42536?sort=time

    https://zh.wikipedia.org/wiki/HTTP_ETag

Tornado实现分析:

  先从Tornado处理一个请求的调用顺序开始看(摘自文档:http://www.tornadoweb.cn/documentation):

  1. 程序为每一个请求创建一个 RequestHandler 对象
  2. 程序调用 initialize() 函数,这个函数的参数是 Application 配置中的关键字 参数定义。(initialize 方法是 Tornado 1.1 中新添加的,旧版本中你需要 重写 __init__ 以达到同样的目的) initialize 方法一般只是把传入的参数存 到成员变量中,而不会产生一些输出或者调用像 send_error 之类的方法。
  3. 程序调用 prepare()。无论使用了哪种 HTTP 方法,prepare 都会被调用到,因此 这个方法通常会被定义在一个基类中,然后在子类中重用。prepare可以产生输出 信息。如果它调用了finish(或send_error` 等函数),那么整个处理流程 就此结束。
  4. 程序调用某个 HTTP 方法:例如 get()post()put() 等。如果 URL 的正则表达式模式中有分组匹配,那么相关匹配会作为参数传入方法。

  在一个请求结束的时候肯定会进行Etag的处理,所以找到调用的 finish() 函数:

  地址:tornado/web.py(删除了部分不在此主题的代码)

 1 def finish(self, chunk=None):
 2     # Automatically support ETags and add the Content-Length header if
 3     # we have not flushed any content yet.
 4     if not self._headers_written:
 5         if (self._status_code == 200 and
 6             self.request.method in ("GET", "HEAD") and
 7                 "Etag" not in self._headers):
 8             self.set_etag_header()
 9             if self.check_etag_header():
10                 self._write_buffer = []
11                 self.set_status(304)
12         if self._status_code in (204, 304):
13             assert not self._write_buffer, "Cannot send body with %s" % self._status_code
14             self._clear_headers_for_304()
15         elif "Content-Length" not in self._headers:
16             content_length = sum(len(part) for part in self._write_buffer)
17             self.set_header("Content-Length", content_length)

    分析:

      在调用 finish() 函数的时候,对HTTP请求进行判断,如果 状态码为200,请求的方法为 GET 或 HEAD,并且 Etag 不在HTTP头信息里面,则说明该请求是第一次发生。接下来,调用 set_etag_header() 函数,将 etag 写入到 header头信息中:

  地址:tornado/web.py

1 def set_etag_header(self):
2     etag = self.compute_etag()
3     if etag is not None:
4         self.set_header("Etag", etag)

    分析:

      接着调用 compute_etag() 函数生成 etag,如果返回成功,则调用 set_header() 函数将 etag 写入header头信息的 “Etag” 字段。接着看 compute_etag() 函数:

  地址:tornado/web.py

1 def compute_etag(self):
2     hasher = hashlib.sha1()
3     for part in self._write_buffer:
4         hasher.update(part)
5     return ‘"%s"‘ % hasher.hexdigest()

    分析:

      这里通过 调用 hashlib库 生成相应的 etag,然后通过对于 self._write_buffer的循环,当服务端文件有改变的时候,调用hashlib中的 update() 函数更新生成的新的对象 hasher,从而返回最新的 etag

      注:self._write_buffer在初始化的时候已经进行了定义 self._write_buffer = [ ], 如果某一个页面有改变,则会进行记录,从而来判断是否客户端请求的页面在服务端是否有改变

  这里对于 etag 的生成函数 set_etag_header() 函数已经介绍完了,接着进行 check_etag_header() 校验函数的分析:

  地址:tornado/web.py

 1 def check_etag_header(self):
 2     etags = re.findall(
 3         br‘\*|(?:W/)?"[^"]*"‘,
 4         utf8(self.request.headers.get("If-None-Match", ""))
 5     )
 6     if not computed_etag or not etags:
 7         return False
 8
 9     match = False
10     if etags[0] == b‘*‘:
11         match = True
12     else:
13         # Use a weak comparison when comparing entity-tags.
14         def val(x):
15             return x[2:] if x.startswith(b‘W/‘) else x
16
17         for etag in etags:
18             if val(etag) == val(computed_etag):
19                 match = True
20                 break
21     return match

    分析:

      首先获取 请求的header头信息中的 “If-None-Match” 字段,获取到该 etag,并通过正则表达式匹配,获取符合该条件的字符串。如果 没有获取到header头信息中的 etag字段,则返回 False,否认返回 True。

  之后,如果该  check_etag_header() 函数 返回True 的话, 则说明,该请求中包含有该 etag,接下来t通过  self._write_buffer = [ ] 对这个字段进行清空处理(表明该请求的页面暂时没有任何修改), 并且返回 状态码304 给客户端。

时间: 2024-08-30 03:08:30

Tornado Etag实现源码分析的相关文章

Tornado源码分析 --- Cookie和XSRF机制

Cookie和Session的理解: 具体Cookie的介绍,可以参考:HTTP Cookie详解 可以先查看之前的一篇文章:Tornado的Cookie过期问题 XSRF跨域请求伪造(Cross-Site-Request-Forgery): 简单的说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品).由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行.这利用了web中用户身份验证的一个漏洞:

Tornado源码分析系列之一: 化异步为'同步'的Future和gen.coroutine

转自:http://blog.nathon.wang/2015/06/24/tornado-source-insight-01-gen/ 用Tornado也有一段时间,Tornado的文档还是比较匮乏的,但是幸好其代码短小精悍,很有可读性,遇到问题时总是习惯深入到其源码中.这对于提升自己的Python水平和对于网络及HTTP的协议的理解也很有帮助.本文是Tornado源码系列的第一篇文章,网上关于Tornado源码分析的文章也不少,大多是从Event loop入手,分析Event loop的工作

Tornado源码分析 --- Redirect重定向

"重定向"简单介绍: "重定向"指的是HTTP重定向,是HTTP协议的一种机制.当client向server发送一个请求,要求获取一个资源时,在server接收到这个请求后发现请求的这个资源实际存放在另一个位置,于是server在返回的response中写入那个请求资源的正确的URL,并设置reponse的状态码为301(永久)或者 302(暂时),当client接受到这个response后就会根据新的URL重新发起请求.重定向有一个典型的特症,即,当一个请求被重定

[Android]Volley源码分析(二)Cache

Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源码思路往下,来看下Volley对Cache的处理逻辑. 我们回想一下昨天的简单代码,我们的入口是从构造一个Request队列开始的,而我们并不直接调用new来构造,而是将控制权反转给Volley这个静态工厂来构造. com.android.volley.toolbox.Volley: public static RequestQueue newRequestQueue(Context conte

OpenStack_Swift源码分析——Object-auditor源码分析(2)

1 Object-aduitor审计具体分析 上一篇文章中,讲解了Object-aduitor的启动,其中审计的具体执行是AuditorWorker实现的,在run_audit中实例化了AuditorWorker类,并调用audit_all_objects方法,下面看此方法的具体代码实现: def audit_all_objects(self, mode='once', device_dirs=None): #run_forever传过来的mode 为forever description =

Tornado 高并发源码分析之三--- Application 对象

Application 对象主要工作: 服务器启动时: 1.在新建一个app的时候,根据设置好的 URL 和回调函数 Handler 封装成URLSpec 对象 服务器运行时: 2.在请求到来,将 HTTPServer 封装好的HTTPRequest 传入_RequestDispatcher对象,_RequestDispatcher对象根据传入的 HTTPRequest 使用URLSpec解析匹 match 正则匹配找到对应的 RequestHandler ,执行它的 _execute 方法 A

Tornado 高并发源码分析之四--- HTTPServer 与 TCPServer 对象

主要工作: 服务器启动的时候做的事: 1.把包含了各种配置信息的 application 对象封装到了 HttpServer 对象的 request_callback 字段中,等待被调用 2.TCPServer 通过 listen 方法启动端口监听, 封装_handle_connection回调函数,并注册到 IOLoop 中 服务器运行时做的事: 3.当有请求到来时,注册在 IOLoop 中的 _handle_connection 将会被调用, _handle_connection 方法将会调

6 Application 源码分析

Application 是Tornado重要的模块之一,主要是配置访问路由表及其他应用参数的设置. 源代码位于虚拟运行环境文件夹下(我的是env),具体位置为env > lib>sit-packages>tornado>web.py.      注释大体意思: Application是由请求handlers集合组成,配置好application之后,直接作为参数传递给HTTPServer. 这个类的构造函数包含URLSpec对象集合或者(正则表达式,request handler)

TeamTalk源码分析之login_server

login_server是TeamTalk的登录服务器,负责分配一个负载较小的MsgServer给客户端使用,按照新版TeamTalk完整部署教程来配置的话,login_server的服务端口就是8080,客户端登录服务器地址配置如下(这里是win版本客户端): 1.login_server启动流程 login_server的启动是从login_server.cpp中的main函数开始的,login_server.cpp所在工程路径为server\src\login_server.下表是logi