You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Grails中如何缓存从数据库读取的图片?

实现数据库存储图片的浏览器缓存

要让从数据库读取的图片被浏览器缓存,核心是给响应添加HTTP缓存头,并处理浏览器的缓存验证请求(返回304 Not Modified)。以下是具体实现步骤:

1. 完善FileData域类,添加更新时间字段

首先需要给存储图片的FileData添加记录最后修改时间的字段,作为缓存验证的依据:

class FileData {
    String path
    byte[] data
    Date lastUpdated // 记录资源最后修改时间

    static constraints = {
        path blank: false, unique: true
        data nullable: false, maxSize: 16_777_215
    }

    static mapping = {
        autoTimestamp true // 开启Grails自动时间戳维护,自动更新lastUpdated
    }
}

2. 修改控制器uploads方法,添加缓存头与验证逻辑

在返回图片数据前,添加缓存相关响应头,并处理浏览器的缓存验证请求,避免重复传输图片数据:

def uploads(String path) {
    FileData imageData = FileData.findByPath("/${path}")
    if (!imageData) {
        response.sendError(404)
        return
    }

    // 生成ETag:用资源ID+最后更新时间作为唯一标识,内容变化时ETag自动改变
    String eTag = "\"${imageData.id}-${imageData.lastUpdated.time}\""
    // 设置Last-Modified头:告知浏览器资源最后修改时间
    response.setDateHeader("Last-Modified", imageData.lastUpdated.time)
    // 设置ETag头:资源的唯一标识,比Last-Modified验证更精确
    response.setHeader("ETag", eTag)
    // 设置Cache-Control:允许公共缓存(如CDN、代理),缓存时长设为1年(可按需调整)
    response.setHeader("Cache-Control", "public, max-age=31536000")

    // 验证浏览器的缓存请求:如果资源未修改,直接返回304 Not Modified
    String ifNoneMatch = request.getHeader("If-None-Match")
    long ifModifiedSince = request.getDateHeader("If-Modified-Since")

    // 匹配ETag 或者 Last-Modified未过期,返回304
    if ((ifNoneMatch != null && ifNoneMatch.equals(eTag)) ||
        (ifModifiedSince != -1 && imageData.lastUpdated.time <= ifModifiedSince + 1000)) {
        response.sendError(304)
        return
    }

    // 资源有更新,返回图片数据
    response.contentType = URLConnection.guessContentTypeFromName(path) ?: 'application/octet-stream'
    response.getOutputStream().withCloseable { out ->
        out.write(imageData.data)
        out.flush()
    }
}

关键缓存头说明

  • Cache-Control: public, max-age=31536000:
    • public:允许CDN、代理服务器等公共缓存节点缓存该资源,提升访问速度;
    • max-age=31536000:告诉浏览器可以直接缓存该资源1年,期间无需向服务器发起请求。
  • Last-Modified:记录资源最后修改的时间戳,浏览器下次请求会携带If-Modified-Since头,服务器对比后判断资源是否更新。
  • ETag:资源的唯一标识,当资源内容(或修改时间)变化时ETag会改变,浏览器请求时携带If-None-Match头,服务器匹配一致则返回304。

额外说明

你当前图片URL中的?1676524906000时间戳参数可以保留,当需要强制刷新缓存(比如更新图片内容)时,修改这个时间戳即可让浏览器重新请求新资源;配合上面的缓存头,正常情况下浏览器会优先使用本地缓存,无需重复下载。

内容的提问来源于stack exchange,提问作者kofhearts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:56:20