聊聊高并发系统之HTTP缓存
副标题[/!--empirenews.page--]
《聊聊高并发系统之HTTP缓存》要点: 简介最近遇到很多人来咨询我关于浏览器缓存的一些问题,而这些问题都是类似的,因此总结本文来解答以后遇到类似问题的朋友. 因本文主要以浏览器缓存场景介绍,所以非浏览器场景下的一些用法本文不会介绍,而且本文以chrome为测试浏览器. 浏览器缓存是指当我们使用浏览器访问一些网站页面或者http服务时,根据服务端返回的缓存设置响应头将响应内容缓存到浏览器,下次可以直接使用缓存内容或者仅需要去服务端验证内容是否过期即可.这样的好处可以减少浏览器和服务端之间来回传输的数据量,节省带宽提升性能. 首先看个例子;当我们第一次访问http://item.jd.com/1856588.html时将得到如下响应头: 然后接着按F5刷新页面,将得到如下响应头 第二次返回的相应状态码为304,表示服务端文档没有修过过,浏览器缓存的内容还是最新的.
接下来我们看下如何在Java应用层控制浏览器缓存. 示例Last-Modified如下是我们的spring mvc缓存测试代码: @RequestMapping("/cache") public ResponseEntity<String> cache( ? ? ?HttpServletRequest request,? ? ?//为了方便测试,此处传入文档最后修改时间 ? ? ?@RequestParam("millis") long lastModifiedMillis,? ? ?//浏览器验证文档内容是否修改时传入的Last-Modified ? ? ?@RequestHeader (value = "If-Modified-Since",required = false) Date ifModifiedSince) { ? ?//当前系统时间 ? ?long now = System.currentTimeMillis(); ? ?//文档可以在浏览器端/proxy上缓存多久 ? ?long maxAge = 20; ? ?//判断内容是否修改了,此处使用等值判断 ? ?if(ifModifiedSince != null && ifModifiedSince.getTime() == lastModifiedMillis) { ? ? ? ?return new ResponseEntity<String>(HttpStatus.NOT_MODIFIED); ? ?} ? ?DateFormat gmtDateFormat = new SimpleDateFormat("EEE,d MMM yyyy HH:mm:ss 'GMT'",Locale.US); ? ?String body = "<a href=''>点击访问当前链接</a>"; ? ?MultiValueMap<String,String> headers = new HttpHeaders(); ? ?//文档修改时间 ? ?headers.add("Last-Modified",gmtDateFormat.format(new Date(lastModifiedMillis))); ? ?//当前系统时间 ? ?headers.add("Date",gmtDateFormat.format(new Date(now))); ? ?//过期时间 http 1.0支持 ? ?headers.add("Expires",gmtDateFormat.format(new Date(now + maxAge))); ? ?//文档生存时间 http 1.1支持 ? ?headers.add("Cache-Control","max-age=" + maxAge); ? ?return new ResponseEntity<String>(body,headers,HttpStatus.OK); } 为了方便测试,测试时将文档的修改时间通过millis参数传入,实际应用时可以使用如商品的最后修改时间等替代. 首次访问首次访问http://localhost:9080/cache?millis=1471349916709,将得到如下响应头: 响应状态码200表示请求内容成功,另外有如下几个缓存控制参数: Last-Modified:表示文档的最后修改时间,当去服务器验证时会拿这个时间去; Expires:http/1.0规范定义,表示文档在浏览器中的过期时间,当缓存的内容超过这个时间则需要重新去服务器获取最新的内容; Cache-Control:http/1.1规范定义,表示浏览器缓存控制,max-age=20表示文档可以在浏览器中缓存20秒. 根据规范定义Cache-Control优先级高于Expires;实际使用时可以两个都用,或仅使用Cache-Control就可以了(比如京东的活动页sale.jd.com).一般情况下Expires=当前系统时间(Date) + 缓存时间(Cache-Control: max-age).大家可以在如上测试代码进行两者单独测试,缓存都是可行的. F5刷新接着按F5刷新当前页面,将看到浏览器发送如下请求头: 此处发送时有一个If-Modified-Since请求头,其值是上次请求响应中的Last-Modified,即浏览器会拿这个时间去服务端验证内容是否发生了变更.接着收到如下响应信息: 响应状态码为304,表示服务端告诉浏览器说“浏览器你缓存的内容没有变化,直接使用缓存内容展示吧”. 注:在测试时要过一段时间更改下参数millis来表示内容修改了,要不然会一直看到304响应. Ctrl+F5强制刷新如果你想强制从服务端获取最新的内容,可以按Ctrl+F5: 浏览器在请求时不会带上If-Modified-Since,并带上Cache-Control:no-cache和Pragma:no-cache,这是为了告诉服务端说我请给我一份最新的内容. from cache当我们按F5刷新、Ctrl+F5强制刷新、地址栏输入地址刷新时都会去服务端验证内容是否发生了变更.那什么情况才不去服务端验证呢?即有些朋友还会发现有一些“from cache”的情况,这是什么情况下发生的呢? 从A页面跳转到A页面或者从A页面跳转到B页面时: 大家可以通过如上方式模拟,即从A页面跳转到A页面也是情况1.此时如果内容还在缓存时间之内,直接从浏览器获取的内容,而不去服务端验证. 访问页面http://item.jd.com/11056556.html,然后点击面包屑中的HTTP权威指南时会跳转到当前页面,此时看到如下结果,页面及页面异步加载的一些js、css、图片都from cache了. 还有如通过浏览器历史记录进行前进后退时也会走from cache.本文是基于chrome 52.0.2743.116 m版本测试,不同浏览器行为可能存在差异. Age一般用于代理层(如CDN),大家在访问京东一些页面时会发现有一个Age响应头,然后强制刷新(Ctrl+F5)后会发现其不断的变化;其表示此内容在代理层从缓存到现在经过了多长时间了,即在代理层缓存了多长时间了. Vary(编辑:上饶站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |