【发布时间】:2013-07-23 21:38:10
【问题描述】:
我正在尝试使用 Spring MVC 控制器提供一些资产。我的资产是由数据库管理的,因此必须以这种方式提供服务。该服务从数据库中查找资产的元数据,从文件系统中读取文件并构建响应。
这是我的控制器的样子。
@Controller
@RequestMapping("/assets")
public class AssetController {
@Autowired
private AssetService assetService;
@RequestMapping("/{assetName:.+}")
public ResponseEntity<byte[]> getAsset(@PathVariable("assetName") String assetName) throws FileNotFoundException, IOException {
Asset asset = assetService.findByName(assetName);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf(asset.getContentType()));
headers.setCacheControl("max-age=1209600");
headers.setLastModified(asset.getModifiedOn().getTime()); // always in the past
return new ResponseEntity<byte[]>(assetService.toBytes(asset), headers, OK);
}
}
看起来足够简单明了?人们希望看到浏览器缓存图像。但是尽管尝试了Cache-Control、Expires、Last-Modified-On 和ETag 的所有组合,但我没有成功。
以下是在两个连续请求期间吐出的 HTTP 标头(已删除的不相关标头)。
GET /adarshr-web/assets/Acer.png HTTP/1.1
Host: localhost:8080
Pragma: no-cache
Cache-Control: no-cache
HTTP/1.1 200 OK
Cache-Control: max-age=1209600
Last-Modified: Sun, 21 Jul 2013 11:56:32 GMT
Content-Type: image/png
Date: Tue, 23 Jul 2013 21:22:58 GMT
----------------------------------------------------------
GET /adarshr-web/assets/Acer.png HTTP/1.1
Host: localhost:8080
If-Modified-Since: Sun, 21 Jul 2013 11:56:32 GMT
Cache-Control: max-age=0
HTTP/1.1 200 OK <-- Why not 304 Not Modified?
Cache-Control: max-age=1209600
Last-Modified: Sun, 21 Jul 2013 11:56:32 GMT
Content-Type: image/png
Date: Tue, 23 Jul 2013 21:23:03 GMT
但是,当我在诸如
- http://www.google.co.uk/images/srpr/logo4w.png(Google 的徽标)
- http://fbstatic-a.akamaihd.net/rsrc.php/v2/yI/r/0PsXdTWc41M.png(Facebook 的手机图片)
我看到诸如此类的标头(针对 Facebook URL 显示)表明响应正在被浏览器缓存。
GET /rsrc.php/v2/yI/r/0PsXdTWc41M.png HTTP/1.1
Host: fbstatic-a.akamaihd.net
Pragma: no-cache
Cache-Control: no-cache
HTTP/1.1 200 OK
Content-Type: image/png
Last-Modified: Sat, 15 Jun 2013 00:48:42 GMT
Cache-Control: public, max-age=31535893
Expires: Wed, 23 Jul 2014 21:27:47 GMT
Date: Tue, 23 Jul 2013 21:29:34 GMT
----------------------------------------------------------
GET /rsrc.php/v2/yI/r/0PsXdTWc41M.png HTTP/1.1
Host: fbstatic-a.akamaihd.net
If-Modified-Since: Sat, 15 Jun 2013 00:48:42 GMT
Cache-Control: max-age=0
HTTP/1.1 304 Not Modified <-- Note this
Content-Type: image/png
Last-Modified: Sat, 15 Jun 2013 00:48:42 GMT
Cache-Control: public, max-age=31535892
Expires: Wed, 23 Jul 2014 21:27:47 GMT
Date: Tue, 23 Jul 2013 21:29:35 GMT
注意事项:
- 我的 Spring 配置中没有
<mvc:resources />部分,因为我在控制器中执行的操作完全相同。即使添加它也没有任何区别。 - 由于上述原因,我没有在 Spring 配置中再次定义
org.springframework.web.servlet.mvc.WebContentInterceptor。我试过添加一个,但没有任何收获。 - 我已经尝试了https://developers.google.com/speed/docs/best-practices/caching 中解释的所有方法。
- 我可以在所有浏览器中复制它。
【问题讨论】:
-
我是否应该实现将
If-Modified-Since请求标头值与asset.getModifiedOn值进行比较并返回304的逻辑?是不是有点太低级了? -
你必须执行最后修改的检查,幸运的是 Spring 让这很容易:static.springsource.org/spring/docs/3.1.x/…
-
@Devon_C_Miller 是的,这似乎可以解决问题。您可以将其发布为答案,以便我奖励您吗?
-
您好 +adarshr,您能否提供您如何实现本主题中提到的答案?我似乎仍然有麻烦。你用这个方法分开了吗?
-
@Moody 与下面接受的答案没有太大区别。除了,我的返回
ResponseEntity<byte[]>而不是String。
标签: java http caching spring-mvc