聊聊高并发系统之HTTP缓存(2)
一般用于代理层(如CDN),用于代理层和浏览器协商什么情况下使用哪个版本的缓存内容(比如压缩版和非压缩版),即什么情况下后续请求才能使用代理层缓存的该版本内容,比如如下响应是告知浏览器Content-Encoding:gzip,即缓存代理层缓存了gzip版本的内容;那么后续的请求在请求时Accept-Encoding头部中包含gzip时才能使用改代理层缓存. Via一般用于代理层(如CDN),表示访问到最终内容经过了哪些代理层,用的什么协议,代理层是否缓存命中等等;通过它可以进行一些故障诊断. ETag@RequestMapping("/cache/etag") public ResponseEntity<String> cache( ? ? ?HttpServletRequest request,? ? ?HttpServletResponse response,? ? ?//浏览器验证文档内容的实体 If-None-Match ? ? ?@RequestHeader (value = "If-None-Match",required = false) String ifNoneMatch) { ? ?//当前系统时间 ? ?long now = System.currentTimeMillis(); ? ?//文档可以在浏览器端/proxy上缓存多久 ? ?long maxAge = 10; ? ?String body = "<a href=''>点击访问当前链接</a>"; ? ?//弱实体 ? ?String etag = "W/\"" + md5(body) + "\""; ? ?if(StringUtils.equals(ifNoneMatch,etag)) { ? ? ? ?return new ResponseEntity<String>(HttpStatus.NOT_MODIFIED); ? ?} ? ?DateFormat gmtDateFormat = new SimpleDateFormat("EEE,Locale.US); ? ?MultiValueMap<String,String> headers = new HttpHeaders(); ? ?//ETag http 1.1支持 ? ?headers.add("ETag",etag); ? ?//当前系统时间 ? ?headers.add("Date",gmtDateFormat.format(new Date(now))); ? ?//文档生存时间 http 1.1支持 ? ?headers.add("Cache-Control",HttpStatus.OK); } 其中ETag用于发送到服务端进行内容变更验证的,而Catch-Control是用于控制缓存时间的(浏览器、代理层等).此处我们使用了弱实体W\”343sda”,弱实体(”343sda”)只要内容语义没变即可,比如内容的gzip版和非gzip版可以使用弱实体验证;而强实体指字节必须完全一致(gzip和非gzip情况是不一样的),因此建议首先选择使用弱实体.nginx在生成etag时使用的算法是Last-Modified + Content-Length计算的: ngx_sprintf(etag->value.data,”\&;%xT-%xO\&;”, r->headers_out.last_modified_time, r->headers_out.content_length_n) 到此简单的基于文档修改时间和过期时间的缓存控制就介绍完了,在内容型响应我们大多数根据内容的修改时间来进行缓存控制,ETag根据实际需求而定(比如).另外还可以使用html Meta标签控制浏览器缓存,但是对代理层缓存无效,因此不建议使用. 总结1、服务端响应的Last-Modified会在下次请求时以If-Modified-Since请求头带到服务端进行文档是否修改的验证,如果没有修改则返回304,浏览器可以直接使用缓存内容; 2、Cache-Control:max-age和Expires用于决定浏览器端内容缓存多久,即多久过期,过期后则删除缓存重新从服务端获取最新的;另外可以用于from cache场景; 3、http/1.1规范定义的Cache-Control优先级高于http/1.0规范定义的Expires; 4、一般情况下Expires=当前系统时间 + 缓存时间(Cache-Control:max-age); 5、http/1.1规范定义了ETag来通过文档摘要的方式控制. Last-Modified与ETag同时使用时,浏览器在验证时会同时发送If-Modified-Since和If-None-Match,按照http/1.1规范,如果同时使用If-Modified-Since和If-None-Match则服务端必须两个都验证通过后才能返回304;且nginx就是这样做的.因此实际使用时应该根据实际情况选择.还有If-Match和If-Unmodified-Since本文就不介绍了. 接下来我们看下如何使用nginx进行缓存控制. nginx缓存设置nginx提供了expires、etag、if-modified-since指令来进行浏览器缓存控制. expires假设我们使用nginx作为静态资源服务器,此时可以使用expires进行缓存控制. location /img { alias /export/img/; expires 1d; } 当我们访问静态资源时,如http://192.168.61.129/img/1.jpg,将得到类似如下的响应头: (编辑:ASP站长网) |