博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Tornado源码分析 --- Etag实现
阅读量:6911 次
发布时间:2019-06-27

本文共 3649 字,大约阅读时间需要 12 分钟。

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() 函数:

  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_code14             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头信息中

 

  set_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() 函数:

 

   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() 校验函数的分析:

   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 = False10     if etags[0] == b'*':11         match = True12     else:13         # Use a weak comparison when comparing entity-tags.14         def val(x):15             return x[2:] if x.startswith(b'W/') else x16 17         for etag in etags:18             if val(etag) == val(computed_etag):19                 match = True20                 break21     return match

   分析:

    首先服务端获取 客户端发送过来的 header头信息 中的 “If-None-Match” 字段,拿到该 etag,并通过正则表达式匹配,查看是否跟服务端保存的etag相同。如果 没有获取到header头信息中的 etag字段或跟服务端etag不匹配,则返回 False,否认返回 True。

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

 

转载于:https://www.cnblogs.com/ShaunChen/p/6601242.html

你可能感兴趣的文章
不错的资源哦
查看>>
多线程概念
查看>>
emqttd 2.2安装和测试使用
查看>>
Objective-C之优雅的命名
查看>>
php output_buffering 缓存使用
查看>>
深度学习和神经网络的区别是什么
查看>>
Decorator模式
查看>>
每日练习
查看>>
LeetCode算法题-First Unique Character in a String(Java实现)
查看>>
【小程序】小程序开发自定义组件的步骤>>>>>>>>>小程序开发过程中报错:jsEnginScriptError...
查看>>
OSI模型
查看>>
用Quick Cocos2dx做一个连连看(三)
查看>>
好久没做.Net开发了,今天配置IIS和.Net Framework 4.0遇到点问题
查看>>
emoji情感分类器
查看>>
简单理解java反射机制
查看>>
Codeforces 399B - Red and Blue Balls
查看>>
实验五
查看>>
Qt资源
查看>>
n个骰子的点数
查看>>
Linux硬盘扩容(非LVM)
查看>>