1. 概要

ほとんどのWebアプリケーションには、要求のロギング、検証、認証などの操作を実行するユースケースがあります。 さらに、このようなタスクは通常、HTTPエンドポイントのセット間で共有されます。

幸いなことに、Spring Webフレームワークは、まさにこの目的のためにフィルタリングメカニズムを提供します。

このチュートリアルでは、フィルタースタイルのタスクを特定のURLセットの実行に含めたり除外したりする方法を学習します。

2. 特定のURLのフィルター

Webアプリケーションが、パスやコンテンツタイプなど、リクエストに関する情報をログに記録する必要があるとします。 これを行う1つの方法は、ロギングフィルターを作成することです。

2.1. ロギングフィルター

まず、 OncePerRequestFilterクラスを拡張し、doFilterInternalメソッドを実装する LogFilter クラスでロギングフィルターを作成しましょう:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
  FilterChain filterChain) throws ServletException, IOException {
    String path = request.getRequestURI();
    String contentType = request.getContentType();
    logger.info("Request URL path : {}, Request content type: {}", path, contentType);
    filterChain.doFilter(request, response);
}

2.1. ルールインフィルター

選択したURLパターンに対してのみロギングタスクを実行する必要があると仮定します。 /健康 /よくある質問/*。 このために、ログフィルターを使用して登録します FilterRegistrationBean 必要なURLパターンのみに一致するように:

@Bean
public FilterRegistrationBean<LogFilter> logFilter() {
    FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new LogFilter());
    registrationBean.addUrlPatterns("/health","/faq/*");
    return registrationBean;
}

2.2. 除外フィルター

ロギングタスクの実行からURLを除外する場合は、次の2つの方法で簡単に実現できます。

  • 新しいURLの場合、フィルターで使用されるURLパターンと一致しないことを確認してください
  • 以前にロギングが有効にされていた古いURLの場合、このURLを除外するようにURLパターンを変更できます

3. 可能なすべてのURLをフィルタリングする

LogFilter にURLを含めるという以前のユースケースは、最小限の労力で簡単に満たすことができました。 ただし、フィルターがワイルドカード(*)を使用してすべての可能なURLパターンに一致する場合は、トリッキーになります。

この状況では、包含ロジックと除外ロジックを自分で作成する必要があります。

3.1. カスタムフィルター

クライアントは、リクエストヘッダーを使用して、有用な情報をサーバーに送信できます。 現在、Webアプリケーションが米国でのみ動作しているとしましょう。つまり、他の国からのリクエストを処理したくないということです。

さらに、WebアプリケーションがX-Country-Codeリクエストヘッダーを介してロケールを示していると想像してみましょう。 したがって、各リクエストにはこの情報が含まれており、フィルターを使用する明確なケースがあります。

ヘッダーをチェックするFilterを実装して、条件を満たさないリクエストを拒否しましょう。

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
      FilterChain filterChain) throws ServletException, IOException {

    String countryCode = request.getHeader("X-Country-Code");
    if (!"US".equals(countryCode)) {
        response.sendError(HttpStatus.BAD_REQUEST.value(), "Invalid Locale");
        return;
    }

    filterChain.doFilter(request, response);
}

3.2. フィルター登録

まず、let’s use the フィルタを登録するためのアスタリスク(*)ワイルドカード 考えられるすべてのURLパターンに一致させるには:

@Bean
public FilterRegistrationBean<HeaderValidatorFilter> headerValidatorFilter() {
    FilterRegistrationBean<HeaderValidatorFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new HeaderValidatorFilter());
    registrationBean.addUrlPatterns("*");
    return registrationBean;
}

後で、ロケール要求ヘッダー情報を検証するタスクを実行するために必要とされないURLパターンを除外することができます。

4. URLの除外

このセクションでは、お客様のFilterのURLを除外する方法を学習します。

4.1. 素朴な戦略

/ health に、アプリケーションのピンポンヘルスチェックを実行するために使用できるWebルートがあることをもう一度想像してみてください。

これまでのところ、すべてのリクエストがフィルターをトリガーします。 推測できるように、ヘルスチェックに関してはオーバーヘッドです。

それでは、 / health リクエストをフィルターの本体から除外して、単純化しましょう。

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
  FilterChain filterChain) throws ServletException, IOException {
    String path = request.getRequestURI();
    if ("/health".equals(path)) {
    	filterChain.doFilter(request, response);
    	return;
    }

    String countryCode = request.getHeader("X-Country-Code");
    // ... same as before
}

doFilterメソッド内にこのカスタムロジックを追加すると、/healthエンドポイントとフィルターの間に結合が導入されることに注意する必要があります。 そのため、 doFilter メソッド内で対応する変更を行わずにヘルスチェックエンドポイントを変更すると、フィルタリングロジックが破損する可能性があるため、最適ではありません。

4.2. shouldNotFilterメソッドの使用

以前のアプローチでは、URL除外とフィルターのタスク実行ロジックの間に緊密な結合を導入しました。 他の部分に変更を加えることを意図しているときに、ある部分に誤ってバグを導入する可能性があります。

代わりに、 shouldNotFilter メソッドをオーバーライドすることで、2セットのロジックを分離できます。

@Override
protected boolean shouldNotFilter(HttpServletRequest request)
  throws ServletException {
    String path = request.getRequestURI();
    return "/health".equals(path);
}

その結果、 doInternalFilter()メソッドは、単一責任の原則を尊重します。

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
  FilterChain filterChain) throws ServletException, IOException {
    String countryCode = request.getHeader("X-Country-Code");
    // ... same as before
}

5. 結論

このチュートリアルでは、Spring Boot WebアプリケーションのサーブレットフィルターからURLパターンを除外する方法について、ロギングとリクエストヘッダーの検証という2つのユースケースについて説明しました。

さらに、すべての可能なURLパターンを照合するために*ワイルドカードを使用するフィルターの特定のURLセットを除外するのは難しいことを学びました

いつものように、チュートリアルの完全なソースコードは、GitHubから入手できます。