【问题标题】:how to add cache control headers to image served by spring mvc如何将缓存控制标头添加到 spring mvc 提供的图像中
【发布时间】:2015-02-14 14:58:54
【问题描述】:

我正在尝试在 Spring MVC 中实现二进制内容控制器。

一切正常,但我想在响应中添加缓存控制标头。

我检查了这个相关问题:Unable to cache images served by Spring MVC

但它使用了不同的方法。我想使用这个 requestMapping - 产生注释。到目前为止,这是我所拥有的,但我不确定如何使用缓存控制元素设置响应标头。

@RequestMapping(value="/binaries/**", method = RequestMethod.GET, produces={MediaType.TEXT_PLAIN_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.IMAGE_GIF_VALUE,
 MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
public @ResponseBody byte[] serveResource(WebRequest webRequest, String uri) throws IOException {
    String path = (String)request.getAttribute( HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE );

    BinaryFile bf = binaryService.findByUri(path.replaceFirst("/binaries", ""));
    if (webRequest.checkNotModified(bf.getLastModifiedDate().toDate().getTime()))
    {
        return null;
    };
    return bf.getResource();
}

【问题讨论】:

    标签: spring-mvc


    【解决方案1】:

    你可以像这样使用ResponseEntity

    @ResponseBody
    public ResponseEntity<byte[]> serveResource() {
        //..
        return ResponseEntity.ok()
                 .lastModified(lastModified)
                 .body(bf);
    }
    

    serve resources directly with Spring Resource Handling support

    请注意multiple HTTP caching improvements are scheduled for Spring Framework 4.2,现在是时候就此发表您的意见了(您可以对问题发表评论/投票)。

    【讨论】:

    • 感谢我正在使用 Spring 资源,但是因为我正在通过应用程序上传文件,所以似乎没有一种好方法可以将它们可靠地存储在 J2ee 集群中的文件系统上。我在 Stack Overflow 上读到的所有内容都建议将它们存储在持久存储中。标头可以正常工作,但最后修改的内容在 HTTPS 中无法正常工作,并且 max-age 似乎不适用于浏览器刷新(我不确定是否应该这样做)。
    • 哦,我顺便配置了WebContentInterceptor把headers放上了。
    【解决方案2】:

    这个怎么样:

    public @ResponseBody byte[] serveResource(WebRequest webRequest, HttpServletResponse response, String uri) throws IOException {
      response.addHeader("Cache-Control", "private, max-age=0, no-cache");
    // ...
    

    【讨论】:

      【解决方案3】:

      所以我只是重新实现了资源处理,并认为我会将答案发布回这个问题。

      基本上我使用了新的 ResourceHandling 框架,而且实现起来非常容易。

      1. 创建了一个由 DB 中的 CLOB 支持的 BinaryImage 类。从 Spring 4.1+ 实现 Resource 接口。

      2. 然后我创建了一个新的ResourceResolver,它根据已知路径“/images”查找传入的请求。

      3. 然后在WebMVC框架中进行配置。

      2 & 3 的代码如下(1 被省略,实现接口很简单):

      /**
       * The Frontend Binary Controller
       */
      @Component
      public class BinaryResourceResolver implements ResourceResolver{
      
          private static Logger logger = LogManager.getLogger(BinaryResourceResolver.class.getName());
      
          @Autowired
          HttpServletRequest request;
      
          @Autowired
          BinaryImageService binaryService;
      
          @Override
          public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations, ResourceResolverChain chain) {
              if (!requestPath.startsWith("/"))
              {
                  requestPath = "/" + requestPath;
              }
              Resource bf = binaryService.findByUrl(requestPath);
      
              return bf;
          }
      
          @Override
          public String resolveUrlPath(String resourcePath, List<? extends Resource> locations, ResourceResolverChain chain) {
              return null;
          }
      
      
      }
      

      那么配置代码:在一个扩展WebMVCConfigurerAdapter的配置类中

      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
              registry.addResourceHandler("/resources/**").addResourceLocations(new String[]{"/resources/", "/products/", "/categories/"})
                      .setCachePeriod(30);
              registry.addResourceHandler("/assets/**").addResourceLocations(new String[]{"/assets/"}).setCachePeriod(3600);
              registry.addResourceHandler("/frontend/**").addResourceLocations(new String[]{"/frontend/"}).setCachePeriod(3600);
      
      
          registry.addResourceHandler("/images/**").setCachePeriod(3600).resourceChain(true).addResolver(binaryResourceResolver);
          registry.setOrder(-1);
      }
      

      【讨论】:

        【解决方案4】:

        您应该在返回字节数组时提供最后修改的标头

        if (webRequest.checkNotModified(bf.getLastModifiedDate().toDate().getTime()))
        {
            return null;
        };
        
        SimpleDateFormat dateFormat=new SimpleDateFormat();
        response.addHeader("Last-Modified",    dateFormat.format(bf.getLastModifiedDate().toDate().getTime()));   
        return bf.getResource();
        

        【讨论】:

          猜你喜欢
          • 2011-10-08
          • 2016-06-12
          • 1970-01-01
          • 2011-10-28
          • 2012-05-23
          • 1970-01-01
          • 2019-03-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多