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

Spring应用中HTTP 304 Not Modified状态码的适用场景与优势

HTTP 304 Not Modified 在Spring应用中的实战场景与性能价值

核心逻辑回顾

304 Not Modified 是HTTP缓存体系的关键状态码:客户端请求资源时,携带之前服务端返回的Last-Modified(资源最后修改时间)或ETag(资源唯一标识),服务端比对后确认资源未更新,就返回304,让客户端直接复用本地缓存内容,无需传输完整响应体。

实战场景与Spring实现示例

1. 静态资源缓存(JS/CSS/图片)

Spring Boot默认对classpath:/static/下的静态资源做基础缓存配置,可自定义优化强化304逻辑:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)
                        .mustRevalidate()); // 强制客户端过期后验证资源状态
    }
}

用户二次请求同一静态资源时,会自动携带If-Modified-Since请求头,Spring资源处理器会比对文件最后修改时间,一致则返回304,避免重复传输大体积静态文件。

2. 低频更新的动态内容(文章详情、用户资料)

对于不频繁改动的动态页面/数据,可手动实现304验证逻辑:

@GetMapping("/article/{id}")
public ResponseEntity<Article> getArticle(@PathVariable Long id,
                                          @RequestHeader(value = "If-Modified-Since", required = false) String ifModifiedSince) {
    Article article = articleService.getById(id);
    if (article == null) {
        return ResponseEntity.notFound().build();
    }

    // 把文章更新时间转为HTTP标准的GMT格式
    String lastModified = DateTimeFormatter.RFC_1123_DATE_TIME.format(
            article.getUpdateTime().atZone(ZoneId.of("GMT")));

    if (lastModified.equals(ifModifiedSince)) {
        // 资源未修改,返回304
        return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();
    }

    // 返回资源并携带Last-Modified响应头
    return ResponseEntity.ok()
            .header(HttpHeaders.LAST_MODIFIED, lastModified)
            .body(article);
}

用户刷新页面时,若文章未更新,服务端直接返回304,客户端复用本地缓存内容,减少数据库查询和响应体传输开销。

3. 公共数据API接口(城市列表、商品分类)

针对更新频率极低的公共数据接口,用ETag做精确校验(比Last-Modified更适合内容无时间变化但可能被修改的场景):

@GetMapping("/api/cities")
public ResponseEntity<List<City>> getCities(@RequestHeader(value = "If-None-Match", required = false) String ifNoneMatch) {
    List<City> cities = cityService.getAllCities();
    // 用数据的MD5生成唯一ETag
    String etag = "\"" + DigestUtils.md5DigestAsHex(JacksonUtils.writeValueAsBytes(cities)) + "\"";

    if (etag.equals(ifNoneMatch)) {
        return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();
    }

    return ResponseEntity.ok()
            .header(HttpHeaders.ETAG, etag)
            .body(cities);
}

比如编辑城市名称后又改回原内容,Last-Modified会变化但内容不变,ETag能准确识别资源未改动,返回304。

最佳实践

  • 优先复用Spring原生缓存能力:静态资源尽量依赖Spring Boot自动配置,避免手动重复实现基础逻辑;
  • 按需选择校验方式:文件类资源用Last-Modified(实现简单),动态内容优先用ETag(校验更精确);
  • 合理设置缓存过期策略:静态资源可设30天有效期,动态内容设1-24小时,同时启用mustRevalidate,确保资源更新后客户端能获取最新版本;
  • 避免滥用304:实时性要求极高的资源(如实时订单状态)禁用304,防止客户端获取旧数据。

性能与效率提升点

  • 大幅减少带宽消耗:304响应体为空,相比传输完整响应体,静态资源场景可节省90%以上带宽;
  • 降低服务器负载:减少数据库查询、序列化/反序列化操作,降低CPU和内存占用,提升服务器并发处理能力;
  • 优化用户体验:客户端直接复用本地缓存,页面加载速度显著提升,减少等待时间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:23:24