Cache headers in Django

ref:
https://blog.othree.net/log/2012/12/22/cache-control-and-etag/ << 建議讀一下
http://zhangxiaofei576342.blog.163.com/blog/static/2086199020101026113241602/
http://blog.toright.com/posts/3414/%E5%88%9D%E6%8E%A2-http-1-1-cache-%E6%A9%9F%E5%88%B6.html

Cache-Control header

優先級(由高至低):

no-store >> 完全不存下來,所以完全沒有 cache
no-cache >> 還是可能會 cache,但還是會每次都問有沒有新內容
max-age=60 >> 在 60 秒內不會再 request

ref:
http://tools.ietf.org/html/rfc2616#section-14.9
http://www.php-oa.com/2008/12/03/http-head.html

Cache Middleware

如果有啟用 Django 的 cache middleware(例如 UpdateCacheMiddleware 和 FetchFromCacheMiddleware)
每一個 request 都會被標上 Cache-Control: max-age=600
那個 600 是根據 CACHE_MIDDLEWARE_SECONDS

只要設置了 max-age > 0
response header 中就會被自動加入 Cache-ControlExpiresLast-Modified 兩個欄位

ref:
https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-CACHE_MIDDLEWARE_SECONDS

@never_cache decorator

from django.views.decorators.cache import never_cache

@never_cache
def myview(request):
    pass

如果你單純的就是不希望被 cache
就使用這種方式

上面這個 decorator 只會設置 Cache-Control: max-age=0
max-age=0 是馬上過期

@cache_control decorator

from django.views.decorators.cache import cache_control

class SongDetail(SVAPIDetailView):
    serializer_class = api_serializers.SongDetailSerializer

    @cache_control(no_store=True, no_cache=True, max_age=0)
    def get(self, request, song_id):
        do_something()

        return Response(data)

不知道為什麼,只設置 no-store 和 no-cache 的話
iOS 的 AFNetworking 還是會 cache
照道理說 no-store 的優先權應該是最高的
目前的解法是使用 Cache-Control: max-age=0

ref:
https://docs.djangoproject.com/en/dev/topics/cache/#controlling-cache-using-other-headers

Last-Modified 和 Etag

Last-Modified 要跟 response 的 If-Modified-Since 一起用
ETag 要跟 response 的 If-None-Match 一起用

Last-Modified 是說這個 URI 在什麼時候被修改了
是 GMT 時間

ETag 是 Entity Tag
是這個 URI 的 hash 值(但是用什麼來 hash 你可以自己決定,檔案內容之類的)
因為 hash 可能是個耗時的操作
所以 YSlow 建議不要用 ETag
用 Last-Modified、Expires 或 Cache-Control: max-age=xxx 就可以了

Vary header

Varnish, Squid 這一類的 cache proxy 多半會根據 URL 和 Vary header 提到的 header 來做一個 hash
用這個 hash 來判斷緩存有沒有命中
Vary header 可能會長這樣:

Vary: Accept-Encoding
Vary: Accept-Encoding,User-Agent
Vary: X-Some-Custom-Header,Host
Vary: *

假設有兩個 requests 請求同一個檔案(URL 一樣)
但是這兩個 requests 的 User-Agent 不同(比如說是兩個不同的 browser)
第二個 request 的緩存就不會命中
因為 hash 結果會不一樣

ref:
http://shunter.blog.51cto.com/2183398/1076521