ETag : Entity Tag,实体标记,跟HTTP_IF_NONE_MATCH一起决定是返回304还是返回客户端所请求的资源(图片、js文件等,经测试,对普通的文本或HTML无效)。
1、直接在头部加ETag标签
代码如下:
def img(request):
cli_etag=request.META['HTTP_IF_NONE_MATCH']
if cli_etag == "0000":
return http.HttpResponseNotModified()
image = Image.open("/root/Pictures/map.jpg")
_buffer = StringIO.StringIO()
image.save(_buffer, "PNG")
_buffer.seek(0)
data=_buffer.read()
response=HttpResponse(content=data,content_type="image/png")
response["ETag"]="0000"
return response
此时的ETag的值完全自己定义,没有格式的要求。
2、借用中间件:CommonMiddleWare
在settings.py中进行如下设置:
- 在MIDDLEWARE_CLASSES中加入'django.middleware.common.CommonMiddleware'。(如果没有的话)
- USE_ETAGS = True
然后就可以使用了。代码如下:
def img(request):
image = Image.open("/root/Pictures/map.jpg")
_buffer = StringIO.StringIO()
image.save(_buffer, "PNG")
_buffer.seek(0)
data=_buffer.read()
response=HttpResponse(content=data,content_type="image/png")
return response
中间件跟切面编程或装饰器很像,原理如下图所示:
对于response,就是上图中右侧的部分,如果跟踪调试的话,你会发现有这么几条语句:
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
这个就是在逐层调用中间件的方法了。此时,CommonMiddleware所起的作用就是对reponse进行封装,加上ETag标签,此时ETag的值是response的MD5值,如果ETag没有发生变化就会返回http.HttpResponseNotModified(),否则的话就返回reponse。
3、借用另一种中间件:django.middleware.http.ConditionalGetMiddleware
此时所有需要计算tag值的view只需要加个装饰器就可以了,代码如下:
def img_etag(request):
return "0000"
@etag(img_etag)
def img(request):
image = Image.open("/root/Pictures/map.jpg")
_buffer = StringIO.StringIO()
image.save(_buffer, "PNG")
_buffer.seek(0)
data=_buffer.read()
response=HttpResponse(content=data,content_type="image/png")
return response
相对于上一种方法来说,不但服务器压力小了,带宽也有可能减少了。img_etag就是返回etag的函数,它的参数必须跟img的一模一样,如果img_etag函数所返回的值与HTTP中请求头的一样,那下面的view就不会执行了,直接返回304。
针对这种中间件还有其他用法,参考
Conditional View Processing。
参考
后记
之前一直用文本在测试ETag,发现怎么着都不行,在这个尝试和搜索的过程中,发现还有很多东西要看,比如cache-control的使用,expire的设置等等。