HTTP 缓存中的 Vary

相信熟悉 Http 协议的人都了解,在 Response Headers 中传回 Cache-Control 的参数,可以实现客户端的缓存,当然仅仅用客户端缓存,大多数时候其实不能满足要求,要更好的交互,更快的接口响应,大多数时候会在服务端加入缓存。

Nginx Module

这里以 Nginx ngx_http_fastcgi_module 为例子,具体描述下服务端使用缓存的例子。

set $cache_key $request_uri;

fastcgi_cache_path /var/tmp/nginx-cache levels=1:2 keys_zone=cache_zone:64M;
fastcgi_cache cache_zone;
fastcgi_cache_key $cache_key;
fastcgi_cache_lock on;
fastcgi_cache_lock_age 3s;
fastcgi_cache_lock_timeout 3s;

本例子是以 reqest_uri 作为 cache key。在服务端接收到相同的 request_uri 的时候,会直接在 ngx_http_fastcgi_module 这个模块中将缓存的数据直接 return。

Vary

根据上述使用 request_uri 作为缓存的 key,很大程度可以缓解接口性能问题。但是同样会衍生出一个问题。其实 ngx_http_fastcgi_module 这个模块的缓存,会将整个 Response 的全部信息缓存进去,所以能预想到 Response header 的 access-control-allow-origin 这个头部会别缓存成起来,而根据业务逻辑不同,大多数业务系统都只会对 Request 的 Origin 进行单独签发。

这种情况下就可能会造成同一个接口,在不同 Host 请求时,某些域名会出现跨域,而且过一段时间后又好了的玄学问题。为了解决这一情况,最快捷的做法是设置 cache_key 前缀。即改为:

set $cache_key $http_origin/$request_uri;

但是其实缓存空间是有限的,我们通过对 cache_zone 的设置为 64M,所以更改 cache_key 的快速解决方案似乎不是最优解。所以这里在 Response Header 中加入 Vary

Vary: Origin

我们在响应的时候,将 Vary 加入响应的头部,解决了问题。

Nginx Vary 的探究

Vary 很方便地解决了服务端缓存 Origin 的问题,但是衍生出一个问题。服务端缓存的目的是为了实现更少请求到达业务层,同一个接口下,通过校验 Origin ,不是当前缓存成功的 Origin 会击穿缓存到达业务层,而业务层再对该请求处理,重新包装 access-control-allow-origin 后重新被 Nginx 缓存。周而复始,似乎反而没有起到该有的缓存效果。

为了确认 Vary 方案是否跟上述所想相同,查阅了相关文档。

If the header includes the "Vary" field with the special value "*", such a response will not be cached (1.7.7). If the header includes the "Vary" field with another value, such a response will be cached taking into account the corresponding request header fields (1.7.7).

根据文档,即缓存会考虑相应的请求头字段,对缓存进行管理。那么其实原理就跟在 cache key 中加入前缀是一样的。

总结

不管是更改 cache key 还是修改利用 Vary 都是实现一样的效果,且会占用内存。笔者认为在单系统中,两种方式其实都是可行的,排除掉恶意攻击,在既定的 origin 情况下,其实内存是不会占用多少,不管是更改 cache key 前缀或者使用 Vary。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!