かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その7 )( src/main/resources/static の下の css や js ファイルにアクセスできない原因とは? )

概要

記事一覧はこちらです。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その6 )( FindBugs 3.0.1 → SpotBugs 3.1.7 に切り替える ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • ここまでいろいろ変更したので Tomcat を起動して画面から正常に動作するか確認しようとしたところ、最初のログイン画面が正常に表示されていませんでした。
    • CSS が適用されていないようなのですが、原因を調査します。

参照したサイト・書籍

目次

  1. Spring Boot 1.5 の時と 2.0 の時の CSS のリクエスト・レスポンスを比較してみる
  2. src/main/resources/static の下のファイルにアクセスできない原因を調査・解消する
  3. src/main/resources/static の下のファイルにキャッシュ期間を設定する

手順

Spring Boot 1.5 の時と 2.0 の時の CSS のリクエスト・レスポンスを比較してみる

1.5 の時はログイン画面は正常に表示されていたので、1.5 の時と 2.0 の時の CSS のリクエスト・レスポンスを比較してみます。まずは 2.0 から。

Tomcat を起動して DevTools を起動した Chromehttp://localhost:8080/ にアクセスすると、コンソールに MIMEtext/html になっているというエラーメッセージが表示されています。

f:id:ksby:20180929091430p:plain

  • Refused to apply style from '<URL>' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
  • Refused to execute script from 'http://localhost:8080/' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.

Fiddler でログイン画面表示時のキャプチャを取得し、/css/bootstrap.min.css のリクエスト・レスポンスを見てみると、以下のようになっていました。

f:id:ksby:20180929091845p:plain

HTTP/1.1 302
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Location: http://localhost:8080/
Content-Length: 0
Date: Sat, 29 Sep 2018 00:18:08 GMT

HTTPステータスコードが 302 で Location: http://localhost:8080/ ヘッダが返ってきていました。なぜかリダイレクトされています。。。

次に 1.5 の時を見てみます。master ブランチへ切り替えてから build し直して Tomcat を起動し、ブラウザでアクセスします。画面も正常に表示され、コンソールには何も表示されていません。

f:id:ksby:20180929194301p:plain

Fiddler で /css/bootstrap.min.css のリクエスト・レスポンスを見てみると、以下のようになっていました。

f:id:ksby:20180929194453p:plain

HTTP/1.1 200
Last-Modified: Sat, 29 Sep 2018 10:35:37 GMT
Cache-Control: no-store
Accept-Ranges: bytes
Content-Type: text/css
Content-Length: 117309
Date: Sat, 29 Sep 2018 10:44:10 GMT

HTTPステータスコードは 200 が返ってきます。

状況は分かったので 2.0 の作業用ブランチに戻します。Spring Boot 1.5+Spring Security の構成の時には src/main/resources/static の下のファイルにアクセスできた(200 が返ってきていた)のですが、Spring Boot 2.0+Spring Security の構成だとアクセスできなくなっているようです。

src/main/resources/static の下のファイルにアクセスできない原因を調査・解消する

stackoverflow で Serving static web resources in Spring Boot & Spring Security application という QA を見つけました。

この中の回答によると、1.5 以下では public/** or static/** がデフォルトで許可されていましたが、2.0 ではデフォルトで全て許可されなくなったそうです。

src/main/java/ksbysample/webapp/lending/config/WebSecurityConfig.java の以下の点を変更します。

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します
                // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します
                // .antMatchers("/country/**").permitAll()
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                .antMatchers("/fonts/**").permitAll()
                ..........
  • .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() を追加します。

Tomcat を起動してブラウザでアクセスすると、今度は画面が正常に表示されました。

f:id:ksby:20180930002750p:plain

Fiddler で見ると HTTPステータスコードの 200 が返ってきています。

f:id:ksby:20180930083514p:plain

HTTP/1.1 200
Last-Modified: Sat, 29 Sep 2018 23:28:18 GMT
Accept-Ranges: bytes
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: text/css
Content-Length: 117309
Date: Sat, 29 Sep 2018 23:34:21 GMT

src/main/resources/static の下のファイルにキャッシュ期間を設定する

※以降の変更はコミットはしません。

src/main/resources/static の下のファイルにアクセスできるようになりましたが、Cache-Control: no-cache, no-store, max-age=0, must-revalidate 等の HTTP ヘッダが付いていてキャッシュが無効になっています。css や js はキャッシュを設定したいことがあるので、設定してみます。

src/main/java/ksbysample/webapp/lending/config/WebMvcConfig.java に addResourceHandlers メソッドを override して設定します。

package ksbysample.webapp.lending.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;

import java.util.concurrent.TimeUnit;

/**
 * ???
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * Thymeleaf 3 のパフォーマンスを向上させるために SpEL コンパイラを有効にする
     *
     * @param templateEngine {@link SpringTemplateEngine} オブジェクト
     */
    @Autowired
    public void configureThymeleafSpringTemplateEngine(SpringTemplateEngine templateEngine) {
        templateEngine.setEnableSpringELCompiler(true);
    }

    /**
     * css, js のキャッシュ期間を設定する(css は 1時間、js は 15分)
     *
     * @param registry {@link ResourceHandlerRegistry} オブジェクト
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**")
                .addResourceLocations("classpath:/static/css/")
                .setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());

        registry.addResourceHandler("/js/**")
                .addResourceLocations("classpath:/static/js/")
                .setCacheControl(CacheControl.maxAge(15, TimeUnit.MINUTES).cachePublic());
    }

}

Tomcat を起動して css, js のレスポンスを見るとキャッシュ期間が設定されていることが確認できます。

/cssCache-Control: max-age=3600, public とキャッシュ期間が1時間で設定されています。

f:id:ksby:20180930092201p:plain

HTTP/1.1 200
Last-Modified: Sat, 29 Sep 2018 23:28:18 GMT
Cache-Control: max-age=3600, public
Accept-Ranges: bytes
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Content-Type: text/css
Content-Length: 117309
Date: Sun, 30 Sep 2018 00:20:13 GMT

/js は Cache-Control: max-age=900, public とキャッシュ期間が15分で設定されています。

f:id:ksby:20180930092307p:plain

HTTP/1.1 200
Last-Modified: Sat, 29 Sep 2018 23:28:18 GMT
Cache-Control: max-age=900, public
Accept-Ranges: bytes
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Content-Type: application/javascript
Content-Length: 84349
Date: Sun, 30 Sep 2018 00:20:13 GMT

履歴

2018/09/30
初版発行。