プログラミング

実装・エラー解決

Spring MVCのレスポンスヘッダでno-store,no-cacheを付与する

この記事に書いてあること

Spring MVCを使っていて、レスポンスヘッダにno-storeやno-cacheという項目を付与したい場面があったのでメモ。

旧Spring MVCのXML設定は、既存システムを保守するときの参考として残します。以下にSpring Boot 3.5.16で実行したJava版も示します。

前提

  • Spring MVC 5.x
  • Java11

結論

Spring MVCの現在の書き方では、保存を禁止したいレスポンスに Cache-Control: no-store を設定します。no-cache は再利用する前に検証を求める指示です。個人データを返すAPIの保存を禁止し、公開ヘルプだけは5分間の共有キャッシュを許可する例を比較します。

実行用サンプル

JDK 17とMaven 3.9系で mvn test を実行します。ZIPにはソース全文・テスト・pom.xml・READMEを収録しています。

CacheController.java の全文

package info.syachiku.auditweb;

import java.time.Duration;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
class CacheController {
    @GetMapping("/account/details")
    ResponseEntity<String> accountDetails() {
        return ResponseEntity.ok()
                .cacheControl(CacheControl.noStore())
                .body("テスト用の個人データ");
    }

    @GetMapping("/help")
    ResponseEntity<String> help() {
        return ResponseEntity.ok()
                .cacheControl(CacheControl.maxAge(Duration.ofMinutes(5)).cachePublic())
                .body("公開ヘルプ");
    }
}

MockMvcで /account/details の Cache-Control が no-store、/help が max-age=300, public になることを確認しました。例の個人データはテスト用の固定文字列です。実際の個人データへのアクセス制御は認証・認可で行います。

ここからは旧世代の servlet-context.xml による設定例です。出力はSpringのバージョンと設定に依存します。

Cache-Control: no-cache, no-store
Pragma: no-cache
Expires: 0

次は旧システムの設定を読み解くための例です。現在の新規設定には先に示した CacheControl を使います。

<interceptors>
  <bean id="webContentInterceptor"
        class="org.springframework.web.servlet.mvc.WebContentInterceptor">
    <property name="cacheSeconds" value="0"/>
    <property name="useExpiresHeader" value="true"/>
    <property name="useCacheControlHeader" value="true"/>
    <property name="useCacheControlNoStore" value="true"/>
  </bean>
</interceptors>

なお、servlet-context.xmlの書き方次第では、mvc:interceptorsとしたり、beans:beanとしないといけない場合があります。

ちょっと説明

cacheSeconds

  • -1: キャッシュ関連のヘッダーは出力しません。
  • 0: no cache 関連のヘッダーが出力されます。
  • 1以上: 100を指定した場合、'Cache-Control: max-age=100'というヘッダが出力されます。

useExpiresHeader

trueにすると、Expiresヘッダが出力されます。

Expires: Thu, 01 Jan 1970 00:00:00 GMT

useCacheControlHeader

trueにすると、以下のヘッダが出力されます。

Cache-Control: no-cache

useCacheControlNoStore

trueにすると、以下のヘッダが出力されます。

Cache-Control: no-store

-実装・エラー解決
-,