Python公开课 - Django自动添加Last-Modified和ETag

什么是Last-Modified和ETag

Last-Modified

在浏览器第一次请求某一个URL时,正常情况下服务器端的返回状态码 HTTP 200,内容是请求的资源,同时有一个Last-Modified的属性标记此文件在服务期端最后被修改的时间,格式类似这样:

Last-Modified: Fri, 12 May 2018 18:53:33 GMT

当客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送 If-Modified-Since 报头,询问该时间之后文件是否有被修改过:

If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT

如果服务器端的资源没有变化,则自动返回 HTTP 304 状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。

从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。

ETag

HTTP 协议规格说明定义ETag为“被请求变量的实体值”。你也可以将ETag理解为一个可以与Web资源关联的记号(token)。

典型的Web资源可以一个Web页,但也可能是JSON或XML文档。

服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端,以下是服务器端返回的格式:

  ETag: "50b1c1d4f775c61:df3"

客户端的查询更新格式是这样的:

  If-None-Match: W/"50b1c1d4f775c61:df3"

如果ETag没改变,则返回状态304然后不返回,这也和Last-Modified一样。

Django中如何配置Last-Modified和ETag

在Django项目里,对于一个响应或者页面返回来说,一般都是通过view来进行处理,它会提供两个HTTP头信息:ETag和Last-Modified。

这两个头信息可以在view自行编码操作,也可以通过ConditionalGetMiddleware中间件来设置ETag,在Django2.2版本中,默认配置已经含有了。

Django中有三个decorator,可以为响应添加Last-Modified和ETag。

  • condition(etag_func=None, last_modified_func=None)
  • etag(etag_func)
  • last_modified(last_modified_func)

要注意的是,官网给的使用方法都是针对function-based view,如果你使用的是class-based view,需要在url配置中调用decorator,示例如下:

def etag_func(request, *args, **kwargs):
    pk = kwargs['pk']
    try:
        obj = Article.objects.get(id=pk)
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        last_modified = obj.update_time.strftime(GMT_FORMAT)
        m = hashlib.md5()
        m.update(last_modified.encode('utf8'))
        return m.hexdigest()
    except Article.DoesNotExist:
        return None



def last_modified_func(request, *args, **kwargs):
    pk = kwargs['pk']
    try:
        obj = Article.objects.get(id=pk)
        return obj.update_time
    except Article.DoesNotExist:
        return None


urlpatterns = [
    url('^/detail-(?P<pk>\d+).html', condition(etag_func=etag_func, last_modified_func=last_modified_func)(views.Detail.as_view())),

]

效果如图所示:

 Django自动添加Last-Modified和ETag